Repository navigation
feat(desktop): redesign automations dashboard with stats, grouped list, and cleaner top bar - #6291
Conversation
…t, and cleaner top bar Modeled on Cursor Automations and Codex Scheduled tasks (research in apps/desktop/plans/automations-ui-improvements.md): - Cursor-style page layout: centered content column, page title, stat cards (Active / Created 7d / Failed 7d with success percentages), list-controls row, table in a rounded card, CLI hint demoted to a footnote - Codex-style default grouping: "Up next" ordered by soonest run with countdown in the Status column, "Paused" section below; column sort switches to a flat list - Slimmer table: Workspace/Device/Agent columns removed, project shown as a muted tag next to the name, dispatch wording changed to created/creating (a run's success = workspace created) - Failed stat card toggles a failing-automations filter; live name search; pause/resume from the row menu; skeleton loading; minimal empty state with per-category template suggestions
📝 WalkthroughWalkthroughThe automation dashboard now includes seven-day statistics, search and failure filters, scope tabs, updated sorting, loading and empty states, pause/resume actions, and revised run timing displays. The plans document lifecycle semantics, onboarding, run history, and scheduling phases. ChangesAutomation dashboard redesign
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant AutomationsPage
participant useFailedAutomations
participant AutomationStatCards
participant AutomationRow
participant AutomationActionsMenuItems
AutomationsPage->>useFailedAutomations: read run statuses and latest-run records
useFailedAutomations-->>AutomationsPage: return failure data and workspace links
AutomationsPage->>AutomationStatCards: provide seven-day statistics
AutomationStatCards-->>AutomationsPage: toggle failed-only filtering
AutomationsPage->>AutomationRow: render filtered automation data
AutomationRow->>AutomationActionsMenuItems: provide enabled state and toggle callback
AutomationActionsMenuItems->>AutomationsPage: invoke pause or resume mutation
AutomationsPage-->>AutomationRow: render updated enabled state
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (5)
apps/desktop/plans/automations-ui-improvements.md (1)
25-26: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDo not expose next-run data only on hover.
Line 25 makes the next-run time hover-only. Keyboard and touch users cannot reliably access hover content. Render the time in the row or expose it through a focusable, accessible popover.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/plans/automations-ui-improvements.md` around lines 25 - 26, Update the automation table specification around the Columns definition so each row visibly renders the next-run time or exposes it through a keyboard- and touch-accessible focusable popover, rather than hover-only content. Preserve the existing Status column and next-run information while ensuring it is reliably accessible without pointer hover.apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/components/AutomationActionsMenuItems/AutomationActionsMenuItems.tsx (1)
75-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse a distinct icon for Resume.
When an automation is paused, the menu shows "Run now" and "Resume" with the same
LuPlayicon. A different icon for Resume, such asLuCirclePlay, separates the two actions visually.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/components/AutomationActionsMenuItems/AutomationActionsMenuItems.tsx` around lines 75 - 88, Update the disabled-state branch of the onToggleEnabled menu item in AutomationActionsMenuItems to use a distinct resume icon, such as LuCirclePlay, instead of LuPlay; leave the enabled Pause icon and labels unchanged.apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsx (1)
50-58: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider a fallback for an unknown run status.
LAST_RUN_META[lastRunStatus]reads a synced value. The type comes from the schema, so the map is exhaustive at compile time. If the server starts writing a new status before the desktop client updates,metaisundefinedand Line 212 throws while rendering the row. A default entry keeps the table alive.🛡️ Proposed fix
dispatch_failed: { dot: "bg-red-500", label: "failed", failed: true }, }; + +const UNKNOWN_RUN_META = { dot: "bg-muted-foreground/40", label: "unknown" };- const meta = LAST_RUN_META[lastRunStatus]; + const meta = LAST_RUN_META[lastRunStatus] ?? UNKNOWN_RUN_META;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsx` around lines 50 - 58, Add a fallback metadata entry when resolving LAST_RUN_META for lastRunStatus, so an unrecognized synced status cannot produce undefined before rendering the row. Preserve the existing status-specific metadata and use the fallback’s failed styling and label consistently with the current error-state behavior.apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationStatCards/AutomationStatCards.tsx (1)
49-78: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse phrasing elements inside the button, and make the disabled title reachable.
Two points on the failed card:
- Lines 66 and 74 place
<p>elements inside a<button>. The button content model allows phrasing content only. Use<span>withblockto keep the same layout.- Line 51 disables the button when
canFilterFailedis false. Browsers suppress pointer events on a disabled button, so the explanatorytitleon Line 56 never appears. Keep the button enabled and makeonClicka no-op, or move the explanation to a wrapper element.♻️ Proposed markup change
- <p className={LABEL}> + <span className={cn(LABEL, "block")}> Failed <span className="text-muted-foreground/60">· 7d</span> {failedFilter && ( <span className="ml-1.5 text-red-600 dark:text-red-400"> filtering </span> )} - </p> - <p className={VALUE}> + </span> + <span className={cn(VALUE, "block")}> {failed7d} {pct(failed7d) && <span className={PCT}>{pct(failed7d)}</span>} - </p> + </span>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationStatCards/AutomationStatCards.tsx` around lines 49 - 78, Replace the failed card’s `<p>` elements with `<span>` elements using `block` styling to preserve the layout while keeping button content valid. Update the disabled-state logic around `onToggleFailedFilter` so the button remains enabled and clicking when `canFilterFailed` is false performs no action, allowing the explanatory `title` to remain reachable.apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx (1)
317-347: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueConsider sharing one
automationRunslive query.
useFailedAutomationsalready runs the sameautomationRunsquery with the same three projected fields. This page opens a second identical live query and scans all run rows again on every 30-secondnowtick. Move the seven-day aggregation intouseFailedAutomations, or return the projected rows from that hook, so the page scans the run set once.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx` around lines 317 - 347, Consolidate the duplicate automationRuns live query by reusing useFailedAutomations: move the seven-day created/failed aggregation into that hook or expose its projected runStatRows, then remove the page-level useLiveQuery and duplicate scan while preserving the existing tab filtering and now-based seven-day counts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/plans/automations-ui-improvements.md`:
- Around line 51-54: Update the automation UI specification around the “Stop All
Runs” action to define it only for pending dispatch attempts, or remove the
action entirely. Do not present it as available after workspace creation, since
dispatch is terminal and no completion lifecycle exists.
- Around line 3-4: Update the screenshot reference in the plan to use
repository-stored assets or another shared, versioned location instead of the
workstation-specific ~/Desktop/competitor-screenshots/gallery.html path, while
preserving the cited component filenames.
- Line 16: Make automation_runs.trigger a required field rather than optional,
and persist either schedule or manual for every newly created run, including the
runNow path. Update the automation history behavior to filter and distinguish
runs using trigger instead of inferring from scheduledFor, and define a
migration/default strategy for legacy rows before applying trigger-based
filters.
- Line 57: Define duplicate protection for the Re-run action before exposing it:
make the request idempotent using a stable idempotency key and ensure retries or
double-clicks return the original rerun result without creating another
workspace, or explicitly document and implement an intentional duplicate policy
in the automation.listRuns/re-run flow.
- Line 58: Update the failed-create error rendering described in the plan to
require the classes select-text cursor-text on the visible error message. Keep
the full selectable text outside the hover-only max-w-xs tooltip so the
acceptance criterion is directly testable.
- Around line 60-61: Bound the per-run unread state in the existing
failure-badge watermark store: add a cap or TTL, document which component owns
deletion, and remove entries when the corresponding run or workspace is deleted.
If the state must persist and scale beyond renderer lifetime, use entity-scoped
persistent storage instead of unbounded renderer-local keys.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx`:
- Around line 586-594: Add an aria-label to the Input component in the search
control around the search state, using a clear name such as “Search,” while
preserving the existing value, change handler, placeholder, and styling.
- Around line 688-699: Update the TableBody rendering around renderAutomationRow
to show a no-results message row when visible.length is 0 while
tabVisible.length is greater than 0, covering search and failed-filter results
without affecting existing grouped or sorted rows.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/hooks/useFailedAutomations/useFailedAutomations.ts`:
- Around line 61-79: Update the initial loop that builds latest, before the
latest.get comparison, to skip runs whose parsed createdAt timestamp is not
finite. This prevents invalid timestamps from being inserted into latest; keep
the existing latest-status and last-run-time map construction unchanged for
valid timestamps.
---
Nitpick comments:
In `@apps/desktop/plans/automations-ui-improvements.md`:
- Around line 25-26: Update the automation table specification around the
Columns definition so each row visibly renders the next-run time or exposes it
through a keyboard- and touch-accessible focusable popover, rather than
hover-only content. Preserve the existing Status column and next-run information
while ensuring it is reliably accessible without pointer hover.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsx`:
- Around line 50-58: Add a fallback metadata entry when resolving LAST_RUN_META
for lastRunStatus, so an unrecognized synced status cannot produce undefined
before rendering the row. Preserve the existing status-specific metadata and use
the fallback’s failed styling and label consistently with the current
error-state behavior.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/components/AutomationActionsMenuItems/AutomationActionsMenuItems.tsx`:
- Around line 75-88: Update the disabled-state branch of the onToggleEnabled
menu item in AutomationActionsMenuItems to use a distinct resume icon, such as
LuCirclePlay, instead of LuPlay; leave the enabled Pause icon and labels
unchanged.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationStatCards/AutomationStatCards.tsx`:
- Around line 49-78: Replace the failed card’s `<p>` elements with `<span>`
elements using `block` styling to preserve the layout while keeping button
content valid. Update the disabled-state logic around `onToggleFailedFilter` so
the button remains enabled and clicking when `canFilterFailed` is false performs
no action, allowing the explanatory `title` to remain reachable.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx`:
- Around line 317-347: Consolidate the duplicate automationRuns live query by
reusing useFailedAutomations: move the seven-day created/failed aggregation into
that hook or expose its projected runStatRows, then remove the page-level
useLiveQuery and duplicate scan while preserving the existing tab filtering and
now-based seven-day counts.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: efd46b96-08cd-4cac-b7a0-26591f9cfb05
📒 Files selected for processing (9)
apps/desktop/plans/automations-ui-improvements.mdapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/components/AutomationActionsMenuItems/AutomationActionsMenuItems.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationStatCards/AutomationStatCards.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationStatCards/index.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationsEmptyState/AutomationsEmptyState.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/TemplateCard/TemplateCard.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/hooks/useFailedAutomations/useFailedAutomations.ts
| Anchors: **Cursor Automations** (dashboard, run history, result-as-diff) and **OpenAI Codex/ChatGPT** (create & edit automations *in chat*, NL schedule, unread runs). | ||
| Reference screenshots: `~/Desktop/competitor-screenshots/gallery.html` (filenames cited per component). The `cursor2-*` set (60 files) documents every Cursor surface: dashboard, editor, run history, run detail, creation flows, marketplace. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Make the screenshot references portable.
~/Desktop/competitor-screenshots/gallery.html is local to one workstation. Other reviewers and CI cannot resolve it. Store the assets in the repository or use a shared, versioned reference.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` around lines 3 - 4, Update
the screenshot reference in the plan to use repository-stored assets or another
shared, versioned location instead of the workstation-specific
~/Desktop/competitor-screenshots/gallery.html path, while preserving the cited
component filenames.
|
|
||
| - **Language:** render `dispatched` as **"created"** (with workspace name), not "ran" — the current word implies a completed job. `dispatch_failed` / `skipped_offline` render as "failed to create" with the reason. | ||
| - **Live agent state on run rows:** for a run's workspace, reuse the existing bindings-derived status (`useTerminalAgentStatuses` / `deriveTerminalAgentStatus`: working / permission / failed / idle-review) instead of persisting anything. A run row = "created → [live: agent working / needs review / failed]". Chat-session runs: reuse whatever the workspace list shows for chat agents today; if nothing exists, show "created" only (no new plumbing). | ||
| - **Schema (optional, tiny):** `trigger` (`schedule | manual`) on `automation_runs` so manual re-runs are distinguishable in history (GH Actions' trigger column). Via `db-migrations` skill; never hand-edit `packages/db/drizzle/`. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Make automation_runs.trigger explicit, not optional.
Line 57 requires reliable schedule versus manual history semantics. Line 96 considers inferring manual runs from scheduledFor. That inference is ambiguous for a manual run near its scheduled time. Persist trigger on every new run, including runNow, and define handling for legacy rows before adding trigger filters.
Also applies to: 57-57, 96-97
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` at line 16, Make
automation_runs.trigger a required field rather than optional, and persist
either schedule or manual for every newly created run, including the runNow
path. Update the automation history behavior to filter and distinguish runs
using trigger instead of inferring from scheduledFor, and define a
migration/default strategy for legacy rows before applying trigger-based
filters.
| Cursor's exact spec (adopt the shape, adapt the semantics): | ||
| - Tab header: 3 time-window cards (Last 1h / 24h / 7d) with green succeeded + red failed counts; **Stop All Runs** top-right; search + filter (by Status / Trigger / Tools) on the tab row. | ||
| - Columns: Trigger (icon + "Scheduled · Every Mon at 9AM GMT+7" / manual) · Triggered (absolute time) · Status (**pill chips**: Succeeded green / Failed red / Running orange) · Duration · ⋯ (View details / Edit / Cancel Run — Cancel red, running rows only). Ours: status = created/failed-to-create; "duration" n/a until lifecycle exists; add workspace + live agent state instead. | ||
| - Run detail, two shapes worth mirroring later: transcript + **Run Summary card** (trigger + ordered tool-call list) + follow-up composer; or narrative report beside a diff with a **draft-PR "Mark as ready" gate**. For us: the workspace is the run detail; the follow-up composer maps to opening the session. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Limit Stop All Runs to a defined lifecycle state.
Lines 6-15 define dispatch as terminal when the workspace is created and state that no completion pipeline exists. Lines 52-53 still add Stop All Runs. The action has no defined target after dispatch. Limit it to pending dispatch attempts or remove it.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` around lines 51 - 54,
Update the automation UI specification around the “Stop All Runs” action to
define it only for pending dispatch attempts, or remove the action entirely. Do
not present it as available after workspace creation, since dispatch is terminal
and no completion lifecycle exists.
| - Run detail, two shapes worth mirroring later: transcript + **Run Summary card** (trigger + ordered tool-call list) + follow-up composer; or narrative report beside a diff with a **draft-PR "Mark as ready" gate**. For us: the workspace is the run detail; the follow-up composer maps to opening the session. | ||
|
|
||
| A run's payoff is its workspace, so history = "the workspaces this automation created": | ||
| - **Run History tab on the detail page** (tabs: Overview | Run history), replacing the 10-row sidebar list as the primary surface. Full table via `automation.listRuns` (exists server-side, unused; add pagination): status chip, trigger (schedule vs manual), created-at relative, workspace name + live agent status, sessionKind icon, actions: Open workspace (existing deep link), Re-run. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Define duplicate protection for Re-run.
The model says that each run creates a workspace. A double click or retried non-idempotent request can create multiple workspaces. Add an idempotency key or document an explicit duplicate policy before exposing Re-run.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` at line 57, Define
duplicate protection for the Re-run action before exposing it: make the request
idempotent using a stable idempotency key and ensure retries or double-clicks
return the original rerun result without creating another workspace, or
explicitly document and implement an intentional duplicate policy in the
automation.listRuns/re-run flow.
|
|
||
| A run's payoff is its workspace, so history = "the workspaces this automation created": | ||
| - **Run History tab on the detail page** (tabs: Overview | Run history), replacing the 10-row sidebar list as the primary surface. Full table via `automation.listRuns` (exists server-side, unused; add pagination): status chip, trigger (schedule vs manual), created-at relative, workspace name + live agent status, sessionKind icon, actions: Open workspace (existing deep link), Re-run. | ||
| - **Failed creates get real error surfaces:** full selectable error text in the row/expanded state — today it's a `max-w-xs` hover tooltip, violating our own AGENTS rule. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Record the required renderer classes in this plan.
Line 58 requires selectable error text but does not name the renderer requirement. When implemented, add select-text cursor-text to the rendered error message and keep it outside the hover-only tooltip. This makes the acceptance criterion testable.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` at line 58, Update the
failed-create error rendering described in the plan to require the classes
select-text cursor-text on the visible error message. Keep the full selectable
text outside the hover-only max-w-xs tooltip so the acceptance criterion is
directly testable.
Source: Coding guidelines
| - Keep last-5 in the detail sidebar as a teaser linking to the tab. No separate run-detail route needed — the workspace *is* the run detail; a failed create expands in place. | ||
| - **Unread/review affordance:** extend the existing failure-badge watermark store to "created, not yet opened" so the automations page doubles as a review queue (Codex inbox model). Clearing = opening the workspace. |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file excerpt =="
sed -n '1,120p' apps/desktop/plans/automations-ui-improvements.md 2>/dev/null || true
echo
echo "== search watermark/store/run-detail/localStorage =="
rg -n "failure-badge|watermark|unread|review|localStorage|create, not yet opened|run-detail|detail sidebar" apps/desktop -S || true
echo
echo "== relevant files =="
git ls-files apps/desktop | rg "watermark|inbox|unread|automation|run|detail|localStorage|sqlite" | head -200Repository: superset-sh/superset
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== plan excerpt =="
sed -n '50,70p' apps/desktop/plans/automations-ui-improvements.md
echo
echo "== exact match search =="
rg -n 'failure-badge|watermark|created, not yet opened|lastViewedWorkspaceId|mark.*unread|manual unread|v2-notifications|TerminalAgentStatus' apps/desktop/src apps/desktop/plans -S || true
echo
echo "== candidate files sizes and outlines =="
for f in \
apps/desktop/src/renderer/stores/v2-notifications/store.ts \
apps/desktop/src/renderer/stores/v2-notifications/store.test.ts \
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/\$automationId/components/PreviousRunsList/PreviousRunsList.tsx \
apps/desktop/src/renderer/hooks/host-service/useTerminalAgentStatuses/useTerminalAgentStatuses.ts \
apps/desktop/src/renderer/hooks/host-service/useTerminalAgentStatuses/deriveTerminalAgentStatus.ts
do
if [ -f "$f" ]; then
echo "--- $f ---"
wc -l "$f"
sed -n '1,180p' "$f"
fi
doneRepository: superset-sh/superset
Length of output: 31714
Bound the per-run unread tracking.
If this store expands to a per-run “created, not yet opened” mark, avoid unbounded renderer-local keys. Apply a cap or TTL for per-run unread state, document deletion ownership, and ensure cleanup when the run or workspace is removed. Use entity-scoped persistent storage if unread state must scale this long-term.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/automations-ui-improvements.md` around lines 60 - 61,
Bound the per-run unread state in the existing failure-badge watermark store:
add a cap or TTL, document which component owns deletion, and remove entries
when the corresponding run or workspace is deleted. If the state must persist
and scale beyond renderer lifetime, use entity-scoped persistent storage instead
of unbounded renderer-local keys.
Source: Coding guidelines
| <TableBody> | ||
| {sortField ? ( | ||
| sortedVisible.map(renderAutomationRow) | ||
| ) : ( | ||
| <> | ||
| {upNext.length > 0 && sectionRow("Up next")} | ||
| {upNext.map(renderAutomationRow)} | ||
| {pausedVisible.length > 0 && sectionRow("Paused")} | ||
| {pausedVisible.map(renderAutomationRow)} | ||
| </> | ||
| )} | ||
| </TableBody> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Add a no-results state for search and the failed filter.
showMineEmptyState and showTeamEmptyState depend on tabVisible, not on visible. If the search text or the failed filter removes every row, the table renders with headers and no rows, and the user gets no explanation. Render a message row when visible.length === 0 and tabVisible.length > 0.
💡 Proposed fix
<TableBody>
- {sortField ? (
+ {visible.length === 0 ? (
+ <TableRow className="hover:bg-transparent">
+ <TableCell
+ colSpan={columnCount}
+ className="h-24 text-center text-sm text-muted-foreground"
+ >
+ No automations match your filters.
+ </TableCell>
+ </TableRow>
+ ) : sortField ? (
sortedVisible.map(renderAutomationRow)
) : (🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx`
around lines 688 - 699, Update the TableBody rendering around
renderAutomationRow to show a no-results message row when visible.length is 0
while tabVisible.length is greater than 0, covering search and failed-filter
results without affecting existing grouped or sorted rows.
There was a problem hiding this comment.
1 issue found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/plans/automations-ui-improvements.md">
<violation number="1" location="apps/desktop/plans/automations-ui-improvements.md:4">
P3: The screenshot reference path (`~/Desktop/competitor-screenshots/gallery.html`) is local to one workstation and won't resolve for other reviewers or CI. Consider storing these assets in the repo or linking to a shared, versioned location.</violation>
</file>
Architecture diagram
sequenceDiagram
participant U as User
participant P as AutomationsPage
participant C as Electric Sync Collections
participant F as useFailedAutomations
participant N as useNow (30s tick)
participant A as tRPC automation API
Note over P,C: Page mounts, local-first data via Electric
P->>C: Live queries (automations, automationRuns, users)
C-->>P: Synced rows (server -> local cache)
P->>F: CHANGED: compute latest run per automation
F-->>P: CHANGED: lastRunStatusById + lastRunAtById + failedIds
N->>P: now (ticks every 30s, shared clock)
Note over P: Client-side aggregates, no new server queries
P->>P: NEW: runStats = 7d rollup from automationRuns (created7d/failed7d/active)
P->>P: NEW: group rows -> Up Next (enabled, nextRunAt asc) + Paused sections
alt Failed filter active
P->>P: NEW: narrow table to failedIds
opt No failures remain
P->>P: NEW: auto-clear failedOnly filter
end
end
U->>P: Type in search box
P->>P: NEW: live name filter on visible rows
U->>P: Click sortable header
P->>P: NEW: flatten to flat sorted list (sortField set)
U->>P: Right-click row -> Pause/Resume
P->>A: NEW: automation.setEnabled({ id, enabled })
alt Success
A-->>P: updated automation
P-->>U: toast "paused"/"resumed"
else Failure
P-->>U: toast error message
end
U->>P: Click "Failed" stat card
alt canFilterFailed
P->>P: NEW: toggle failedOnly filter
else Inert (nothing failing now)
P-->>U: NEW: tooltip explains 7d vs current divergence
end
U->>P: Empty state -> "Create automation"
P->>P: NEW: centered CTA + one suggested template per category
P-->>U: open CreateAutomationDialog (template pre-selected)
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| # Automations UI Improvements | ||
|
|
||
| Anchors: **Cursor Automations** (dashboard, run history, result-as-diff) and **OpenAI Codex/ChatGPT** (create & edit automations *in chat*, NL schedule, unread runs). | ||
| Reference screenshots: `~/Desktop/competitor-screenshots/gallery.html` (filenames cited per component). The `cursor2-*` set (60 files) documents every Cursor surface: dashboard, editor, run history, run detail, creation flows, marketplace. |
There was a problem hiding this comment.
P3: The screenshot reference path (~/Desktop/competitor-screenshots/gallery.html) is local to one workstation and won't resolve for other reviewers or CI. Consider storing these assets in the repo or linking to a shared, versioned location.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/plans/automations-ui-improvements.md, line 4:
<comment>The screenshot reference path (`~/Desktop/competitor-screenshots/gallery.html`) is local to one workstation and won't resolve for other reviewers or CI. Consider storing these assets in the repo or linking to a shared, versioned location.</comment>
<file context>
@@ -0,0 +1,96 @@
+# Automations UI Improvements
+
+Anchors: **Cursor Automations** (dashboard, run history, result-as-diff) and **OpenAI Codex/ChatGPT** (create & edit automations *in chat*, NL schedule, unread runs).
+Reference screenshots: `~/Desktop/competitor-screenshots/gallery.html` (filenames cited per component). The `cursor2-*` set (60 files) documents every Cursor surface: dashboard, editor, run history, run detail, creation flows, marketplace.
+
+**Model (settled):** a run does not "end" — it **creates a workspace** with an agent session in it. `dispatched` = workspace created = the run succeeded. There is no completion-tracking pipeline; what happens after creation is the workspace's story, told live (agent status derived from host bindings, diff visible in the workspace). The UI's job is (a) making create-success/failure legible and (b) making the created workspaces easy to review.
</file context>
… links, sticky header - "Needs attention" section pins failing automations above "Up next" in the grouped view - Last-run cell links to the run's workspace with the session deep-linked (same navigation as PreviousRunsList; writer registered) - Run now available on hover for every owned row, replacing the failed-rows-only retry icon - Sticky table header restored relative to the new page scroll container (card no longer clips overflow) - "No automations match" row when search/filter empties the list - useFailedAutomations exposes the full last run (workspace/session ids) instead of separate status/timestamp maps
|
Pushed a second commit with the follow-up polish items:
Deliberately skipped: column resizing — |
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx:637">
P2: The table header will not remain sticky during vertical page scrolling because `Table` still wraps it in `overflow-x-auto`; use a non-overflowing table container here (or move the vertical scroll onto that wrapper) so the sticky ancestor is the scrolling element.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| // sticks relative to the page scroll container. | ||
| <div className="rounded-xl border border-border"> | ||
| <Table className="table-fixed"> | ||
| <TableHeader className="sticky top-0 z-10 rounded-t-xl bg-background shadow-[inset_0_-1px_0_0_var(--color-border)] [&_tr]:border-b-0"> |
There was a problem hiding this comment.
P2: The table header will not remain sticky during vertical page scrolling because Table still wraps it in overflow-x-auto; use a non-overflowing table container here (or move the vertical scroll onto that wrapper) so the sticky ancestor is the scrolling element.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx, line 637:
<comment>The table header will not remain sticky during vertical page scrolling because `Table` still wraps it in `overflow-x-auto`; use a non-overflowing table container here (or move the vertical scroll onto that wrapper) so the sticky ancestor is the scrolling element.</comment>
<file context>
@@ -625,9 +630,11 @@ function AutomationsPage() {
+ <div className="rounded-xl border border-border">
<Table className="table-fixed">
- <TableHeader className="bg-accent/20 [&_tr]:border-border/50">
+ <TableHeader className="sticky top-0 z-10 rounded-t-xl bg-background shadow-[inset_0_-1px_0_0_var(--color-border)] [&_tr]:border-b-0">
<TableRow className="hover:bg-transparent">
<TableHead className={cn(DATA_TABLE_HEAD_CELL, "pl-4")}>
</file context>
…plan - actions column w-12 -> w-20 so the hover Run-now + menu buttons no longer overflow onto the last-run text - plans/automations-onboarding.md: first-visit / returning / launch flows with concrete suggestion-card copy and personalization signals
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/plans/automations-ui-improvements.md (1)
105-105: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winResolve the unread-state decision before implementation.
Line 71 mandates a per-run “created, not yet opened” watermark, but this line keeps per-run versus failure-only tracking open. Choose one model before implementation, then define its retention and cleanup behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/plans/automations-ui-improvements.md` at line 105, Resolve the unread/review model in the “Unread/review model” decision point before implementation: choose either the per-run “created, not yet opened” watermark required by line 71 or the failure-only badge, then document its retention and cleanup behavior, including when the unread state is cleared.
🧹 Nitpick comments (2)
apps/desktop/plans/automations-onboarding.md (2)
35-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep template discovery in one creation surface.
The principles say templates and NL creation are one surface, but this flow adds
Browse all templatesand opens a separate dialog gallery. Make the button expand the inline template surface, or mark the gallery as interim-only and define the Phase 2 replacement.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/plans/automations-onboarding.md` around lines 35 - 39, Update the automation onboarding flow so template discovery remains within the same creation surface as NL input: make “Browse all templates” expand the inline template area, or explicitly label the existing CreateAutomationDialog gallery as interim-only and document its Phase 2 replacement. Keep template card selection as prompt and rrule prefill without instant creation.
64-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDefine the checklist key lifecycle.
If dismissal uses renderer
localStorage, document the singleton bound, deletion owner or path, and behavior when the feature is removed. Registering the key alone is not sufficient under the renderer persistence rules. Add the key toapps/desktop/src/renderer/lib/persisted-keys/persisted-key-registry.test-data.tswhen implementation begins.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/plans/automations-onboarding.md` at line 64, Expand the checklist persistence plan to define the localStorage key’s singleton scope, its deletion owner or cleanup path, and the expected behavior when the feature is removed. When implementation starts, register the key in persisted-key-registry.test-data.ts alongside the persisted-key registry entry.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/plans/automations-onboarding.md`:
- Line 16: Update the ASCII diagram fence in automations-onboarding.md to
specify the text language, using ```text instead of an untyped fence. Then run
bun run lint:fix and verify that bun run lint succeeds.
In `@apps/desktop/plans/automations-ui-improvements.md`:
- Line 53: Align the workspace education with dispatch behavior by updating the
run-model statement in apps/desktop/plans/automations-ui-improvements.md:53-53
and the corresponding onboarding principle in
apps/desktop/plans/automations-onboarding.md:8-8 to describe reuse of
automation.v2WorkspaceId rather than promising a new isolated workspace per run;
do not require fresh workspace creation unless dispatch is changed accordingly.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsx`:
- Around line 242-270: Update the lastRunClickable branch in AutomationRow so
failed runs with v2WorkspaceId retain their failure information: include
lastRunMeta.failed and its message in the existing workspace tooltip content
while preserving the workspace-opening behavior. Ensure the failure tooltip is
not bypassed when both conditions apply.
---
Outside diff comments:
In `@apps/desktop/plans/automations-ui-improvements.md`:
- Line 105: Resolve the unread/review model in the “Unread/review model”
decision point before implementation: choose either the per-run “created, not
yet opened” watermark required by line 71 or the failure-only badge, then
document its retention and cleanup behavior, including when the unread state is
cleared.
---
Nitpick comments:
In `@apps/desktop/plans/automations-onboarding.md`:
- Around line 35-39: Update the automation onboarding flow so template discovery
remains within the same creation surface as NL input: make “Browse all
templates” expand the inline template area, or explicitly label the existing
CreateAutomationDialog gallery as interim-only and document its Phase 2
replacement. Keep template card selection as prompt and rrule prefill without
instant creation.
- Line 64: Expand the checklist persistence plan to define the localStorage
key’s singleton scope, its deletion owner or cleanup path, and the expected
behavior when the feature is removed. When implementation starts, register the
key in persisted-key-registry.test-data.ts alongside the persisted-key registry
entry.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: df709134-58e7-40cf-9d32-6acd73de62f0
📒 Files selected for processing (7)
apps/desktop/plans/automations-onboarding.mdapps/desktop/plans/automations-ui-improvements.mdapps/desktop/src/renderer/lib/persisted-keys/persisted-key-registry.test-data.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AutomationRow/AutomationRow.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/hooks/useFailedAutomations/index.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/hooks/useFailedAutomations/useFailedAutomations.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Grafts #6274's project-less "session" automations onto the redesigned rows: null project renders a muted "Session" tag next to the name.
- aria-label on the search input - failed stat-card tooltip describes the actual toggle action - failed-run workspace link tooltip keeps the failure context - plan docs: correct the run/workspace claim (dispatch reuses pinned workspaces), add Phase 2.5 to the ordering table, fence language
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
* docs: weekly update for PRs merged 2026-08-05 to 2026-08-12 - workspaces: sessions (project-less workspaces, #6274), pin + drag-and-drop pinning (#6364), list/board views with Merged & Deleted history columns (#6296), per-project naming instructions (#6250), multi-PR links per branch with remove/restore (#5924) - automations: session automations (#6280), list health stats + Up next grouping + read-only team automations (#6291, #6276), detail page Settings/Run History tabs, inline run errors, would-run preview, RRule validation (#6305) - editor: image pane pan/pinch/zoom (#6285) - tasks: multi-repo filters, expanded task states, PR author/review filters, PR checks (#6201) - monorepos: per-project sparse checkout (#6034) - customization: project icon + color picker, v1 color carry-over (#6249) - terminal presets: built-in Superset CLI preset (#6270) - agents: resume interrupted sessions + Resume Args setting (#6253, #6265), Superset hooks toggle + scoping (#6072) - cli: interactive command browser + branded help (#6273); reference updated for session mode, --task, --skip-branch-prefix, --session (verified against packages/cli/src/commands) * docs: tighten wording and drop em dashes Shorten this week's additions per the writing guide: one thought per sentence, plainest word, no em dashes as prose punctuation. Also sweeps the three pre-existing em dashes in recipes. * docs: add screenshots from the 08-09 changelog batch cli command browser, agent resume banner, PR view with checks, and the project icon/color picker. Copied into apps/docs/public/images per the SOP rather than referenced across apps.
Links
apps/desktop/plans/automations-ui-improvements.md(this PR ships Phase 1 + the layout redesign; Phases 2-4 deferred)Summary
Why / Context
The list previously answered neither "is this working?" nor "what happens next": last run rendered as a bare
ran/failedword with no timestamp,nextRunAtwas synced on every row but never shown, pause required opening each automation, and 9 columns of mostly-uniform data buried the signal. Competitor research (Cursor, Codex, ChatGPT Tasks, Devin, n8n, Windmill, Kestra, Dagster, Val Town...) converged on: few columns, health stats up top, soonest-run-first ordering, and calm failure surfacing.How It Works
max-w-5xlcolumn (page title → stat cards → Mine/Team tabs + retry-all + search → table in a rounded card → dismissible CLI hint footnote). Window chrome is a bare drag-leaf strip, per the drag-region rule.automation_runscollection, scoped to the active tab; no new queries to the server.nextRunAtasc) and "Paused" sections; clicking any sortable header switches to a flat sorted list.Active · in 2h/Paused(countdown via a shared 30s ticking clock passed down from the page — no per-row timers); the absolute next-run time in the automation's timezone is on hover.useFailedAutomationsnow also exposeslastRunAtById(it already computed the timestamps internally).Manual QA Checklist
Verified end-to-end over CDP against the running dev app with real org data (screenshots captured at each step):
isReady(readiness only gates loading/empty states)automation.setEnabledthe detail page already usesTesting
bun run typecheckbun run lintDesign Decisions
dispatchedis the terminal success state, so the UI now says so instead of implying a finished job.Known Limitations
Follow-ups (in the plan doc)
automations_*MCP tools (NL box → drafting chat → confirmation card)Summary by cubic
Redesigned the Automations dashboard with stat cards, a grouped list (Needs attention → Up next → Paused), and a cleaner top bar. The table is slimmer, searchable, and adds run‑now, pause/resume, last‑run links, and a sticky header.
New Features
Refactors
useFailedAutomationsnow exposeslastRunById(status, timestamp, and workspace/session ids); stats computed client‑side from synced runs (no new server queries).Written for commit e9d7141. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation
Usability