diff --git a/.changeset/12524-header-status-chip.md b/.changeset/12524-header-status-chip.md new file mode 100644 index 0000000000..e8e0b912a7 --- /dev/null +++ b/.changeset/12524-header-status-chip.md @@ -0,0 +1,5 @@ +--- +'@object-ui/app-shell': patch +--- + +Studio: the draft status chip sits in the same place in every pillar's item header (objectui#12524). "Unpublished draft" in Data, Automations and Interfaces, and Access's "saved as draft" note, now follow the item's title and its name or kind chip, before the meta line. In Interfaces it no longer sits among the Design / Run actions at the right of the header, which now holds actions only. `StudioItemHeader` draws the chip from a new `status` prop, so a pillar passes the status and no longer places or styles it. 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 = (