From 11ea36f18ebcaadf6ecf8ea6870ad8267e4e2f3b Mon Sep 17 00:00:00 2001 From: Jesus Armando Anaya Date: Tue, 18 Aug 2026 16:21:52 -0700 Subject: [PATCH] fix(schema): preview narrowing before publishing --- frontend/ui-core/src/patterns/ClassFields.tsx | 16 + frontend/ui-core/src/screens/SchemaEditor.tsx | 298 ++++++----- frontend/ui-core/src/screens/queries.ts | 16 + .../ui-core/src/screens/schemaDraft.test.tsx | 10 + frontend/ui-core/src/screens/screens.test.tsx | 503 ++++++++++++++++-- 5 files changed, 680 insertions(+), 163 deletions(-) diff --git a/frontend/ui-core/src/patterns/ClassFields.tsx b/frontend/ui-core/src/patterns/ClassFields.tsx index 793bcdfd..26bab9dc 100644 --- a/frontend/ui-core/src/patterns/ClassFields.tsx +++ b/frontend/ui-core/src/patterns/ClassFields.tsx @@ -80,6 +80,8 @@ export interface ClassFieldsProps { readonly swatch: string; /** The digit the annotator would bind, or `null` past the ninth class. */ readonly hotkey: number | null; + /** Lock every field while the caller is persisting this exact value. */ + readonly disabled?: boolean; readonly onChange: (next: LabelClassBody) => void; } @@ -88,6 +90,7 @@ export function ClassFields({ slot, swatch, hotkey, + disabled = false, onChange, }: ClassFieldsProps): JSX.Element { return ( @@ -98,6 +101,7 @@ export function ClassFields({ onChange({ ...declared, name: event.target.value })} /> @@ -145,6 +149,7 @@ export function ClassFields({ type="checkbox" className="accent-primary" data-testid={`class-geometry-${slot}-${geometry}`} + disabled={disabled} checked={checked} onChange={(event) => { const next = event.target.checked @@ -193,6 +198,7 @@ export function ClassFields({ data-testid={`class-color-${slot}`} type="color" className="h-9 w-12 rounded-md border border-input bg-card p-1" + disabled={disabled} value={hexOf(swatch)} onChange={(event) => onChange({ ...declared, color: event.target.value })} /> @@ -203,6 +209,7 @@ export function ClassFields({ variant="ghost" size="sm" data-testid={`clear-color-${slot}`} + disabled={disabled} onClick={() => onChange({ ...declared, color: null })} > Derive @@ -225,6 +232,7 @@ export function ClassFields({ onChange({ ...declared, attributes })} /> @@ -258,10 +266,12 @@ export function swatchOf(declared: LabelClassBody, index: number): string { function Attributes({ attributes, classIndex, + disabled, onChange, }: { readonly attributes: readonly AttributeBody[]; readonly classIndex: string; + readonly disabled: boolean; readonly onChange: (next: AttributeBody[]) => void; }): JSX.Element { return ( @@ -272,6 +282,7 @@ function Attributes({ variant="ghost" size="sm" data-testid={`add-attribute-${classIndex}`} + disabled={disabled} onClick={() => onChange([...attributes, { name: "", kind: "string", required: false, default: null }]) } @@ -294,6 +305,7 @@ function Attributes({ onChange(replace(attributes, index, { ...attribute, name: event.target.value })) @@ -305,6 +317,7 @@ function Attributes({ Kind onChange( @@ -386,6 +401,7 @@ function Attributes({ size="icon" aria-label={`Remove attribute ${index + 1}`} data-testid={`remove-attribute-${classIndex}-${index}`} + disabled={disabled} onClick={() => onChange(attributes.filter((_, i) => i !== index))} >