Skip to content

feat(views): tint only the exception rows in list views - #2108

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-2107-exception-row-tints
Oct 14, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-2107-exception-row-tints

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #2107. Everything in the card's table is done here; the half left open is the render check of two kept tints (All Accounts, Unassigned — triage), which paint nothing on the 18.0.0-next.1 pin because of a platform fetch gap (measured below, reported upstream through the seat). The card stays open so they can be measured again once the pin carries the platform fix; no HotCRM change is expected then.
Clause-②: no

What changed

The maintainer chose 「只给例外行上色(推荐)」. Nine list views gave every value of a field a row colour, and each of those fields already draws its own coloured badge in its column, so a page of colour marked no row. Now only the row a user must act on is tinted:

view(s) before after
crm_case All Cases, Unassigned — triage priority: critical red, high orange, medium yellow, low slate is_sla_violated: true → red
crm_task All Tasks priority: urgent red, high orange, normal green, low slate urgent → red
crm_event_attendee Event Attendees response: four colours declined → red
crm_account All Accounts is_active: true green, false slate false → slate
Open Deals, All Events, All Articles, Leads High Priority a colour per stage / status / rating no rowColor
  • Values stay colour NAMES (AGENTS.md §4); the dark-theme half is grid: a rowColor row in dark mode keeps its light-mode fill (bg-*-100) under the dark theme's light text, so the row is unreadable; the tint also skips the frozen columns objectui#12375 and nothing here restyles around it.
  • test/view-references.test.ts: the stage row-colour pins (stageRowColors, "every stage has a row colour …", "stage colours stay distinguishable …") guarded the retired Open Deals map and go with it. The stage-path guard and the generic "rowColor keys on select fields are actual option values" guard stay. No new test.
  • Docs, all three locales: service/cases, service/sla-and-escalation (a breach is now what turns a case row red; the priority hex list is gone), sales/activities, sales/leads, sales/opportunities. sales/accounts already said "the grey rows are the inactive ones" and is unchanged (see Acceptance notes).
  • Cases keep the ruling's first option (is_sla_violated). The priority critical alternative was not taken: no measured profile loses the field (below), and the triage gap is the platform's fetch, not the key.

Measurements (light theme, own dev server on port 4107, fresh seeded DB, DOM probe of each tbody tr)

Row class and computed background-color, grouped by the row's own key cell:

list tinted rows (bg-red-100 / bg-slate-100) untinted rows
All Cases (admin) 13, all SLA Violated = true, oklch(0.936 0.032 17.717) 25, all false, rgb(246, 246, 249)
All Tasks 2, both Urgent 5: High 2, Normal 2, Low 1
Event Attendees 1, Declined 24: Accepted 20, No Response 3, Tentative 1
Open Deals / All Events / All Articles / High Priority 0 10 / 29 / 4 / 5
All Accounts (Stark Medical set inactive) 0 9, Stark Medical among them
Unassigned — triage (CASE-00018 breached and CASE-00031 not, both unassigned) 0 2
  • H1 (boolean key works): yes. The REST rows carry is_sla_violated as JSON true/false, and colors: { true: 'red' } paints exactly the 13 flagged rows.
  • H2 (who can read the field): signed in as each demo persona after pnpm demo:staff, All Cases selects is_sla_violated and paints every flagged row: service.agent 2 rows (1 red), service.manager 8 (6 red), sales.manager 38 (13 red), admin 38 (13 red). na.rep reads no case at all (readScope: 'own', owns none), so nothing to tint. No profile loses the field.
  • H3 (who turns red): 13 of 38 seeded cases carry is_sla_violated = true: 4 open (new 1, in progress 1, escalated 2) and 9 settled (closed 6, resolved 3), the late-close breaches SLA reporting shows 0% violations / 100% met although cases are closed after their SLA due date: is_sla_violated is set only by the open-case sweep, so a late close never records the breach #2070 records. The docs say a closed-late case stays red.
  • H4: the stage pins are removed; the generic guard still reads the narrowed Task and Attendee keys. One-off proof: task.view.ts colors: { urgent: 'red' } mutated to { critical: 'red' } (scripts/ablation-replace.mjs, anchor 1 → 0, blob 6233b9c4 → e3a5aa0f), vitest run test/view-references.test.ts went red: view "all_tasks": rowColor key "critical" is not an option of crm_task.priority (1 failed, 54 passed). Restored: blob equal to HEAD, git diff HEAD empty.

