Skip to content

feat(action): conditional visibility + undoable actions (CRM demo) - #1992

Merged
os-zhuang merged 1 commit into
mainfrom
feat/action-conditional-progress-undo
Jun 16, 2026
Merged

feat(action): conditional visibility + undoable actions (CRM demo)#1992
os-zhuang merged 1 commit into
mainfrom
feat/action-conditional-progress-undo

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

Action UX follow-ups (the third batch from the conversion-wizard review): conditional action visibility and an undoable action affordance.

1. Conditional action visibility

Action.visible / Action.disabled CEL predicates were already evaluated by the action renderers — this wires the CRM example up to use them: Convert Lead now declares visible: record.status != "converted", so the button disappears on already-converted leads instead of the user clicking it and hitting the flow's guard screen (kept as a server-side backstop).

2. Undoable actions

New Action.undoable flag. A single-record update action that sets it gets an Undo affordance on its success toast (backed by the client UndoManager). New CRM Reassign Lead list action demonstrates it — reassigns assigned_to, restorable from the toast (and Ctrl+Z).

Changes

  • spec: Action.undoable.
  • app-crm: Convert Lead gains visible; new Reassign Lead undoable action.

Verification

Browser E2E (console + app-crm):

  • Convert Lead is hidden on a converted lead, shown on a new/qualified lead.
  • Reassign Lead → param dialog → updates assigned_to, toast shows "Undo" → clicking Undo restores the prior owner.

Smoke test (29) passes. Pairs with the objectui companion PR.

🤖 Generated with Claude Code

- spec: UI Action gains `undoable` (single-record update actions offer an Undo
affordance on success). `visible`/`disabled` CEL predicates already existed.
- app-crm: Convert Lead action gains `visible: record.status != "converted"`
(the button hides on converted leads instead of relying on the flow's guard
screen). New "Reassign Lead" list action (`undoable`) demonstrates the Undo
affordance — reassigns `assigned_to`, restorable from the toast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercelBot commented Jun 16, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specBuildingBuildingPreview, CommentJun 16, 2026 11:17pm

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation protocol:ui tooling size/s labels Jun 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

