From a9136d8c0f5f717e969a80528be56166c06cd4d5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 09:47:07 +0000 Subject: [PATCH 1/2] fix(console): Flow Runs reads the served flat flow item only, and its fixtures feed that shape (objectui#12829) The flow list's `loadFlows` normalization read `name` and `label` as `it.spec.X ?? it.X` and kept `spec: it.spec ?? it`. No server of `meta.getItems('flow')` wraps an item in `spec`: objectstack's `readFlattenedMetaItems` serves the definitions themselves (the `?preview=draft` path included), and the spec types `items` as unknown. The arm goes, with the `updatedAt ?? updated_at` read nothing renders, and every fixture that fed the wrapped shape now feeds the served one. The objectui#12783 pin's wrapped case now pins that a wrapped item is not read. Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB --- .../consoleFaces.displayLocale-9909.test.tsx | 2 +- ...FlowRunsPage.flattenedLabel-12783.test.tsx | 22 +++++++++---------- .../FlowRunsPage.sharedSelect-11865.test.tsx | 7 +++--- .../src/pages/developer/FlowRunsPage.test.tsx | 3 ++- .../src/pages/developer/FlowRunsPage.tsx | 16 ++++++-------- ...ataEnvelope.contractEnvelope-6917.test.tsx | 11 +++++----- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/apps/console/src/pages/consoleFaces.displayLocale-9909.test.tsx b/apps/console/src/pages/consoleFaces.displayLocale-9909.test.tsx index faf8f3959e..0b2a183969 100644 --- a/apps/console/src/pages/consoleFaces.displayLocale-9909.test.tsx +++ b/apps/console/src/pages/consoleFaces.displayLocale-9909.test.tsx @@ -70,7 +70,7 @@ const { STORED, approvalsApiStub, ADAPTER, AUTH, I18N } = vi.hoisted(() => { // its flow and run loads on it, so a fresh one per call re-ran them on every // render and its runs table never settled (objectui#11865 surfaced it). const client = { - meta: { getItems: async (type: string) => (type === 'flow' ? [{ spec: { name: 'sync_flow', label: 'Sync' } }] : []) }, + meta: { getItems: async (type: string) => (type === 'flow' ? [{ name: 'sync_flow', label: 'Sync' }] : []) }, automation: { execute: async () => ({ success: true }), listRuns, getRun: async () => ({ run: null }) }, }; const ADAPTER = { diff --git a/apps/console/src/pages/developer/FlowRunsPage.flattenedLabel-12783.test.tsx b/apps/console/src/pages/developer/FlowRunsPage.flattenedLabel-12783.test.tsx index 9485bd23f9..a913416ad9 100644 --- a/apps/console/src/pages/developer/FlowRunsPage.flattenedLabel-12783.test.tsx +++ b/apps/console/src/pages/developer/FlowRunsPage.flattenedLabel-12783.test.tsx @@ -10,18 +10,19 @@ * the flat item but the label from `it.spec.label` alone, so on a real server * every flow was listed by its API name only, `showcase_batch_reminders` where * "Batch Task Reminders (Loop) (showcase_batch_reminders)" belongs. The page's - * other suites feed `{ spec: {...} }` items, which is why none of them saw it. + * other suites fed `{ spec: {...} }` items, which is why none of them saw it. * * What is pinned: * - a flattened answer, shaped as the served list is: the option text is * `label (name)`; - * - a `spec`-wrapped answer: the same text (the page still reads that form, - * `spec` first, as it reads the name); + * - a `spec`-wrapped item is NOT read (objectui#12829): no server serves that + * shape, so the page keeps no arm for it and such an item lists no flow; * - an unlabelled flow: its bare name, not the name standing in for a label. * - * DIRECTION, observed on unchanged `main`: the flattened case is red there (the - * option reads the bare name); the other two are green there by design, as - * no-regression guards for the forms the fix must not disturb. + * DIRECTION, observed on unchanged `main` at objectui#12783: the flattened case + * was red there (the option read the bare name); the unlabelled case is green + * by design, as a no-regression guard. The `spec`-wrapped case is red on any + * page that still reads a `spec` arm (objectui#12829). */ import '@testing-library/jest-dom/vitest'; @@ -100,19 +101,16 @@ describe('the flow picker names a labelled flow by its label (objectui#12783)', ]); }); - it('a spec-wrapped answer: the same text', async () => { + it('a spec-wrapped item is not read: it lists no flow (objectui#12829)', async () => { catalog.answer = { type: 'flow', items: [ { spec: { name: 'showcase_batch_reminders', label: 'Batch Task Reminders (Loop)', variables: [] } }, - { spec: { name: 'nightly_sync', variables: [] } }, ], }; render(); - expect(await optionTexts()).toEqual([ - 'Batch Task Reminders (Loop) (showcase_batch_reminders)', - 'nightly_sync', - ]); + expect(await screen.findByText('No flow definitions found.')).toBeInTheDocument(); + expect(screen.queryByRole('combobox')).not.toBeInTheDocument(); }); it('an unlabelled flow: its bare name, never the name doubled as a label', async () => { diff --git a/apps/console/src/pages/developer/FlowRunsPage.sharedSelect-11865.test.tsx b/apps/console/src/pages/developer/FlowRunsPage.sharedSelect-11865.test.tsx index 8104e7a02c..dcae3bd013 100644 --- a/apps/console/src/pages/developer/FlowRunsPage.sharedSelect-11865.test.tsx +++ b/apps/console/src/pages/developer/FlowRunsPage.sharedSelect-11865.test.tsx @@ -36,7 +36,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'; const { execute, listRuns, catalog, ADAPTER } = vi.hoisted(() => { - const catalog = { flows: [] as Array<{ spec: Record }> }; + const catalog = { flows: [] as Array> }; const execute = vi.fn(async () => ({ success: true, status: 'completed', durationMs: 1 })); const listRuns = vi.fn(async () => ({ runs: [] })); // A STABLE singleton: a fresh object per render loops the page's fetch effects. @@ -56,8 +56,9 @@ vi.mock('@object-ui/app-shell', async (importOriginal) => ({ // Imported AFTER the mocks so the page picks them up. import { FlowRunsPage } from './FlowRunsPage'; -const REASSIGN = { spec: { name: 'reassign_wizard', label: 'Reassign', variables: [] } }; -const NIGHTLY = { spec: { name: 'nightly_sync', variables: [] } }; +// Flows as the server lists them: flattened, `name` and `label` on the item (objectui#12829). +const REASSIGN = { name: 'reassign_wizard', label: 'Reassign', variables: [] }; +const NIGHTLY = { name: 'nightly_sync', variables: [] }; beforeEach(() => { catalog.flows = [REASSIGN, NIGHTLY]; diff --git a/apps/console/src/pages/developer/FlowRunsPage.test.tsx b/apps/console/src/pages/developer/FlowRunsPage.test.tsx index 9295d58460..89a6355db8 100644 --- a/apps/console/src/pages/developer/FlowRunsPage.test.tsx +++ b/apps/console/src/pages/developer/FlowRunsPage.test.tsx @@ -40,7 +40,8 @@ const { execute, ADAPTER, authFetch } = vi.hoisted(() => { })); const ADAPTER = { getClient: () => ({ - meta: { getItems: async (type: string) => (type === 'flow' ? [{ spec: flow }] : []) }, + // The served list item IS the flow definition (objectui#12829). + meta: { getItems: async (type: string) => (type === 'flow' ? [flow] : []) }, automation: { execute, listRuns: async () => ({ runs: [] }) }, }), }; diff --git a/apps/console/src/pages/developer/FlowRunsPage.tsx b/apps/console/src/pages/developer/FlowRunsPage.tsx index 5147dc4b43..0b2baeeb1a 100644 --- a/apps/console/src/pages/developer/FlowRunsPage.tsx +++ b/apps/console/src/pages/developer/FlowRunsPage.tsx @@ -66,7 +66,6 @@ interface FlowItem { name: string; label?: string; spec?: any; - updatedAt?: string; } interface RunSummary { @@ -218,15 +217,14 @@ export function FlowRunsPage() { : Array.isArray(result?.items) ? result.items : []; - // The served list is flattened: `name` and `label` sit on the item - // itself, with no `spec` member. Both are read the same way, `spec` - // first, so the picker names a labelled flow `label (name)` on the list - // the server answers (objectui#12783). + // The served list is flattened: each item IS the flow definition, its + // `name` and `label` on the item itself, so the picker names a labelled + // flow `label (name)` (objectui#12783). No server wraps an item in a + // `spec` member, so none is read (objectui#12829). const normalized: FlowItem[] = items.map(it => ({ - name: it?.spec?.name ?? it?.name, - label: it?.spec?.label ?? it?.label, - spec: it?.spec ?? it, - updatedAt: it?.updatedAt ?? it?.updated_at, + name: it?.name, + label: it?.label, + spec: it, })).filter(f => f.name); setFlows(normalized); if (!selectedFlowName && normalized.length > 0) { diff --git a/apps/console/src/pages/developer/developerMetadataEnvelope.contractEnvelope-6917.test.tsx b/apps/console/src/pages/developer/developerMetadataEnvelope.contractEnvelope-6917.test.tsx index 2658f4cdee..4c2c077804 100644 --- a/apps/console/src/pages/developer/developerMetadataEnvelope.contractEnvelope-6917.test.tsx +++ b/apps/console/src/pages/developer/developerMetadataEnvelope.contractEnvelope-6917.test.tsx @@ -77,13 +77,12 @@ vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } })); import { FlowRunsPage } from './FlowRunsPage'; import { PublicFormsPage } from './PublicFormsPage'; -/** A flow definition, as `meta.getItems('flow')` rows carry it. */ +/** A flow definition, as `meta.getItems('flow')` rows carry it: the item IS + * the definition, flattened, with no `spec` member (objectui#12829). */ const FLOW = { - spec: { - name: 'reassign_wizard', - label: 'Reassign', - variables: [{ name: 'recordId', type: 'text', isInput: true }], - }, + name: 'reassign_wizard', + label: 'Reassign', + variables: [{ name: 'recordId', type: 'text', isInput: true }], }; /** A published public form, on the `ViewItem` shape `GET /meta/view` serves: From 3b75d796ee9ad9e317cc6033e16c7662880ff731 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 09:54:55 +0000 Subject: [PATCH 2/2] chore(changeset): declare objectui#12829 as releasing nothing Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB --- .changeset/12829-flow-runs-flat-items.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changeset/12829-flow-runs-flat-items.md diff --git a/.changeset/12829-flow-runs-flat-items.md b/.changeset/12829-flow-runs-flat-items.md new file mode 100644 index 0000000000..061486a385 --- /dev/null +++ b/.changeset/12829-flow-runs-flat-items.md @@ -0,0 +1,4 @@ +--- +--- + +Console Flow Runs page: the flow list reads the served flat `meta.getItems('flow')` item only (`name` and `label` on the item itself), and the page's test fixtures feed that shape. The removed `spec`-wrapped arm had no producer: no server serves that shape, so no behaviour a user can reach changes and nothing is released (objectui#12829).