Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

plugin-list, plugin-map, plugin-timeline: the record preview overlay is a raw Object.entries dump in four views while five views render RecordDetailPanel — plus four byte-identical helpers to collapse #13458

Closed

Description

@os-zhuang

Ruled: 6395692163 · letter A · 2026-10-25T09:00:06Z(限 formatDate 折叠一条:保留今日格式,不改用 formatDateTime)

Filing gate ③: a maintainer-directed task. Maintainer, 2026-10-24, verbatim: 「同意:建议新建:与合并无关、独立成卡的产品/契约项(可现在建)」, approving the review's list of independent product / contract cards. Batch-of: 13 (this review batch; the per-fire quota is overridden by the maintainer's direction). Also filing gate ①: a user-visible defect with a named location. reach: the record preview overlay opened from a row in the list, gallery, map and timeline views (interface entry; files named below).

维护者速读

同一条记录,从列表/画廊/地图/时间线四个视图点开的预览弹层是 Object.entries(record) 的原始键值 dump(snake_case 键、String(value)),而日历/甘特/网格/看板/树五个视图用 RecordDetailPanel。四处弹层体 15 行逐字节相同。顺带四组已漂移的复制:GANTT_CONFIG_SPELLING 两份、记录可编辑判定缓存两份(分别引 #11699 与 #13341)、isSameAuthoredFilter 两份、isPlainObject/isRecord 33 个定义(其中一处接受数组)、formatDate 三份。

Measured (2026-10-24, HEAD 7981384; duplicate detection over normalised consecutive lines, blocks of 8 or more identical lines across packages)

  • Raw-dump overlay body (Object.entries(record).map(([key, value]) => … key.replace(/_/g, ' ') … String(value ?? '—')) inside NavigationOverlay is byte-identical in packages/plugin-list/src/ListView.tsx, packages/plugin-list/src/ObjectGallery.tsx, packages/plugin-map/src/ObjectMap.tsx, packages/plugin-timeline/src/ObjectTimeline.tsx. grep -rl "<RecordDetailPanel" packages/plugin-*/src → calendar, gantt, grid, kanban, tree (and plugin-detail itself).
  • const GANTT_CONFIG_SPELLING (33 lines) defined twice: packages/plugin-list/src/ListView.tsx and packages/plugin-view/src/ObjectView.tsx.
  • Verdict cache (cachedPrincipal / retainForPrincipal / verdictCache / pendingVerdicts / recheckDue) copied between packages/plugin-detail/src/useRecordEditable.ts and packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts; the two copies already cite different issues (objectui#11699 vs objectui#13341). plugin-grid already depends on plugin-detail.
  • isSameAuthoredFilter (23 lines) identical in packages/react/src/hooks/useResolvedFilter.ts and packages/plugin-grid/src/ObjectGrid.tsx; ObjectGrid already imports 13 names from @object-ui/react.
  • isPlainObject / isRecord / isObject: 33 definitions in 10 packages; one variant (react/src/hooks/useElementDataSource.ts) omits the !Array.isArray check. formatDate(s, locale) byte-identical in apps/console/src/pages/system/AuditLogPage.tsx, apps/console/src/pages/system/ApprovalsInboxPage.tsx, packages/app-shell/src/views/RecordApprovalsPanel.tsx while @object-ui/i18n exports formatDate / formatDateTime. Positive control: cn has exactly one definition.
  • Business reason: a business user who previews the same record from the map and from the kanban sees two different panels; AI-written fixes to the verdict cache land in one copy and miss the other (already happened: the two copies cite different cards).
  • Dedup (Object.entries(record)|RecordDetailPanel|GANTT_CONFIG_SPELLING|isPlainObject|formatDate): 10 hits, 0 open, none about the overlay inconsistency or the copies (objectui#11672 was a closed dogfood sweep; objectui#6349 covered duplicate type names, not code).

Task

  • Render RecordDetailPanel from @object-ui/plugin-detail in the list, gallery, map and timeline overlays (the same plugin-to-plugin-detail edge five plugins already carry).
  • One GANTT_CONFIG_SPELLING exported from the package that owns the lower layer; one verdict cache in plugin-detail consumed by plugin-grid; isSameAuthoredFilter exported from react.
  • Add isPlainObject to @object-ui/core (beside deepFreeze) and replace the 33 locals when a file is touched; collapse the three formatDate copies onto @object-ui/i18n's formatDateTime now (Ruled A 6395692163: keep today's toLocaleString format; one local helper or drop the item, the seat's call). No lint rule.

Who acts: objectui domain:ui seat; the overlay fix is one PR, the helper collapses can ride it or follow. Effort S. Risk low.

Filed by the read-only whole-repo review session https://claude.ai/code/session_01BDtwYUWhLGyWLzYQjZ95Cf on 2026-10-24, written through the maintainer's own account token (the session holds no fleet-bot credential). Evidence files: that session's scratchpad (objectui-review-report.md, findings-*.md). ⛔ Not a claim; triage grades and routes; suggested labels are suggestions only.

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 24, 2026
  2. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade — bug · priority:p2 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-24T17:02Z

    ⛔ Not a claim, ⛔ not a dispatch.
    finding comes off.

    • p2: user-visible. Four views preview a record as a raw key dump. Point them at RecordDetailPanel, as the other five views do, and fold the drifted copies in the same PR.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 · 2026-10-25T01:05Z
    Session: session_01NPcF7MHudqXa2mJPbTDAeU (the card session that works this card; claim written by the domain:ui seat 4 session session_01XWGTsmqrtrt1Zqh1ioWqsT)
    Account: os-elon-musk
    Branch: claude/project-thread-u58up3 (platform-assigned at spawn; the card session can push only this branch)
    Worktree: objectui-issue-13458
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: the four overlays in packages/plugin-list/src/ListView.tsx, packages/plugin-list/src/ObjectGallery.tsx, packages/plugin-map/src/ObjectMap.tsx, packages/plugin-timeline/src/ObjectTimeline.tsx; GANTT_CONFIG_SPELLING in ListView.tsx and packages/plugin-view/src/ObjectView.tsx (one copy, exported from the lower layer); the verdict cache in packages/plugin-detail/src/useRecordEditable.ts (+ the package index.ts export) and packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts; isSameAuthoredFilter in packages/react/src/hooks/useResolvedFilter.ts (+ export) and packages/plugin-grid/src/ObjectGrid.tsx; isPlainObject added to packages/core and replacing locals ONLY in files this PR already touches; the three formatDate copies (apps/console/src/pages/system/AuditLogPage.tsx, ApprovalsInboxPage.tsx, packages/app-shell/src/views/RecordApprovalsPanel.tsx); their tests; .changeset/13458-*.md (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: objectui's list, gallery, map and timeline overlays render a raw Object.entries dump | RecordDetailPanel from plugin-detail, already used by five views | every user previewing a record from those four views
    Thread-read: 6387047307
    Premise: holds — on objectui main cd70b78 each of the four overlay files carries one Object.entries(record) body; GANTT_CONFIG_SPELLING is defined in ListView.tsx and ObjectView.tsx; isSameAuthoredFilter in ObjectGrid.tsx and useResolvedFilter.ts
    Serial constraints cleared: (1) seat 1's objectui#13442 claims packages/plugin-list/src/ListView.tsx, packages/plugin-view/src/ObjectView.tsx and packages/plugin-grid/src/hooks/**, but its PR #13474 touches none of those three files at this reading — ordinary concurrency, merge main before opening and again before landing; (2) seat 4's objectui#13386 (plugin-detail/src/**, DetailSection.tsx and the tab fold) — this card only imports RecordDetailPanel and moves the verdict cache into useRecordEditable.ts; #13386 must not touch useRecordEditable.ts, this card must not touch DetailSection.tsx or RecordDetailPanel's internals; a shared plugin-detail/src/index.ts export line is resolved by whichever lands second
    Writes: all PR, comment and label writes go only through objectstack's relay (scripts/pm/fleet-write); never write with GitHub MCP.

  4. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 13458,
      "status": "done",
      "branch": "claude/project-thread-u58up3",
      "pr": "https://github.com/objectstack-ai/objectui/pull/13486",
      "session": "session_01NPcF7MHudqXa2mJPbTDAeU",
      "premise_still_valid": true,
      "summary": "ListView, ObjectGallery, ObjectMap and ObjectTimeline record overlays now mount RecordDetailPanel (read-only, as grid/tree; a row with no object name or string/number id keeps the plain reading). GANTT_CONFIG_SPELLING is one copy in @object-ui/core; isSameAuthoredFilter is exported from @object-ui/react and ObjectGrid drops its copy; isPlainObject is added to @object-ui/core (no touched file carries a local, so none replaced). Stopped and reported, not done: the verdict-cache merge (single-record vs batch probe semantics differ; a shared map would cross-feed verdicts) and the formatDate -> formatDateTime collapse (visible format change, pinned by consoleFaces.displayLocale-9909.test.tsx). PR says Part of #13458 for that reason.",
      "tests": "New pins: recordPreviewPanel-13458 in plugin-list (ListView, ObjectGallery, fallback), plugin-map, plugin-timeline; core is-plain-object.test.ts. Reverse check at 34f867e: overlay files restored from cd70b78 -> Tests 4 failed | 1 passed (5); restored -> green. vitest over packages/plugin-list/, plugin-map/, plugin-timeline/, useResolvedFilter, ObjectGrid.filterContextTokens-10607, ObjectView 6152/8980, packages/core/src/utils/ -> Test Files 357 passed (357), Tests 4445 passed | 37 skipped (4482), lock VERDICT command-exit 0.",
      "gates": "turbo type-check (core, react, plugin-grid, plugin-list, plugin-map, plugin-timeline, plugin-view) :: exit 0 (24/24); check:phantom-deps, check:unused-deps, check:new-line-citations, check:lockfile-integrity, check:lockfile-dedupe, check:changeset-claims, check:pending-changeset-literals, check:self-import, check:control-bytes, check:unreferenced-sources :: exit 0; eslint changed ts/tsx :: exit 0 (0 errors). NOT MEASURED: check:readme-exports, reason: needs all packages' dist built (failed on unbuilt untouched plugin-calendar/gantt/kanban). CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "6 — github issue_read x3 (card + comments), no MCP writes",
      "api_writes": "2 relay writes so far — pr_create objectui#13486; this os-dev-report comment",
      "open_questions": [
        {
          "question": "The verdict caches (useRecordEditable single-record, useRecordCrudVerdicts batch) differ in behaviour; merge them or keep two?",
          "options": [
            "A keep two, close the card's bullet as not-a-copy",
            "B a follow-up card designs one cache that keeps both behaviours"
          ],
          "recommendation": "A unless a measured double-ask between grid and record page is shown, because merging changes which verdict seeds the record page"
        },
        {
          "question": "formatDate -> formatDateTime changes the audit/approvals timestamp face (drops seconds, spells the month) and needs consoleFaces.displayLocale-9909 re-pinned. Accept the format change?",
          "options": [
            "A accept: collapse onto formatDateTime (style long keeps seconds) and re-pin the test",
            "B keep the three locals"
          ],
          "recommendation": "seat/maintainer call; a product-visible format, not a mechanical fold"
        }
      ],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — FLAT_MAP_CONFIG_SPELLING and pickFlatMapConfig are duplicated between ListView.tsx and ObjectView.tsx (not named by the card); RecordDetailPanel.tsx docblock still says five renderers (left for the objectui#13386 owner)"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Claim amendment · domain:ui#4 · 2026-10-25T01:37Z · amends the claim 6391748942 (append-only; the claim's other lines stand)

    File surface, added on the card session's request (each is what the claimed edits need, no behaviour beyond them):

    • Package wiring for the new RecordDetailPanel import: packages/plugin-list/package.json, packages/plugin-map/package.json, packages/plugin-timeline/package.json, and the matching pnpm-lock.yaml lines.
    • The one-copy homes in @object-ui/core: packages/core/src/utils/gantt-config-spelling.ts, packages/core/src/utils/is-plain-object.ts (+ its test, + packages/core/src/index.ts exports).
    • Docs that described the old preview: content/docs/guide/user-state-persistence.md, packages/plugin-detail/README.md (consumer list only; no plugin-detail/src/** edit, so the serial line with objectui#13386 holds).

    Scope narrowed by the card session's stop (report 6392009435):

    • Verdict caches (useRecordEditable.ts, useRecordCrudVerdicts.ts): left as they are. The seat reads them as two operations, not one copy: a single-record probe vs a batch probe with per-row stale/recheck (objectui#11699 vs Every Setup save, delete or action is followed by 2–6 POST /api/v1/security/explain calls (6 after one business-unit create) — batch or cache the explain call per page (hotcrm#2194 R2-T2-U09) #13341). One shared map would cross-seed grid and record-page verdicts. Dropped from this card; no follow-up is owed unless a later finding shows real drift.
    • formatDate → formatDateTime (the three admin-page copies): moving them changes the visible timestamp (drops seconds, spells out the month), and consoleFaces.displayLocale-9909 pins today's look. That is a product choice, not a mechanical collapse, so it goes to the human decision queue and is not in this PR.
    • The PR therefore says Part of #13458. At landing the seat comments here naming what is left (the formatDate item, pending its decision) and closes the card or returns it to pm:queue to match.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    ACCEPT → PR #13486 comment 6392184479 · domain:ui#4 · 2026-10-25T01:57Z. Landing under the maintainer's standing word; the card stays open for the formatDate item.

  7. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Landed in part, back to the queue · domain:ui#4 · 2026-10-25T02:59Z

    PR #13486 merged at 2026-10-25T02:18Z, merge commit 96c3649493132f2dae6e69f8e2067c77a69d3792 (Part of #13458). It delivers the four overlays (list, gallery, map, timeline) on RecordDetailPanel, GANTT_CONFIG_SPELLING as one copy in @object-ui/core, isSameAuthoredFilter exported from @object-ui/react, and isPlainObject in core.

    Left on this card: only the three formatDate copies (AuditLogPage.tsx, ApprovalsInboxPage.tsx, RecordApprovalsPanel.tsx). Moving them to formatDateTime changes the visible timestamp (drops seconds, spells out the month), and consoleFaces.displayLocale-9909 pins today's look. That choice is with the maintainer's decision queue. The seat recommends keeping today's look: fold the three copies into one local helper with identical output, or drop the item. The verdict caches are dropped from this card (two operations, not a copy; amendment 6392035005).

    The claim is released in this stroke: pm:dispatched → pm:queue, assignee cleared. Whoever claims next should read the decision first.


    Generated by Claude Code

  8. os-elon-musk commented on Oct 25, 2026

    @os-elon-musk
    Collaborator

    Ruling: batch #13 item 1 · letter A · maintainer 「13458 A ; 2277 2038 同意」 2026-10-25T09:00:06Z

    A = 三处 formatDate(s, locale)(审计日志页、审批收件箱页、记录审批面板)保留今日格式(new Date(s).toLocaleString(locale):数字日期 + 带秒时间)。不改用 @object-ui/i18n 的 formatDateTime(它没有一档能复现 toLocaleString,medium 档会丢秒),也不为此给 i18n 加档。A 之内「折成一个本地 helper(app-shell 导出、console 两页复用)还是直接删掉此条」归 UI 席位决定,不需再裁。钉 consoleFaces.displayLocale-9909.test.tsx 不动。

    此裁决只管本卡的 formatDate 折叠一条;主项(四个视图的预览弹层改用 RecordDetailPanel)已由 PR #13486 完成,其余 helper 折叠按卡上任务继续。裁不派:domain:ui 席位 4 收尾。批 #13 简报:https://claude.ai/artifact/PqFEhLdWm4A335J6n16JmP


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Closed by the seat · domain:ui#4 · 2026-10-25T09:03Z

    Executing ruling 6395692163 (batch #13 item 1, A: the three formatDate(s, locale) copies keep today's toLocaleString(locale) look). Within A, the seat drops the fold. The copies in AuditLogPage, ApprovalsInboxPage (console) and RecordApprovalsPanel (app-shell) are three identical four-line functions in two packages. Folding them means a new export on @object-ui/app-shell's public barrel for a three-line wrapper around Date#toLocaleString. That is a new public name to keep stable, and objectstack#25677 archives this repo at cutover. The duplication costs less than the surface. consoleFaces.displayLocale-9909.test.tsx stays as it is.

    Everything else on this card has landed: the four overlays on RecordDetailPanel, GANTT_CONFIG_SPELLING, isSameAuthoredFilter and isPlainObject (PR #13486, merged 2026-10-25T02:18Z). The verdict caches were dropped by amendment 6392035005. So the card closes completed, and pm:queue comes off in this stroke.


    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

No one assigned

    Labels

    area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions