Skip to content

feat(app-shell): Automations pillar — rail grouped by object, flow meta and switch in the item header, Canvas · Variables · Runs · Problems · Debug tabs (objectui#12454) - #12481

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-12454-automations-pillar-layout
Oct 15, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/issue-12454-automations-pillar-layout

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12454
Clause-②: no
Nothing on @object-ui/app-shell's package entry changes.

The Automations pillar takes the redesign of epic objectui#12446 (decisions 1, 3 and 5), on top of the layout skeleton (objectui#12459, cf430cd).

What changed

  • Rail grouped by trigger object (decision 5). studio-design/flowGrouping.ts is a pure function: the served flow definitions and the scope's object index in, ordered groups out. A flow is grouped under the first answer from these steps, in order: (1) its Start node's object (config.objectName, or config.timeRelative.object for a time-relative sweep); (2) the first data node of its own graph, in graph order, on one of the package's objects; (3) the first record write anywhere in it, nested regions included. A flow with none of these goes in a trailing "No object" group. Groups are sorted by label, show a count and can be folded. A search filters within the groups.
  • Rows: a 14 px trigger glyph (bolt record-triggered, clock scheduled, pointer screen, corner arrow autolaunched), the label on one 32 px line, and a 6 px status dot: green On, grey Not running here, amber Refused, hollow ring Off. The status words are the dot's visually hidden text. The row's title gives the whole label, the trigger kind and the status words. The legend sits in the rail's footer slot.
  • Item header: the flow's Trigger, Status, Run as and version form the header's meta. One component, FlowMetaPills, renders them here and in the designer's info bar, so both read the same trigger and run status (objectui#11779). The Enabled switch is 36 × 20 px. Its title begins with "Off by default · review before enabling", and a visually hidden line carries the same sentence. The full-width band has been gone since the skeleton.
  • Tab row: Canvas, Variables, Runs, Problems (with a count pill) and Debug replace the info bar's four buttons. Variables, Runs and Problems open as the tab's body, not as sheets, because each is a list that reads well at the content width. Debug keeps the canvas visible, with the simulator beside it, because the simulator paints its run on the canvas. Picking a problem in the Problems body opens the Canvas tab with that element selected and revealed. The canvas stays mounted under the body sections, so pan and zoom survive a tab switch.
  • Canvas: flush under the tabs, on the sidebar surface with a 20 px dot grid. The zoom control (−, percentage, +, fit) floats at the bottom right.

The metadata-admin designer (FlowPreview / FlowCanvas)

The Studio look is scoped by a provider. FlowPreviewChromeProvider, exported from FlowPreview.tsx, carries the open section and the problem-count reporter. Under it, the preview draws no info bar and no frame. The designer does not provide it, so it keeps its info bar, its meta pills and its side panels unchanged.

The canvas restyle in FlowCanvas.tsx (sidebar surface, 20 px dots, zoom control bottom right) applies to both surfaces. I checked it with objectui's verify skill: the console preview gallery, preview-gallery.html?only=flow, run headless with Chromium on this branch. It showed 14 node cards, the info bar's Trigger and Status pills, Runs, Problems and Debug, the Problems panel opening beside the canvas, the zoom control, Add node, and no page errors.

Pins kept, and one reversed as the card asks

  • objectui#11665 (StudioDesignSurface.flowCanvasChip-11665): unchanged from origin/main and green. The header shows the flow's label, not the API name. The API name is on the label's tooltip. The canvas hint stays in the header row as a visually hidden line, which also describes the Canvas tab.
  • objectui#11779 (flowStatusTruth-11779), objectui#11785 (authorRefusal-11785), objectui#11786 (heldIncomplete-11786), objectui#11795 (narrowRow-11795), objectui#12303 (the switch's read-only description and wrapper): all unchanged and green.
  • objectui#11794's wrapping label is reversed, as the card's "truncating flow label" asks. AutomationsPillar.railSearch-11794 is updated: it reads rows by test id, so a group header is never counted as a row, and it pins the one-line label with the whole name in the row's title.

Deviation list (against docs/design/studio-redesign/automations.html)

  1. The artboard shows an API-name chip. It is not rendered, because flowCanvasChip-11665 pins the API name to the tooltip (objectui#11665).
  2. The meta keeps the Label: captions (Trigger: screen · Status: On · Run as: user · v1) instead of Trigger · screen, and adds Status. Seven pinned tests read the header's Status: pill by that text: flowStatusTruth-11779, narrowRow-11795, automationsReadOnly-11124, automationsReadOnlySelect-11546, autosaveInFlight-11204, flowRegistration-12349 and packageLessFlows-11553. Status also carries objectui#11779's rule that the header agrees with the rail.
  3. There is no divider and no "more" button. The pillar has no flow action to put behind it, and an empty menu would be a dead control.
  4. The group header's chevron sits after the count, not before the label. StudioRailGroup is the skeleton's shared component, and StudioRail.tsx takes additive edits only.
  5. The legend is pinned in the rail's footer slot instead of following the last group. It says "Autolaunched" rather than "Subflow", because the corner arrow marks every flow started by something else: a subflow, a button or an API call. Off and Refused appear in the legend only while some flow in the rail reads that way.
  6. Node cards keep today's styling: 12 px radius, 36 px tile, cyan get-record, sky loop, rose end, the raw GET_RECORD kind word, 240 px width. The card markup is NodeCard in metadata-admin/previews/flow-canvas-parts.tsx, outside this claim's file surface. The width is the layout engine's NODE_W, and the card keeps layout as the engine's.
  7. The Configuration aside is unchanged. It still shows the "Configuration" eyebrow, then the metadata inspector's own "Node" header and close, and the decision's Branches table instead of outcome cards with a dashed "Add outcome". Those parts live in inspectors/_shared.tsx (InspectorShell) and inspectors/FlowObjectListField.tsx, outside this claim's file surface. Only the double padding is fixed (the aside's body padding gives way to the inspector's own).
  8. "Add node" stays at the canvas's top right while the canvas is editable. The artboard draws no add control.
  9. The Problems pill is amber for warnings and takes the destructive tint when an error is among them. The artboard draws it amber always. An error-level problem is one the server refuses.
  10. The screenshots show HotCRM as objectstack dev serves it. That package is read-only (code-provided), so the switch is disabled and no Add node shows. The artboard draws a writable package. The artboard's PNG also renders the rail wider than 240 px, so labels truncate sooner here. The row's title gives the whole label.

Screenshots (1280 px)

  • After: docs/design/studio-redesign/after/12454-automations-light.png, docs/design/studio-redesign/after/12454-automations-dark.png. Taken from the local console (Vite on this branch) against HotCRM served by objectstack dev (hotcrm 63db83e), on "Enroll Members in Campaign" with "Campaign Open?" selected.
  • Before: docs/design/studio-redesign/after/skeleton-automations-light.png and -dark.png (cf430cd).

Grouping measured on HotCRM, re-read

Measured on hotcrm 63db83e, from GET /api/v1/meta/flow?package=app.objectstack.hotcrm on a fresh objectstack dev. The package now serves 26 flows, not the card's 23. The three new ones each fall under an object that already had a group, so the ten groups stand:

Group Count
Account 2
Campaign 2
Campaign Member 2
Contact 1
Contract 3
Forecast 1
Lead 4
Opportunity 8
Quote 1
Task 2

flowGrouping.test.ts pins this over those definitions, trimmed to the keys the grouping reads and inlined in the test with the hotcrm commit named.

Every HotCRM screen flow names its record on its Start node, so no action metadata is read: the "action that references the flow" step has no instance to serve, and it is not built. Forecast Snapshot first queries sys_user, a platform object outside the package. It therefore groups under the record it writes, crm_forecast, as the card measured.

Test evidence (HEAD 1de2c1d)

  • Every test in studio-design/ that reaches the pillar, the rail, FlowStatusDot or the flow previews, plus flowGrouping.test.ts and the new AutomationsPillar.tabs-12454.test.tsx: pnpm exec vitest run --maxWorkers=2 over 30 files gives Test Files 30 passed (30), Tests 273 passed (273).

  • Every metadata-admin flow preview and canvas test, plus the other files that name the pillar or the previews: 28 files give Test Files 28 passed (28), Tests 409 passed (409).

  • pnpm --filter @object-ui/app-shell run type-check: exit 0. pnpm --filter @object-ui/app-shell run build: exit 0, dist completeness 1094 files.

  • eslint --no-inline-config on the eight touched source files: exit 0, no errors.

  • Ablation: one mutation per pinned behaviour, applied through ablation-replace (the anchor hit once, the mutation was verified on disk, and the file was restored to HEAD's blob each time). All ten legs went red:

    Mutation Tests that turned red
    grouping's write step flowGrouping, 3 failed
    the dot's status words FlowStatusDot, 6 failed
    search within groups railSearch-11794, 3 failed
    the row title railSearch plus tabs-12454, 2 failed
    the header's canvas hint flowCanvasChip-11665 plus packageLessFlows-11553, 4 failed
    the meta's Status caption narrowRow-11795 plus flowStatusTruth-11779, 12 failed
    the refusal strip authorRefusal-11785, 3 failed
    the held notice heldIncomplete-11786, 2 failed
    the Start-node trigger write newFlowTrigger-11788 plus flowPresets-11861, 7 failed
    the Problems count pill tabs-12454, 1 failed
  • Local gates: node scripts/check-changeset-presence.mjs, pnpm check:i18n-keys, pnpm check:i18n-drift, pnpm check:i18n-designer-parity, pnpm check:new-line-citations and node scripts/check-changeset-no-major.mjs all exit 0. The full farm is CI's.

Acceptance notes

  • File surface. Two test files are outside the claim's listed surface: AutomationsPillar.railSearch-11794.test.tsx (updated; the card names AutomationsPillar.* as stay-green-or-update) and the new AutomationsPillar.tabs-12454.test.tsx, which pins acceptance 3. No other test pinned it. flow-canvas-parts.tsx, _shared.tsx and FlowObjectListField.tsx were not touched (deviations 6 and 7). Restyling the node cards and the aside needs them added to a claim.
  • PM mechanism assumptions. Measured as follows:
    1. Confirmed: the switch was already in the header actions slot.
    2. Partly falsified: the node cards are NodeCard in flow-canvas-parts.tsx, not FlowCanvas.tsx.
    3. Partly falsified: the aside's header is InspectorShell in _shared.tsx, and the outcomes are FlowObjectListField.
    4. Confirmed: StudioRailGroup and the footer slot sufficed, and StudioRail.tsx is untouched.
    5. Falsified, in the lighter direction: no action metadata is needed.
  • Lint. In StudioDesignSurface.tsx, React Compiler's preserve-manual-memoization warning now also reports doCreateFlow. The component already reported two of these at cf430cd, so the compiler was already skipping it. Removing this branch's line from doCreateFlow does not clear the new warning, and I have not found its cause. FlowPreview.tsx loses one no-explicit-any.
  • Unchanged and outside this card's surface. HotCRM's decision nodes route by out-edge conditions, so the inspector's Branches table reads "No items yet".

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


Generated by Claude Code

  • Patch round 1 (seat REWORK 6192072808): flowGrouping collates in the locale the pillar hands in (the locale is now required and the machine-locale fallback is removed); the census machineLocaleCensus-9909 is green at 2c87994. Patch round 2 removes the process line from the changeset text.

…ations rail reads off each flow

A pure function: served flow definitions and the scope's object index in,
ordered groups out. The Start node's object, else the first data node of the
flow's own graph on one of the scope's objects, else the first record write
anywhere in the flow; a flow with none lands in a trailing "No object" group.
Pinned on HotCRM's served flow list (hotcrm 63db83e): 26 flows in ten groups.

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
…rries the flow's meta and a tab row in the item header

- Rail: groups by the object each flow is about (flowGrouping), each with
  its count, foldable; rows carry a trigger glyph, a one-line label (the
  row's title holds it whole) and a 6 px status dot; a legend sits in the
  rail's footer. A search filters within the groups.
- Item header: Trigger · Status · Run as · version as the header's meta,
  one component with the designer's info bar (FlowMetaPills); the "off by
  default" sentence moves onto the Enabled switch (title and description).
- Tab row: Canvas, Variables, Runs, Problems (with its count), Debug. Under
  the Studio's chrome (FlowPreviewChromeContext) the preview draws no info
  bar and no frame; Variables, Runs and Problems are the tab's body, Debug
  keeps the canvas beside the simulator. The designer is unchanged.
- Canvas: the sidebar surface with a 20 px dot grid; the zoom control floats
  at the bottom right.

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
…int and an empty flow's tabs

- The Enabled switch keeps objectui#12303's description (the read-only
  reason alone); the "off by default" sentence is its title's first line and
  a visually hidden line after it.
- The canvas hint the header printed describes the Canvas tab (title and
  description).
- A flow with no node yet keeps its tab row; its Canvas section offers the
  first node.
- Tests: railSearch-11794 reads rows by test id and pins the one-line label
  with the whole name on the row's title; flowCanvasChip-11665 reads the meta
  line beside the label; packageLessFlows-11553's miss case pins that no tab
  row is offered with no flow open.

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
… the objectui#11665 and objectui#11553 pins as they were

The hint is a visually hidden line of the header's meta and the Canvas tab's
description, so the row still reads it whole; the API name stays on the
label's tooltip and is not printed (objectui#11665). The two pins are back to
their origin/main bytes.

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
…angeset for objectui#12454

- AutomationsPillar.tabs-12454: the five tabs with Canvas open, the Problems
  tab's count pill against the Problems body, no duplicate of the four former
  info-bar buttons, a picked problem opening the canvas on its node, the
  Variables and Debug sections, and the rail row under its object's group
  with its trigger glyph and the legend.
- FlowPreview provides its chrome through FlowPreviewChromeProvider (the file
  exports components only); flowGrouping reads a flow's graphs through one
  guarded helper.
- .changeset/12454-automations-pillar-layout.md (minor, app-shell).

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
… light and dark (objectui#12454)

Taken from the local console (Vite, this branch) against HotCRM served by
`objectstack dev` (hotcrm 63db83e), on "Enroll Members in Campaign" with the
"Campaign Open?" decision selected, the artboard's region. The before pair is
the skeleton's `after/skeleton-automations-light.png` / `-dark.png`.

Claude-Session: https://claude.ai/code/session_01SJn1GEkrbbBQkhGC26wEDw
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests package: app-shell labels Oct 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 69 chunks) 3079.7 KB 3119.4 KB
Main entry chunk (gzip) 73.2 KB 350 KB
Entry file index-CtPezR9z.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) 20.90KB 7.67KB
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) 592.70KB 142.91KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 251.43KB 70.46KB
fields (index.js) 282.89KB 72.11KB
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.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.16KB 69.28KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.92KB 72.66KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 127.42KB 32.56KB
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.05KB 23.86KB
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

席位核对 — REWORK (patch round 1) · objectui#12454 · head 1de2c1d · 2026-10-15T12:29Z

Seat domain:ui#4, session session_01SJn1GEkrbbBQkhGC26wEDw.

The one item to fix: Test (shard 5/16) (job 116395636167) is red because of this PR. packages/i18n/src/__tests__/machineLocaleCensus-9909.test.ts lists packages/app-shell/src/views/studio-design/flowGrouping.ts:150: return new Intl.Collator(undefined, { sensitivity: 'base' });, which formats in the machine locale. The census's own remedy applies: thread the display locale into the pure helper, as the pillar already holds it. Do not add a DECLARED entry, because the group order is author-visible. The aggregate Test check is red only because of that shard.

Not to fix here:

  • Spec Main Shape Gate is the base-wide red from objectstack#23638, anchored on objectui#12464, objectui#12468 and PR objectui#12485.
  • Targets 4 and 5 (node-card styling, and the node aside) move to a follow-up card in the epic's subtree, so this PR stays inside its claim, as the report recommended.

Everything else reviewed so far stands for the ACCEPT:

  • the deviation list (the objectui#11665 api chip, the Label: captions kept for objectui#11779's pins, no divider or more button, the legend wording);
  • the truncating rail label, which the card's target 1 asks for; the objectui#11794 test was updated in the same PR, as the card's acceptance 4 allows;
  • 26 flows on hotcrm 63db83e, not 23.

The patch round runs as a cloud continuation of the same claim (6189041643) on the same branch, because the original subagent ended with a container restart.


Generated by Claude Code

… pillar hands in

The census in machineLocaleCensus-9909 flagged flowGrouping's fallback
collator, which formatted in the machine locale. The locale option is now
required and the collator is built from it directly; flowGrouping.test.ts
pins the zh-CN and en-US group orders for a label pair that differs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SCz2zoDR7YzaAc82kFEYPx
…tomations-pillar-layout

# Conflicts:
#	packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 69 chunks) 3082.1 KB 3119.4 KB
Main entry chunk (gzip) 73.3 KB 350 KB
Entry file index-B19mauB0.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) 20.90KB 7.67KB
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) 594.75KB 143.42KB
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) 282.89KB 72.11KB
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.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.16KB 69.28KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.92KB 72.66KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 127.76KB 32.64KB
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.05KB 23.86KB
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

