Repository navigation
feat(app-shell,i18n): Studio orders an object's related lists, and a field group can place a related table - #27303
Merged
objectstack-fleet[bot] merged 6 commits intoOct 28, 2026
Conversation
…ces a related table in a field group WIP: RelatedListsEditor over the inbound relationships deriveRelatedLists derives (includeHidden), a shared OrderedRowList extracted from HighlightFieldsEditor, the group inspector's relatedList picker, and related-table groups that are no drop target in the form designer. Claude-Session: https://claude.ai/code/session_cdb7a717-def7-4e71-9988-f089fbaa18ff Co-authored-by: Claude <noreply@anthropic.com>
…lated-table placement; changeset Claude-Session: https://claude.ai/code/session_cdb7a717-def7-4e71-9988-f089fbaa18ff Co-authored-by: Claude <noreply@anthropic.com>
…lated-lists-editor
Claude-Session: https://claude.ai/code/session_cdb7a717-def7-4e71-9988-f089fbaa18ff Co-authored-by: Claude <noreply@anthropic.com>
… object list Claude-Session: https://claude.ai/code/session_cdb7a717-def7-4e71-9988-f089fbaa18ff Co-authored-by: Claude <noreply@anthropic.com>
…s vocabulary's objects reader Claude-Session: https://claude.ai/code/session_cdb7a717-def7-4e71-9988-f089fbaa18ff Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff 席位核对 · PR #27303 ← #27054 round 2 · epic PM
|
objectstack-fleet
Bot
deleted the
claude/issue-27054-related-lists-editor
branch
October 28, 2026 17:13
This was referenced Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #27054
Clause-②: no
Metadata-protocol: none
Round 2 of the card, its fifth and last item: Studio authors
relatedLists(the key #27069 shipped in PR #27215) as a drag-to-order list of the object's inbound relationships, and a field group can place a related table (fieldGroups[].relatedList). The other four items landed in PR #27163.维护者速读
fieldGroups[].relatedList;放置了关联表的分组在设计器里显示为该表,不再接受拖入字段。relatedLists: ['task', 'event', …], an ordered list of child relationships likehighlightFieldsis of fields; unlisted ones follow the derived order; a name that matches no inbound relationship is refused #27069 落地了relatedLists与分组relatedList两个键,但 Studio 没有控件,作者只能手写,而且手写的错名会被defineStack拒绝。deriveRelatedLists只加了一个记录页从不传的可选项includeHidden,以及把条目匹配抽成一个导出函数(行为不变,spec: an object declares the business order of its related lists —relatedLists: ['task', 'event', …], an ordered list of child relationships likehighlightFieldsis of fields; unlisted ones follow the derived order; a name that matches no inbound relationship is refused #27069 的顺序 pin 照绿)。回滚 = revert 本 PR。ui/packages/app-shell/src/views/studio-design/RelatedListsEditor.tsx(写入前校验write)、relatedListVocabulary.ts(词表 =deriveRelatedLists加includeHidden,不另写关系枚举)、ObjectGroupInspector.tsx的RelatedTablePlacement。pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/ObjectSettingsPanel.relatedListsOrder-27054.test.tsx,预期 5 个用例全绿;截图见下方证据分支。What changes
relatedLists(RelatedListsEditor, mounted in the Semantic roles card under highlight fields).deriveRelatedListsasked with a newincludeHiddenoption, so the editor offers exactly what the record page reads, plus the FKs arelatedList: falsehides (an entry may still name those:defineStackandpackages/lintvalidate-related-list-refscount them, and all three skip the audit FKs). No second relationship enumeration exists.aria-disabledand no drag, in the derived order (ownedmaster_detailchildren, then lookups). The add picker offers exactly that tail. Each item is spelled the child name, orchild.fieldwhen that child points here through more than one FK.hidden, and the switch stays on the field. A primary list is badgedin body.acceptRelatedListEntries. It keeps, in order and once, each entry that names at least one inbound relationship. A stored entry that names none keeps its row, shown in red with a sentence saying the next change leaves it out. The add picker goes through the same check.getTypeStatus('object')is notready). At that point a stored entry naming another object's FK cannot be told from a misspelling, so a write would drop it.deriveRelatedListsitself, split into body tables and side cards (the order applies within each).relatedList(ObjectGroupInspector→RelatedTablePlacement). A "Place a related table here" picker over the same vocabulary, checked by the same function before it writes. The picker is withheld while the group still holds fields, because the object parse refuses a field whose group is a table group. A relationship another group already places is not offered again. Clearing the picker removes the key.ObjectFormDesigner). A group that carriesrelatedListis drawn in its place as a "Related table" card. It is no field container: its droppable is disabled, and it is left out of the container map that drags, keyboard steps and the commit read. Without this the new picker would create a group that invites a drop the save then refuses.OrderedRowList). The drag + up / down + remove rows are extracted fromHighlightFieldsEditor, which now uses them too, so the code is not copied. The round-1 highlight pins pass unchanged.deriveRelatedLists.ts:relatedListEntryNames(entry, list)is now the one reading of an entry, shared byresolveRelatedListOrderand the editors, and the optionalincludeHiddenflags hidden FKsisHidden. The record page passes neither, so its output is byte-identical.Tests (head
5c2b715589)ObjectSettingsPanel.relatedListsOrder-27054.test.tsx(5) andObjectGroupInspector.relatedListPlacement-27054.test.tsx(5). These cover the three acceptance pins:['event.related_to', 'task'], andderiveRelatedListsover the real fixture registry changes its order to match;'nope'/'event.nope'never reaches a written value;The files also cover the add picker, removing the last entry, writing nothing while loading, group placement, the withheld picker, de-duplication across groups, and the designer's table card.
Test Files 21 passed (21) / Tests 181 passed (181).0d45c0e71f):packages/app-shell/src/views/studio-design/,packages/app-shell/src/utils/__tests__/,packages/app-shell/src/views/metadata-admin/inspectors/andpackages/i18n/gaveTest Files 567 passed | 1 skipped (568) / Tests 6360 passed | 22 skipped.pnpm --filter @object-ui/app-shell --filter @object-ui/i18n run type-check: exit 0 on the final head.--listFilesOnlyshows both new pins in the app-shell test program.scripts/ablation-replace.mjs. The anchorconst accepted = acceptRelatedListEntries(next, relationships);was replaced withconst accepted = [...next];, and the tool reported anchor 1 → 0, replacement 0 → 1, blobeb202671ad73→6d9ac4f61fbd. Result:Tests 1 failed | 4 passed (5), and the one red is exactly "a name that matches no inbound relationship never enters a written value" (expected [ Array(4) ] to deeply equal [ 'task', 'note' ]). Restore: blob == HEADeb202671ad73,git diff HEADempty,grep -cafter: anchor 1, mutant 0. The pin importssrcby relative path, so there is no dist leg.--freshbackend and the Console dev server, both on private ports, on this branch. In a scratch writable package (Customer + Ticket / Contract (master-detail) / Visit (two FKs) / Survey (relatedList: false)) I authored an order and placed a table. The publish door accepted the result:relatedLists: ['desk_visit.referred_by', 'desk_ticket'],fieldGroups[0].relatedList: 'desk_contract'. A stored'nope'showed as unmatched, and one move-up wrote['desk_ticket'].Screenshots, on the never-merged branch
claude/issue-27054-r2-evidenceat20360a7f0f:Gates (head
5c2b715589)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, which derived 34 families from 14 paths against merge base0d45c0e71. I ran each one and captured its exit code before any pipe. 33 exited 0.pnpm --dir ui exec vitest run scripts/exited 1 for host-only reasons:select-affected-tests-wiringcases fail onmapfile: command not found(macOS bash 3.2);Test timed out in 15000msunder batch load.Re-run alone,
check-i18n-call-site-keys,check-vi-mock-inherit,markdown-test-inputsandcheck-hand-rolled-comment-maskgaveTests 259 passed (259). Thecheck-i18n-dead-keysreal-tree case stays NOT MEASURED locally (it timed out). The gate itself (pnpm --dir ui run check:i18n-dead-keys) exits 0, and none of the new keys is listed.--ranreconciliation:Run reconciliation — 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN.pnpm check:changeset-fixed(roster under.changeset),pnpm check:i18n-stale-fill, andpnpm --dir ui runwithcheck:new-line-citations(0 new),check:i18n-keys,check:i18n-drift(18 keys added, 0 en values changed) andcheck:i18n-dead-keys.eslint --no-inline-configover the changed files: 0 new findings. The one error,react-hooks/static-componentsinObjectSettingsPanel.tsx, and the warnings inderiveRelatedLists.ts/ObjectFormDesigner.tsxare onmainalready.flock, soos-verify-lock.shnever took the shared lock.Acceptance notes
fieldGroups[].relatedListis onmain; the record page that draws it is console record page v3: frameless detail sections, one merged timeline (discussion + activity + field changes), compact related cards, header 1 primary + 2 secondary + ⋯ — the synthesized default page, drawn from the object's roles; the dead BuildPageOptions hints go #27055, which is in flight (console record page v3: frameless detail sections, one merged timeline (discussion + activity + field changes), compact related cards, header 1 primary + 2 secondary + ⋯ — the synthesized default page, drawn from the object's roles; the dead BuildPageOptions hints go #27055 remains open and is not addressed here). The key is spec-declared and passes the publish door, so authoring it now is what the ruling asked for.relatedLists: ['nope', 'desk_ticket']published from a package-scoped Studio publish with no refusal.validate-related-list-refsdocuments why in its header: a named child not in the stack is refused only whenwholeCollectionis set, and stays unjudged under a package closure. The.describe()onrelatedListssays such an entry is refused. The editor's pre-write check closes this for Studio. Raised in the report for the seat to judge, not filed from here.ObjectFormCanvas) also editsfieldGroupsand has no placement picker. The ruling named Studio's field-group editor, so it is left as it is.Generated by Claude Code