feat(record-pages): Details tabs reference the objects' fieldGroups (lead, opportunity, case) - #1990
Merged
objectstack-fleet[bot] merged 4 commits intoOct 3, 2026
Conversation
The lead record page's record:details sections become ten `{ group }`
references to crm_lead's fieldGroups (ruling C, decision batch #21), so
membership has one declaration site and the page curates only the order.
Notes, Do Not Call / Email Opt Out, the follow-up dates and the conversion
block become reachable on the Details tab.
The four page-only section names leave the locale packs with the sections
(`os validate` refuses a translation keyed to an undeclared section), and
the two pins that read the sections resolve the group's members instead.
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
…the Details tab
The opportunity record page's three hand-written record:details sections
become seven `{ group }` references to crm_opportunity's fieldGroups, the
same class ruling as the lead page. Primary Contact, the win/loss fields,
probability, approval status and the forecast metrics become reachable on
the Details tab; the strip's fields stay out of it because the renderer
drops what record:highlights registered.
The two page-only section names leave the locale packs with the sections.
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
The case record page's three hand-written record:details sections become
six `{ group }` references to crm_case's fieldGroups, the same class ruling
as the lead and opportunity pages. escalated_date, written by three flows
and shown nowhere, arrives with the Escalation group; first_response_date
and resolved_by_article arrive with theirs.
The three page-only section names leave the locale packs with the
sections. The create-form pin resolves a group section to its members, and
first_response_date's roster entry records the surface it gained.
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT Co-authored-by: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
This was referenced Oct 3, 2026
hotlong
pushed a commit
that referenced
this pull request
Oct 3, 2026
…ion and narrative groups Since #1990 every Details section is a `{ group }` reference to one of crm_opportunity's fieldGroups, so a group the object declares renders on the record page only once the page names it. The two groups REQ-0006 adds are referenced right after `sales_process`, in the order the object declares them, and both keep `hideEmpty: false` on #1211's reasoning: every member is something the seller is expected to fill in, and no deal that predates REQ-0006 carries any of them, so the platform default would hide both sections on every existing deal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
hotlong
pushed a commit
that referenced
this pull request
Oct 3, 2026
…tive and status-change gate, for reps and admins
- content/docs/sales/opportunity-qualification{,.zh-Hans,.zh-Hant}.mdx:
the user-facing page REQ-0006's product response asks for — whether a
deal is worth pursuing, the customer's procurement calendar against our
close date, the deal narrative, the business line, and the optional
sign-off on a won/lost call (off by default; how a request, approval
and rejection play out; how an admin arms it). Business concepts, not a
field roster. Registered in the three sales meta files.
- content/docs/administration/automation{,.zh-Hans,.zh-Hant}.mdx: the
Opportunity Status Change Approval row, the header count 30 -> 31, and
a paragraph under Approvals; the ledger in
test/automation-docs-coverage.test.ts gains its two Chinese row labels.
- content/docs/sales/opportunities{,.zh-Hans,.zh-Hant}.mdx: the Tender This
Quarter row and section (ten saved views), the two new field groups and
the new fields in the field-group table, the customer calendar on the
form's Forecast tab, and the Details tab described as the object's
groups — it has been a list of `{ group }` references since #1990, so
"three sections holding seven fields" was already untrue and this
branch's two new sections would have made it more so. The zh-Hant name
is pinned in test/docs-view-rosters.test.ts.
- README.md: 30 -> 31 flows, the count the stack registers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
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 #806
Fixes #1452
Fixes #970
What changed
The three record pages that author their own
record:detailsbody (lead, opportunity, case) now write every section as a{ group: 'KEY' }reference to the object'sfieldGroups. This is maintainer ruling C (decision batch #21, 2026-09-03, verbatim 「批次 #21 同意」), ruled once for the class. Membership now has one declaration site, thegroup:on each field. The page curates only the order.Not done, by the ruling and the dispatch: no
fields:enumeration, nohideEmpty, no hand-mirrored groups, nofieldGroupschange, nosrc/*/views/*.view.tschange.One commit per card:
51b4d611(#806, lead),6543e055(#1452, opportunity),ca778782(#970, case),42a65819(changeset).Measurement first: the restart probe (#806
Restart-probe:) reads greenSetup:
origin/main0b2a9d4d,@objectstack/console17.6.0, headless Chromium/opt/pw-browsers/chromium, port 4806.objectstack start --artifactwith a fresh home and a fresh SQLite DB, from a cwd that has noobjectstack.config.ts. The server ran in its own session and was torn down by process group.record:detailssections oflead_detail_pagediffer between legs. Each leg was a scratchpad copy ofdist/objectstack.json. The worktree was never edited.GET /api/v1/meta/pages/lead_detail_pagename/label/fieldssections{ group }entries, in crm_leadfieldGroupsordername/label/fieldssectionsEvery leg passed three gates: health, the listener PID belongs to the started process group, and the served metadata equals the leg artifact. All three legs logged the same two to four
Failed to load resource: 404console lines.objectstack startloadedobjectstack.config.tsrather than--artifactand served the authored sections. The served-metadata gate caught this, and B was re-run from a cwd with no config.What the Details tab reaches, before and after
Both runs used the same seed, the same browser procedure and the same gates. Before is artifact
0b2a9d4d; after isca778782. "After a click" means one of two things:fieldGroupsentry declarescollapse: 'collapsed', so you click the heading; orLead (a suspected-duplicate lead with notes, do-not-call and follow-up dates set)
notes,do_not_call,email_opt_out,next_followup_date,last_contacted_date,need_type,estimated_amount,conversion_approval_status,full_name,is_converted, andconverted_account/converted_contact/converted_opportunity/converted_date.descriptionis now inside Additional Info, which starts collapsed. Duplicate Management also starts collapsed (the banner copy still says to open it).Opportunity (a new deal with a primary contact and no campaign)
primary_contact,stage_entry_date,approval_status,approved_date,win_reason,loss_reason,loss_details,days_in_stage,is_private.crm_campaignwhile it is empty. The Campaigns group has that one member, and a group whose members are all empty renders nothing. The field is on the Edit form, and the group renders once a campaign is set.collapsible: true. Notes & Next Steps is not collapsible, becausecollapsiblecannot sit besidegroup.amountandexpected_revenueare both in the strip. It stays referenced so that a future member reaches the tab.Case (an open case, plus a second case with a resolution and a first-response date)
escalated_date, the crm_case 与 crm_lead 同病:三套互不相同的字段分组(fieldGroups 6 / 详情页 3 / 表单 3),escalated_date 三处写入、零处展示 #970 subject, under Escalation. Alsosubject,is_closedand, on the second case,first_response_dateandresolved_by_article.internal_notesis still reachable on the open case, in the System group. Measured: the group renders becauseis_closedis a boolean that always holds a value.resolutionandresolution_time_hourswhile they are empty. The Resolution group, and SLA & Priority once the strip's fields leave it, have no member with a value, so they render nothing. Measured on the second case: both groups render once a member carries a value. Close Case collects the resolution as a required screen input, andresolution_time_hoursis readonly and derived at close.Pins that moved with the sections
test/lead-duplicate-visibility.test.ts: the duplicates section is now found bygroup: 'duplicates'. Its members resolve from crm_lead's fields. The same four-field and strip-disjoint assertions apply, plus a new check that the section does not re-enumeratefields.test/detail-section-dedup.test.ts: a group-reference section enumerates nothing, so the strip-dedupe rule has nothing to read in it. Its "carries at least one field" assertion now counts the group's visible members on the page's object. Thelead_detail_pageexemption is removed because that page no longer enumerates anything.test/case-create-form-narrowing.test.ts: thedetail.detailssurface now expands a{ group }section into its members.first_response_date's roster entry changes from no surface todetail.details, with the reason (it arrives with theslagroup).No skip and no quarantine.
Token ratchet (
pnpm hygiene:tokens, comment-stripped)src/salessrc/serviceNo ceiling moved.
Verification
pnpm verifyat42a65819, under the shared lock, printedos-verify-lock: VERDICT command-exit 0 · held the lock 174s:lint:i18n-gate: 0describe.runIf16.x branch intest/dataset-granularity.test.ts)Acceptance notes
src/sales/translations/{en,zh-CN,ja-JP,es-ES}/objects.{pipeline,service}.ts.os validaterefuses a_sectionstranslation keyed to a section name nothing declares (translation-target-unknown, an error). The page-only names had to leave with the sections: leadinfo/crm_contact/detail/description, opportunityinfo/description, caseinfo/status/description. Their comments were re-stated.test/field-groups-coverage.test.tsprose that this change made false (it called crm_lead "the standing counter-example") was re-stated.src/service/views/case.view.ts, around lines 359–372, names the detail page's "Status & SLA section" and "Description section". Those sections no longer exist. That file is excluded by the ruling and held by 26 sections authorspan: 'full'and do not span the row at modal width — measured pixel-identical to writing nothing, and 24 of them were rewritten INTO that spelling by PR #1605 #1870.crm_opportunity._sections.crm_forecaststill reads "Stage & Forecast" (阶段与预测 / ステージ・売上予測 / Etapa y Previsión). en reads "Forecast & Metrics". This wording predates this PR and was written for the old page section of the same name. It is now the heading of the Forecast & Metrics group on the opportunity Details tab. Values were not changed (⛔ no coined translations).first_response_datenow has a human surface. It is in theslagroup and writable on the object (noreadonly), so the Details tab's inline edit applies where a profile grants update. Inline edit itself was not measured. Its single writer isevent.hook.ts. Whether it should be readonly is an object decision, not this card's.columns: '2'does not reach group sections. They lay out their own column count; Identity rendered 4 columns. Measured in the browser, renderer behaviour, not changed here.src/serviceinteraction layer to about 6,000, andsrc/salesto about 30,000 (the sales suggestion predates this PR). Ceilings are untouched here.Generated by Claude Code