feat(list): unify conditional formatting + row-action visibility onto the CEL engine (#1584)#2544
Draft
os-zhuang wants to merge 1 commit into
Draft
feat(list): unify conditional formatting + row-action visibility onto the CEL engine (#1584)#2544os-zhuang wants to merge 1 commit into
os-zhuang wants to merge 1 commit into
Conversation
… the CEL engine (#1584) Converge the list-view conditional tier — conditional formatting (list / grid / kanban) and row-action `visible` / `disabled` — onto @objectstack/formula's CEL engine, matching how @objectstack/spec already types these surfaces (ExpressionInputSchema / CEL) and how the server evaluates them (framework ADR-0058). The whole platform now speaks one expression dialect. - @object-ui/core: new evalRowPredicate + resolveConditionalFormatting helpers (one implementation of the three formatting rule shapes; dialect routing — a { dialect: 'cel' } envelope is always CEL, a bare string is CEL unless it carries legacy-only syntax which routes to the old engine with a one-time deprecation warning; native { field, operator, value } translated to CEL). - @object-ui/react: new useRowPredicate hook (canonical CEL, ambient scope). - Consumers converged: ListView.evaluateConditionalFormatting (thin wrapper), ObjectGrid row styling (inline copy removed), kanban card styles, grid and data-table row-action menus. plugin-view now forwards top-level conditionalFormatting to the kanban branch (previously dropped). - Row-action visible fails closed (broken -> hidden + warn); disabled fails soft. The CEL `in` operator now works in row predicates. - Legacy FormField.condition {field, equals/notEquals/in} retired to a CEL translation (back-compat); FieldDesigner migrated to visibleWhen. Unit + jsdom component tests; docs/skill updated; live e2e spec added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LwrWThBJgvcfPtqNHpstB
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1584. Converges the list-view conditional tier — conditional formatting (list / grid / kanban) and row-action
visible/disabled— onto@objectstack/formula's CEL engine, the same engine the server uses (framework ADR-0058). Previously these evaluated on the legacy JS-dialectExpressionEvaluator, even though@objectstack/specalready types them as CEL (ListViewSchema.conditionalFormatting[].conditionandActionSchema.visibleareExpressionInputSchema). This was a spec-compliance gap:toPredicateInputunwrapped a{ dialect: 'cel', source }envelope and fed it to the wrong dialect. Now the whole platform speaks one expression dialect.What changed
@object-ui/core— new zero-React helpers next toevalFieldPredicate:evalRowPredicate(pred, row, opts)— one boolean predicate over a row on the canonical CEL engine; bindsrecord.*, bare fields,data.*, and the host predicate scope (features/user).resolveConditionalFormatting(record, rules, scope)— the single implementation of all three historical rule shapes.{ dialect: 'cel' }envelope is always CEL; a bare string is CEL per the spec contract, unless it carries legacy-only syntax (${…},===/!==,?.,.includes()) → routed to the legacy engine with a one-time deprecation warning. The native{ field, operator, value }form is translated to CEL.@object-ui/react— newuseRowPredicatehook (canonical CEL + ambient predicate scope).ListView.evaluateConditionalFormattingis now a thin wrapper (export kept);ObjectGrid.getRowStyle's inline copy deleted; kanban card styles use the shared helper; grid + data-table row-action menus switch to the CEL path.plugin-view'sObjectViewkanban branch now forwards top-levelconditionalFormatting(it was silently dropped for kanban).visiblefails closed (hidden + warn, aligns withActionEngine);disabledfails soft (not disabled + warn). Nothing silent.condition{ field, equals/notEquals/in }retired to a CEL translation at theform.tsxentry (back-compat preserved); the twoFieldDesignerauthoring sites migrated tovisibleWhen.Capability gain
The CEL
inoperator and list membership (record.status in ['sent','paid']) now work in row predicates — the legacy parser had noinoperator and silently failed open on them.Back-compat
Near-zero blast radius (full-tree survey found no real authored usages of these features; only package-test fixtures). Existing conditional-formatting rules, row-action predicates, and form
conditionmetadata keep working via translation / dialect routing (with deprecation warnings on legacy-dialect strings).Naming (settled by ADR-0089)
Actions keep
visible(ADR-0089 renamed only field/view/page keys;action.zod.tskeepsvisible, already CEL). Spec{ condition, style }stays canonical for formatting; ObjectUI-local shapes are back-compat translations.useCondition/useExpression(schema/widget${}tier) are untouched — only row/record predicate call-sites moved.Tests
packages/core/.../listConditional.test.ts— 19 tests: three rule shapes, dialect routing,in, legacy fallback + warn, fail-closed + warn, missing-key.packages/react/.../useExpression.test.ts—useRowPredicate: boolean short-circuit, scope merge, CELin, fail-closed.packages/plugin-grid/.../RowActionMenu.test.tsx— CELinshow/hide end-to-end on the real menu.packages/components/.../form-legacy-condition.test.tsx— legacycondition→ CEL (equals / notEquals / in), reactive.e2e/live/list-row-action-cel.spec.ts— live spec guarding the row-action-menu render path against the showcase task list'svisible: '!record.done'action.All touched-package suites pass (core + react 1327; grid + kanban 216; components/list/view/designer 508).
turbo type-checkgreen across all touched packages. No new lint errors.Notes / follow-ups
visiblepredicate; the gate semantics are covered deterministically by the jsdom component tests. The live stack isn't runnable in the authoring sandbox.@objectstack/formula'scelEngine.evaluatere-parses per call (cel-js exposes no AST re-execution). Acceptable at page-size row counts; worth an upstream program cache in@objectstack/formulaif it shows up hot.🤖 Generated with Claude Code
Generated by Claude Code