From cb56e472dd18967f47a446aeeb7b1299c7d4703c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 09:55:48 +0000 Subject: [PATCH 1/5] feat(app-shell): Data pillar header buttons, seven flat tabs with a 1000 px fold, flush Records body (objectui#12450) Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw Co-authored-by: Claude --- .../src/views/metadata-admin/i18n.ts | 4 + .../DataPillar.flatTabs-12450.test.tsx | 212 ++++++++++++++++++ .../studio-design/StudioDesignSurface.tsx | 142 +++++++++--- .../src/views/studio-design/dataTabsFold.ts | 37 +++ packages/plugin-list/src/ListView.tsx | 4 + 5 files changed, 365 insertions(+), 34 deletions(-) create mode 100644 packages/app-shell/src/views/studio-design/DataPillar.flatTabs-12450.test.tsx create mode 100644 packages/app-shell/src/views/studio-design/dataTabsFold.ts diff --git a/packages/app-shell/src/views/metadata-admin/i18n.ts b/packages/app-shell/src/views/metadata-admin/i18n.ts index 586378f59d..e13e2d076b 100644 --- a/packages/app-shell/src/views/metadata-admin/i18n.ts +++ b/packages/app-shell/src/views/metadata-admin/i18n.ts @@ -3394,6 +3394,8 @@ const ENGINE_STRINGS_EN: Record = { 'engine.studio.hooks.newLabel': 'New hook', 'engine.studio.data.addFieldTitle': 'Add a field (then set its type and properties on the right)', 'engine.studio.data.addField': 'Add field', + 'engine.studio.data.objectSettings': 'Object settings', + 'engine.studio.data.moreActions': 'More actions', 'engine.studio.data.editFieldProps': 'Edit field properties', 'engine.studio.data.draftObjectTitle': 'Unpublished new object', 'engine.studio.data.draftObjectHint': @@ -6546,6 +6548,8 @@ const ENGINE_STRINGS_ZH: Record = { 'engine.studio.hooks.newLabel': '新钩子', 'engine.studio.data.addFieldTitle': '添加一个字段(随后在右侧设置类型与属性)', 'engine.studio.data.addField': '添加字段', + 'engine.studio.data.objectSettings': '对象设置', + 'engine.studio.data.moreActions': '更多操作', 'engine.studio.data.editFieldProps': '编辑字段属性', 'engine.studio.data.draftObjectTitle': '未发布的新对象', 'engine.studio.data.draftObjectHint': diff --git a/packages/app-shell/src/views/studio-design/DataPillar.flatTabs-12450.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.flatTabs-12450.test.tsx new file mode 100644 index 0000000000..9316815d72 --- /dev/null +++ b/packages/app-shell/src/views/studio-design/DataPillar.flatTabs-12450.test.tsx @@ -0,0 +1,212 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * objectui#12450 — the Data pillar's flat tab row, and the object header's two + * icon buttons. + * + * Decision B of epic objectui#12446 (maintainer, 2026-10-15): seven flat tabs + * — Records, Form, Validations, Hooks, Actions, API, Settings — when the + * content column is 1000 px or wider; narrower, the last five fold back into + * "Advanced ▾". The folded form keeps its own pins in + * `DataPillar.advancedKeepsName-11794.test.tsx`; this file pins the flat form. + * + * What a DOM test can and cannot see: happy-dom evaluates no container query, + * so both forms are in the tree here, exactly as they are in a browser, and + * which one is DISPLAYED is decided by CSS this environment does not run. The + * pins therefore read what decides it — the content column is the query + * container, the five flat tabs carry the class that displays them at the + * fold width and above, the Advanced trigger carries the class that hides it + * there, and both classes name `DATA_TABS_FOLD_WIDTH` — and the browser + * screenshots on the pull request show the two widths rendered. + * + * The REAL `DataPillar`; the records grid and two panels are stubbed, because + * only which panel is open is under test, not what it draws. + */ + +import '@testing-library/jest-dom/vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render, screen, waitFor, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MemoryRouter } from 'react-router-dom'; + +const servedObject = { + name: 'showcase_account', + label: 'Account', + fields: { name: { type: 'text', label: 'Account Name' } }, +}; + +const mockClient = { + list: vi.fn(async () => [{ name: 'showcase_account', label: 'Account' }]), + listDrafts: vi.fn(async () => []), + layered: vi.fn(async () => ({ effective: servedObject, code: servedObject })), + getDraft: vi.fn(async () => null), + save: vi.fn(async () => ({ ok: true })), +}; + +vi.mock('../metadata-admin/useMetadata', async (importOriginal) => { + const mod = await importOriginal(); + return { ...mod, useMetadataClient: () => mockClient, useMetadataTypes: () => ({ entries: [] }) }; +}); + +vi.mock('./packages-io', async (importOriginal) => { + const mod = await importOriginal(); + return { ...mod, fetchPackages: vi.fn(async () => []) }; +}); + +vi.mock('@object-ui/react', async (importOriginal) => { + const mod = await importOriginal(); + return { ...mod, useAdapter: () => ({}) }; +}); + +vi.mock('@object-ui/plugin-view', async (importOriginal) => { + const mod = await importOriginal>(); + return { ...mod, ObjectView: () =>
}; +}); + +vi.mock('./ObjectValidationsPanel', () => ({ ObjectValidationsPanel: () =>
})); +vi.mock('./ObjectSettingsPanel', () => ({ ObjectSettingsPanel: () =>
})); + +import { DataPillar } from './StudioDesignSurface'; +import { SurfaceDeepLinkProvider } from './surfaceDeepLinkChannel'; +import { + DATA_CONTENT_CONTAINER, + DATA_TAB_FLAT_ONLY, + DATA_TAB_FOLDED_ONLY, + DATA_TABS_FOLD_WIDTH, +} from './dataTabsFold'; +import { t } from '../metadata-admin/i18n'; + +const FLAT_KEYS = ['rules', 'hooks', 'actions', 'api', 'settings'] as const; +const ROW_NAMES = ['records', 'form', ...FLAT_KEYS].map((k) => t(`engine.studio.data.tab.${k}`, 'en')); +const ADVANCED = t('engine.studio.data.tab.advanced', 'en'); + +afterEach(() => { + cleanup(); + vi.clearAllMocks(); +}); + +async function renderPillar(props: { readOnly?: boolean } = {}) { + render( + + + + + , + ); + await waitFor(() => expect(screen.getByTestId('records-panel')).toBeInTheDocument(), { timeout: 8000 }); +} + +/** The header's tab row: the `nav` the item header draws its tabs into. */ +function tabRow(): HTMLElement { + const nav = screen.getByTestId('data-object-header').querySelector('nav'); + expect(nav, 'the object header draws no tab row').not.toBeNull(); + return nav as HTMLElement; +} + +/** Split a class attribute into its tokens. */ +function classesOf(el: Element): string[] { + return (el.getAttribute('class') ?? '').split(/\s+/).filter(Boolean); +} + +describe('the Data pillar’s seven flat tabs (objectui#12450)', () => { + it('both class strings name the fold width, so the rule and its constant cannot drift apart', () => { + const query = `@min-[${DATA_TABS_FOLD_WIDTH}px]:`; + expect(DATA_TABS_FOLD_WIDTH).toBe(1000); + expect(DATA_TAB_FLAT_ONLY.split(' ')).toEqual(['hidden', `${query}inline-flex`]); + expect(DATA_TAB_FOLDED_ONLY.split(' ')).toEqual([`${query}hidden`]); + }); + + it('the tab row holds the seven tabs in the artboard’s order, then the folded trigger', async () => { + await renderPillar(); + const row = tabRow(); + const buttons = within(row).getAllByRole('button'); + expect(buttons.map((b) => b.textContent)).toEqual([...ROW_NAMES, ADVANCED]); + expect(buttons.at(-1)).toBe(screen.getByTestId('data-tabs-advanced')); + }); + + it('the content column is the query container, and it holds the tab row it measures for', async () => { + await renderPillar(); + const column = screen.getByTestId('data-content-column'); + expect(classesOf(column)).toContain(DATA_CONTENT_CONTAINER); + expect(column).toContainElement(tabRow()); + }); + + it('the five panels’ flat tabs display only at the fold width and above; the trigger only below it', async () => { + await renderPillar(); + for (const key of FLAT_KEYS) { + const tab = screen.getByTestId(`data-tab-flat-${key}`); + for (const cls of DATA_TAB_FLAT_ONLY.split(' ')) expect(classesOf(tab)).toContain(cls); + // `cn` merges the tab's own `inline-flex` away: an unconditional + // display class left beside `hidden` would show the tab at every width. + expect(classesOf(tab)).not.toContain('inline-flex'); + } + const trigger = screen.getByTestId('data-tabs-advanced'); + expect(classesOf(trigger)).toContain(DATA_TAB_FOLDED_ONLY); + expect(classesOf(trigger)).not.toContain('hidden'); + }); + + it('CONTROL: Records and Form are displayed at every width', async () => { + await renderPillar(); + const row = tabRow(); + for (const name of ROW_NAMES.slice(0, 2)) { + const tab = within(row).getByRole('button', { name }); + expect(classesOf(tab)).toContain('inline-flex'); + expect(classesOf(tab)).not.toContain('hidden'); + expect(classesOf(tab).some((c) => c.startsWith('@'))).toBe(false); + } + }); + + it('a flat tab opens its panel and takes the active underline; the folded trigger mirrors it', async () => { + await renderPillar(); + const validations = screen.getByTestId('data-tab-flat-rules'); + expect(validations).toHaveAttribute('aria-pressed', 'false'); + + await userEvent.click(validations); + await waitFor(() => expect(screen.getByTestId('rules-panel')).toBeInTheDocument()); + expect(validations).toHaveAttribute('aria-pressed', 'true'); + // The two forms say the same thing: at the narrower width the trigger is + // the one on screen, and it shows a power panel is open. + expect(screen.getByTestId('data-tabs-advanced')).toHaveAttribute('aria-pressed', 'true'); + + await userEvent.click(screen.getByTestId('data-tab-flat-settings')); + await waitFor(() => expect(screen.getByTestId('settings-panel')).toBeInTheDocument()); + expect(screen.queryByTestId('rules-panel')).toBeNull(); + expect(validations).toHaveAttribute('aria-pressed', 'false'); + expect(screen.getByTestId('data-tab-flat-settings')).toHaveAttribute('aria-pressed', 'true'); + }); +}); + +describe('the object header’s icon buttons (objectui#12450)', () => { + const OBJECT_SETTINGS = t('engine.studio.data.objectSettings', 'en'); + const MORE_ACTIONS = t('engine.studio.data.moreActions', 'en'); + const ADD_FIELD = t('engine.studio.data.addField', 'en'); + + it('each is named by an aria-label; Object settings opens the Settings panel', async () => { + await renderPillar(); + const header = screen.getByTestId('data-object-header'); + const settings = within(header).getByRole('button', { name: OBJECT_SETTINGS }); + expect(settings).toHaveAttribute('aria-label', OBJECT_SETTINGS); + expect(within(header).getByRole('button', { name: MORE_ACTIONS })).toHaveAttribute('aria-label', MORE_ACTIONS); + + await userEvent.click(settings); + await waitFor(() => expect(screen.getByTestId('settings-panel')).toBeInTheDocument()); + expect(screen.getByTestId('data-tab-flat-settings')).toHaveAttribute('aria-pressed', 'true'); + }); + + it('More holds Add field, which adds a field and opens its inspector', async () => { + await renderPillar(); + // Add field left the header row: no labelled button for it there now. + const header = screen.getByTestId('data-object-header'); + expect(within(header).queryByRole('button', { name: ADD_FIELD })).toBeNull(); + + await userEvent.click(screen.getByTestId('data-object-more')); + await userEvent.click(await screen.findByRole('menuitem', { name: ADD_FIELD })); + expect(await screen.findByTestId('data-field-inspector', undefined, { timeout: 4000 })).toBeInTheDocument(); + }); + + it('CONTROL: a read-only package keeps Object settings and draws no More, whose one entry it does not offer', async () => { + await renderPillar({ readOnly: true }); + expect(screen.getByTestId('data-object-settings')).toBeInTheDocument(); + expect(screen.queryByTestId('data-object-more')).toBeNull(); + }); +}); diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx index 49eca97add..12a4c43efd 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx @@ -34,6 +34,7 @@ import { AppMark, type AppMarkApp } from '../../layout/AppMark.js'; import { STUDIO_HEADER, STUDIO_HEADER_ICON_BUTTON, STUDIO_KIND_CHIP } from './studio-tokens.js'; import { StudioInspector } from './StudioInspector.js'; import { StudioItemHeader, StudioTab } from './StudioItemHeader.js'; +import { DATA_CONTENT_CONTAINER, DATA_TAB_FLAT_ONLY, DATA_TAB_FOLDED_ONLY } from './dataTabsFold.js'; import { StudioRail, StudioRailRow } from './StudioRail.js'; import { GridFieldAuthoringProvider, @@ -101,11 +102,13 @@ import { ChevronDown, Lock, Settings, + Settings2, Home as HomeIcon, Shield, ShieldCheck, ShieldQuestion, Menu, + MoreHorizontal, PanelRightClose, PanelRightOpen, type LucideIcon, @@ -4468,11 +4471,26 @@ export function renderStudioGridList(props: { // the channel and dropped the leftover parameter). ...listSchema, viewType: 'grid', - showSearch: true, - showSort: true, - showFilters: true, - showGroup: true, - showHideFields: true, + // objectui#12450 — the Records toolbar the Data pillar's artboard + // draws: Hide fields, Filter, Group and Sort as labelled buttons, + // then Refresh, Search and Add record. That is the list's wide form + // (`compactToolbar: false`, one button per control); the bundled + // Display form the console's list pages default to (objectui#12423) + // would fold Hide fields and Group away. Density is not offered: the + // artboard has no density control. The toggles are spelled in + // `userActions`, the protocol's home for them (the bare `show*` + // spellings this used are retired tombstones, objectui#7924), and + // the slot's own `userActions` — what a view declares — still wins. + compactToolbar: false, + userActions: { + search: true, + sort: true, + filter: true, + group: true, + hideFields: true, + rowHeight: false, + ...(listSchema.userActions as Record | undefined), + }, inlineEdit: true, addDeleteRecordsInline: true, // Fold "+ New" into this toolbar (next to Hide fields/Filter/Group/ @@ -5107,15 +5125,13 @@ export function DataPillar({ // rendered fills the field rail below without a remount. const inspector = useRegisteredMetadataInspector('object'); - // The object-level tabs (Data pillar). A shadcn/HIG segmented control: a - // recessed `bg-muted` track with an elevated `bg-background` pill on the - // active segment — the inverse of the old transparent-track/grey-active - // styling, which read as toolbar chrome rather than a distinct nav layer. + // The object-level tabs (Data pillar): underline tabs in the item header. // objectui#5813 — the 90% path is Records / Form (fields ARE the grid's - // columns, with Add field right beside them, so a separate fields tab would - // ADD a surface, not remove one). The five power tabs keep their panels - // untouched behind one "Advanced" menu — capability stays, the default view - // stops taxing every visit with seven choices (maintainer ruling 2026-08-24). + // columns, so a separate fields tab would ADD a surface, not remove one). + // objectui#12450 — the five power panels are flat tabs beside them when the + // content column has room, and fold back into one "Advanced" menu when it + // does not (maintainer ruling 2026-10-15, decision B of epic objectui#12446; + // the rule lives in `dataTabsFold.ts`). const dataTabs: ReadonlyArray<{ key: typeof viewMode; label: string }> = [ { key: 'grid', label: t('engine.studio.data.tab.records', locale) }, { key: 'form', label: t('engine.studio.data.tab.form', locale) }, @@ -5128,6 +5144,10 @@ export function DataPillar({ { key: 'settings', label: t('engine.studio.data.tab.settings', locale) }, ]; const activeAdvancedTab = advancedDataTabs.find((tabDef) => tabDef.key === viewMode); + // The two views Add field serves; `addField` itself refuses the rest. + const addFieldOffered = Boolean(current) && (viewMode === 'grid' || viewMode === 'form') && !readOnly && objLoaded; + // objectui#12450 — the Records grid draws flush with the content column. + const recordsFlush = Boolean(current) && objLoaded && viewMode === 'grid' && hasBaseline; // The selected object's own icon (from its metadata) — prefer the loaded // draft body, fall back to the rail header. getIcon degrades to Database. @@ -5136,12 +5156,15 @@ export function DataPillar({ ); // objectui#12459 — the object's tab row lives in the item header (the - // skeleton's scaffold): the two primary tabs flat, "Advanced" as the - // overflow it was (objectui#5813). The trigger keeps its own name whichever - // panel is open (objectui#11794): renamed to the panel ("Validations ▾") it - // hid the one word that says sibling panels sit behind it. Where you are - // still shows twice — the trigger takes the active look while one of its - // panels is open, and the menu marks that panel as the checked radio item. + // skeleton's scaffold). objectui#12450 — seven flat tabs at a content column + // of `DATA_TABS_FOLD_WIDTH` and wider; narrower, the five power panels fold + // into "Advanced". Both forms are rendered and a container query on the + // content column displays exactly one of them (see `dataTabsFold.ts`). + // Folded, the trigger keeps its own name whichever panel is open + // (objectui#11794): renamed to the panel ("Validations ▾") it hid the one + // word that says sibling panels sit behind it. Where you are still shows + // twice — the trigger takes the active look while one of its panels is + // open, and the menu marks that panel as the checked radio item. const dataTabRowEl = current ? ( <> {dataTabs.map((tab) => ( @@ -5149,9 +5172,20 @@ export function DataPillar({ {tab.label} ))} + {advancedDataTabs.map((tab) => ( + selectViewMode(tab.key)} + className={DATA_TAB_FLAT_ONLY} + > + {tab.label} + + ))} - + {t('engine.studio.data.tab.advanced', locale)} @@ -5223,7 +5257,7 @@ export function DataPillar({ })} -
+
{/* objectui#12459 — the object header sits inside the content column, over the thing it names, instead of spanning the rail. */} ) : null} - {current && (viewMode === 'grid' || viewMode === 'form') && !readOnly && objLoaded && ( - + {/* objectui#12450 — the header's two icon buttons. Object + settings opens the Settings panel (a shortcut that still + works when that tab is folded into Advanced); More holds + Add field, which left the header row for it. Add field + stays reachable from the grid's own "+" column and the form + designer's button too. More is drawn only when it holds + something: Add field is not offered on a read-only package, + before the object loads, or on the five power panels. */} + {current && ( +
+ + {addFieldOffered && ( + + + + + + + {t('engine.studio.data.addField', locale)} + + + + )} +
)} } tabs={dataTabRowEl} /> -
+ {/* objectui#12450 — the Records grid runs flush with the column: no + body padding and no framed card around the list, so its toolbar, + grid and footer span the column's full width. Every other view + keeps the padded body. */} +
{!current ? ( objectsLoaded && objects.length === 0 ? ( /* Fresh package: the first act is creating an object — say so and @@ -5313,7 +5387,7 @@ export function DataPillar({ locale={locale} // objectui#11785 — "Show me" opens the named field's inspector. onShow={(target) => setFieldSel({ kind: target.kind, id: target.id })} - className="mb-2 px-3 py-1.5 text-[11px]" + className={cn('mb-2 px-3 py-1.5 text-[11px]', recordsFlush && 'mx-6 mt-3')} /> )} {objHeld && ( @@ -5326,7 +5400,7 @@ export function DataPillar({ ? undefined : (target) => setFieldSel({ kind: target.kind, id: target.id }) } - className="mb-2 px-3 py-1.5 text-[11px]" + className={cn('mb-2 px-3 py-1.5 text-[11px]', recordsFlush && 'mx-6 mt-3')} /> )} {!objLoaded ? ( @@ -5397,7 +5471,7 @@ export function DataPillar({ {/* Records grid — fields are the columns. Header "+" adds a field, the * per-column edit affordance opens the field editor, and dragging a * column header reorders the object's fields (all via the context). */} -
+
(({ )} data-testid="search-icon-button" title={searchTerm ? `${t('list.search')}: ${searchTerm}` : t('list.search')} + // An icon-only button names itself (objectui#12450), the same + // two-attribute shape as Refresh: `title` alone is a tooltip, + // and with a keyword the button's text was the bare keyword. + aria-label={searchTerm ? `${t('list.search')}: ${searchTerm}` : t('list.search')} > {/* Persisted keyword restored from storage keeps filtering after From d2f6de0ed0358c4b3ae2f488120f0510d0dd5b11 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:07:06 +0000 Subject: [PATCH 2/5] test(app-shell): add fields through the header's More menu, open power panels by their flat tab (objectui#12450) Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw Co-authored-by: Claude --- .../DataPillar.authorRefusal-11785.test.tsx | 5 +++-- ...Pillar.choiceWithoutOptions-11253.test.tsx | 3 ++- ...aPillar.designerRegistryPopulated.test.tsx | 12 +++++++++--- .../DataPillar.gridProjection.test.tsx | 6 +++--- .../DataPillar.heldIncomplete-11786.test.tsx | 7 ++++--- ...llar.inspectorBelongsToView-11781.test.tsx | 4 +++- .../DataPillar.panelGate.test.tsx | 4 +++- ...illar.picklistServedOptions-10202.test.tsx | 3 ++- .../StudioDesignSurface.formFields.test.tsx | 3 ++- .../StudioDesignSurface.gridColumns.test.tsx | 3 ++- .../__tests__/dataPillarAddField.ts | 19 +++++++++++++++++++ 11 files changed, 52 insertions(+), 17 deletions(-) create mode 100644 packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts diff --git a/packages/app-shell/src/views/studio-design/DataPillar.authorRefusal-11785.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.authorRefusal-11785.test.tsx index 2520d2190e..5ce06e0649 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.authorRefusal-11785.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.authorRefusal-11785.test.tsx @@ -75,6 +75,7 @@ vi.mock('@object-ui/react', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { registerBuiltinInspectors } from '../metadata-admin/inspectors'; import { t, tFormat } from '../metadata-admin/i18n'; @@ -102,7 +103,7 @@ describe('Studio data page — a held Picklist reads as a sentence (objectui#117 , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await screen.findByText('Type', { selector: 'label' }, { timeout: 4000 }); const apiName = (controlUnder('API name') as HTMLInputElement).value; const label = (controlUnder('Label') as HTMLInputElement).value; @@ -138,7 +139,7 @@ describe('Studio data page — a held Picklist reads as a sentence (objectui#117 , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await screen.findByText('Type', { selector: 'label' }, { timeout: 4000 }); const apiName = (controlUnder('API name') as HTMLInputElement).value; await userEvent.click(controlUnder('Type')); diff --git a/packages/app-shell/src/views/studio-design/DataPillar.choiceWithoutOptions-11253.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.choiceWithoutOptions-11253.test.tsx index d5ff9977b7..a0b43696b6 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.choiceWithoutOptions-11253.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.choiceWithoutOptions-11253.test.tsx @@ -93,6 +93,7 @@ vi.mock('@object-ui/react', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { registerBuiltinInspectors } from '../metadata-admin/inspectors'; import { tFormat } from '../metadata-admin/i18n'; @@ -159,7 +160,7 @@ async function addFieldAndType(typeLabel: RegExp): Promise { , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await screen.findByText('Type', { selector: 'label' }, { timeout: 4000 }); const fieldName = (controlUnder('API name') as HTMLInputElement).value; expect(fieldName, 'the new field has no API name: the harness is dead').not.toBe(''); diff --git a/packages/app-shell/src/views/studio-design/DataPillar.designerRegistryPopulated.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.designerRegistryPopulated.test.tsx index 0d5450d705..6be440272b 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.designerRegistryPopulated.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.designerRegistryPopulated.test.tsx @@ -189,7 +189,9 @@ describe('Data pillar consumers with the registries POPULATED (#6846 contrast)', assertRegistriesPopulated(); renderPillar(); - fireEvent.click(await screen.findByRole('button', { name: 'Actions' })); + // objectui#12450 — the flat tab; the passthrough menu draws the folded + // entry as a second button of the same name. + fireEvent.click(await screen.findByTestId('data-tab-flat-actions')); // `ActionDefaultInspector`'s Name control, carrying the action's identifier. expect(await screen.findByDisplayValue('send_email')).toBeInTheDocument(); expectNoEmptyStateSentence(); @@ -199,7 +201,9 @@ describe('Data pillar consumers with the registries POPULATED (#6846 contrast)', assertRegistriesPopulated(); renderPillar(); - fireEvent.click(await screen.findByRole('button', { name: 'Hooks' })); + // objectui#12450 — the flat tab; the passthrough menu draws the folded + // entry as a second button of the same name. + fireEvent.click(await screen.findByTestId('data-tab-flat-hooks')); fireEvent.click(await screen.findByText('Guard')); // Controls only `HookDefaultInspector` renders… expect(await screen.findByTestId('hook-name')).toBeInTheDocument(); @@ -214,7 +218,9 @@ describe('Data pillar consumers with the registries POPULATED (#6846 contrast)', assertRegistriesPopulated(); renderPillar(); - fireEvent.click(await screen.findByRole('button', { name: 'Settings' })); + // objectui#12450 — the flat tab; the passthrough menu draws the folded + // entry as a second button of the same name. + fireEvent.click(await screen.findByTestId('data-tab-flat-settings')); // `ObjectDefaultInspector`'s Name control, carrying the object's name. expect(await screen.findByTestId('object-name-input')).toHaveValue('showcase_task'); expect(screen.getByTestId('object-access-posture')).toBeInTheDocument(); diff --git a/packages/app-shell/src/views/studio-design/DataPillar.gridProjection.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.gridProjection.test.tsx index fc26101682..18e69c5a92 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.gridProjection.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.gridProjection.test.tsx @@ -26,7 +26,7 @@ import '@testing-library/jest-dom/vitest'; import * as React from 'react'; import { describe, it, expect, vi, afterEach } from 'vitest'; -import { render, screen, fireEvent, cleanup, waitFor } from '@testing-library/react'; +import { render, screen, cleanup, waitFor } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; /** The object as the SERVER has it: two published, materialised fields. */ @@ -86,6 +86,7 @@ vi.mock('@object-ui/plugin-view', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { SurfaceDeepLinkProvider } from './surfaceDeepLinkChannel'; import { registerBuiltinInspectors } from '../metadata-admin/inspectors'; @@ -119,8 +120,7 @@ describe('DataPillar grid projection (cloud#1652)', () => { renderPillar(); await waitFor(() => expect(columnsNow()).toContain('book_name')); - const addField = screen.getByRole('button', { name: /添加|add field/i }); - fireEvent.click(addField); + await addFieldFromMoreMenu(); // The draft grew a `field_`; the projection must not have. await waitFor(() => expect(columnsNow()).toContain('book_name')); diff --git a/packages/app-shell/src/views/studio-design/DataPillar.heldIncomplete-11786.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.heldIncomplete-11786.test.tsx index 06a4a9fce2..7e600790cc 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.heldIncomplete-11786.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.heldIncomplete-11786.test.tsx @@ -78,6 +78,7 @@ vi.mock('@object-ui/react', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { registerBuiltinInspectors } from '../metadata-admin/inspectors'; import { t, tFormat } from '../metadata-admin/i18n'; @@ -121,7 +122,7 @@ async function addFieldAs(typeOption: RegExp): Promise<{ name: string; label: st , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await screen.findByText('Type', { selector: 'label' }, { timeout: 4000 }); const name = (controlUnder('API name') as HTMLInputElement).value; const label = (controlUnder('Label') as HTMLInputElement).value; @@ -206,7 +207,7 @@ describe('Studio data page — complete bodies are sent as before (objectui#1178 , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await waitFor(() => expect(puts.length).toBe(1), { timeout: 4000 }); expect(screen.queryByTestId('studio-held')).toBeNull(); }); @@ -229,7 +230,7 @@ describe('Studio data page — complete bodies are sent as before (objectui#1178 , ); fireEvent.click(await screen.findByRole('button', { name: 'Form' })); - fireEvent.click(await screen.findByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); const strip = await screen.findByTestId('studio-refusal', undefined, { timeout: 4000 }); expect(puts.length).toBe(1); expect(within(strip).getByTestId('studio-refusal-message')).toHaveTextContent( diff --git a/packages/app-shell/src/views/studio-design/DataPillar.inspectorBelongsToView-11781.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.inspectorBelongsToView-11781.test.tsx index 1564973acc..d8af70a9eb 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.inspectorBelongsToView-11781.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.inspectorBelongsToView-11781.test.tsx @@ -118,7 +118,9 @@ describe('DataPillar — the field inspector belongs to the view that opened it ])('switching from Form to %s closes it', async (tabKey) => { await openInspectorOnForm(); - fireEvent.click(screen.getByRole('button', { name: L(tabKey) })); + // objectui#12450 — the first match is the flat tab: the passthrough menu + // draws a power panel's folded entry as a second button of the same name. + fireEvent.click(screen.getAllByRole('button', { name: L(tabKey) })[0]); await waitFor(() => expect(rail()).toBeNull()); }); diff --git a/packages/app-shell/src/views/studio-design/DataPillar.panelGate.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.panelGate.test.tsx index 74bef95e2c..bcda3355e5 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.panelGate.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.panelGate.test.tsx @@ -135,7 +135,9 @@ async function openRuleGuard() { , ); - fireEvent.click(await screen.findByRole('button', { name: 'Validations' })); + // objectui#12450 — the flat tab; the passthrough menu draws the folded + // entry as a second button of the same name. + fireEvent.click(await screen.findByTestId('data-tab-flat-rules')); fireEvent.click(await screen.findByText('Expression')); return screen.getAllByRole('combobox').find((el) => el.tagName === 'TEXTAREA') as HTMLTextAreaElement; } diff --git a/packages/app-shell/src/views/studio-design/DataPillar.picklistServedOptions-10202.test.tsx b/packages/app-shell/src/views/studio-design/DataPillar.picklistServedOptions-10202.test.tsx index 40c86eebb4..4eb3852967 100644 --- a/packages/app-shell/src/views/studio-design/DataPillar.picklistServedOptions-10202.test.tsx +++ b/packages/app-shell/src/views/studio-design/DataPillar.picklistServedOptions-10202.test.tsx @@ -132,6 +132,7 @@ vi.mock('@object-ui/plugin-view', async (importOriginal) => { vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), dismiss: vi.fn() } })); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; const dataSource = createEmptyDataSource(); @@ -178,7 +179,7 @@ describe('Studio data page — a picklist-bound field is saved without its serve it('the draft autosave (an added field) sends no bound field with `options`, and the inline select byte-identical', async () => { renderData(); await waitFor(() => expect(fieldCountShown()).toBe('3 fields'), { timeout: 8000 }); - fireEvent.click(screen.getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await outlastDebounce(); await waitFor(() => expect(puts.length).toBeGreaterThan(0), { timeout: 4000 }); diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.formFields.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.formFields.test.tsx index 25b2e4b60c..7b32071b3f 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.formFields.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.formFields.test.tsx @@ -141,6 +141,7 @@ vi.mock('@object-ui/plugin-form', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; beforeEach(() => { dataSource = createDataSource(); @@ -242,7 +243,7 @@ describe('Studio Data pillar form preview — `fields` keeps a stable identity ( await mountSettledFormPreview(); const before = fieldsSnapshots[fieldsSnapshots.length - 1]; - fireEvent.click(screen.getAllByRole('button', { name: /Add field/i })[0]); + await addFieldFromMoreMenu(); await waitFor( () => { diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.gridColumns.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.gridColumns.test.tsx index 51f85aa219..1237ff95ab 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.gridColumns.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.gridColumns.test.tsx @@ -97,6 +97,7 @@ vi.mock('@object-ui/react', async (importOriginal) => { }); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; beforeEach(() => { dataSource = createDataSource(); @@ -185,7 +186,7 @@ describe('Studio Data pillar grid — the columns array keeps a stable identity it('a fresh columns array of EQUAL content still refetches — identity-churn liveness', async () => { const before = await mountSettledGrid(); - fireEvent.click(screen.getAllByRole('button', { name: /Add field/i })[0]); + await addFieldFromMoreMenu(); await waitFor(() => expect(dataSource.find.mock.calls.length).toBeGreaterThan(before), { timeout: 4000, diff --git a/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts b/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts new file mode 100644 index 0000000000..ea281ec5fc --- /dev/null +++ b/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts @@ -0,0 +1,19 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Add a field the way the Data pillar's header offers it (objectui#12450). + * + * Add field left the object header row for the header's More menu, so a suite + * that adds a field "from the header" opens that menu first and picks the + * entry. The real Radix menu opens on a pointer press, which `fireEvent.click` + * does not send, so both steps go through `userEvent`. Read by test id, not by + * name, so a suite rendered under another locale reaches the same entry. + */ + +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +export async function addFieldFromMoreMenu(): Promise { + await userEvent.click(await screen.findByTestId('data-object-more')); + await userEvent.click(await screen.findByTestId('data-object-add-field')); +} From e1699ce0f778d6d0cdbaee23ca8207ff2a6c984f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:20:58 +0000 Subject: [PATCH 3/5] test(app-shell): the surface suites add fields through the More menu (objectui#12450) Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw Co-authored-by: Claude --- ...ignSurface.autosaveInFlight-11204.test.tsx | 9 ++++---- ...esignSurface.autosaveSwitch-11232.test.tsx | 16 +++++++------- ...DesignSurface.cancelledLoad-11331.test.tsx | 13 +++++++----- ...urface.draftVersionConflict-11773.test.tsx | 7 ++++--- .../__tests__/dataPillarAddField.ts | 21 ++++++++++++++++--- 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveInFlight-11204.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveInFlight-11204.test.tsx index dc63d8571a..11c4dff373 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveInFlight-11204.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveInFlight-11204.test.tsx @@ -156,6 +156,7 @@ vi.mock('@object-ui/plugin-view', async (importOriginal) => { vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), dismiss: vi.fn() } })); import { AutomationsPillar, DataPillar, InterfacesPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { registerMetadataPreview } from '../metadata-admin/preview-registry'; import { registerMetadataInspector } from '../metadata-admin/inspector-registry'; @@ -270,17 +271,17 @@ describe('Data pillar — an edit taken while an object save is in flight (objec } const fieldNames = (body: Record) => readFields(body.fields).entries.map((e) => e.name); const fieldCountShown = () => screen.getByText(/^\d+ fields$/).textContent; - const addField = () => fireEvent.click(screen.getByTitle(/^Add a field/)); + const addField = () => addFieldFromMoreMenu(); it('the autosave: an added field stays on screen and lands in the next save', async () => { renderData(); await waitFor(() => expect(fieldCountShown()).toBe('2 fields'), { timeout: 8000 }); const release = holdNextSave(); - addField(); + await addField(); await screen.findByTestId('data-autosaving', undefined, { timeout: 8000 }); expect(savesOf('object').map(fieldNames)).toEqual([['title', 'status', 'field_3']]); - addField(); + await addField(); expect(fieldCountShown()).toBe('4 fields'); await release(); @@ -300,7 +301,7 @@ describe('Data pillar — an edit taken while an object save is in flight (objec fireEvent.click(await screen.findByRole('button', { name: 'Reverse columns' }, { timeout: 8000 })); await screen.findByTestId('data-autosaving', undefined, { timeout: 8000 }); expect(savesOf('object').map(fieldNames)).toEqual([['status', 'title']]); - addField(); + await addField(); expect(fieldCountShown()).toBe('3 fields'); await release(); diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveSwitch-11232.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveSwitch-11232.test.tsx index bec771f8de..bdaaae4d17 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveSwitch-11232.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveSwitch-11232.test.tsx @@ -189,6 +189,7 @@ vi.mock('./StudioAiCopilot', () => ({ StudioChatDock: () => null })); vi.mock('../../preview/DraftChangesPanel', () => ({ DraftChangesPanel: () => null })); import { AutomationsPillar, DataPillar, InterfacesPillar, StudioDesignSurface } from './StudioDesignSurface'; +import { ADD_FIELD_OFFERED, addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { registerMetadataPreview } from '../metadata-admin/preview-registry'; import { registerMetadataInspector } from '../metadata-admin/inspector-registry'; @@ -424,7 +425,7 @@ describe('Data pillar — an object switch inside the debounce, the control (obj ); await waitFor(() => expect(screen.getByText(/^\d+ fields$/)).toHaveTextContent('2 fields'), SLOW); - fireEvent.click(screen.getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); const release = holdLoad('object', 'acme_note'); fireEvent.click(screen.getByRole('button', { name: /Note/ })); await pastDebounce(); @@ -437,7 +438,7 @@ describe('Data pillar — an object switch inside the debounce, the control (obj await pastDebounce(1800); expect(server.saves).toEqual([]); // The control's own control: an edit on the opened object saves to it. - fireEvent.click(screen.getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await waitFor(() => expect(server.saves).toHaveLength(1), SLOW); expect(savesOf('object', 'acme_note').map((b) => readFields(b.fields).entries.map((e) => e.name))).toEqual([ ['body', 'field_2'], @@ -675,13 +676,14 @@ describe("the load window: nothing of the previous item is offered, shown or sav const release = holdLoad('object', 'acme_note'); fireEvent.click(screen.getByRole('button', { name: /Note/ })); - const offered = screen.queryByTitle(/^Add a field/); - if (offered) fireEvent.click(offered); + // objectui#12450 — Add field lives in the header's More menu, drawn + // exactly when it is offered. + if (screen.queryByTestId(ADD_FIELD_OFFERED)) await addFieldFromMoreMenu(); await pastDebounce(); expect(savesRead()).toEqual([]); const shownDuringLoad = { fieldCount: screen.queryByText(/^\d+ fields$/) !== null, - addField: screen.queryByTitle(/^Add a field/) !== null, + addField: screen.queryByTestId(ADD_FIELD_OFFERED) !== null, }; await release(); @@ -690,7 +692,7 @@ describe("the load window: nothing of the previous item is offered, shown or sav expect(server.saves).toEqual([]); // The control: a field added after the load saves once, to its own object. - fireEvent.click(screen.getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await waitFor(() => expect(server.saves).toHaveLength(1), SLOW); expect(server.saves.map((s) => [s.type, s.name, s.body.label, fieldNamesOf(s.body)])).toEqual([ ['object', 'acme_note', 'Note', ['body', 'field_2']], @@ -744,7 +746,7 @@ describe('a package switch: Automations and Data open nothing of the previous pa await switchToBeta(); await screen.findByRole('button', { name: /Beta item/ }, SLOW); await waitFor(() => expect(screen.getByText(/^\d+ fields$/)).toBeInTheDocument(), SLOW); - fireEvent.click(screen.getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(); await waitFor(() => expect(server.saves).toHaveLength(1), SLOW); expect(server.saves.map((s) => [s.type, s.name, s.packageId, s.body.label, fieldNamesOf(s.body)])).toEqual([ ['object', 'beta_item', PKG_B, 'Beta item', ['name', 'field_2']], diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.cancelledLoad-11331.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.cancelledLoad-11331.test.tsx index e50e4c6640..67d369c96d 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.cancelledLoad-11331.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.cancelledLoad-11331.test.tsx @@ -137,6 +137,7 @@ vi.mock('@object-ui/react', async (importOriginal) => { }); import { DataPillar, InterfacesPillar } from './StudioDesignSurface'; +import { ADD_FIELD_OFFERED } from './__tests__/dataPillarAddField'; import { registerMetadataPreview } from '../metadata-admin/preview-registry'; import { DashboardPreview } from '../metadata-admin/previews/DashboardPreview'; import { createEmptyDataSource, failOnAbsorbedFetchError } from './__tests__/emptyDataSource'; @@ -154,7 +155,9 @@ afterEach(() => { }); const NO_DESIGNER = /cannot be previewed or designed here/; -const ADD_FIELD = 'Add a field (then set its type and properties on the right)'; +// objectui#12450 — "the object opened" reads as "Add field is offered": the +// header's More menu, which holds it, is drawn exactly then. +const ADD_FIELD = ADD_FIELD_OFFERED; /** The pillar's canvas: each pillar renders exactly one `main`. */ function canvas(): HTMLElement { @@ -225,7 +228,7 @@ describe('Data pillar — a new metadata client while the open object loads (obj rerender(dataTree()); await openAccount(); - expect(await screen.findByTitle(ADD_FIELD)).toBeInTheDocument(); + expect(await screen.findByTestId(ADD_FIELD)).toBeInTheDocument(); expect(within(canvas()).queryByText('Loading…')).toBeNull(); // Read once by the cancelled load and once by its replacement. expect(reads('object', 'acme_account')).toBe(2); @@ -237,13 +240,13 @@ describe('Data pillar — a new metadata client while the open object loads (obj await waitFor(() => expect(reads('object', 'acme_account')).toBe(1)); await openAccount(); - expect(await screen.findByTitle(ADD_FIELD)).toBeInTheDocument(); + expect(await screen.findByTestId(ADD_FIELD)).toBeInTheDocument(); expect(within(canvas()).queryByText('Loading…')).toBeNull(); }); it('a new client after the object loaded reads nothing again: the buffer is kept', async () => { const { rerender } = render(dataTree()); - expect(await screen.findByTitle(ADD_FIELD)).toBeInTheDocument(); + expect(await screen.findByTestId(ADD_FIELD)).toBeInTheDocument(); expect(reads('object', 'acme_account')).toBe(1); remintClient(); @@ -256,6 +259,6 @@ describe('Data pillar — a new metadata client while the open object loads (obj }); expect(reads('object', 'acme_account')).toBe(1); - expect(screen.getByTitle(ADD_FIELD)).toBeInTheDocument(); + expect(screen.getByTestId(ADD_FIELD)).toBeInTheDocument(); }); }); diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.draftVersionConflict-11773.test.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.draftVersionConflict-11773.test.tsx index d26248dfe9..ba6ce8fd44 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.draftVersionConflict-11773.test.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.draftVersionConflict-11773.test.tsx @@ -163,6 +163,7 @@ vi.mock('@object-ui/plugin-view', async (importOriginal) => { vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), info: vi.fn(), dismiss: vi.fn() } })); import { DataPillar } from './StudioDesignSurface'; +import { addFieldFromMoreMenu } from './__tests__/dataPillarAddField'; import { createEmptyDataSource } from './__tests__/emptyDataSource'; import { readFields } from '../metadata-admin/previews/object-fields-io'; @@ -200,7 +201,7 @@ async function loaded(editor: HTMLElement, count: string): Promise { /** Add a field and wait until the autosave carrying it has landed. */ async function addFieldAndSave(editor: HTMLElement): Promise { const before = server.saves.length; - fireEvent.click(within(editor).getByTitle(/^Add a field/)); + await addFieldFromMoreMenu(editor); await waitFor(() => expect(server.saves.length).toBe(before + 1), { timeout: 8000 }); await waitFor(() => expect(within(editor).queryByTestId('data-autosaving')).toBeNull(), { timeout: 8000 }); } @@ -226,7 +227,7 @@ async function raceTwoEditors(): Promise<{ a: HTMLElement; b: HTMLElement }> { await loaded(b, '3 fields'); await reorderAndSave(b); // B: status before title expect(serverDraftFields()).toEqual(['status', 'title', 'field_3']); - fireEvent.click(within(a).getByTitle(/^Add a field/)); // A's stale copy + field_4 + await addFieldFromMoreMenu(a); // A's stale copy + field_4 await screen.findByTestId('draft-conflict-dialog', undefined, { timeout: 8000 }); return { a, b }; } @@ -256,7 +257,7 @@ describe('Data pillar — a draft saved elsewhere is not overwritten in silence await loaded(b, '2 fields'); await addFieldAndSave(a); // A: + field_3, the first draft expect(serverDraftFields()).toEqual(['title', 'status', 'field_3']); - fireEvent.click(within(b).getByTitle(/^Add a field/)); // B's first save, built on the published object + await addFieldFromMoreMenu(b); // B's first save, built on the published object await screen.findByTestId('draft-conflict-dialog', undefined, { timeout: 8000 }); const refused = server.saves[server.saves.length - 1]!; expect([refused.ifMatch, refused.ifNoneMatch]).toEqual([undefined, '*']); diff --git a/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts b/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts index ea281ec5fc..f1f98516bc 100644 --- a/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts +++ b/packages/app-shell/src/views/studio-design/__tests__/dataPillarAddField.ts @@ -8,12 +8,27 @@ * entry. The real Radix menu opens on a pointer press, which `fireEvent.click` * does not send, so both steps go through `userEvent`. Read by test id, not by * name, so a suite rendered under another locale reaches the same entry. + * + * More is drawn exactly when Add field is offered (its one entry; see the + * header in `DataPillar`, pinned both ways by + * `DataPillar.flatTabs-12450.test.tsx`), so {@link ADD_FIELD_OFFERED} is the + * id a suite reads to ask "is Add field offered here?" — the question the + * header button's title used to answer. */ -import { screen } from '@testing-library/react'; +import { screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -export async function addFieldFromMoreMenu(): Promise { - await userEvent.click(await screen.findByTestId('data-object-more')); +/** The More trigger's test id; present exactly when Add field is offered. */ +export const ADD_FIELD_OFFERED = 'data-object-more'; + +/** + * Open the header's More menu and pick Add field. `scope` is the editor whose + * More to open when a suite renders more than one; the menu itself portals to + * the document, and only one is open at a time. + */ +export async function addFieldFromMoreMenu(scope?: HTMLElement): Promise { + const where = scope ? within(scope) : screen; + await userEvent.click(await where.findByTestId(ADD_FIELD_OFFERED)); await userEvent.click(await screen.findByTestId('data-object-add-field')); } From 45d8046f7aabd6d717cd3a5079facdd0a1fadc2f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:48:59 +0000 Subject: [PATCH 4/5] chore(changeset): Studio Data pillar layout, list search button name (objectui#12450) Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw Co-authored-by: Claude --- .changeset/12450-data-pillar-layout.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/12450-data-pillar-layout.md diff --git a/.changeset/12450-data-pillar-layout.md b/.changeset/12450-data-pillar-layout.md new file mode 100644 index 0000000000..c53e1f9e3d --- /dev/null +++ b/.changeset/12450-data-pillar-layout.md @@ -0,0 +1,11 @@ +--- +'@object-ui/app-shell': minor +'@object-ui/plugin-list': patch +--- + +Studio Data pillar layout (objectui#12450, epic objectui#12446). + +- **Seven flat tabs.** Records, Form, Validations, Hooks, Actions, API and Settings sit in one underline tab row when the content column is 1000px or wider. Below that, the last five fold back into "Advanced ▾", whose trigger keeps its own name whichever panel is open. A container query on the content column decides the fold, so it also responds when the field inspector opens beside the column. +- **Object header buttons.** The object header gains an Object settings button, which opens the Settings panel, and a More button. Add field moves from the header row into the More menu. It is also still in the grid's "+" column header and in the form designer. +- **Records toolbar and grid.** The Records tab drops the framed card and the body padding around the list, so the toolbar, grid and footer run flush with the column. Its toolbar is the list's wide form: Hide fields, Filter, Group and Sort as labelled buttons, then Refresh, Search and Add record. There is no density control. +- **List search button name.** The list toolbar's icon-only Search button now has an `aria-label`, like Refresh. When a keyword is active, its accessible name is "Search: KEYWORD" instead of the bare keyword. From 4c06d3a6ad78651f8722c1f2001ace25049d1b57 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:57:07 +0000 Subject: [PATCH 5/5] docs(design): Data pillar after-screenshots at 1280 px light and dark, and the folded tab row (objectui#12450) Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw Co-authored-by: Claude --- .../after/12450-data-records-dark.png | Bin 0 -> 124939 bytes .../after/12450-data-records-folded-light.png | Bin 0 -> 104336 bytes .../after/12450-data-records-light.png | Bin 0 -> 122153 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/design/studio-redesign/after/12450-data-records-dark.png create mode 100644 docs/design/studio-redesign/after/12450-data-records-folded-light.png create mode 100644 docs/design/studio-redesign/after/12450-data-records-light.png diff --git a/docs/design/studio-redesign/after/12450-data-records-dark.png b/docs/design/studio-redesign/after/12450-data-records-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c9dc2a677caf29452c643d59c1150f339be784 GIT binary patch literal 124939 zcmbTdb#R+a^DSs*N*puCl$aeeJLZ@{X6BfgL1u_CF>}n48DeHTW@ct)X3*99e&26* zYj54!s?{H&8a>m`sHdm<^f{5riqe>9#Aq-uFqq$DBvfHw5TS43Lr~zLFHRol02mk? zm~Rqa0iKyBtBAh1mLxD2JS=ugMQ1F^u(IgPe;V-`w$8XyVQ~8vQvFFr7E-H>NqSaS za~tat(cCi-V1e#ZtQ_1{4=AB|w5|NC2zWG4(ERY*Ec z#^|17BNKjKdNHJ2>D7h9=EGbEei4hX!jp6Mq2d+pd!=c1V_~>t@9E2ECs)M`Ek;H&K z001D`hGmtCUt{moc9>T^_x>O2XHqHKcP~BR0$~#dr=qDUv0FE!Kxy%V1+=uiySuxM zn%pjqo%@cwjs+<)e^tRpN3ENa!^h}bEcL{H^{aNp5><6{#EwdL%XIY|n!lITg}}0j zp>WZG9Jx3@s48TECp1|!WoR7V=~5*O&RG85!^fUBvPzSui$hlL6+{xR+wts*QFeim zj_&S;t8NVXZGnoFT~xG(qyGVa4;Mg|J3(lYl$mK;SYr>Xg>Kl;xaO*IUU&0^*opHb zo`j?as@5XCwR0=6;o=pSQUB{0iMk(|tallP;~mON%0e1TJrXM@ov0C^uBK*ibQC|T7hx7-EZV|i@9+@ZY?!m%ObeY+ zEv`<&pan*Yl5J*wKA12Sq=dSJiEd>rL59(TXZh_L`&X3Q6qH{eIywu-r(7%rJiI*U zW4`p212MKREKEv|CC&&VTA2fefZNN9?@Lg&1%xARAjUG4=>or@!Oihzbf4Y|>MVx2L4HvbBZFxI~xR zYMu={Rv>7uq#Zhb2LtsH5)uK`@OHCAWpooW8YV_YKeB07l-zl&oJ!pL&e82hgy9_Fia(`3i4DYJ0-UHC*?dlxc4!1&WzUgiwcb*xX zuIMyS#qZqK=lIj+CDugmqg}I3VJ7??5+E`up&nU~wEg+V*dwA2y>R zBr4Ug4N%&;HYnl4iGvKd8VC9qy23z(m!B(^b^bM6AtSATeG(}qeWl3X^N znxlo1TLi~dITIjH7mQKG0$cTKLQ71bXd>I(s24}8lhEs1@*iIDtWw};CPO$=VgC@|OCJ!qHcs-0MW6*E*)QWAKw zo9*l9517zRQ3_vgVyFPc10pu$rmS39;`;Y4`1C4*ZH_0b9CC!KxVW##xlrZD_DlKy zdK;fFw0Ym3t+n|W8*kp1Y9^#~4=y%Yj%VZJ<6mB07As{9jgHcm2%tVvFzZU;#mg2> zPO{T0kurW#t^@hnY>Iu#%*lalV~c#Zn5s7I+@K0JHrkIR+uYnlpt_l|n(DyA+ijNU zAkC;x#(gtKwcFj5L{kYAOGKtV^u^^j9M~X|y-xU2FaOI-0w8co�k%zbj_X&BsTC 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