89 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx(via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/implementation-status.mdx(via @objectstack/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via packages/spec)
  • content/docs/concepts/packages.mdx(via @objectstack/spec)
  • content/docs/concepts/setup-app.mdx(via @objectstack/spec)
  • content/docs/concepts/skills.mdx(via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx(via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx(via @objectstack/spec)
  • content/docs/getting-started/cli.mdx(via @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx(via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx(via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx(via @objectstack/spec)
  • content/docs/guides/api-reference.mdx(via @objectstack/spec)
  • content/docs/guides/business-logic.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx(via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx(via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx(via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx(via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx(via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx(via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx(via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx(via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx(via packages/spec)
  • content/docs/guides/data-modeling.mdx(via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx(via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx(via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/guides/formula.mdx(via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx(via packages/spec)
  • content/docs/guides/kernel-services.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx(via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx(via @objectstack/spec)
  • content/docs/guides/packages.mdx(via @objectstack/spec)
  • content/docs/guides/plugin-development.mdx(via @objectstack/spec)
  • content/docs/guides/plugins.mdx(via @objectstack/spec)
  • content/docs/guides/project-scoping.mdx(via @objectstack/spec)
  • content/docs/guides/public-forms.mdx(via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/guides/runtime-services/index.mdx(via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx(via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx(via packages/spec)
  • content/docs/guides/security.mdx(via @objectstack/spec)
  • content/docs/guides/seed-data.mdx(via @objectstack/spec)
  • content/docs/guides/skills.mdx(via @objectstack/spec)
  • content/docs/guides/standards.mdx(via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 84249a4 into mainJun 16, 2026
12 of 14 checks passed
@os-zhuang
os-zhuang deleted the feat/action-conditional-progress-undo branch June 16, 2026 23:19
os-zhuang added a commit that referenced this pull request Jun 17, 2026
…#1992
Pre-existing red on the spec-liveness gate (not from this branch's timezone
change): #1990 added flow.successMessage/errorMessage + action.errorMessage
and #1992 added action.undoable, none classified in the ledgers.
- flow.successMessage → live (service-automation/src/engine.ts:1292)
- flow.errorMessage → live (service-automation/src/engine.ts:1348)
- action.errorMessage → live (objectui toast, error counterpart of successMessage)
- action.undoable → experimental: declared + demoed in #1992 but no runtime
reader yet in framework or objectui (objectui has an UndoManager but does not
key off the action's `undoable` flag). Promote to live once a consumer lands.
Greens the liveness gate (was red on main too).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 17, 2026
)
* feat(runtime): resolve reference timezone onto ExecutionContext (#1978)
ADR-0053 Phase 2 foundation. Adds `ExecutionContext.timezone` (optional IANA
zone) and resolves it once per request in resolveExecutionContext, precedence
user preference -> org default -> UTC:
- user override: sys_user_preference (user_id, key='timezone')
- org default: tenant-scoped sys_setting (namespace='localization',
key='timezone', scope='tenant') — one org per physical tenant (ADR-0002),
so no tenant_id filter
- invalid IANA zone ignored, falls through; every read defensive via tryFind,
never blocks auth
Pure plumbing, no behavior change: nothing reads ctx.timezone yet and an
absent value resolves to UTC (today's behavior). Foundation consumed by the
rest of Phase 2 — tz-aware today()/daysFromNow() (#1980), datetime rendering
(#1981), analytics bucketing (#1982). A discoverable `localization` settings
manifest for the org default is a follow-up; the resolver already reads the
row if present.
Tests: user pref > org default > UTC; invalid zone falls through; anonymous
leaves it unset. Runtime suite green (387), spec kernel green (682).
Closes#1978.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(spec): classify 4 liveness properties left unclassified by #1990/#1992
Pre-existing red on the spec-liveness gate (not from this branch's timezone
change): #1990 added flow.successMessage/errorMessage + action.errorMessage
and #1992 added action.undoable, none classified in the ledgers.
- flow.successMessage → live (service-automation/src/engine.ts:1292)
- flow.errorMessage → live (service-automation/src/engine.ts:1348)
- action.errorMessage → live (objectui toast, error counterpart of successMessage)
- action.undoable → experimental: declared + demoed in #1992 but no runtime
reader yet in framework or objectui (objectui has an UndoManager but does not
key off the action's `undoable` flag). Promote to live once a consumer lands.
Greens the liveness gate (was red on main too).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 25, 2026
…ability) (#2317)
* chore: bump objectui to 8a3b351a5a32
fix(console): gate the AI surface on the service-ai capability, not the agent catalog (#1992)
objectui@8a3b351a5a320e6769a1616e85a6fd05aabd3279
* chore(showcase): remove the AI agent — service-ai is an enterprise capability
The showcase defined a `showcase_assistant` agent + a skill + two tools, all of
which need the enterprise `@objectstack/service-ai` runtime to be served. The
open-source showcase shouldn't require an enterprise capability, so drop the AI
block entirely:
- delete `src/agents/index.ts` (agent + skill + tools) and its config wiring
(`agents` / `skills` / `tools`);
- remove the `@objectstack/service-ai` dependency (added in #2311 to back the
agent — no longer needed);
- drop the descriptive `ai` entry from the coverage map and update the seed test
(`agents.length` 1 → 0).
The showcase now boots as a Community-Edition shape: no AI service is registered,
discovery reports `services.ai` unavailable, and `/api/v1/ai/agents` 404s — so
the console hides its AI surface. `tsc --noEmit` + all 39 showcase tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 28, 2026
…eaders gate it (#3714) (#3829)
The liveness ledger marked `action.undoable` `experimental` on a #1992-era note
("no runtime reader yet ... objectui has an UndoManager but does not key off
this field"). True when written, falsified since: objectui wired two readers,
both gating real behaviour — app-shell useConsoleActionRuntime.tsx:409 builds
the undo operation the success toast's Undo button invokes (:147), and
RecordDetailView.tsx:545 restores the record's prior field values (:404).
Because the CLI liveness lint warns on `experimental` as well as `dead`,
authoring a *working* property produced a "declared but NOT enforced at runtime"
warning — telling authors and AI to skip a shipped feature.
- ledger: `experimental` -> `live` with the two readers as evidence
- README: action row 33|1|2 -> 34|0|2; `undoable` joins `flow.status` as the
second understatement, with the cost of understating spelled out
- protocol docs: drop the "currently has no effect" claim
- CLI lint test: experimental-path assertion repoints to agent.memory, plus a
regression guard that `undoable` is now silent
Schema, parsed shape and runtime are unchanged — only the classification.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/stooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang