feat(workflows): add responsive library card actions (#6008)

**Category:** improvement
**User Impact:** Users can scan what each workflow does and trigger,
edit, duplicate, enable, disable, or delete it directly from the
library.
**Problem:** The workflow list buried common actions and did not expose
each automation's trigger-to-action shape at a glance.
**Solution:** Add a responsive workflow library with a persistent create
tile, compact trigger/action diagrams, prominent workflow titles with
supporting descriptions, and shared card actions while preserving
existing detail, editor, and run-history entry points. Card toggles
refresh both list and open-detail caches so status and definition stay
consistent.

<details>
<summary>File changes</summary>

**desktop/src/features/workflows/ui/WorkflowActionsMenu.tsx**
Adds a shared card menu for trigger, edit, duplicate, enable/disable,
and delete actions.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**
Reworks cards around the prototype's visual hierarchy: color-coded
trigger, action flow, sentence-case eyebrow, prominent title, supporting
description, status, channel, and update date without a footer clock
icon.

**desktop/src/features/workflows/ui/WorkflowsView.tsx**
Adds the responsive grid, create tile, mutation wiring, and list/detail
cache invalidation. Container breakpoints keep cards two-across at
medium widths and three-across in the 1280px desktop layout.

**desktop/src/features/workflows/ui/workflowDefinition.ts**
Adds immutable enabled-state updates plus narrow trigger and
first-action readers used only to select card icons.

**desktop/src/features/workflows/ui/workflowDefinition.test.mjs**
Covers neutral icon selection, enabled-state immutability, and status
presentation.

**desktop/tests/e2e/workflows.spec.ts**
Covers the create tile, title/description hierarchy, selected-card
enable/disable consistency, and deterministic narrow/medium/wide
captures while retaining existing action coverage.

</details>

## Reproduction steps

1. Open **Workflows** and confirm the create tile stays first as cards
flow from one to three columns with available width.
2. Confirm each card shows a sentence-case trigger eyebrow, prominent
workflow title, supporting description when present, status, channel,
and update date without a clock icon.
3. Open a card's overflow menu and trigger, edit, duplicate,
enable/disable, or delete the workflow.
4. Leave the detail panel open while toggling and confirm its badge and
JSON definition update with the card.

## Screenshots

Real built E2E UI with representative workflow data at three viewport
sizes.

### Narrow — 800 × 720

![Workflow library at 800 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-narrow-482d1b4c8.png)

### Medium — 1024 × 720

![Workflow library at 1024 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-medium-482d1b4c8.png)

### Wide — 1280 × 720

![Workflow library at 1280 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-wide-482d1b4c8.png)

### Card actions

![Workflow library actions at 1280 by
720](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6008/workflow-library-wide-actions-482d1b4c8.png)

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Taylor Ho
2026-08-17 09:56:34 -07:00
committed by GitHub
parent f716eef437
commit edc4a09aaa
19 changed files with 1038 additions and 238 deletions

View File

@@ -13,6 +13,7 @@ import type {
type RawWorkflow = {
id: string;
revision: string;
name: string;
owner_pubkey: string;
channel_id: string | null;
@@ -94,6 +95,7 @@ type RawApprovalActionResponse = {
function fromRawWorkflow(raw: RawWorkflow): Workflow {
return {
id: raw.id,
revision: raw.revision,
name: raw.name,
ownerPubkey: raw.owner_pubkey,
channelId: raw.channel_id,
@@ -220,10 +222,12 @@ export async function createWorkflow(
export async function updateWorkflow(
workflowId: string,
yamlDefinition: string,
expectedRevision: string,
): Promise<WorkflowSaveResult> {
const raw = await invokeTauri<RawWorkflowSaveResponse>("update_workflow", {
workflowId,
yamlDefinition,
expectedRevision,
});
return fromRawWorkflowSave(raw);
}

View File

@@ -2,6 +2,7 @@ export type WorkflowStatus = "active" | "disabled" | "archived";
export type Workflow = {
id: string;
revision: string;
name: string;
ownerPubkey: string;
channelId: string | null;