このコミットが含まれているのは:
@@ -1,9 +1,10 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import CountsConditionValues from '@/components/counts/CountsConditionValues'
|
||||
import DateTimeField from '@/components/common/DateTimeField'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { countsEventTypes, countsFieldLabel, countsFilterFields,
|
||||
useCountsDefinition }
|
||||
import { countsConditionInputs, countsEventTypes, countsFieldLabel, countsFilterFields,
|
||||
countsSetOperators, useCountsDefinition }
|
||||
from '@/lib/countsDefinitions'
|
||||
import useDialogue from '@/lib/dialogues/useDialogue'
|
||||
import { inputClass } from '@/lib/utils'
|
||||
@@ -33,12 +34,14 @@ const ConditionEditor = (
|
||||
})
|
||||
const { field, operator } = condition
|
||||
const operators = fields.find (item => item.key === field)?.operators ?? []
|
||||
const inputs = countsConditionInputs (fields.find (item => item.key === field), operator)
|
||||
useEffect (() => {
|
||||
controls.setActions ([{ label: label (initial == null ? 'add' : 'shared:actions.edit'),
|
||||
onSelect: () => save (condition) }])
|
||||
}, [controls, condition, initial, label, save])
|
||||
return <div className="space-y-2">
|
||||
<select value={field} aria-label={message ('field').text} className={inputClass ()}
|
||||
<select value={field} aria-label={message ('field').text}
|
||||
className={inputClass (false, 'h-9 w-full')}
|
||||
onChange={event => {
|
||||
const field = event.target.value
|
||||
const operator = fields.find (item => item.key === field)?.operators[0]
|
||||
@@ -47,17 +50,39 @@ const ConditionEditor = (
|
||||
{fields.filter (field => field.operators.length > 0).map (field => (
|
||||
<option key={field.key} value={field.key}>{fieldName (field.key)}</option>))}
|
||||
</select>
|
||||
<select value={operator} aria-label={message ('operator').text} className={inputClass ()}
|
||||
<select value={operator} aria-label={message ('operator').text}
|
||||
className={inputClass (false, 'h-9 w-full')}
|
||||
onChange={event => setCondition (previous => {
|
||||
const operator = event.target.value
|
||||
const next = { ...previous, operator }
|
||||
if (operator !== 'range') delete next.end
|
||||
if ((operator === 'like') !== (previous.operator === 'like')) delete next.value
|
||||
const choices = countsConditionInputs (fields.find (item => item.key === field), operator)
|
||||
if (countsSetOperators.includes (operator))
|
||||
{
|
||||
delete next.value
|
||||
delete next.end
|
||||
next.input = choices.includes (previous.input ?? 'single') ? previous.input : choices[0]
|
||||
}
|
||||
else
|
||||
{
|
||||
delete next.values
|
||||
delete next.input
|
||||
}
|
||||
return next
|
||||
})}>
|
||||
{operators.map (key => <option key={key} value={key}>
|
||||
{message (`operators.${key}`).text}</option>)}
|
||||
</select>
|
||||
<label className="block text-sm">{label ('pattern.input')}
|
||||
<select value={condition.input ?? inputs[0]}
|
||||
className={inputClass (false, 'h-9 w-full')}
|
||||
onChange={event => setCondition (previous => ({ ...previous,
|
||||
input: event.target.value as CountsCondition['input'] }))}>
|
||||
{inputs.map (input => <option key={input} value={input}>
|
||||
{message (`pattern.${input}`).text}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -99,7 +124,7 @@ const CountsAdditionalConditions = ({ params, update }: {
|
||||
const options: string[] = type === 'boolean' ? ['true', 'false'] : [...countsEventTypes]
|
||||
const namespace = type === 'boolean' ? 'truthValues' : 'events'
|
||||
return <select value={condition[key] ?? ''} disabled={condition.blank}
|
||||
className={inputClass (false, 'h-7 w-36 min-w-0 max-w-full py-1')}
|
||||
className={inputClass (false, 'h-9 w-36 min-w-0 max-w-full py-1')}
|
||||
aria-label={aria.text}
|
||||
lang={aria.language}
|
||||
onChange={event => patch (index, { [key]: event.target.value })}>
|
||||
@@ -110,13 +135,13 @@ const CountsAdditionalConditions = ({ params, update }: {
|
||||
</select>
|
||||
}
|
||||
if (type === 'datetime')
|
||||
return <DateTimeField precision="second" className="h-7 w-48 min-w-0 max-w-full py-1"
|
||||
return <DateTimeField precision="second" className="h-9 w-48 min-w-0 max-w-full py-1"
|
||||
value={condition[key] ?? ''} disabled={condition.blank}
|
||||
aria-label={aria.text} lang={aria.language}
|
||||
onChange={value => patch (index, { [key]: value ?? '' })}/>
|
||||
return <input value={condition[key] ?? ''} disabled={condition.blank}
|
||||
type={(type === 'integer' || type === 'interval') ? 'number' : 'text'}
|
||||
className={inputClass (false, 'h-7 w-36 min-w-0 max-w-full py-1')}
|
||||
className={inputClass (false, 'h-9 w-36 min-w-0 max-w-full py-1')}
|
||||
aria-label={aria.text} lang={aria.language}
|
||||
onChange={event => patch (index, { [key]: event.target.value })}/>
|
||||
}
|
||||
@@ -130,24 +155,32 @@ const CountsAdditionalConditions = ({ params, update }: {
|
||||
<Button type="button" variant="ghost" size="sm" onClick={() => edit (index)}
|
||||
aria-label={`${fieldName (condition.field)} ${message (
|
||||
`operators.${condition.operator}`).text}`}
|
||||
className="h-7 min-w-0 max-w-full justify-start gap-2 whitespace-normal px-1 text-left">
|
||||
className="min-w-0 max-w-full justify-start gap-2 whitespace-normal px-1 text-left">
|
||||
<span className="min-w-0 break-words">{fieldName (condition.field)}</span>
|
||||
{condition.operator !== 'range' && <span aria-hidden="true" className="shrink-0">
|
||||
{label (`operatorSymbols.${condition.operator}`)}</span>}
|
||||
</Button>
|
||||
{countsSetOperators.includes (condition.operator) ? (
|
||||
<CountsConditionValues key={`${condition.field}:${condition.operator}`}
|
||||
condition={condition}
|
||||
field={metadata.find (field => field.key === condition.field)!}
|
||||
definition={definition} params={params}
|
||||
maximum={Math.max (0, 100 - conditions.reduce ((sum, item, position) =>
|
||||
sum + (position === index ? 0 : item.values?.length ?? 0), 0))}
|
||||
change={values => patch (index, { values })}/>) : (
|
||||
<div className="inline-flex min-w-0 max-w-full items-center gap-1">
|
||||
{valueInput (condition, index, 'value')}
|
||||
{condition.operator === 'range' && <>
|
||||
<span aria-hidden="true" className="shrink-0">{label ('operatorSymbols.range')}</span>
|
||||
{valueInput (condition, index, 'end')}
|
||||
</>}
|
||||
</div>
|
||||
</div>)}
|
||||
<div className="inline-flex shrink-0 items-center gap-1">
|
||||
<label className="inline-flex items-center gap-1 text-sm">
|
||||
<input type="checkbox" checked={condition.blank ?? false}
|
||||
onChange={event => patch (index, { blank: event.target.checked })}/>
|
||||
{label ('blank')}</label>
|
||||
<Button type="button" variant="ghost" size="sm" className="h-7 px-1"
|
||||
<Button type="button" variant="ghost" size="sm" className="px-1"
|
||||
aria-label={message ('remove').text}
|
||||
onClick={() => write (conditions.filter ((_, position) => index !== position))}>
|
||||
×</Button>
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする