Skip to content

Console records: a hover card on every record reference (compact related rows, relation columns, lookup chips) shows the target's declared highlightFields without navigating #27604

Closed

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

Filed from the record-page epic #26676 as a sub-issue (the maintainer, 2026-10-29, looking at Twenty's inline relation expand: 「他的相关表字段点击下拉箭头可以展开」; the seat recommended a stateless hover card over an inline accordion and the maintainer answered 「同意」). It adds one face to a referenced record — a glance — without a drill-down; it is not part of the v4 anatomy (#27524) and flies on its own.

Source (main 273137d227)

Target

  1. One hover card for every record reference: hovering the name in a compact related row, a relation cell in a list / the enlarged tab's table, or a lookup chip in the details column shows, after ~400 ms, a card with the target's icon + name (a link that opens it the way a click would) and its declared highlightFields minus the name (max 6), in the target object's own field renderers (chips, currency, dates). Keyboard: focusing the reference and pressing Space shows the same card; Esc hides it.
  2. Stateless: no expand state, no stretching of the host; the card floats (popover), dismisses on mouse-out / blur; one card at a time.
  3. Data: one request per shown card, cached per record for the page's life; never prefetched for every row (a list of 200 rows must not fire 200 requests).
  4. Scope: console only, every object; the card's content comes from metadata (highlightFields), nothing authored per object; ⛔ packages/spec/**, no new key. Objects whose highlightFields resolve to nothing show the name and the object label only.

File surface

