Skip to content

fix(components): FilterBuilder 值落在选项集外时清到空形或显示出来,不再隐形 (#4874) - #5030

Merged
yinlianghui merged 3 commits into
mainfrom
claude/issue-4874-filter-value-domain
Aug 17, 2026
Merged

fix(components): FilterBuilder 值落在选项集外时清到空形或显示出来,不再隐形 (#4874)#5030
yinlianghui merged 3 commits into
mainfrom
claude/issue-4874-filter-value-domain

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#4874

实施依据 = 2026-08-17 05:03Z 维护者裁定(A + C 组合,B 维持否决),不是卡面的开放三选。

前提验证(jsdom,origin/maine71c854

卡面症状原样复现,而且是三张脸而非一张:

场景行里的值控件显示
文本 acme → 切到 picklist 列(won/lostvalue: "acme"(照样持久化、照样下发查询)值 trigger 文本 ""
options: [] 的 lookup 列带 acc_007acc_007值 trigger 文本 ""(空 Select)
picklist 列 in ["acme","won"]带着 acme只画出 Won/Lost 两个勾选框,acme 哪儿都没勾

第二、三张脸此前没被单独记过:前者是「options present-but-empty」——[] 是真值,所以它进不到远程 picker 分支,落进一个空 Select;后者是同一机制的多值面。

A/C 分流的机械判据

hasStaticOptionDomain(field) = options 是非空数组。这是全 PR 唯一的分流点:

  • 非空数组 ⇒ 静态列:选项集就是该列的全部值域,值不在其中是本地可判定的「装不下」,切列时清到空形;
  • options 缺席 / options: [](未到位)/ 非数组 ⇒ 远程异步列:本地选项集为该值背书不了,一律原样保留。options 缺席正是 renderValueInput 自己那条远程 picker 分支的条件(!field?.options);options: [] 不是「值域为空」而是「还没到」——@object-ui/fieldsderiveFilterFieldsArray.isArray(f.options) 原样映射过来,picklist 值没到位时产出的就是它,对它做成员判定会清掉世上任何值。

第二个判据 isOptionDrivenValueControl(field, operator)renderValueInput 的分支顺序回答「该控件是否只能显示选项内的值」:list → 勾选框列表(是);pairbetween 画两个普通区间框、从不读 options(否,结构性回答,不靠「select 桶今天不给 between」这个巧合);scalar → 只对 select/lookup 族画 Select(text 列即使带 options 也仍是普通输入框,什么都显示得出来,因此不判)。

改动

  • A 半边narrowFilterValueToOptions:切 field 时对静态选项列做成员判定,不匹配清到 FilterBuilder 切换行的 field 后 value 原样留下 —— 文本值落到 number 列,输入框显示空而行仍带着该值 #4781 那套空形(标量 ''、列表逐项过滤后 []pair 不动)。列表逐项而非连坐——每项都是独立筛选项,一颗坏项不该丢掉用户写对的那几项(["won","acme","lost"]["won"])。成员判定用 String() 两端比,与控件判定可见性的方式逐字一致(勾选框的 selectedValues.map(String).includes(String(opt.value))、Radix 拿 SelectValue 匹配已挂载的 SelectItem value)——两个答案一旦分叉,就又回到「行带值、控件显示不出来」。顺带钉住 FilterBuilder 值控件把「假值」当成「空」—— 布尔 false 与数字 0 显示为空,行却带着该值 #4873 的交界:选项 id '0' 不会被当成「未填」清掉。
  • C 半边(渲染路径,无条件):Select 把选项外的值挂成一个临时 SelectItem,标签用值本身——与 LookupValuePicker 对没有 label 的 id 的做法(resolved[id] || id)同一个答案;多值勾选框列表把它渲染成一行已勾选、可取消的条目。无条件是有意的:控件欠的不变量是「trigger 显示行里真正带着的东西」,而它带着什么与怎么带来的无关(切列、已存视图读回、选项集晚到)。也因此不必为了显示去改写传入的 value——静默改写一份已存视图比隐形更糟。
  • B 维持否决:仓内已不存在「行带值、控件空白」的形态。

LookupValuePickeroptions 缺席的真远程列)本来就把 id 兜底显示出来,未改动,只是补了钉子。

验证

反向验证(先书面预判,commit 后变异,git checkout -- 还原)

变异预判实测
① 撤 changeField 里的成员判定调用静态列用例红红 5 项。其中一条读作 expected 'acme' to be 'Select value' —— C 独在时值可见但被错留,正是 B 的形态
② 撤 Select 临时项远程列可见性用例红(trigger 空串)红 2 项,expected '' to be 'acc_007' / 'acc_042';picker 的 id-input 那条按预判仍绿(另一个控件)
②b 撤勾选框临时行多值可见性用例红红 2 项(少一行 + 取消勾选后剩 ['acme'] 而非 ['won']
③ 撤 hasStaticOptionDomain 守卫,把远程列也接成员清空「合法 lookup id 被清」用例红 —— 裁定专门要防的那条红 4 项,expected 'Select value' to be 'acc_007'比预判多一条且性质不同:非数组 options 那条不是答错而是在 optionKeysOf抛异常(对字符串 .map)—— 判据函数同时是该路径的全性保证。已把这个实测方向写在用例旁边,免得下一个人以为靠的是读取端的宽容

Generated by Claude Code

yinlianghuiand others added 2 commits August 17, 2026 17:22
带 `options` 的 select/lookup 列,其值控件是受控的 Radix Select,而 `SelectValue`
只认已挂载的 `SelectItem`。于是文本列的 `equals "acme"` 指到 picklist 列(选项
`won` / `lost`)之后,值控件显示空,行里仍是 `value: "acme"` ——
`foldFilterGroupToSpecRules` 照样持久化,实时网格照样拿 `stage equals "acme"`
去查。#4768(operator)、#4781(值的类型)之后「看不见的值」的第三张脸,成因是
值域而不是类型:`select` / `lookup` 属于文本族,`"acme"` 在类型上装得下。
按 2026-08-17 维护者裁定(A + C 组合):
- `narrowFilterValueToOptions` 是 A 半边:切 field 时对**静态选项列**做成员判定,
不匹配的值清到 #4781 那套空形(标量 `''`、列表逐项过滤后 `[]`)。逐项而非连坐 ——
每一项都是独立的筛选项,一颗坏项不该丢掉用户写对的那几项;
- `hasStaticOptionDomain` 是 A/C 分流的唯一机械判据:`options` 是**非空数组** ⇒
静态列,选项集就是它的全部值域;`options` 缺席 / `options: []`(未到位)/ 非数组
⇒ 远程异步列,本地选项集为该值背书不了,一律原样保留;
- C 半边在渲染路径,且**无条件**成立:Select 把选项外的值挂成一个临时项(标签用值
本身,与 `LookupValuePicker` 对没有 label 的 id 的做法一致),多值列表把它渲染成
一行已勾选、可取消的条目。无论值是切列带来、从已存视图读回,还是选项集晚到才对
不上,控件都显示行里真正带着的东西 —— 也因此不需要为了显示去改写传入的 `value`。
- ⛔ B(保值但容忍隐形)维持否决:「行带值、控件空白」这个形态不再存在。
Co-authored-by: Claude <noreply@anthropic.com>
反向验证第三条(把远程列也接成员清空)撤掉 `hasStaticOptionDomain` 之后,这条用例
不是答错而是在 `optionKeysOf` 里抛异常(对字符串 `.map`)。判据函数同时是这条路径
的全性保证,把这个实测方向写在用例旁边,免得下一个人以为靠的是读取端的宽容。
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)25.3 KB350 KB
Entry fileindex-DjHrk47M.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)25.13KB5.40KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.79KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.71KB1.22KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)501.81KB112.13KB
core (index.js)4.11KB1.62KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)159.03KB44.08KB
fields (index.js)233.27KB58.22KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.84KB1.45KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)39.16KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.35KB3.31KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.42KB1.42KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.81KB0.83KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.75KB18.37KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)127.85KB32.73KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)241.12KB60.43KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)120.42KB29.03KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)197.61KB53.03KB
plugin-kanban (index.js)52.72KB14.54KB
plugin-list (index.js)111.17KB26.99KB
plugin-map (index.js)18.72KB6.09KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)41.97KB11.33KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)83.81KB20.49KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)27.53KB9.41KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.28KB0.68KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)10.76KB3.17KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)6.92KB2.40KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

外部传入的 `["acme","acme"]` 会画出两行同 key 的临时条目,而取消勾选是按值过滤的
(一次去掉全部同值项),所以一行才是「取消它会发生什么」的诚实计数。
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)25.3 KB350 KB
Entry fileindex-C7u1J7Dt.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)9.56KB3.59KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)8.92KB3.41KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)25.13KB5.40KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.79KB
auth (createAuthenticatedFetch.js)6.34KB2.43KB
auth (index.js)2.71KB1.22KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.02KB0.88KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)501.82KB112.14KB
core (index.js)4.11KB1.62KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)159.03KB44.08KB
fields (index.js)233.27KB58.22KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.35KB1.38KB
i18n (pickLocalized.js)3.69KB1.73KB
i18n (provider.js)23.12KB7.62KB
i18n (useDisplayLocale.js)2.84KB1.45KB
i18n (useObjectLabel.js)27.59KB6.63KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)39.16KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.35KB3.31KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.42KB1.42KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.81KB0.83KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.75KB18.37KB
plugin-chatbot (index.js)181.21KB43.14KB
plugin-dashboard (index.js)127.85KB32.73KB
plugin-designer (index.js)212.39KB42.83KB
plugin-detail (index.js)241.12KB60.43KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)120.42KB29.03KB
plugin-gantt (index.js)164.10KB39.87KB
plugin-grid (index.js)197.61KB53.03KB
plugin-kanban (index.js)52.72KB14.54KB
plugin-list (index.js)111.17KB26.99KB
plugin-map (index.js)18.72KB6.09KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)41.97KB11.33KB
plugin-timeline (index.js)26.68KB7.66KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)83.81KB20.49KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)27.53KB9.41KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.28KB0.68KB
react (schema-input.js)1.45KB0.83KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (index.js)4.77KB2.16KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)10.76KB3.17KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)6.92KB2.40KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.05KB1.52KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

CI 状态记录(head fc4c6c1,截至开单后约 80 分钟):14 项 completed、0 failure(含 Control Byte Scan、Changeset Declaration / Bump Policy / Fixed Group、Build & E2E、Live E2E、Build Docs、Doc Component Type Check、Internal Docs Link Check、Skill Guide Path Check、label);仍在 in_progress 的 6 项是 Test shard 1-4/4、Type Check、Lint、Bundle Analysis。

这不是本 PR 的红,是当时 CI 侧的普遍降速,证据三条:

  1. 同一时段 main 上一条合并队列触发的 Lint 运行(run 32053705804,head 1c9c342,内容是 span 的废弃提示落后 div 两步:仍是逐次渲染告警,且照旧对 kind:'html' tier 自产节点开火 #4917 的 span 改动,与本 PR 无关)于 18:11:20Z 启动,同样长时间 in_progress —— 卡的不是这个分支;
  2. main 上 Lint 的正常基线是 约 4 分钟(实测最近 8 次:4.5 / 3.9 / 4.1 / 4.3 / 3.9 min),本次 Run linter 单步已跑 60 分钟以上,量级不对;
  3. 本 PR 第一版 head 上的 label 检查曾以 HttpError: No server is currently available to service your request 失败(GitHub API 侧 5xx,发生在 actions/labeler@v7 内部),重跑后 success —— 同一时间窗的平台抖动。

被卡住那 6 项对应的本地证据已全部跑过并在正文里:packages/components/src/__tests__/ 89 files / 834 tests passed、消费半径 196 files / 2995 passed、packages/app-shell/src/views/ 261 files / 2464 passed、仓根 turbo run type-check 81/81、改动文件 eslint 0 errors。

按分派纪律本 PR 保持 draft,不自行 undraft、不入合并队列;请在 CI 恢复后复看这 6 项。


Generated by Claude Code

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

更正上一条评论(5318508367):它的两条主要依据是错的,由我读了过期数据得出,在此撤回。

错在哪:上一条依据的是 GET /pulls/5030/check-runs 报的 status,而该端点当时对多个已完成的 job 仍返回 in_progress。改用 jobs 端点(/actions/runs/<id>/jobs,带每一步的时间戳)复核后:

  • Lint 根本没有慢 —— 本 PR 的 Lint 完成于 18:13:35,Run linter 单步 18:09:47→18:13:35 约 3m48s,正好落在 main 的 3.9-4.5 分钟基线上。上一条说的「单步已跑 60 分钟以上」不存在。
  • 我引为旁证的那条 main 合并队列 Lint 运行(32053705804)也早已 success —— 18:11:20→18:15:13,约 3m53s。上一条说它「同样长时间 in_progress」同样是读了过期状态。

因此「CI 侧普遍降速」这个结论不成立,请勿据此为本 PR 的任何红开脱。上一条唯一站得住的是第 3 点:首版 head 的 label 曾因 actions/labeler@v7 内部的 GitHub API 5xx 失败,重跑后 success(那条有 job 日志正文佐证)。

按 jobs 端点核出的真实状态(head fc4c6c1):16 项 completed、0 failure —— Lint ✅、Type Check ✅(Run type-check 6m41s,与本地 turbo type-check 5m19s 同量级)、Bundle Analysis ✅、Build & E2E ✅、Live E2E ✅、Test shard 3/4 ✅(Run tests 7m47s)、其余轻量门禁 ✅。

仍未完成:Test shard 1/4、2/4、4/4 —— 三者的 Run tests 步骤自 18:10:1x 起持续运行,与 shard 3/4 的 7m47s 相差一个量级。这一条我没有查明原因,也不主张它与本改动无关:能说的只是本改动新增的测试文件只会落进四个分片中的一个,而本地对应范围全部跑绿(components __tests__ 89 files / 834 tests、消费半径 196 files / 2995 tests、app-shell views 261 files / 2464 tests)。请在这三个分片落地后按其真实结论复看;若为红,以红为准。

PR 保持 draft。


Generated by Claude Code

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

最终更正:CI 全绿,上面两条评论关于「卡住/未完成」的说法全部作废。

按 jobs 端点逐个核对(head fc4c6c1,run 32053578173),四个测试分片全部 success,整条 CI 早在 18:19:10Z 就跑完了 —— 距启动约 9 分钟:

Job结论Run tests 步骤耗时完成时刻
Test (shard 1/4)✅ success8m10s18:18:33Z
Test (shard 2/4)✅ success8m15s18:18:37Z
Test (shard 3/4)✅ success7m47s18:18:01Z
Test (shard 4/4)✅ success8m51s18:19:10Z

连同 Lint(3m48s)、Type Check(6m41s)、Bundle Analysis、Build & E2E、Live E2E、Control Byte Scan、三条 Changeset 门禁、label 等:20 项 check、0 failure(Test (coverage)dependabot 为 path-filter skipped,按约定计绿)。

根因是我的观测方法,不是 CI,也不是本改动:GET /repos/{o}/{r}/pulls/{n}/check-runs 在此后约 70 分钟里一直对这些早已完成的 job 返回 status: in_progress(过期缓存),我据此先编出了「CI 普遍降速」,又据此编出了「三个分片仍在跑、原因未明」。两条都不成立。可信的是 jobs 端点(/actions/runs/<id>/jobs/actions/jobs/<id>):它带每一步的 started_at / completed_at,前后两次更正都是它纠出来的。给后来者的教训:轮询 PR 检查状态时以 jobs 端点的时间戳为准,check-runsstatus 字段可能长时间过期,把绿读成「还在跑」。

至此本 PR 的远端验证与本地验证结论一致(本地:components __tests__ 89 files / 834 tests、消费半径 196 files / 2995 tests、app-shell views 261 files / 2464 tests、仓根 type-check 81/81)。按分派纪律仍保持 draft,不自行 undraft、不入合并队列。


Generated by Claude Code

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM 验收 ✅ ACCEPT(#4874,批次 21 —— 维护者 05:03Z A+C 裁定实施件)

实物核验(merge-base e71c854ce 与报告一致):3 files,+717/−10 —— A 半边 narrowFilterValueToOptions 作为 changeField 第三步(形状→类型→值域,#4781 空形逐字沿用未自造);C 半边渲染路径无条件临时项。模型标识 msg/diff 双 0;releases/ 零触碰;changeset components patch。

CI 亲读:20/20 check runs completed,零失败(两项 path-filter skipped 计绿;shard 4 于 18:19:10Z 收官,本 PM 同源复读与 dev 的 jobs 端点核验一致)。

判据采信:hasStaticOptionDomain 的三分(非空数组/缺席/[]/非数组)每支都有实测依据 —— 尤其 options: [] 判「未到位」而非「值域为空」那条,两个上游透传点的产出证据成立;变异③还实测出非数组支是判据函数的全性保证(不靠读取端宽容)。deviation 复看结论:两处扩展均采信 —— (a) 多值勾选框临时行:不做则 ⛔B 形态在多值面存活,正是裁定要消灭的;(b) 临时项无条件渲染:控件欠的不变量是「显示行里真正带着的东西」,值来源不止切列一途,且避免为显示改写 value prop —— 静态列清空仍严格限定在用户切 field 时,与裁定 A 半边无冲突。变异①的 expected 'acme' to be 'Select value' 读数(C 独在=B 形态)是 A/C 互不替代的直接实证。

CI 状态双误报的处置:dev 前两条 CI 评论错误、第三条公开逐条更正作废 —— 根因是 GET /pulls/:n/check-runs 对已完成 job 连续 ~70 分钟返回过期 in_progress,可信源是 jobs 端点(带步级时间戳)。更正纪律执行到位(与本车道 #4845 先例同规);该端点陷阱记入 PM 案头,后续亲读遇「长时间 in_progress + 时长远超基线」先用 jobs 端点交叉验证再下结论。

#5031(空数组 lookup 列拒远程搜索 —— 改一整类列画哪个控件,属用户可见行为变更)按其自述转 needs-user-decision。残余风险(局部 options 页)按裁定应有之义如实记录不自行收紧,正确。undraft + auto-merge(squash)。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 17, 2026 18:22
@yinlianghui
yinlianghui added this pull request to the merge queueAug 17, 2026
Merged via the queue into main with commit 384f30dAug 17, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-4874-filter-value-domain branch August 17, 2026 18:22
os-zhuang pushed a commit that referenced this pull request Aug 18, 2026
…remote picker
The remote-picker branch in `renderValueInput` tested `!field?.options`, and
`[]` is truthy, so a lookup column with `referenceTo` and an empty options
array never reached `LookupValuePicker`: scalar operators drew a Select with
zero candidates and no search box, `in`/`notIn` drew an empty checkbox list.
The same column with the `options` key absent got full remote search.
PR #5030 had already established the single criterion for this question —
`hasStaticOptionDomain(field)` (options is a non-empty array) — and ruled
`options: []` to be remote/not-yet-in-place on the value-domain side. The two
sides therefore disagreed about one column. Per the maintainer ruling of
2026-08-17, the branch now reads that same criterion.
Non-empty `options` keeps the static Select; the branch's other conjuncts are
unchanged, so a column with nothing to search against routes exactly as before.
Fixes#5031
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FilterBuilder 值落在选项集之外时值控件显示空 —— 文本值切到 picklist 列后行仍带着该值

1 participant

@yinlianghui