The platform gap (not routed around)

All Accounts and Unassigned — triage tint by a field that is not one of their columns, and the console's list fetch selects only the columns plus view bindings and predicate operands, never rowColor.field:

  • All Accounts: select=id,name,industry,type,annual_revenue,number_of_employees,health_score, no is_active.
  • Unassigned — triage: select=id,case_number,subject,crm_account,crm_contact,priority,status,origin,sla_due_date,is_escalated,is_closed,owner_id, no is_sla_violated.
  • Control: All Cases has is_sla_violated as a column, selects it, and paints every flagged row.

So useRowColor reads undefined and paints nothing. The account tint has painted nothing on this pin before this PR too. Adding a column only to make the tint show would route around the platform (AGENTS.md §2, §4), so it is not done. A comment beside each of the two maps records the measurement.

Acceptance notes

  • The attendee tint shows on the Event Attendees object list (/crm_event_attendee). That list is not in the app's navigation. An event's Related tab draws its own related list and reads no list-view rowColor: the declined attendee on that tab is untinted, before and after this PR. This is an observation only, not filed.
  • content/docs/sales/accounts.mdx says the grey rows are the inactive ones. That matches the declared tint, but on 18.0.0-next.1 it does not render (gap above). It was untrue on the pin before this PR as well. It is left unchanged and becomes true with the platform fix.
  • The changeset tells the release-notes reader that the triage and accounts tints are not visible yet.

Verification (head d9a5739c)

  • pnpm validate: exit 0, ✓ Validation passed
  • pnpm typecheck: exit 0
  • pnpm lint: exit 0, 18 suggestion(s), no warnings or errors
  • pnpm lint:i18n-gate: exit 0, ✓ i18n lint gate: 0 i18n/missing-* issues
  • pnpm hygiene: exit 0, ✓ source hygiene clean
  • pnpm hygiene:tokens: exit 0, ✓ source token ratchet clean
  • pnpm build: exit 0, ✓ Build complete
  • pnpm test: exit 0, Test Files 179 passed (179), Tests 3658 passed | 1 skipped (3659)

Playwright e2e is left to CI.


Generated by Claude Code

… a tint

Nine list views gave every value of a field a row colour, and each of
those fields is already a column that draws its own coloured badge, so a
page of colour marked no row. The four lists that keep a tint now colour
only the row a user must act on:

- Cases (All Cases, Unassigned - triage): is_sla_violated true -> red
- Tasks: priority urgent -> red
- Event attendees: response declined -> red
- Accounts: is_active false -> slate

Open Deals, Events, Knowledge Articles and Leads' High Priority carry no
rowColor any more. The stage row-colour pins in view-references.test.ts
guarded the retired Open Deals map and go with it; the generic "rowColor
keys are real option values" guard stays and still reads the Task and
Attendee keys.

Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv

Co-authored-by: Claude <noreply@anthropic.com>
… render

Every doc page that described a list's row tint, in all three locales,
now says what the lists do: a breached case is the red row in All Cases
(and stays red once closed late), an urgent task is the red row, and
Open Deals and High Priority leads carry no tint. The priority hex list
on the SLA page is gone.

The All Accounts and Unassigned - triage tints are declared but paint
nothing on 18.0.0-next.1: the console's list fetch selects only the
columns, and neither list has a column for its tint's field. A comment
beside each says so, and the changeset tells the release-notes reader.

Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Oct 14, 2026 2:54pm UTC

Request Review

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