ui/packages/plugin-detail/src/RelatedCardStack.tsx / relatedListCompact.ts (the row's reference), the lookup / relation field renderers in ui/packages/components/src/** (one shared RecordHoverCard component beside the existing lookup popover), the list / grid relation cells in ui/packages/plugin-list / plugin-grid, i18n (the object label fallback), tests beside, changeset.

Acceptance

  1. Tests: the card shows the declared highlights minus the name for a lead, a contact (no status field — nothing invented) and a product; a reference with no highlights shows name + object label; one request per card, none on row render; keyboard Space / Esc; the card never changes the host's layout.
  2. Screenshots on HotCRM: the card over a related row in the split pane, over a relation cell in the 任务 tab's table, and over a lookup chip in the details column, on a never-merged evidence branch.
  3. The epic seat verifies in the console preview before ACCEPT (maintainer: 「车队开发完后你审核效果」).

Activity

  1. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    Claim: PM loop round 1
    Session: session_01Utp6CbDAucNyQ4UtzCJKyh
    Account: os-bill
    Branch: claude/project-thread-xisvxo (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27604
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: a shared RecordHoverCard in ui/packages/fields/src/ beside ReferencedRecordLink (amended 2026-10-30T01:57Z: fields depends on components, and the card draws highlightFields through the target's own cell renderers, so it cannot live in components without a cycle; ⛔ components/src/ui/** still untouched), exported from @object-ui/fields for plugin-detail's compact related row (RelatedList.tsx compact face ~L2890); the lookup/relation cells wired once through LookupCellRenderer → ReferencedRecordLink; @object-ui/i18n packs for the object-label fallback if needed; tests beside; root .changeset/; ⛔ packages/spec/**; ⛔ plugin-detail RelatedList.tsx ~L811 docblock (in-flight PR #27793) (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier on fec60e00: no path-derived mandate), effort: xhigh
    Clause-②: yes (widening)
    Metadata-protocol: none
    Responsibility: a stateless hover card on every record reference shows the target name + declared highlightFields (max 6, name excluded) in its own renderers, one request per shown card cached per record, keyboard Space/Esc, host layout unchanged; tests + screenshots on a never-merged evidence branch; the epic seat re-measures in the console preview before ACCEPT
    Thread-read: none
    Premise: holds
    Serial constraints cleared: maintainer 2026-10-30 01:47Z/01:49Z dispatch-now; in-flight #27626 (seat 4) adds a data-layer cache — keep this card's cache local

    Dispatched 2026-10-30T01:52Z to a card thread of the seat's project; the order lives in the project. ⛔ The thread posts no claim and writes no assignee.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6Ca4Vk1969xZxELoSFG
    os-dev-report

    {
      "issue": 27604,
      "status": "done",
      "branch": "claude/project-thread-xisvxo",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27912",
      "head": "090db133549c4ab7b5dbb8127a9e76a1d7255e11",
      "session": "session_01Utp6Ca4Vk1969xZxELoSFG (card thread, mode:thread; seat session_01Utp6CbDAucNyQ4UtzCJKyh)",
      "premise_still_valid": true,
      "summary": "Premise true on main: a record reference only linked to its target, with no preview. One card for every record reference: new RecordHoverCard in @object-ui/fields, wired into ReferencedRecordLink (the anchor LookupCellRenderer draws, so a list relation column, a related list's table and enlarged view, and a details-column lookup chip) and into the name of a compact related row (RelatedList compact face). After 400 ms hover or Space on the focused reference it shows the target's icon, its name (opens as a click on the reference does) and the declared highlightFields minus the name field and minus fields the viewer may not read, capped at 6, drawn with getCellRenderer; Esc / pointer-out / blur hide it; one card at a time; portalled to document.body so the host layout is unchanged. No highlightFields declared: name plus object label. Read seam: nothing on render; one dataSource.findOne per shown card (with $expand only for readable reference highlights), kept in a module-local Map in RecordHoverCard.tsx (at most 200, dropped on subscribeDataChanges). It calls findOne on whatever DataSource the host hands it, so #27626's data-objectstack in-flight dedupe sits underneath with no second layer here. No spec change, no new metadata key; new public export RecordHoverCard (Clause-2 yes, widening).",
      "files_changed": [
        ".changeset/27604-record-hover-card.md",
        "ui/packages/fields/src/RecordHoverCard.tsx",
        "ui/packages/fields/src/__tests__/RecordHoverCard-27604.test.tsx",
        "ui/packages/fields/src/__tests__/RecordHoverCard.fieldAccess-27604.test.tsx",
        "ui/packages/fields/src/index.tsx",
        "ui/packages/plugin-detail/src/RelatedList.tsx",
        "ui/packages/plugin-detail/src/__tests__/RelatedList.compactHoverCard-27604.test.tsx"
      ],
      "tests": "New 3 files, 15 tests (lead, contact with no status field, product, no-highlights object, unreadable record, unreadable highlight field, 200 rows with 0 reads then 1 per shown card and a cache hit, hover delay, focus vs Space/Esc, one card at a time, host markup unchanged, title opens through the host; compact row hover, Space/Esc, title). On e57402aa: the 3 new files plus 34 existing files that render LookupCellRenderer / recordHref / RelatedListCompactContext in fields, plugin-detail, plugin-grid, plugin-list: Test Files 37 passed (37), Tests 283 passed (283), VERDICT command-exit 0; type-check fields + plugin-detail exit 0; eslint on the 6 changed ui files 0 errors. Ablation (scripts/ablation-replace.mjs, anchor 'name !== nameField &&' 1 -> 0, restored, git diff HEAD empty): 1 failed | 10 passed. On merged head 49504eb8: plugin-detail closure rebuilt, both type-checks, same 37 files: 37 passed, 283 passed, VERDICT command-exit 0. On 090db133 (main merged again, 6 commits outside ui/): 3 new files, 15 passed, VERDICT command-exit 0. Browser (Chromium, examples/app-showcase, 49504eb8): 0 by-id reads after the Projects list rendered, 1 read after one hover on an Account cell; cards seen on a list relation cell, a details lookup chip and a compact related row; Space showed one card without navigating, Esc left none. Evidence branch claude/issue-27604-evidence @ a8b2da2d, folder evidence/27604/ (3 PNG, 2 Playwright scripts, README).",
      "gates": "dispatch-gates --commands on e57402aa and again on 49504eb8: 35 derived, each recorded as `<command> :: exit <code>` (all exit 0, check-sdui-manifest and its --self-test included) plus check:changeset-fixed exit 0; --ran reconciliation both times: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. check:new-line-citations 0 new. 090db133 adds only files outside ui/. CI families: see PR check-runs.",
      "line_budget": "n/a — no skills/** or ledgered file touched (net +1147 / -35 over 7 files, 518 of them the new component)",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "deviations": [
        "Component placed in @object-ui/fields, not under components/src/ui/**: fields depends on components, and the card draws target values with getCellRenderer from fields. Agreed with the seat, which amended the Claim's file surface.",
        "Screenshots taken on examples/app-showcase (showcase_account declares highlightFields), not HotCRM: this container reaches only this repository.",
        "PR body line 2 links this card thread (cmsg_016iMXWSZDzqWRWvWzdNo8wgDSnrkE4tAZzd2PBTPkxkA8), not the seat thread named in the order: the session's required attribution block names this thread and says to keep its link exactly. Line 1 is as ordered.",
        "Harness post-PR assignee/reviewer step skipped per the maintainer's routing rule; relay read-back shows no assignees.",
        "Two GitHub MCP reads (mcp__github__issue_read on 27604) made before reading this order, which forbids MCP; the card and comments were then read through REST. No MCP write.",
        "Commit trailers are the model-free pair from AGENTS.md (Claude-Session + Co-authored-by: Claude), not the harness's model-named co-author line."
      ],
      "mcp_calls": "4 — mcp__github__issue_read x2 (reads, see deviations); mcp__claude-code-remote__get_session x1 (session id lookup); mcp__claude-code-remote__subscribe_pr_activity x1 (PR 27912 event subscription, not a GitHub write)",
      "api_writes": "2 — relay pr_create (repository_dispatch -> POST /repos/objectstack-ai/objectstack/pulls, draft, read-back identical 10198 bytes, assignees none); this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/27604/comments). git pushes (designated branch, evidence branch) not counted.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Report taken 2026-10-30T03:28Z.

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    This card is claimed by ui seat 4 and is not waiting in the queue. Its PR is #27912: green, NOT governed and mergeable_state clean. The PR had stayed draft only for the epic seat's preview check. The maintainer ruled at 10:39Z that the seat accepts and merges on its own. ACCEPT → PR #27912 comment 6520829118 · 2026-10-30T10:42Z. The PR is now marked ready with automerge on, and the card closes when it merges.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:uienhancementNew feature or requestpm:dispatchedpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions