Skip to content

feat(app-shell): the draft status chip sits in one place in every Studio item header (objectui#12524) - #12589

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-12524-header-status-chip
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-12524-header-status-chip

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12524
Clause-②: no

What changed

  • Target 1 (one place). StudioItemHeader takes the item's status as data (a new status prop: label and an optional tooltip) and draws one shared amber chip, StudioStatusChip, right after the identity (the title, then the api-name or kind chips) and before the meta. The identity chips sit in an always-rendered contents wrapper (data-slot="identity-chips"). It draws no box, so the layout is unchanged, and the chip is the same child of the same title row in Data, Automations, Interfaces and Access. The title stays a direct child of the row, which the objectui#11665 pin reads.
  • Target 2 (actions only on the right). Interfaces' "Unpublished draft" leaves the actions slot. The right slot keeps, in order: the autosaving spinner, the read-only link, Open in Data, Design / Run, and the properties toggle. Data's saved-at meta and Automations' Enabled switch stay at the right. Access's read-only link is an action, so it stays there too (objectui#12453 behaviour unchanged).
  • Target 3 (the header places it). Data, Automations and Interfaces pass status with the engine.studio.unpublishedDraft text; Access passes its writable "This package's objects · saved as draft" note (engine.studio.access.banner, tooltip engine.studio.access.bannerTitle). No pillar writes the chip markup any more. No i18n keys added or retired; every existing data-testid stays.

Decisions and deviations

  • Slot shape: a typed status prop rather than chips. The header owns both the chip's position and its look, and the prop refuses markup or a link, so a pillar cannot misplace or restyle it.
  • Access: the writable note is treated as Access's status (the only draft signal the pillar shows, and the card's measured Access chip). In a read-only package the link stays in actions. Permission sets have no per-set draft status today.
  • The open-set Access header (the permission matrix page) is unchanged: its note stays at the tab row's right end, where objectui#12456 put it so the set's label is not truncated. That file is outside this change.
  • The chip now has shrink-0 whitespace-nowrap. At 1280 px in the Automations header, main's chip wrapped to two lines (37 px) while the title still truncated; it now stays on one line (21 px). The title truncation exists either way, from that pane's width.
  • Deviation list against the artboards: no change beyond the above.

Screenshots (1280 px, a writable package with a draft object, flow, page and app; console at d9376cc against HotCRM 63db83e)

The screenshots live on the never-merged branch claude/issue-12524-evidence; this branch carries no PNG.

Test evidence (head d9376cc)

  • New: StudioItemHeader.statusPlace-12524.test.tsx, 4 passed. It renders the four real pillars with a draft and asserts the chip is a child of the title row at one shared index, after the title and the identity chips, outside the actions. It also asserts the Interfaces actions keep their order with no chip among them. CONTROL: no draft, no chip (Data, Automations, Interfaces); a read-only package, no Access status, and the read-only link in the actions slot.
  • Ablation: moving the Interfaces chip back into the actions turns 2 of 4 red. After restoring with git checkout HEAD, git diff HEAD is empty.
  • Full app-shell suite (the file set of pnpm --filter @object-ui/app-shell test), run in 8 shards because of the session's 10-minute command cap: 1420 files passed and 1 skipped; 13538 tests passed and 9 skipped. The existing StudioDesignSurface.flowCanvasChip-11665 pin is green, unmodified.
  • type-check (source and test configs), build, eslint on the touched files (0 errors), check:i18n-keys, check:i18n-drift, check-changeset-presence and check:new-line-citations: all exit 0.

Acceptance notes

  • Permission sets show no item-level draft status: the Access note says how edits save, not whether this set has a pending draft. Recorded only; not part of this change.

Session: https://claude.ai/code/session_01GzRy6FiHuy1vpBecH2KRYM


Generated by Claude Code

…ui#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 <noreply@anthropic.com>
…(objectui#12524)

The `contents` wrapper now holds only the identity chips (api name and kind
chips), always rendered, so the title stays the row's child as the
objectui#11665 pin reads it, and the status chip keeps one index in every
pillar.

Claude-Session: https://claude.ai/code/session_01GzRy6FiHuy1vpBecH2KRYM
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3092.6 KB 3119.4 KB
Main entry chunk (gzip) 73.3 KB 350 KB
Entry file index-DGaBnX4P.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 596.60KB 143.79KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 254.55KB 71.19KB
fields (index.js) 283.09KB 72.13KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 145.69KB 39.39KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.91KB 69.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.83KB 46.61KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 262.82KB 72.91KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.82KB 33.09KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · objectui#12524 · head d9376cc · 2026-10-16T00:54Z

Seat domain:ui#4, session session_01SJn1GEkrbbBQkhGC26wEDw. Checked against GitHub and the diff, not against the report (relayed on the card). The seat opened this PR from the dev's pr_title_draft and pr_body_draft (degraded channel); the body is the dev's, verbatim.

Checklist

  • Form: draft → main, assignee os-sales. The first line is Fixes #12524, and the next line is exactly Clause-②: no. git merge-tree against current main (1b3b5b1) is clean. Three commits on f23eb01, with no rewrite.
  • Sibling: feat(app-shell): Studio home returns to the Studio landing; the two Setup exits say so #12590 (objectui#12513) conflicts with this PR on one import line at the top of StudioDesignSurface.tsx (both extend adjacent imports). This PR lands first. The seat then has objectui#12513's session merge main and keep both imports.
  • Diff:
    • StudioItemHeader.tsx gets a typed status prop ({label, title}) and draws the one shared StudioStatusChip after the identity chips and before the meta. The identity chips sit in an always-rendered contents wrapper, so the chip has the same index in the title row in every pillar. The h1 stays a direct child of the row, which the objectui#11665 pin reads.
    • StudioDesignSurface.tsx: only the four headers' status / chips / actions props and the accessNoteEl they feed. The Interfaces draft span leaves actions, and the right slot holds actions only.
    • No i18n key added or retired, and every existing testid stays.
  • Tests: the new StudioItemHeader.statusPlace-12524 (4 tests) renders the four real pillars with a draft and asserts the chip's parent and index, the Interfaces actions' order, and two CONTROLs. One ablation turned 2 of 4 red. The full app-shell file set ran in 8 shards (1420 files, 13538 tests passed). Shard 1 caught two real failures in the objectui#11665 pin on the first wrapper, which d9376cc fixed without touching the pin.
  • Changeset: user-facing prose; patch for @object-ui/app-shell.
  • Contract faces: none. status is an optional prop of an internal component.
  • Screenshots: the four headers in light and dark, plus the whole Interfaces window, on the never-merged claude/issue-12524-evidence (33ef46f). The seat sent them to the maintainer at 2026-10-16T00:54Z.
  • CI on d9376cc: running at this record. Landing waits for green.

Rulings on the open questions and deviations

  1. The slot's shape: A, a typed status prop. The measured defect was a pillar putting the chip in the wrong slot. A makes that structurally impossible: the prop takes data, not markup (axis 3). It fulfils target 3's intent, "the pillars stop placing it themselves", with a stricter contract than the card's word "chips".
  2. Access's writable note as its status: A. It is the only draft signal the pillar shows, and it is the card's measured Access chip. In a read-only package the link stays in actions. The caveat is recorded: the note is package-level, and permission sets have no per-set draft status. Nothing is filed, since there is no pull.
  3. shrink-0 whitespace-nowrap on the chip: accepted. It was measured at 1280 px: two lines become one, and the title truncation comes from the pane width either way.
  4. The full suite run in 8 shards over the identical file set: accepted. The session's 10-minute command cap made one run impossible, and CI runs the whole suite on the merge ref.
  5. The degraded channel over the file's delivery rule: A, as on every cloud card today.

Implemented-by: cloud session session_01GzRy6FiHuy1vpBecH2KRYM, branch claude/issue-12524-header-status-chip
Reviewed-by: seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing · head d9376cc · 2026-10-16T01:06Z

  • Checks on d9376cc: 34 success, plus 3 expected skips (dependabot, Test (coverage), Test (coverage shard …)). Nothing is red. The 16 test shards carry the full @object-ui/app-shell suite as one CI run, which covers the ACCEPT's note that the dev ran it in 8 local shards.
  • Mergeable: yes (clean). git merge-tree against current main (3eb3ec1) is clean. The queue's merge group runs the full CI on the combined tree.
  • Sibling: feat(app-shell): Studio home returns to the Studio landing; the two Setup exits say so #12590 (objectui#12513) waits behind this PR. Once this merges, it takes main and resolves the shared import line, as its ACCEPT records.
  • Path surface: no governed path; Governed Surface Queue Guard is green. The ACCEPT 6205536987 lists the files.
  • Nothing has been posted since the ACCEPT: no review, no review comment and no objection.
  • Action: mark it ready for review, then enable auto-merge through the merge queue. Fixes #12524 closes the card on merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 01:06
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 01:07
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit ae923ec Oct 16, 2026
38 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12524-header-status-chip branch October 16, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The draft status chip sits in the same place in every pillar's item header

2 participants