Uh oh!
There was an error while loading. Please reload this page.
feat(plugin-dashboard): dataset-bound metric 卡接上已声明的 colorVariant 强调色 (#3359) - #3799
Conversation
…d colorVariant (#3359) `DashboardWidgetSchema.widgets[].colorVariant` was spec-declared, offered by every authoring surface, and authored 16 times in shipped metadata — yet `dataset` is REQUIRED on the widget schema, so every legal widget reaches `DatasetWidget`, which read the key nowhere. Declared but never enforced (objectstack#5010 ruling B). The metric card now reads it and maps it onto the accent system this package already has: the big number is tinted the way `MetricWidget`'s chrome-less `bare` layout tints it, since a dataset-bound metric renders no icon chip and no card of its own. Both class tables moved into one shared `colorVariants.ts` so the two layouts cannot drift into disagreeing palettes. Vocabulary is the spec's `WidgetColorVariantSchema` enum, read from the spec in the tests rather than restated. Off-spec tokens (including the designer swatch picker's display-only `green`/`red`/`amber` aliases) get no accent and no aliasing — invalid metadata is rejected where it is authored, not laundered here (AGENTS.md #0.1). Undeclared, and the enum's own `default`, render byte-for-byte as before — pinned against the origin/main@f9d70a72e capture.
The latest updates on your projects. Learn more about Vercel for GitHub. |
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
commented
Aug 8, 2026
✅ 验收通过(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt)—— undraft + auto-merge。 git 实物核验( 验证质量:字节级基线( 跨仓杂事已办:objectstack#6774 已立(liveness/dashboard.json 翻 live + 解除 PR #5255 正向对照, Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#3359
objectstack#5010 维护者裁决 B 的 objectui 半边实现单,spec 零改动。
前提复核(实读 objectui
origin/main@f9d70a72e/ objectstackorigin/main@ea1d9165d)前提成立,且比正文描述多一层字节级证据:
dataset在DashboardWidgetSchema必填(objectstackpackages/spec/src/ui/dashboard.zod.ts),因此所有合法 widget 经DashboardRenderer.tsx两处派发口(isSelfContained分支的 dataset-bound 口、Card 分支的 dataset-bound 口)恒走DatasetWidget;isSelfContained = widget.type === 'metric' && !datasetBound,dataset-bound metric 落在后者。grep -c colorVariant packages/plugin-dashboard/src/DatasetWidget.tsx= 0;邻近词反查categoryColors= 4,证伪「扫描器/路径错」。colorVariant: 'success'与完全不声明,渲染出的 DOM 逐字符相同:(为绕开 GitHub body 的 HTML 清洗,上面用
标签.class=代替尖括号书写;完整字节串以字符串常量BASELINE_UNDECLARED落在测试文件里。)type: 'metric'——platform-objects/src/apps/dashboards/system_overview.dashboard.ts7 处,examples/app-showcase的ops-dashboard4 处 +revenue-pulse5 处。用到的 token 恰好是 7 个非 default 强调色的全集。(app-showcase 各 page 里还有若干object-metric组件块也写colorVariant,那是properties里传给ObjectMetricWidget的另一条已生效路径,不在本单计数内。)实现
DatasetWidget的 metric 卡读widget.colorVariant,映射到本包已有的强调色体系,不新造一套:MetricWidget的bare布局 —— 所以强调色落在大数字的文字色上,复用VARIANT_TEXT_CLASSES。同一个声明在 inlinebareKPI 与 dataset-bound KPI 上从此读起来一致。VARIANT_ICON_CLASSES/VARIANT_TEXT_CLASSES从MetricWidget.tsx提到新的src/colorVariants.ts,两个布局共用(纯搬移,MetricWidget渲染零变化;MetricColorVariant在原处 re-export 保持源码兼容)。设计器那份色板的注释本来就自称 "mirrors the renderer's colorVariant tokens",复制第二份正是把 declared≠enforced 换成更难查的 declared≠declared。metricAccentTextClass(value)对三种输入统一返回undefined(即不追加任何 class):未声明、枚举自带的'default'(它就是「无强调色」的名字)、以及任何非 spec token。不做??兜底、不认别名 —— 非法 token 由 spec 的 Zod 枚举在授权/发布处拒绝,消费端再认一种拼法就是给 AI 生成的元数据造第二套事实契约(AGENTS.md #0.1);同时一个纯装饰键也不该让整个 widget 渲染失败,所以是「无强调色」而非报错。词表三方对照(spec ↔ 设计器 ↔ 渲染器)
spec 枚举实读:
objectstack packages/spec/src/ui/dashboard.zod.ts:28WidgetColorVariantSchema。color-variant-field.tsx:19-27(canonical 8)colorVariants.ts→ 大数字文字色defaultdefault/#9ca3afblueblue/#3b82f6text-blue-600 dark:text-blue-400tealteal/#14b8a6text-teal-600 dark:text-teal-400orangeorange/#f97316text-orange-600 dark:text-orange-400purplepurple/#a855f7text-purple-600 dark:text-purple-400successsuccess/#22c55etext-emerald-600 dark:text-emerald-400warningwarning/#f59e0btext-amber-600 dark:text-amber-400dangerdanger/#ef4444text-rose-600 dark:text-rose-400三方完全对齐,零自造变体。两处机械钉住,不靠这张表的人工核对:
DatasetWidget.colorVariant.test.tsx从@objectstack/spec/ui读WidgetColorVariantSchema.options,断言渲染器两张表的 key 集合 === spec 枚举(并先断言枚举非空,避免空列表下的空转绿)。packages/app-shell/src/views/metadata-admin/color-variant-field.test.tsx(纯测试,无源码改动)把设计器 canonical 行按 spec 顺序钉到同一枚举上。此前这条腿完全没有机械约束。设计器那份色板在 canonical 8 之后还有 3 条
green/red/amber,文件自己注明是「让非 canonical token 也能显示一个合理色块」的显示用别名,且ColorVariantPicker只渲染slice(0, 8)。它们不是渲染器词表:新测试同时钉住「额外条目必须不是 spec token,且必须复用某个 canonical 色值」,防止将来有人把别名悄悄升格成第 9 个可授权变体。缺省不回归证据
改动前先在
origin/main@f9d70a72e上取字节基线(上文 PROBE),再把它写成测试里的字符串常量BASELINE_UNDECLARED(不是 snapshot 文件 —— 回归要在 review diff 里看得见,也不能靠删过期快照「修好」)。断言:colorVariant→container.innerHTML全等基线;colorVariant: 'default'→ 全等基线;chartreuse/green/red/amber/''/#ff0000)→ 全等基线;innerHTML恰好等于「基线把大数字 class 换成基础 class + 该强调色」,即只有一处差异;反向验证(方向事先声明)
本单两个方向同时存在,模板不能一概而论,所以事先写明预测再跑:
实测(把
const accentClass = metricAccentTextClass(widget?.colorVariant)临时改为常量undefined后重跑同一测试文件):9 红全部落在功能半边,14 绿是缺省半边 + 词表 parity —— 与事先声明的方向一致。随后已复原。
验证
重型步骤全部在
flock /tmp/os-heavy-verify.lock下串行、--max-old-space-size=4096、--maxWorkers=2。Changeset
.changeset/dataset-widget-colorvariant-3359.md,@object-ui/plugin-dashboard: patch。档位依据仓内同类先例:同一组件同族的 declared→enforced 改动compareto-kind-convergence.md(范围更大)也是patch;minor在本仓的现存两例都是公共 API 破坏性改名。app-shell 只加了测试、无用户可见变化,故不进 changeset 条目。README 补了colorVariant一节(AGENTS.md #2)。范围外(未在本 PR 触碰)
liveness/dashboard.json该行翻live+ 解除 objectstack PR #5255 钉的「恰好只警告 colorVariant」正向对照 —— 按分诊席点名,由验收本 PR 的执行座位在 objectstack 立单承办(带Blocked-by:本 PR)。本 PR 不改 objectstack 仓。componentSchema色彩逻辑未被搬用(正文第 3 条禁令)。Generated by Claude Code