…eset

The line is PR-body metadata; the changeset text is published verbatim
into @object-ui/app-shell's CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SCz2zoDR7YzaAc82kFEYPx
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 69 chunks) 3082.1 KB 3119.4 KB
Main entry chunk (gzip) 73.3 KB 350 KB
Entry file index-B19mauB0.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) 20.90KB 7.67KB
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) 594.75KB 143.42KB
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) 282.89KB 72.11KB
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.72KB 48.07KB
plugin-dashboard (index.js) 143.88KB 38.88KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 262.16KB 69.28KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 179.38KB 46.59KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 261.92KB 72.66KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 127.76KB 32.64KB
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.05KB 23.86KB
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#12454 · head 6f07ae0 · 2026-10-15T13:30Z

Seat domain:ui#4, session session_01SJn1GEkrbbBQkhGC26wEDw. Checked against GitHub and the diff, not against the reports. This follows the REWORK 6192072808 and two patch rounds.

Checklist

  • Form: draft → main. The first line is Fixes #12454, and the next line is exactly Clause-②: no; the seat corrected that line in the body. Closing keywords scanned: the other hits ("close, and…", "fixed (the aside's…") name no card.
  • Diff (11 files against main):
    • flowGrouping.ts is a pure grouping function: the Start node's object, else the first in-package data node, else the first record written, else "No object". It has its own unit tests, including the ten groups over HotCRM's 26 flows on hotcrm 63db83e.
    • The AutomationsPillar rail uses StudioRailGroup, with glyphs, status dots and a footer legend. The item header carries the meta, and the switch's title holds the off-by-default sentence.
    • The tab row replaces the info-bar buttons.
    • FlowPreview.tsx and FlowCanvas.tsx: the Studio chrome is scoped by FlowPreviewChromeProvider, so the metadata-admin designer keeps its info bar; the dev checked that with the verify gallery.
  • Patch round 1 (21397be, merged with main as 2c87994): the collator now takes the locale the pillar hands in; the locale option is required and the machine-locale fallback is removed. The census machineLocaleCensus-9909 is green, and one new case pins locale-sensitive order. The merge resolved the import block only.
  • Patch round 2 (6f07ae0): two lines deleted from the changeset (the Clause-② process line), nothing else.
  • Changeset prose, checked sentence by sentence against the diff:
    • rail groups by object, in label order, with counts and a trailing "No object" group, read off the flow definition: matches flowGrouping.ts;
    • rows (glyph, one-line label with the whole name in the title, 6 px dot, legend): matches the rail rows and the legend;
    • item header (Trigger, Status, Run as, version, switch title): matches;
    • tab row, with Variables, Runs and Problems as tab bodies and Debug beside the canvas: matches;
    • canvas (flush, 20 px dot grid, zoom bottom right, designer keeps its info bar): matches.
    • minor for @object-ui/app-shell.
  • Contract faces: none. No Clause-②: yes, no packages/spec, no governed path, and no change to the package entry. No contract-review record is owed.
  • Screenshots against automations.png: the rail grouping, header, tabs and dotted canvas match. The node cards and the node aside do not; they moved to objectui#12488. The seat sent them to the maintainer.
  • CI: on 2c87994, 34 success and 3 expected skips. Spec Main Shape Gate is green now that objectui#12485 has landed. On 6f07ae0 CI is running at this record; landing waits for every check to be green on this head.

