Repository navigation
fix(platform-objects): name a team membership by the person and the team, and give a team's Members list its own columns - #30452
Conversation
…lists (red) The team page's Members list leads with the member row's record title, a formula over the two lookup ids, because the relationship authors no columns. Pin the columns both lookups should declare. Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
…d of leading with two raw ids sys_team_member's record title is a formula over its two lookup ids, and a related list with no authored columns leads with the record title, so Setup's team page opened its Members list on a "USER_ID in TEAM_ID" column. Declare relatedListColumns on both lookups: the team's list shows the user and when they joined, a user's list the team and when. Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
…lumns Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
… the team (red) The title reads the two stored lookup ids, so a team's Members panel, a membership's H1 and every reference to the row name it by two raw ids. Pin the one-hop title sys_business_unit_member already uses: the user's name (else email) and the team's name, null when a hop is unresolved. Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
…eam, not two stored ids display_title composed the two lookup ids, so a team's Members panel, a membership's H1 and every reference to the row read USER_ID in TEAM_ID. Read the user's name (else email) and the team's name one hop through the lookups, as sys_business_unit_member's title does (ADR-0079 addendum). Claude-Session: https://claude.ai/code/session_01Utp6CaBLFhcLHEkCSSBNMM Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 11 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 2 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3baee4d2bb012689bd4ebea526501b0846ea27be && git checkout 3baee4d2bb012689bd4ebea526501b0846ea27be
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin df4c06e6b165bb0a30eb86e4ace6258932f69d8a d2e37144b76d5e558fc3c20388832b1fe54e4534 && git checkout -B drift-repro df4c06e6b165bb0a30eb86e4ace6258932f69d8a && git merge --no-ff d2e37144b76d5e558fc3c20388832b1fe54e4534
node scripts/docs-audit/affected-docs.mjs --json df4c06e6b165bb0a30eb86e4ace6258932f69d8a
|
|
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb 席位核对 · ACCEPTHead
Marking ready and arming auto-merge. The remaining CI runs in the queue. |
Requested by Bill · project thread
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
维护者速读
sys_team_member的声明,不存列、不迁移数据;标题按读者权限读一跳,读不到用户或团队时标题为空而不是显示 id。回滚即撤本 PR。packages/platform-objects/src/identity/sys-team-member.object.ts的display_title公式与两个 lookup 上的relatedListColumns;identity-display-title.test.ts新增的sys_team_member描述块。pnpm --filter @objectstack/platform-objects exec vitest run src/identity/identity-display-title.test.ts src/identity/sys-team-derived-related-lists.test.ts,预期 40 条全绿;在 main 的字节上其中 6 条红。Fixes #30421
Clause-②: no — a platform object's shipped declaration: no exported member, accepted value or authorable key changes; what a read serves for the computed
display_titlechanges from two ids to two namesMetadata-protocol: none — shipped platform metadata, not what a metadata author writes
Skills-docs: none —
git grep -e sys_team_member -e relatedListColumns -- 'skills/**'hitsskills/objectstack-data/rules/relationships.md:329,350andskills/objectstack-ui/rules/record-page.md:22, which describerelatedListColumnsin general and stay trueWhat changes
The card's Expected: a team page's members list shows the user plus a useful second column such as when they joined, and no column of raw ids; the same for a user page's teams list.
The seat's ruling, corrected mid-card. The order ruled the producer declaration (
relatedListColumns) and ruled out a formula title that reads related titles, as a change to how formula titles compute. Measured before the change: that capability already ships (ADR-0079 addendum 2026-10-18, a formula title reads one hop through a reference), andsys_business_unit_memberandsys_user_permission_setalready use it; andrelatedListColumnsreaches only the table, while the record page's related column draws each member row titled by the record title (objectuiRelatedList.tsx, compact card:getRecordDisplayName). The seat then ruled, verbatim:1. The record title (
sys-team-member.object.ts,display_title). It wasrecord.user_id + ' in ' + record.team_id, the two stored ids. It is now the expressionsys_business_unit_memberuses, with the team in place of the unit: the user'sname, or theiremailwhere the name is blank, then' in ', then the team'sname, each read one hop through its lookup. Both hops are read as the reader (the engine'scallerauthority): a user or team the reader may not read, or one that no longer exists, leaves the title null, never an id. Neither lookup is read bare beside its hop;sys_team.nameis required stored text, so there is no second hop. The field's label and description are unchanged, so no translation bundle moves. This is what the members panel in the record page's related column, a membership's own H1, and every reference to the row now show.2. The team page's Members list (
team_idlookup). A derived related list with no authored columns leads with the child's record title (ADR-0079, objectuileadWithNameField) and then itshighlightFields. The reader of the relationship's columns is objectui'sderiveRelatedLists(ui/packages/app-shell/src/utils/deriveRelatedLists.ts,relatedListColumnson the FK field becomes the list'scolumns), andRelatedListdraws authored columns as written, with no name lead, dropping only the key back to the parent.team_idnow declaresrelatedListColumns: ['user_id', 'created_at']: the list shows the user and when the membership began. Kept beside the title fix: with names, the led Title column would still repeat the User column and the team the page is about.3. A user's Teams list (
user_idlookup) declaresrelatedListColumns: ['team_id', 'created_at'], the ruled pair. It is latent in Setup today:sys_user_detailis an authoredkind: 'full'page, which draws only the lists it names, and it names no team memberships. It applies on a user page that derives its lists.Changeset:
@objectstack/platform-objectspatch, both declaration lines.Tests
identity-display-title.test.ts(the shared title harness): thesys_team_memberrow now carries the related rows the read path preloads and is titledAda Lovelace in Core Platform, still equal to the retired template's text and never containing an id; a newdescribepins that the formula reads both lookups only through the hop (team_id.name,user_id.email,user_id.name), that a blank name falls back to the email, and that a lookup carrying no related row leaves the title null (three spellings: both, either one).sys-team-derived-related-lists.test.ts(the shared team related-list harness): a new top-leveldescribepins both lookups'relatedListColumns, that neither names the record title, that every column is a field of the member row, and that neither names the key the list drops.Acceptance notes
packages/platform-objects/src/**:sys_member(USER_ID (role); both parents' pages are authored and name their columns, so no list leads with it),sys_two_factor(Two-factor for USER_ID; its parent's page is the authoredsys_user_detail, which does not list it),sys_scim_projection_grantandsys_scim_group_member(no Setup navigation reachessys_scim_userorsys_scim_group, and no authored page lists them). None is a related list a Setup page draws, so none is changed here (the order's rule); their own record titles still read ids, reported to the seat.sys_business_unit_memberalready follows, by the seat's ruling.Verification
All readings on head
d2e37144(the fix's five commits plus one merge ofmainatfdd06415, which touched no file here and none of the package's tests), except the per-step red and ablation legs, each named with its commit.Red on main's bytes, green, ablation
Both legs read
src/directly (relative imports), so no build stands between the mutation and the run.The title a read serves, through the real engine (one-off measurement, not committed)
ObjectQL + SqlDriver (better-sqlite3 in memory) over the built
dist/of@objectstack/objectql,@objectstack/driver-sqland this package atd2e37144, registeringSysUser,SysTeamandSysTeamMember, the setup ofplugin-security/src/business-unit-member-title.test.ts:The engine logged its one
WARN formula field 'display_title' … could not be evaluated, so it reads nullfor the unreadable-user read, as designed.Suites, typecheck, lint
Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackond2e37144: 58 commands; each run, exit code recorded before any pipe.--ran: 58 derived, 57 run, 1 NOT-MEASURED, 0 UNRUN.pnpm check:i18namong them (after building its declared prerequisite closure).pnpm check:dual-build-cjs-loads, exit 3 (prerequisite: every workspace package'sdist/; this tree has no full build). CI'sLint & Repo Gatescarries it.node scripts/check-plugin-teardown-shape.mjs --self-test: exit 0 after fetching its control commit into this shallow clone.check:authz-resolver,check:changeset-fixed,check:error-code-casing,check:filter-alias-parity, all exit 0.Dogfood: not owed (no
!in the title, no(narrowing)arm).Generated by Claude Code