Skip to content

object-metric: a money KPI's value is cut with an ellipsis (1,290,00… / 2,017,50…) at 1024 and 1440 px inside a page:card — viewport-based spans give a narrowed column's tile too little width #12942

Closed

Description

@objectstack-fleet

Filing gate ①: a reproduced, user-visible defect. reach: a public door, the console page /_console/apps/app.objectstack.hotcrm/page/sales_home_page on @objectstack/* 18.0.0-next.3 (console objectui 5e15928b4631). It was measured by the objectstack-ai/hotcrm#2125 dev (os-dev report on that card, session_01BDgipbNowaGa139em8Fhoq), and the maintainer had flagged the page as ugly (「这个页面这么丑」). Filed by the hotcrm repo:hotcrm seat (os-project-manager, same session). ⛔ Not a claim. Grade, domain:* and routing are triage's.

Reader who acts: the objectui triage / domain:ui seat.

What happens

On Sales Home, the Key Performance Indicators card holds four object-metric tiles inside a page:card. The money values are cut with an ellipsis, so the tile hides the figure it exists to show:

  • Revenue (Won): 1,290,00… at 1024 px, 1,290,0… at 1440 px.
  • Pipeline Value: 2,017,50… at 1024 px, 2,017,5… at 1440 px.

The value cell is font-bold … whitespace-nowrap text-ellipsis tabular-nums text-xl @[160px]:text-2xl. Its scrollWidth / clientWidth reads 126 / 106 at 1024 px and 152 / 124 at 1440 px.

Layout context, read on the same build:

  • page:card lays its children in a 12-column grid with spans by type (object-metric: col-span-12 md:col-span-6 xl:col-span-3). So the tiles sit one row at 1440 (about 174 px each) and 2 × 2 at 1024 (about 156 px each), in a main column the page's aside narrows to 376 px.
  • The breakpoints are viewport-based, so a tile in a narrowed column takes a span too small for its value.

What done looks like

A metric tile never truncates its primary value. Either the value scales down (container query) before it would ellipsize, or the tile's span follows its container rather than the viewport. A rendered test pins a seven-digit money value at the narrowest span.

Dedupe

MCP search_issues on objectui, "object-metric value truncated ellipsis KPI tile number cut off tabular-nums": 9 hits, all closed, none about the value truncating. The nearest are #12623 (the title truncating), #12704 (tile height) and #11254 (number format).


Generated by Claude Code

Activity

  1. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 18, 2026
  2. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p2 · area:records · domain:ui · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T07:52Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read on objectui main 32b492b67c:
      • packages/plugin-dashboard/src/metricTile.ts:32 METRIC_TILE_VALUE_CLASS still clips the value with overflow-hidden text-ellipsis whitespace-nowrap at text-xl / @[160px]:text-2xl.
      • packages/components/src/renderers/layout/page-block-span.ts:37 maps object-metric to the viewport-based TILE span.
    • Grade p2. A KPI tile hides the figure it exists to show. It was measured on 18.0.0-next.3 on HotCRM's Sales Home, a page the maintainer called ugly. The value is still in the DOM, so it holds no release.
    • Route: the value scales before it would clip (a container-query step below text-xl), so ⛔ a money value is never ellipsized.
      • Making the tile's span follow its container instead of the viewport changes every page's grid, so it is not taken here. If the dev finds scaling alone cannot fit a seven-digit value at the narrowest span, they report it before widening the scope.
    • Scope = the card's Done when: a rendered test pins a seven-digit money value at the narrowest span, with before and after screenshots at 1024 px and 1440 px.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5 (priority:p2)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12942-metric-value-scale
    Worktree: objectui-issue-12942
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-dashboard/src/metricTile.ts (METRIC_TILE_VALUE_CLASS and its container-query steps) and the tile renderer(s) that read it under packages/plugin-dashboard/src/, with tests beside them. Plus one .changeset/12942-*.md for @object-ui/plugin-dashboard. ⛔ Not packages/components/src/renderers/layout/page-block-span.ts (triage ruled the viewport span out of scope). Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: no
    Responsibility: @object-ui/plugin-dashboard's METRIC_TILE_VALUE_CLASS clips the value with text-ellipsis at text-xl / @[160px]:text-2xl | none: no platform path scales a metric value today | every viewer of an object-metric tile in a narrowed column; HotCRM's Sales Home (objectstack-ai/hotcrm#2125) today.
    Thread-read: 6247342683
    Serial constraints cleared: no open objectui PR touches packages/plugin-dashboard/. The in-flight claims (objectui#12943, #12946: @objectstack/spec ranges; #12724, #12725: chatbot and Studio surfaces) are disjoint.
    Claimed at: 2026-10-18T08:07Z

  4. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12942,
    "status": "done",
    "branch": "claude/issue-12942-metric-value-scale",
    "pr": "#12950",
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB (parent's; subagent run)",
    "premise_still_valid": true,
    "summary": "metricTile.ts now has a value size ladder (METRIC_TILE_VALUE_LADDER plus metricTileValueClass, metricTileValueEm and metricTileValueTitle). The plain tiles (MetricWidget, so object-metric too, and MetricCard) pick a rung by how wide the value draws. A short value (4.5 em or less) keeps today's text-xl @[160px]:text-2xl face. A longer one starts at 14 px and steps up at container widths ceil(48 + maxEmpx), where 48 px is the Card's value inset. Past the last rung it stays 14 px, and the value carries its full figure as a title tooltip. Browser reading on Chromium with Inter: 1,290,000.00 went from 126/106 clipped (20 px) to 106/106 (14 px) at a 156 px tile, and from 152/124 clipped (24 px) to 124/124 (18 px) at a 174 px tile. The before figures match the card exactly. The span is unchanged and DatasetWidget is untouched (no Card inset; noted in Acceptance notes).",
    "tests": "On 0f9795d. New metricTileValueScale-12942.test.tsx: 8 passed. It pins (a) object-metric with fallbackValue 1290000 and format 0,0.00 on the scaled rung (14 px at a 154 px container, 18 px at 172), not @[160px]:text-2xl, with the title set; and (b) CONTROL: 4,210 keeps METRIC_TILE_VALUE_CLASS with no title. It also re-derives every ladder step from the formula. Reverse check on the committed tree (MetricWidget reverted to METRIC_TILE_VALUE_CLASS; injected=1, removed_left=0 by grep -c): 2 failed / 6 passed with the control green. Restored with git checkout HEAD --; git diff HEAD = 0 bytes; blob hash 897bbcf2 matches HEAD. Targeted vitest: 36 plugin-dashboard files naming METRIC_TILE_VALUE_CLASS, metricTile, MetricWidget, MetricCard or object-metric, 36 files / 378 tests passed (lock VERDICT command-exit 0). Closure build pnpm --filter '@object-ui/plugin-dashboard^...' build exit 0. type-check exit 0, and tsconfig.test.json lists the new test. eslint (package form) on the 4 changed source files: 0 errors, 1 existing warning; no type-aware linting in eslint.config.js. Pre-tsc battery (15 check:
    commands) plus check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence and check:new-line-citations: all exit 0. NOT MEASURED: the full packages/plugin-dashboard/ directory run, reason: the dispatch declares it to CI.",
    "mcp_calls": "0",
    "api_writes": "3 — git push x2 (branch probe and commit; not REST), fleet-write dispatch pr_create (POST /repos/objectstack-ai/objectstack/dispatches, executing POST /repos/objectstack-ai/objectui/pulls and POST /repos//issues/12950/assignees), and this os-dev-report comment via the fleet-write comment op. Zero label writes: objectui path labels come from labeler.yml and the dispatch named none.",
    "gates": "closure-build 0; type-check 0; targeted-vitest 0 (36 files/378 tests); lint(narrowed, 4 files) 0; check:phantom-deps 0; check:self-import 0; check:unreferenced-sources 0; check:doc-example-readers 0; check:handler-key-reads 0; check:side-effects-array 0; check:element-data-source-declaration 0; check:spec-symbols 0; check:action-forward-parity 0; check:designer-field-key-parity 0; check:icon-record-names 0; check:i18n-keys 0; check:i18n-drift 0; check:i18n-designer-parity 0; check:control-bytes 0; check-hand-rolled-comment-mask 0; check-changeset-fixed 0; check-changeset-presence 0; check:new-line-citations 0; CI: in_progress",
    "files_changed": [
    "packages/plugin-dashboard/src/metricTile.ts",
    "packages/plugin-dashboard/src/MetricWidget.tsx",
    "packages/plugin-dashboard/src/MetricCard.tsx",
    "packages/plugin-dashboard/src/tests/metricTileValueScale-12942.test.tsx",
    ".changeset/12942-metric-value-scale.md"
    ],
    "deviations": "One tsc --listFiles count of tsconfig.test.json ran outside the verify lock. No screenshots are attached: the PR body records the scrollWidth/clientWidth numbers instead, which A4 accepts. Until the dataset-bound tile gets its own inset-free ladder, it stays on the old constant.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · DatasetWidget's headed metric tile keeps METRIC_TILE_VALUE_CLASS (value room = the whole container, clip below about 133 px for a 6.6 em value); not measured clipping on any page; noted in the PR's Acceptance notes, not filed"
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-18T08:43Z

    PR #12950 at head 0f9795d, reviewed against the claim 6247460680, triage's route 6247342683 and the dev report 6247669204.

    • What changed: metricTile.ts gains a value size ladder (METRIC_TILE_VALUE_LADDER, metricTileValueClass, metricTileValueEm, metricTileValueTitle). The plain tiles (MetricWidget, and so every object-metric block, and MetricCard) pick a rung by how wide the formatted value draws: a short value (≤ 4.5 em) keeps today's text-xl @[160px]:text-2xl; a longer one starts at 14 px and steps up at container widths derived as ceil(48 + maxEm × px) (48 px = the Card's content inset). Past the last rung the value stays at 14 px and carries the full figure as its tooltip. Both callers pass strings (MetricCard.value: string | number; MetricWidget's displayValue is a template string), so the width estimate reads the figure the tile draws.
    • Route held: the value scales; the tile span (page-block-span.ts) is untouched. Scaling alone fits the seven-digit figure, so no wider change was needed.
    • Browser reading (Chromium, Inter), 1,290,000.00: 156 px tile 126/106 clipped at 20 px → 106/106 at 14 px; 174 px tile 152/124 clipped at 24 px → 124/124 at 18 px. The before figures reproduce the card's exactly. Numbers are in the PR body; no screenshots attached.
    • Clause-②: no, confirmed: the new names are module exports of metricTile.ts only; src/index.tsx re-exports none of them and the package's exports map has the single "." entry. No contract review owed.
    • Tests: metricTileValueScale-12942.test.tsx (8 tests) pins an object-metric with 1290000 / 0,0.00 on the scaled rung (14 px at a 154 px container, 18 px at 172) with the title set, a CONTROL (4,210 keeps METRIC_TILE_VALUE_CLASS, no title), and re-derives every ladder step from the formula. Reverse check: reverting MetricWidget turns 2 red with the control green; restore proven by blob hash. The 36 plugin-dashboard files naming these symbols pass (378 tests); type-check and the pre-tsc battery exit 0. The full packages/plugin-dashboard/ directory is declared to CI.
    • Acceptance notes, not filed: DatasetWidget's headed metric tile keeps METRIC_TILE_VALUE_CLASS: it has no Card inset, so the ladder measured against a Card does not apply, and its value has the container's whole width (a clip would start below about 133 px for a 6.6 em value). No page was measured clipping there.
    • Trailers: the one commit carries only the model-free pair.
    • CI at head: all 36 check-runs on 0f9795d are complete: 33 success, 3 skipped (dependabot and the two coverage jobs), none failed; mergeable_state: clean. Path surface (5 files, +262 / −7): packages/plugin-dashboard/src/** and one changeset, no governed path.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-18T08:57Z

    PR #12950 merged through the merge queue as 0707b4ae37120d45d6401170666a0b76cb7a3546, which is on main; Fixes #12942 closes this card. Verified by content: all 5 of the PR's files on main are blob-identical to the accepted head 0f9795d. The merge commit's message names no model.

    What landed:

    • A metric tile's value scales before it would clip. A long value (a seven-digit money figure with cents) steps down from 24 px to 14 px as the tile narrows, so 1,290,000.00 fits whole in a 156 px tile (14 px) and a 174 px tile (18 px). A short value keeps its 20 / 24 px face; a value too wide even at 14 px keeps the ellipsis and shows the full figure as its tooltip. Applies to MetricCard, MetricWidget and every object-metric block; the tile span is unchanged. @object-ui/plugin-dashboard: patch.

    For hotcrm: Sales Home's Key Performance Indicators show Revenue (Won) and Pipeline Value whole once the console build HotCRM runs carries the merge commit above (objectstack-ai/hotcrm#2125). The dataset-bound headed metric tile is unchanged (see the ACCEPT). This seat now removes pm:dispatched.


    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, 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