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

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Building Building Preview, Comment Jun 16, 2026 11:17pm

Request Review

@github-actions github-actions Bot 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 main Jun 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant