Repository navigation
feat(fields): Setup's notification topic and channel fields pick from the served list and still take a typed value - #31069
Conversation
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
…heir words Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
… faces Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
… their labelling and sweep rows Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
…ys in the form-type drift guards Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
…n widget keys Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibzyvUbUU6pC3x3Amrx
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf Contract reviewServed-tier: Owed by the ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
|
domain:ui#2 · os-tesla · session_01L9qibw7DekEe3wx5f3zphf 席位核对 · ACCEPT · 2026-11-07T01:32Z · head
|
Requested by Tesla · project thread
Fixes #31062
Part of #30208
Clause-②: yes (widening) — five new
fields.preferenceOption.*keys in every published@object-ui/i18npack, andfield:notification-topic/field:notification-channeljoin@object-ui/fields' registered widget keys (RegisteredFieldWidgetType); nothing is narrowed.Metadata-protocol: none
维护者速读
preference-options接口,*排第一;仍可直接输入列表外的值。invoices.paid、emial),通知就会静默不发或发错渠道;按裁决 E([Decision] 通知偏好 topic/channel: pickers, refuse unmatched values, or free text as ruled on #25346? #30527)给出可选列表并保留自由输入。notification-topic/notification-channel的三个字段;接口失败或返回空列表时退回原来的文本框;回滚即 revert 本 PR。ui/packages/fields/src/widgets/RegistryRefField.tsx(填充分支PreferenceOptionField)、ui/packages/fields/src/widgets/preferenceOptions.ts(读取与共享请求)、ui/packages/fields/src/index.tsx(注册)。invoices.paid点 "Use …",字段显示 "invoices.paid (not in the list)";Channel 列表里 push 显示 "(not configured)" 且可选。43dd3c69的 diff 复核:24 个文件、+776 / −28,无受治理路径。设置里通知偏好与模板的「主题」「渠道」字段改为可填写的下拉:列表来自GET /api/v1/messaging/preference-options(经宿主已认证的 fetch,整页共用一次请求),*排在最前;手输的值原样保存,不在列表中的值保留并标注;未配置的渠道照列、标注、可选;请求失败或列表为空时回到原来的文本框。新增五条文案进所有语言包。Clause-② 改为 yes (widening),席位 TIER_DEFAULT 复核 PASS(6700168365)。CI 全绿,同意落地。What changes
sys_notification_preference.topic/.channelandsys_notification_template.topicdeclarewidget: 'notification-topic'/'notification-channel'since #31004; nothing registered them, so they rendered as text boxes. This PR registers both asfield:WIDGETkeys in@object-ui/fields, so the record form picks them up with no per-page code.Home: option (a), a fillable arm on
RegistryRefField. It registers throughfieldWidgetMap, the field widget registry the record form already consults forFieldSchema.widget, besideposition-ref/permission-ref; option (b) would live inapp-shellbesideFlowReferenceField, which only the flow inspector reads, and would need its own route into the record form. The arm reuses the registry picker's four-state catalog machinery (IDLE / LOADING / FAILED / LOADED, generalised fromuseRegistryCatalogtouseCatalog(reader, origin, list)with one module-level reader per arm), and differs from the registry arm only where an open list must:GET /api/v1/messaging/preference-optionsthrough the host's authenticated fetch (SchemaRendererContext.apiFetch, the console's existingcreateAuthenticatedFetchpath; no new fetch helper). One request per fetch function for the page, shared by the topic and the channel field; a failed read is not kept. Listed in the server's order,*first, shown as "All topics ()" / "All channels ()".data-not-in-list), on the edit and the read face. Nothing is refused or rewritten.data-not-configured) and is selectable.fields.preferenceOption.*keys in every console pack;zh-Hantregenerated fromzh-Hanswithgen:zh-hant.position-ref(objectui#7611) ripple:FIELD_WIDGET_LABELLING, the bare-name skip list,INLINE_EXCLUDED_FIELD_TYPESand the two fields widget sweeps; under the seat's claim amendments 6699576193 and 6699989026, twowidgetHintOnlyrows inapp-shellparamValueShape.ts, the two names inplugin-detail'sinlineEditTypeCoverageexcluded bucket, andui/packages/cli/src/utils/known-schema-types.tsregenerated bynode ui/scripts/regenerate-known-schema-types.mjs(two lines, no hand edit). Thedequote census moves 108 → 109 for the new„{{value}}“ verwendenrow.Out of scope, unchanged: the template's
channel(channel_renders_template, no widget, still a text box), quiet hours, row 5 of #30208, any server change.Tests
ui/packages/fields/src/widgets/__tests__/RegistryRefField.preferenceOptions-31062.test.tsx, 14 cases:*first, the door's order, one shared read for two fields), and both keys resolve throughfield:WIDGETin the registry;Ablation (
scripts/ablation-replace.mjs, src import, no build in the path): deleting the'notification-topic'loader fromfieldWidgetMapturns "notification-topicis registered and lists the door" red (expected undefined to be defined, 1 failed / 12 passed); restore verified blob == HEAD.Acceptance notes
no). The PR adds five keys to every published@object-ui/i18npack and two registered widget keys; some recent i18n-key PRs declared thatyes (widening)and someno, so the seat may want to amend.ui/packages/i18n/src/locales/*.tspacks, in a different block; whichever lands second takes a textual merge.pnpm check:eager-closureneeds a Console build and is CI's: the arm adds code to@object-ui/fields, which rides the eagerui-componentschunk.Verification
Readings name their tree. Gates and type-check at
da4d45a2; the last commit1fc7c752adds only the regeneratedknown-schema-types.ts, and the uiscripts/suite was re-run on it. Re-deriving at1fc7c752gives the same 38 families.Live before, on main 23cf11a (showcase backend --fresh, Console dev server, admin sign-in)
INPUT type=text, prefilled*. Notification Templates → New: Topic and Channel areINPUT type=text. No request to the options route.GET /api/v1/messaging/preference-options(signed in):200, 28 topics (*first, thenapproval.*,auth.*,collab.mention, the showcase flow topics such asinvoice.signoff,project.digest,task.assigned, andnotify), 5 channels:*,inbox,email,sms, andpushwithconfigured: false. Anonymous:401.Live after, on this branch (same backend)
All channels (*),inbox,email,sms,push (not configured).invoices.paidin the topic search and picked "Use …": the trigger reads "invoices.paid (not in the list)" withdata-not-in-list=true. Pickedpush (not configured). Save, thenGET /api/v1/data/sys_notification_preferencereads backtopic: invoices.paid,channel: push.INPUT type=text.200once per page load.Tests
pnpm --dir ui exec vitest run packages/fields/src/widgets/__tests__/RegistryRefField.preferenceOptions-31062.test.tsx: 14 passed.packages/fields/whole,packages/i18n/,packages/components/src/renderers/form/, the plugin-formposition-refform test, the app-shell form-type guards and the cli ratchet: 8 reds before the ripple rows (all named above), then green on the rerun of every red file (361 + 367 + 48 tests).pnpm --filter @object-ui/fields --filter @object-ui/i18n --filter @object-ui/app-shell run type-checkafter a dts build of their closure: exit 0.Derived gates (dispatch-gates --commands, 38 families; every line exit 0)
Reconciled with
dispatch-gates.mjs --ran: 38 derived, 38 run, 0 NOT-MEASURED. Record:/mnt/project-files/ui-seat-2/r2026-11-06/31062/gates-ran-1fc7c752.list. Includesnode scripts/check-sdui-manifest.mjs(exit 0),pnpm check:nul-bytes,pnpm check:cross-package-test-inputs,pnpm check:type-check-coverage,pnpm check:type-check-debt,pnpm check:undeclared-dep-imports, the changeset gates, andpnpm --dir ui exec vitest run scripts/(170 passed, 2 skipped).