From 3723265f56a08e7c3f709af0a4d1341d64891775 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 23:00:09 +0000 Subject: [PATCH 1/3] feat(app-shell): the item header owns the status chip's place (objectui#12524) StudioItemHeader takes the item's status as data (`status`) and draws the amber chip itself, after the identity (title, api-name and kind chips) and before the meta. The Data, Automations and Interfaces pillars pass their "Unpublished draft" status through it, and Access its writable "saved as draft" note; the Interfaces chip leaves the actions slot, which now holds actions only. The identity sits in one `contents` wrapper, so the chip is the same child of the same row in every pillar. Claude-Session: https://claude.ai/code/session_01GzRy6FiHuy1vpBecH2KRYM Co-authored-by: Claude --- .../studio-design/StudioDesignSurface.tsx | 45 +-- ...tudioItemHeader.statusPlace-12524.test.tsx | 286 ++++++++++++++++++ .../views/studio-design/StudioItemHeader.tsx | 62 +++- 3 files changed, 353 insertions(+), 40 deletions(-) create mode 100644 packages/app-shell/src/views/studio-design/StudioItemHeader.statusPlace-12524.test.tsx diff --git a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx index 844ff8cf0f..5d519af29a 100644 --- a/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx +++ b/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx @@ -39,7 +39,7 @@ import { STUDIO_KIND_CHIP, } from './studio-tokens.js'; import { StudioInspector } from './StudioInspector.js'; -import { StudioItemHeader, StudioTab } from './StudioItemHeader.js'; +import { StudioItemHeader, StudioStatusChip, StudioTab, type StudioItemStatus } from './StudioItemHeader.js'; import { overlayPath } from './BuilderLanding.js'; import { DATA_CONTENT_CONTAINER, DATA_TAB_FLAT_ONLY, DATA_TAB_FOLDED_ONLY } from './dataTabsFold.js'; import { StudioRail, StudioRailGroup, StudioRailRow } from './StudioRail.js'; @@ -4014,13 +4014,11 @@ export function InterfacesPillar({ ) : undefined } + // objectui#12524 — the draft status sits after the kind chip, as in + // every pillar; the right slot holds actions only. + status={hasDraft && draftLoaded ? { label: t('engine.studio.unpublishedDraft', locale) } : undefined} actions={ <> - {hasDraft && draftLoaded && ( - - {t('engine.studio.unpublishedDraft', locale)} - - )} {/* objectui#5813 — drafts auto-save; the spinner is the affordance. */} {saving === 'draft' && ( @@ -5805,13 +5803,7 @@ export function DataPillar({ titleProps={current ? undefined : { className: 'text-[13px] font-normal text-muted-foreground' }} apiName={current?.name} meta={current && objLoaded ? tFormat('engine.studio.data.fieldCount', locale, { count: fieldCount }) : undefined} - chips={ - hasDraft && objLoaded ? ( - - {t('engine.studio.unpublishedDraft', locale)} - - ) : undefined - } + status={hasDraft && objLoaded ? { label: t('engine.studio.unpublishedDraft', locale) } : undefined} actions={ <> {/* objectui#5813 — drafts auto-save (see useDraftAutoSave above); the @@ -7412,13 +7404,7 @@ export function AutomationsPillar({ {t('engine.studio.auto.designersMissing', locale)} ) } - chips={ - hasDraft && flowLoaded ? ( - - {t('engine.studio.unpublishedDraft', locale)} - - ) : undefined - } + status={hasDraft && flowLoaded ? { label: t('engine.studio.unpublishedDraft', locale) } : undefined} actions={ <> {/* objectui#5813 — drafts auto-save; the spinner is the affordance. */} @@ -7965,19 +7951,20 @@ export function AccessPillar({ // the note was, and the link's title carries the note's sentence. An open // set's header draws it at the tab row's right end (objectui#12456: the // title row truncated the set's label at the 1280 px design width). - const accessNoteEl = readOnly ? ( + // objectui#12524 — the writable note is this pillar's draft status: the + // header draws it in the status place every pillar shares. The read-only + // link is an action, so it stays in the actions slot. + const accessStatus: StudioItemStatus | undefined = readOnly + ? undefined + : { label: t('engine.studio.access.banner', locale), title: t('engine.studio.access.bannerTitle', locale) }; + const accessNoteEl = accessStatus ? ( + + ) : ( - ) : ( - - {t('engine.studio.access.banner', locale)} - ); const accessExplainEl = (