复核人:repo:hotcrm 执行席(#1353)· 判决 ACCEPT · 钉 head d9a5739c8bd962e6d7f206740986929bba7e8ba3 · 2026-10-14T15:03Z

形态:一卡一 PR,Part of #2107(见范围外去向),Clause-②: no;25 文件,+62/−135 = 197 行(< 3,000,派发预算约 250);路径面无 governed 面(8 个 view 文件、test/view-references.test.ts、5 个文档页 × 3 语 = 15 个文件、1 个 changeset)→ 非 Tier H,席位落地。

前提实测:diff 逐项对裁决「只给例外行上色(推荐)」的表:All Cases 与 Unassigned — triage → is_sla_violated { true: 'red' };Tasks → { urgent: 'red' };Event Attendees → { declined: 'red' };Accounts → { false: 'slate' };Open Deals、All Events、All Articles、Leads High Priority 的 rowColor 连同注释删除。值全是颜色名,无 hex、无 bg-*、无 dark:(深色半边归 objectstack-ai/objectui#12375)。测试只删钉旧 stage 配色的两条(stageRowColors 及其两个 it),通用的「rowColor key 是选项值」守卫保留,未加新门禁;dev 的切除实验(task key 改 critical)证该守卫仍咬。文档 cases / sla-and-escalation / activities / leads / opportunities 三语同步,accounts 原文与新声明一致未动。Cases 取裁决首选 is_sla_violated:dev 实测 service.agent / service.manager / sales.manager / admin 均可读该字段并见红行,种子 38 例中 13 例违约(4 未结、9 已结)。

门禁 check-runs(钉 head):Build and Test (22.x) ✓ · Typecheck and Build ✓ · Quality Checks ✓ · Check Changeset ✓ · Playwright ✓ · link-check ✓ · CodeQL ✓ · Analyze Code (javascript) ✓ · Label Pull Request ✓ · Vercel Preview Comments ✓ — 10/10 success,mergeable_state clean,base f4ac253f = 当前 origin/main。

接受的偏差:① Part of 而非 Fixes(下条);② account 与 triage 两处 rowColor 旁注明本 pin 不出色及上游去向,属 rowColor 块注释,在认领落点内;③ lead.view.ts 头注释改写以不再描述已删的评分行色。

范围外去向:dev 实测 All Accounts 与 Unassigned — triage 两处保留的行色在 18.0.0-next.1 上不出色——console 列表 $select 只取列与视图绑定,不取 rowColor.field,而 is_active / is_sla_violated 在这两个视图不是列。席位在 objectui df05784 复读 packages/plugin-list/src/ListView.tsx selectFields:分组与条件格式有收集,rowColor 无,证实;已提 objectstack-ai/objectui#12376。⛔ 不加列绕过(AGENTS.md §2)。dev 的开放问题(关卡与否)席位判 A:保留 Part of,合并后 #2107 转 pm:blocked,Blocked-by: objectstack-ai/objectui#12376,升到带修复的 pin 后重测这两个列表。未立卡记录:参会人行色只在未入导航的 Event Attendees 对象列表可见,活动详情 Related 页签的相关列表不读列表视图 rowColor(改前改后一致)。

落地条款:席位经中继 pr_ready + automerge_enable,以 objectstack-fleet[bot] 入合并队列;合并后在 #2107 落探针表并转 pm:blocked。

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 14, 2026 15:05
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 4de5343 Oct 14, 2026
11 checks passed
sunhaolin pushed a commit that referenced this pull request Oct 14, 2026
Brings the finished picklist migration onto main 4de5343 (@objectstack
18.0.0-next.1, the two-package artifact, the suites on @objectstack/verify
and SQL). Conflicts, each resolved toward main's behaviour plus the
migration:

- objectstack.config.ts: main's composeStacks artifact. The picklists
  register with the app package instead: objectstack.composition.ts
  gains appPicklists (sales + revenue barrels) and hands it to
  createHotCrmAppStack. Every picklist-bound field is an app-package
  field; the service package references none.
- src/sales/objects/_picklists.ts: stays deleted. Main's two comment
  edits (#2035, #2040) are carried to where the comments moved:
  payment_terms.picklist.ts now names quote_accepted_contract_draft.
- contract.object.ts: main's hook name, the branch's picklist reference.
- opportunity.view.ts: main's (the stage rowColor map is gone, #2108).
- executive.dashboard.ts, mappings/_shared.ts: the branch's comments.
- 14 suites: main's imports, drivers and syncSchemas(), plus the
  branch's picklist lines. Engine suites still built with
  ObjectQL.create register the app's lists (the factory takes no
  picklists on 18.0.0-next.1). global-actions reads related_to_type off
  the booted registry's served field; i18n-references checks picklist
  translation keys against the lists the booted registry holds.
  actions-flows-integrity keeps both non-vacuity guards. view-references
  drops the retired rowColor pins and keeps the mass_update_stage pin.
- test/helpers/stack-picklists.ts reads the composed view (the artifact
  carries packages[] only) and resolves a field's options through the
  platform's SchemaRegistry.resolvePicklistOptions instead of a local
  lookup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8mZuzuyZAHSrgQKmv6ASv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline documentation Improvements or additions to documentation metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants