このコミットが含まれているのは:
2026-10-26 12:44:22 +09:00
コミット f91f9d0eb5
23個のファイルの変更、637行の追加、316行の削除
+17 -13
ファイルの表示
@@ -2,24 +2,24 @@ import { useState } from 'react'
import DateTimeField from '@/components/common/DateTimeField'
import { Button } from '@/components/ui/button'
import { countsFieldLabel, countsFilterFields, countsOperators, readCountsJSON }
import { countsFieldLabel, countsFilterFields, readCountsJSON, useCountsDefinition }
from '@/lib/countsDefinitions'
import useDialogue from '@/lib/dialogues/useDialogue'
import { inputClass } from '@/lib/utils'
import { useUITranslation } from '@/lib/useUITranslation'
import type { CountsResource } from '@/lib/counts'
import type { CountsCondition } from '@/lib/countsDefinitions'
import type { CountsCondition, CountsDefinition } from '@/lib/countsDefinitions'
const ConditionEditor = ({ resource, initial, save }: {
resource: CountsResource; initial?: CountsCondition
const ConditionEditor = ({ definition, initial, save }: {
definition: CountsDefinition; initial?: CountsCondition
save: (condition: CountsCondition) => void },
) => {
const { label, message } = useUITranslation ('counts')
const fields = countsFilterFields (resource)
const fields = countsFilterFields (definition)
const [field, setField] = useState (initial?.field ?? 'resource_id')
const [operator, setOperator] = useState (initial?.operator ?? 'eq')
const operators = definition.fields.find (item => item.key === field)?.operators ?? []
return <div className="space-y-2">
<select value={field} aria-label={message ('field').text} className={inputClass ()}
onChange={event => { setField (event.target.value); setOperator ('eq') }}>
@@ -28,7 +28,7 @@ const ConditionEditor = ({ resource, initial, save }: {
</select>
<select value={operator} aria-label={message ('operator').text} className={inputClass ()}
onChange={event => setOperator (event.target.value)}>
{countsOperators[fields[field]].map (key => <option key={key} value={key}>
{operators.map (key => <option key={key} value={key}>
{message (`operators.${key}`).text}</option>)}
</select>
<Button type="button" onClick={() => save ({ ...initial, field, operator })}>
@@ -37,17 +37,19 @@ const ConditionEditor = ({ resource, initial, save }: {
}
const CountsAdditionalConditions = ({ resource, params, update }: {
resource: CountsResource; params: URLSearchParams
const CountsAdditionalConditions = ({ params, update }: {
params: URLSearchParams
update: (key: string, value: string) => void },
) => {
const { label, message } = useUITranslation ('counts')
const definition = useCountsDefinition ()
const dialogue = useDialogue ()
const conditions = readCountsJSON<CountsCondition[]> (params, 'conditions', [])
const write = (next: CountsCondition[]) => update ('conditions', JSON.stringify (next))
const edit = (index?: number) => {
void dialogue.form ({ title: label ('additionalConditions'), body: controls => (
<ConditionEditor resource={resource} initial={index == null ? undefined : conditions[index]}
<ConditionEditor definition={definition}
initial={index == null ? undefined : conditions[index]}
save={condition => {
write (index == null ? [...conditions, condition]
: conditions.map ((item, position) => position === index ? condition : item))
@@ -61,10 +63,11 @@ const CountsAdditionalConditions = ({ resource, params, update }: {
<Button type="button" variant="outline" size="sm" onClick={() => edit ()}>
{label ('add')}</Button></legend>
{conditions.map ((condition, index) => {
const datetime = countsFilterFields (resource)[condition.field] === 'datetime'
const datetime = countsFilterFields (definition)[condition.field] === 'datetime'
return <div key={index} className="flex flex-wrap items-center gap-1">
<button type="button" onClick={() => edit (index)}>
{label (countsFieldLabel (condition.field))} · {label (`operators.${condition.operator}`)}
{label (countsFieldLabel (condition.field))}
{' · '}{label (`operators.${condition.operator}`)}
</button>
{(condition.operator === 'range' ? ['value', 'end'] as const : ['value'] as const)
.map (key => datetime ? <DateTimeField precision="second" key={key}
@@ -80,7 +83,8 @@ const CountsAdditionalConditions = ({ resource, params, update }: {
onChange={event => patch (index, { blank: event.target.checked })}/>
{label ('blank')}</label>
<button type="button" aria-label={message ('remove').text}
onClick={() => write (conditions.filter ((_, position) => index !== position))}>×</button>
onClick={() => write (conditions.filter (
(_, position) => index !== position))}>×</button>
</div>
})}
</fieldset>