Accepted deviations

  1. Targets 4 and 5 (node cards and the node aside) are not built: their files are shared metadata-admin surfaces outside the claim. They are carried by objectui#12488 (Blocked-by: #12454).
  2. The artboard's api chip is not rendered: flowCanvasChip-11665 pins the API name to the tooltip (objectui#11665), and that pin file is byte-identical to main.
  3. The header meta keeps its Label: captions and adds Status, because seven pins read them (objectui#11779). There is no divider and no more button, since the pillar has no flow action for them.
  4. The rail label truncates on one line, with the whole name in the row title; the card's target 1 asks for it. AutomationsPillar.railSearch-11794 was updated in the same PR, which the card's acceptance 4 allows. objectui#11794 fixed a stub label, and it was not a ruling.
  5. The card counted 23 flows; HotCRM has 26. The ten groups stand.
  6. The legend says "Autolaunched" where the artboard says "Subflow".

Out-of-scope findings (both reported "noted, not filed"):

  • The decision inspector's Branches reads "No items yet" while the edges carry conditions. The seat is investigating this, at the maintainer's request, together with the flow's Problems warnings.
  • A React Compiler memoization skip at doCreateFlow. Acceptance notes.

Implemented-by: os-dev subagent of session_01SJn1GEkrbbBQkhGC26wEDw (main work), and cloud session session_01SCz2zoDR7YzaAc82kFEYPx (patch rounds), branch claude/issue-12454-automations-pillar-layout
Reviewed-by: seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing · head 6f07ae0 · 2026-10-15T13:47Z


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 15, 2026 13:47
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 15, 2026 13:47
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 8146afe Oct 15, 2026
38 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12454-automations-pillar-layout branch October 15, 2026 14:01
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landed · PR #12481 merged as 8146afe on main · read 2026-10-15T14:01Z

probe on origin/main 8146afe reading control
studio-design/flowGrouping.ts present: flowTriggerGlyph, flowGroupObject, groupFlowsByObject —
new Intl.Collator(locale, …) in flowGrouping.ts (the patch-round-1 fix) 1 hit, :196 —
FlowPreviewChromeProvider 1 hit in metadata-admin/previews/FlowPreview.tsx, 3 in StudioDesignSurface.tsx —
AutomationsPillar.tabs-12454.test.tsx and flowGrouping.test.ts present AutomationsPillar.railSearch-11794.test.tsx updated in the same commit
.changeset/12454-automations-pillar-layout.md present —
docs/design/studio-redesign/after/12454-automations-{light,dark}.png present —

State change: the card closed as completed through Fixes #12454. pm:dispatched is removed in this act; pm:epic, domain:ui and area:studio stay. objectui#12488 (targets 4 and 5) had its only Blocked-by: target here, so it is dispatched next from this seat.


Generated by Claude Code

github-merge-queue Bot pushed a commit that referenced this pull request Oct 15, 2026
… the Studio Records grid and console lists draw every row (objectui#12480) (#12502)

Fixes #12480
Clause-②: no

## Root cause

The rows are not missing: they are drawn, below the fold of the grid's
scroll box. One row is very tall.

- `data-table` keeps a cell to one line with `truncate` unless the
column is authored `wrap: true`. `truncate` is nowrap + overflow hidden
+ ellipsis. It bounds inline content only. It never bounds the cell
body's height.
- The three rich-content cell renderers (`markdown`, `html`, `richtext`,
the `RICH_TEXT_FIELD_TYPES` table in `@object-ui/fields`) draw a block
document: paragraphs, headings, lists. Blocks stack under nowrap.
- HotCRM's `crm_account` has a `description` markdown field. Its seed
gives Acme Corporation a long multi-paragraph description. The Studio
Records grid shows every non-system field as a column (37 here), so the
Description column is in the grid, off-screen to the right.
- Result: Acme's row grows to the document's height (456 px in
Chromium). Its visible cells are vertically centred in that row, which
reads as "a tall empty band, then the row". The rows after it sit below
the scroll box's bottom edge, and the footer still counts them.
- The committed screenshot fits this exactly: row 9 starts at y 586, and
a 456 px row centred there puts its text at y 814. The screenshot shows
it at y 815.

The trigger is the content, not the row count. The 8-row object in the
card did not reproduce it because it has no long rich-content value. An
8-row object with one does the same thing (table below).

PR #12479 is not the cause: the screenshot's commit `cf430cd` is an
ancestor of #12479's merge commit (`git merge-base --is-ancestor` exit
0).

## The fix

`ObjectGrid` (`packages/plugin-grid/src/ObjectGrid.tsx`). Every column
passes through `applyColumnChrome`. That function now also runs a new
step, `withOneLineRichText`. For a column whose field resolves to a
rich-content renderer and which is not authored `wrap: true`, it wraps
the renderer's output in a `line-clamp-1` box. The first line of the
document shows; the rest is cut.

- The renderer itself is unchanged, so its sanitising pipeline stays the
trust boundary.
- A column authored `wrap: true` still shows the whole document, as
authored.
- The record-detail drawer resolves its renderers separately, so it
still shows the full document.

Why not in `data-table`: it does not know field types. A generic height
clamp there would also clip legitimate one-line widgets that are taller
than one text line. Measured on the same harness: thumbnails 32 px,
select badges 22 px, against a line height of 16 to 19.5 px.

Measured per type on the harness: only `markdown`, `html` and `richtext`
exceed one line. Before the fix, at the first row: html 176 px and
richtext 104 px. textarea, json, address, multi-select, file, image and
code stay within 16–32 px. So the clamp covers the whole class.

## Browser readings (Chromium `/opt/pw-browsers/chromium`, 1280 x 900)

Scratch harness in `apps/console` (never committed, deleted after). It
uses the real `ObjectView` (plugin-view) with `renderStudioGridList` as
its `renderListView` slot, inside a `min-h-0 flex-1 overflow-auto` body
like the Data pillar's `data-records-body`. A mock data source supplies
`crm_account`-shaped fields, plus a `description` markdown field
carrying the Acme description on the last row. The "console" rows mount
`ListView` (plugin-list) directly with its default toolbar, which is the
body the console's object list page renders. No backend ran.

| case | rows | before: tall row / rows inside the box | after |
|---|---|---|---|
| Studio, plain text only (control) | 8 / 9 / 10 | none, all 41 px, 8/8,
9/9, 10/10 visible | not re-measured in the browser; the jsdom CONTROL
pin holds it |
| Studio, one long markdown description | 8 | last row 456 px, 7 of 8
visible | all 41 px, 8 of 8 |
| Studio, one long markdown description | 9 | last row 456 px, 8 of 9
visible | all 41 px, 9 of 9 |
| Studio, one long markdown description | 10 | last row 456 px, 9 of 10
visible, table 873 px in a 642 px box | all 41 px, 10 of 10, table 458
px |
| console list body, same data | 8 / 9 / 10 | last row 456 px; 7/8, 8/9,
9/10 visible | all 36 px, 8/8, 9/9, 10/10 |

Triage's second question: **yes, console list pages show the same
thing.** They render through the same `ObjectGrid`, and this fix covers
both.

## Tests (head `256cd24d4`)

- New:
`packages/plugin-grid/src/__tests__/ObjectGrid.richTextOneLine-12480.test.tsx`
(jsdom does no layout, so these read the class contract and the row
count).
- 10 rows with a markdown, an html and a richtext column: 10 body rows;
30 clamps (`line-clamp-1`), one per rich cell; each document is drawn
inside its clamp; the text column is not clamped.
- `wrap: true` on the markdown column: no clamp, and the list is drawn.
- CONTROL: an 8-row object with no rich-content column: 8 rows, no
clamp, the cell still `truncate`s.
- Ablation (fix committed in `d4005d878`, mutated with objectstack's
`scripts/ablation-replace.mjs --hold` under an EXIT trap):
- The guard line in `withOneLineRichText` was replaced by an
unconditional `return col`. On disk: anchor count 1 to 0, marker count 0
to 1.
- Result: the pin went red (1 failed / 2 passed), and the browser's
console rows above went back to the 456 px row.
- Restored with `git checkout HEAD`. `git diff HEAD` is 0 bytes, and the
file's blob equals the HEAD blob (`887bcfcb3989`).
  - No dist step: the test imports `../ObjectGrid` by source path.
- `vitest run packages/plugin-grid/`: 216 files / 2015 tests passed (on
`d4005d878`). The new pin plus `ObjectGrid.columnWrapForward.test.tsx`:
8 / 8 passed on `256cd24d4`.
- `pnpm --filter @object-ui/plugin-grid type-check` (both `tsc`
projects; the test project includes `src/**/*.test.tsx`): exit 0, after
`pnpm --filter '@object-ui/plugin-grid^...' build` exit 0.
- No public export, prop or schema key changed, so the import-side
packages owe no tests (declared, CI runs them).

## Gates

- `check:phantom-deps`, `self-import`, `unreferenced-sources`,
`doc-example-readers`, `handler-key-reads`, `side-effects-array`,
`element-data-source-declaration`, `spec-symbols`,
`action-forward-parity`, `designer-field-key-parity`,
`icon-record-names`, `i18n-keys`, `i18n-drift`, `i18n-designer-parity`,
`control-bytes` and `new-line-citations`: all exit 0.
- `node scripts/check-changeset-fixed.mjs`,
`check-changeset-presence.mjs` and `check-changeset-no-major.mjs`: exit
0.
- `check:spec-floors`: exit 1, its "no-artifact" prerequisite line (it
wants a whole-workspace build). NOT MEASURED here. It is the known red
on main (objectui#12334).
- Lint, narrowed to the 2 changed files (`eslint --no-inline-config
--format json`). The test file has 0 errors. `ObjectGrid.tsx` has 1
error and 219 warnings; linted the same way, the base blob has 1 error
and 215 warnings. The one error is the same pre-existing
`react-hooks/static-components` far below the edit. The 4 new warnings
are `no-explicit-any` on the new step's `col` / `value` / `row` / schema
reads, the same spelling as its neighbour `withSortability`. The
repo-wide `pnpm lint` is CI's.

## Acceptance notes

- **Content, not count.** The card's "8-row case is fine" is true only
for an object with no long rich-content value. The pin's CONTROL keeps
that case unchanged.
- **`wrap: true` keeps the full document.** A rich-content column
authored `wrap: true` still grows its row to the whole document. That is
the author's choice, and this change keeps it.
- **Not measured.**
- The phone card layout (below 768 px). `ObjectGrid` resolves its own
renderers there, so this change does not reach it.
  - Kanban and gallery cards, which draw the same renderers.
- A dotted lookup-path column (no field definition here, so not
clamped).
- **Merge.** `origin/main` was merged once more right before opening
(`256cd24d4`, a merge commit). PR #12481's region of
`StudioDesignSurface.tsx` is untouched: this diff does not edit that
file.

Changeset: `.changeset/12480-studio-grid-missing-rows.md`
(`@object-ui/plugin-grid` patch).

The dev run's session is `session_01XVp19E1MYUTFM3dnkwz8gB` (seat
`domain:ui#2`).

---
_Generated by [Claude
Code](https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: app-shell tests

Projects

None yet

2 participants