Skip to content

feat(automation): create card model picker, split entry, and chat echo#1143

Merged
Astro-Han merged 14 commits into
devfrom
claude/automation-pr7-create
Jun 4, 2026
Merged

feat(automation): create card model picker, split entry, and chat echo#1143
Astro-Han merged 14 commits into
devfrom
claude/automation-pr7-create

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the issue #950 PR7 create surface (manual create card landed earlier in this branch):

  • Model picker. The create card now drives the real composer model/variant picker instead of a read-only chip. Since the Automations panel renders outside the per-directory LocalProvider, a panel-local controller (automation-model-state) backs the picker from useModels() plus dialog-local model/variant signals. model-picker.tsx now types its model prop against a narrow ModelPickerState interface that the full useLocal().model satisfies as a superset, so composer call sites are untouched. The card self-seeds with the composer's priority (last-used → project default → first connected), matching the "default current/last model" spec.
  • Split create entry. "New automation" opens a menu with Create via chat / Create manually. Create via chat leaves the panel and opens a fresh session in the current project prefilled with a short guiding prompt, via the reactive ?prompt= bootstrap (works whether or not we are already on the new-session route).
  • Chat echo card. When the agent runs the automate tool in chat, a lightweight card echoes the resolved definition (read from tool metadata, never parsed from prose) with a jump into the Automations panel focused on that automation. Navigation flows through the UI data context (onNavigateToAutomation) and a module-level bridge (automations-navigation) so the card stays app-agnostic; the panel reads the requested selection once on mount.
  • Chinese copy. Renamed 自动化 → 定时任务 across the app/ui zh dictionaries; it reads more naturally. English copy keeps "Automation(s)".

Why

PR7 is the create slice of #950. The remaining gaps were a usable model control (the read-only chip couldn't pick a model), the conversational entry (the product's core surface), and the create echo so a chat-created automation is discoverable.

Related Issue

#950

Human Review Status

Pending

Review Focus

  • model-picker.tsx: the ModelStateModelPickerState prop retype. The full useLocal().model is a structural superset, so composer behavior is unchanged — worth a second look.
  • The cross-package seam: ui data context gained an optional onNavigateToAutomation; the automate tool renderer is new. Both are additive.
  • Deep-link selection lifecycle: requestedAutomationID is set before the panel opens and consumed once on the surface's mount (panel is lazily mounted), cleared on manual opens.

Risk Notes

Renderer-only changes (SolidJS router navigation, dialog, message-part rendering). No platform.* / window.api / preload / IPC / updater / deep-link / packaging surface is touched, so dev:desktop was not required; snap (web Chromium) plus Playwright E2E cover the changed surface. The ui data context change is an added optional prop (backward compatible).

How To Verify

bun turbo typecheck                     -> 8/8 packages pass
eslint (all changed app+ui files)       -> 0 problems
bun playwright test e2e/automations/automations-panel.spec.ts
  -> 6 passed: list/detail/pause/delete; create manually -> detail + list;
     template prefills card; create via chat -> panel closes + composer prefilled;
     automate tool card -> jumps into panel detail; escape unwinds
bun run snap automations-surface        -> passed; reviewed grid:
     empty, list, list-hover, detail, create-menu, create-card, schedule

Screenshots or Recordings

Visual check via the automations-surface snap target (grid under docs/design/preview/screenshots/automations-surface.png): the split New-automation menu, the filled create card with the model chip, and the schedule popover all render as expected.

Checklist

  • Type label — this PR carries exactly one of bug, enhancement, task, documentation.
  • Routing labels — this PR carries at least one of app, ui, platform, harness, ci.
  • Priority label — this PR carries exactly one of P0, P1, P2, P3.
  • Human Review Status above is set to Pending, Approved by @<reviewer>, or Not required: <reason>.
  • I linked the related issue, or stated in Summary why there is no issue.
  • I described the review focus and any meaningful risks.
  • I replaced the example block in How To Verify with the real verification steps and the key result for each.
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope.
  • (conditional) I manually checked visible UI or copy changes when needed, with screenshots or recordings.
  • (conditional) I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes. Leave unticked only if no platform/packaging surface was touched.
  • (conditional) I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant.
  • I reviewed the final diff for unrelated changes and suspicious dependency changes.
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English.

Summary by CodeRabbit

  • New Features

    • Manual/chat automation creation dialog with templates, scheduling (once/daily/weekdays/weekly), folder/project picker, model selection, and deep-link/open-to-item support; “automate” tool card navigates to automations.
  • Tests

    • Expanded end-to-end and snapshot coverage for creation flows, schedule picker, model picker focus/escape behavior, and panel navigation.
  • Refactor

    • Simplified popover/dialog/model-picker open/close and focus handling; local model state and schedule utilities reorganized.
  • Internationalization

    • Added/updated English and Chinese strings for automations UI.

Astro-Han added 4 commits June 3, 2026 20:45
Manual side of issue #950 PR7. Adds the create-via-form path; the
create-via-chat toggle and the NL echo card land in follow-up commits.

- store: globalSync.automation.create wraps sdk.automation.create with a
  revision-gated apply (mirrors pause/runNow).
- schedule: draft -> AutomationCreateInput builder (cron shapes the read
  side already humanizes; "once" -> one-shot fireAt via luxon in the
  definition timezone) plus a two-level Schedule popover (frequency inline
  list, time, weekday, raw cron).
- create card: useDialog modal (title + prompt + Project | Schedule |
  Model bar). Model reuses the composer ModelSelectorPopover on an
  independent state so picking here never rewrites the composer selection.
- templates: Daily brief / Weekly review / Project monitor prefill the
  card (empty-state buttons + in-card Use template); no separate gallery.
- surface: New automation entry + empty-state template buttons; opens the
  card and selects the created automation. layout passes projectID.
- i18n: zh + en create/template keys.

Pinned per handoff: context=fresh, recurring stop=never, no worktree.
Verified: bun run typecheck (packages/app) clean; eslint clean on changed
files. Visual snap + E2E land with the remaining PR7 slices.
… via snap

The Automations panel renders outside the per-directory LocalProvider, so
the create card crashed on useLocal (the composer model picker can't be
reused there). Resolve the model from the project default via useProviders
in the surface and pass it in read-only; a panel-local model/variant picker
is a follow-up.

- create card: drop useLocal / ModelSelectorPopover; the model is a
  read-only chip seeded from the surface default. Fix bottom-bar overflow so
  Cancel/Create stay visible with a long project name (chips shrink, buttons
  pinned shrink-0).
- surface: resolve the default model via useProviders().default().
- snap: extend automations-surface to open + fill the create card and expand
  the schedule popover (visual + user-path coverage).

Verified: typecheck + eslint clean; bun run snap automations-surface passes
(6-shot grid reviewed: empty / list / list-hover / detail / create-card /
schedule).
Round out the issue #950 PR7 create surface.

Model picker: the create card now drives the real composer model/variant
picker instead of a read-only chip. The Automations panel renders outside
the per-directory LocalProvider, so a panel-local controller
(automation-model-state) backs the picker from useModels() plus dialog-local
model/variant signals. model-picker.tsx now types its `model` prop against a
narrow ModelPickerState interface that the full useLocal().model satisfies as
a superset, so composer call sites are unaffected. The card self-seeds with
the same priority as the composer (last-used, then project default, then first
connected), matching the "default current/last model" spec.

Split entry: "New automation" opens a menu with Create via chat / Create
manually. Create via chat leaves the panel and opens a fresh session in the
current project, prefilled with a short guiding prompt via the reactive
?prompt= bootstrap (works whether or not we are already on the new-session
route).

Echo card: when the agent runs the automate tool in chat, a lightweight card
echoes the resolved definition (read from tool metadata, never parsed from
prose) with a jump into the Automations panel focused on that automation.
Navigation flows through the UI data context (onNavigateToAutomation) and a
module-level bridge (automations-navigation) so the card stays app-agnostic;
the panel reads the requested selection once on mount.

Chinese copy: rename 自动化 to 定时任务 across app/ui zh dictionaries; it reads
more naturally. English copy keeps "Automation(s)".
Functional E2E (automations-panel.spec.ts): create manually adds an
automation and lands on its detail + list; an empty-state template prefills
the create card; create via chat closes the panel and opens a session whose
composer carries the guiding prompt; the automate tool card jumps into the
panel focused on the new automation.

Snap (automations-surface.snap.ts): follow the split entry through the New
automation menu before Create manually, and add the menu to the grid.
@Astro-Han Astro-Han added enhancement New feature or request app Application behavior and product flows ui Design system and user interface P2 Medium priority labels Jun 3, 2026
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements a full automation creation experience: schedule domain and picker, templates, model/variant picker refactor, a multi-field create dialog that calls a new global-sync create API, Automations surface/template integration, navigation wiring for deep-links and tool-card jumps, UI refinements, i18n, and extensive e2e/snapshot tests.

Changes

Automation Creation and Panel Integration

Layer / File(s) Summary
Schedule domain model and utilities
packages/app/src/pages/automations/automation-schedule-form.ts
Defines ScheduleFrequency/ScheduleDraft, time labeling, cronForSchedule, timezone-aware nextDailyFireAt, and buildScheduleInput returning oneshot or cron rhythms.
Schedule picker UI
packages/app/src/pages/automations/automation-schedule-controls.tsx, packages/app/e2e/snap/automations-surface.snap.ts
Adds AutomationScheduleControls with frequency buttons, weekday popover, and a two-column time picker; snapshot test expanded to capture create-menu, create-card, and schedule.
Templates and i18n
packages/app/src/pages/automations/automation-templates.ts, packages/app/src/i18n/*, packages/ui/src/i18n/*
Adds AutomationTemplate and AUTOMATION_TEMPLATES; extends English and Chinese dictionaries with creation/scheduling/template strings and UI tool messages.
Model picker types and popover behavior
packages/app/src/components/prompt-input/model-picker.tsx, packages/app/e2e/prompt/prompt-footer-focus.spec.ts
Introduces PickerModel/ModelPickerState, narrows component prop types, adds modal plumbing for nested popovers, and simplifies popover open/close semantics with closeCause and centralized selectAndClose.
Model state helper and folder picker
packages/app/src/pages/automations/automation-model-state.ts, packages/app/src/pages/automations/automation-folder-picker.tsx
Adds createAutomationModelState to manage dialog-local variant and model visibility and AutomationFolderPicker to select project/worktree.
Automation create dialog component
packages/app/src/pages/automations/automation-create-dialog.tsx
Implements AutomationCreateDialog with title, prompt, schedule, model/variant, folder/project selection, template application, and submit flow that builds AutomationCreateInput and calls globalSync.automation.create.
Global sync automation API
packages/app/src/context/global-sync.tsx
Extends useGlobalSync() to expose automation.create(directory, input) that pins directory, calls SDK create, applies definition to the store, and unpins.
Automations surface and openCreate
packages/app/src/pages/automations/automations-surface.tsx
Refactors AutomationsSurface to accept projectID and requestedID, refactors empty state to render template buttons, and adds openCreate helper and create dropdown (chat vs manual).
Navigation utilities and shell wiring
packages/app/src/utils/automations-navigation.ts, packages/app/src/pages/layout.tsx, packages/app/src/pages/directory-layout.tsx
Adds setOpenAutomations/openAutomation bridge, wires layout with requestedAutomationID and openAutomationByID, and exposes onNavigateToAutomation via DataProvider.
Automate tool card and data context
packages/ui/src/context/data.tsx, packages/ui/src/components/message-part/tools/automate.tsx, packages/ui/src/components/message-part/tools/index.ts
Adds NavigateToAutomationFn to Data context; implements/registers automate tool card that navigates to the automation detail when clicked.
UI refinements
packages/ui/src/components/popover.tsx, packages/ui/src/components/icon.css, packages/ui/src/components/select.css, packages/ui/src/context/dialog.tsx
Refactors Popover open-state handling to createSignal, removes dialog global Escape listener, and standardizes chevron/select icon sizing to 12×12px.
End-to-end tests and snapshots
packages/app/e2e/automations/automations-panel.spec.ts, packages/app/e2e/prompt/prompt-footer-focus.spec.ts, packages/app/e2e/snap/automations-surface.snap.ts
Adds comprehensive Playwright tests for manual/template/chat creation flows, schedule and model picker behaviors (including Escape unwinding and thinking-variant submenu), and snapshot captures for create UI states.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

harness

Poem

🐰 A rabbit nudges buttons bright,

templates bloom in morning light,
Schedules tick and models think,
Tools hop back with one swift link,
Hooray — automations take flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the three main changes: model picker, split entry, and chat echo for the Automations create surface.
Description check ✅ Passed The PR description comprehensively covers all template sections: Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify, Screenshots, and a fully completed Checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/automation-pr7-create

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested priority: P2 (includes user-path files (packages/app/src/components/prompt-input/model-picker.tsx, packages/app/src/context/global-sync.tsx, packages/app/src/i18n/en.ts, packages/app/src/i18n/zh.ts, packages/app/src/pages/automations/automation-create-dialog.tsx, packages/app/src/pages/automations/automation-model-state.ts, packages/app/src/pages/automations/automation-schedule-form.ts, packages/app/src/pages/automations/automation-schedule-picker.tsx, packages/app/src/pages/automations/automation-templates.ts, packages/app/src/pages/automations/automations-surface.tsx, packages/app/src/pages/directory-layout.tsx, packages/app/src/pages/layout.tsx, packages/app/src/utils/automations-navigation.ts)).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a manual creation flow for automations, featuring a new creation dialog, schedule picker, and starter templates, alongside integration with chat-based automation tools. Key feedback from the review highlights several critical improvements: ensuring reactive updates for deep-linked automations by replacing onMount with createEffect, defensively handling potentially missing metadata in the automate tool card to prevent runtime crashes, adding timezone validation fallbacks to avoid serialization errors, and validating custom cron inputs before allowing submission.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/app/src/pages/automations/automations-surface.tsx Outdated
Comment thread packages/ui/src/components/message-part/tools/automate.tsx
Comment thread packages/app/src/pages/automations/automations-surface.tsx Outdated
Comment thread packages/app/src/pages/automations/automation-schedule-form.ts
Comment thread packages/app/src/pages/automations/automation-create-dialog.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/app/src/pages/automations/automations-surface.tsx (1)

117-129: ⚡ Quick win

Consider adding a directory guard in openCreate.

The function gates on projectID but reads directory without validation. If props.directory() returns an empty string (unlikely but possible during edge-case routing transitions), the dialog will be opened with invalid data.

🛡️ Add directory guard
 const openCreate = (template?: AutomationTemplate) => {
   const projectID = props.projectID()
-  if (!projectID) return
   const directory = props.directory()
+  if (!projectID || !directory) return
   dialog.show(() => (
🤖 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 `@packages/app/src/pages/automations/automations-surface.tsx` around lines 117
- 129, openCreate currently guards only projectID but still reads
props.directory(); add a guard to validate directory (e.g., const directory =
props.directory(); if (!directory) return) before calling dialog.show so
AutomationCreateDialog never opens with an empty/invalid directory. Update the
openCreate function to check both projectID and directory (use a trimmed truthy
check if needed) and then pass the validated directory into
AutomationCreateDialog while keeping the existing onCreated behavior
(setSelectedID).
🤖 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 `@packages/app/src/pages/automations/automation-schedule-picker.tsx`:
- Around line 39-42: The setTime handler currently accepts any integers from the
"HH:MM" string and can produce out-of-range hours/minutes; update setTime to
validate and clamp values before calling props.onChange: parse hour/minute as
integers (still guard with Number.isInteger), then clamp hour to 0–23 and minute
to 0–59 (or bail if parsing fails), build the sanitized schedule object from
props.value with the clamped hour/minute, and pass that to props.onChange so
downstream cron/oneshot generation always receives valid time fields.

---

Nitpick comments:
In `@packages/app/src/pages/automations/automations-surface.tsx`:
- Around line 117-129: openCreate currently guards only projectID but still
reads props.directory(); add a guard to validate directory (e.g., const
directory = props.directory(); if (!directory) return) before calling
dialog.show so AutomationCreateDialog never opens with an empty/invalid
directory. Update the openCreate function to check both projectID and directory
(use a trimmed truthy check if needed) and then pass the validated directory
into AutomationCreateDialog while keeping the existing onCreated behavior
(setSelectedID).
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0f2802d9-f05c-4b4b-9406-85f25e602c1c

📥 Commits

Reviewing files that changed from the base of the PR and between 7a4473c and 0fb127c.

📒 Files selected for processing (20)
  • packages/app/e2e/automations/automations-panel.spec.ts
  • packages/app/e2e/snap/automations-surface.snap.ts
  • packages/app/src/components/prompt-input/model-picker.tsx
  • packages/app/src/context/global-sync.tsx
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/pages/automations/automation-create-dialog.tsx
  • packages/app/src/pages/automations/automation-model-state.ts
  • packages/app/src/pages/automations/automation-schedule-form.ts
  • packages/app/src/pages/automations/automation-schedule-picker.tsx
  • packages/app/src/pages/automations/automation-templates.ts
  • packages/app/src/pages/automations/automations-surface.tsx
  • packages/app/src/pages/directory-layout.tsx
  • packages/app/src/pages/layout.tsx
  • packages/app/src/utils/automations-navigation.ts
  • packages/ui/src/components/message-part/tools/automate.tsx
  • packages/ui/src/components/message-part/tools/index.ts
  • packages/ui/src/context/data.tsx
  • packages/ui/src/i18n/en.ts
  • packages/ui/src/i18n/zh.ts

Comment thread packages/app/src/pages/automations/automation-schedule-picker.tsx Outdated
Astro-Han added 10 commits June 3, 2026 22:54
Address design review on the PR7 create surface:
- Drop the unclickable Project knob; the surface already pins the
  automation to its current directory.
- Let the Model knob shrink and truncate long model names instead of
  overflowing the bar.
- Rebuild the Schedule popover on the design-system Select (frequency,
  hour/minute, weekday) instead of hand-rolled and native controls, so
  it stops drifting from the shared picker contract.
- Reduce the schedule to four frequencies (daily / weekdays / weekly /
  once); drop hourly and the opaque custom-cron option. Weekdays is now
  its own frequency, so no weekday multi-select is needed.
- Unify chevrons at size-3 and use plus-small for the New automation CTA.
- Remove the now-orphaned hourly/custom frequency i18n keys.
The shared UI Popover and Dialog context hand-rolled window-capture
focusin/pointerdown/keydown dismiss listeners that were not layer-aware.
A popover opened inside a modal dialog therefore fought the dialog's
focus trap instead of pausing it, and Escape was handled non-layer-aware.

Drop the hand-rolled machinery and rely on Kobalte's native
DismissableLayer: layer-aware Escape (top-most layer closes first) and
outside dismiss. This is the prerequisite for making the create-card
pickers modal — with the old window listeners, modal alone still flashed.
The dropdown chevron-down was 14px, competing with 13px body text. Drop
it to 12px in icon.css (box + svg) and select.css so the affordance sits
quietly below the text. Remove the now-dead size-3 utility on the
Automations CTA chevron — the global rule wins on specificity anyway.
The model picker hand-rolled its focus-outside dismiss with window
listeners and an isPickerContentTarget guard. Inside a modal dialog (the
Automations create card) the parent dialog's focus trap steals focus on
open, the non-layer-aware dismiss treated that as a focus-outside and
flashed the picker shut, then wedged it closed because focus stayed
trapped on the dialog title.

Delegate the dismiss to Kobalte's native DismissableLayer, which already
recognises the parent dialog as an ancestor layer and the nested
Thinking popover as a child layer. Keep only a tiny closeCause flag so
the composer can still restore focus to the prompt on escape/select; an
outside dismiss leaves focus where it went. Add a modal opt-in (default
false preserves the composer's close-on-focus-leave behaviour) so the
create card can run the picker modal and trap focus back into itself.

Covered by a new prompt-footer e2e: Escape closes the picker and returns
focus to the prompt.
…er, modal pickers

Last PR of the Automations series (#950). Replace the standalone
AutomationSchedulePicker with an inline schedule row
(AutomationScheduleControls: frequency segmented switch + weekday/time
popovers) and add an AutomationFolderPicker so the automation can be
filed against any open project instead of only the active one.

All four create-card pickers (time, weekday, folder, model) run modal
inside the dialog so the parent dialog's focus trap can't flash them
shut, and every trigger shares the same cursor-pointer knob styling.
Narrow the dialog to 600px to match the denser layout.

E2E: schedule picker opens/selects/layers-escape under the dialog focus
trap, and the model picker survives the focus trap and reopens.
The pickers used cursor-pointer, which gives the web hand cursor on
hover. PawWork follows the native macOS convention — Button, popover
content, and reset <a> all use cursor: default — so the pickers stuck
out. Match them: explicit cursor-default keeps the arrow over the
div-based triggers (and avoids the text I-beam over their labels).
Threading modal onto the create card's ModelSelectorPopover (the earlier
flash fix) pushed the same focus-trap flash down to the nested thinking
submenu: the outer popover is now modal, so its focus scope keeps an
active trap; when the non-modal thinking popover opened and autofocused
its portalled content, the outer trap immediately pulled focus back and
the non-modal inner DismissableLayer dismissed itself — the submenu
flashed open then shut and looked stuck closed.

Fix at the lowest correct seam: thread modal down to ThinkingLevelSection
so the inner popover's modality matches the outer. Modal outer (create
card) -> modal inner traps focus into itself and stays open; non-modal
outer (composer) -> inner stays non-modal, unchanged.

Verified: e2e time-samples the submenu option count ([4,0,0..] before,
[4,4,4..] after) so a single auto-retrying toBeVisible can't pass on the
flash frame; red before the fix, green after. Composer thinking suite
unaffected.
The create card files an automation against any open project via the
folder picker, but its model list, default and validation came from
useModels/useProviders, which are scoped to the *routed* project
(params.dir) — not the selected folder. Switching the folder to project B
while routed on A left the picker showing A's models and seeding A's
default, so submitting filed B's automation with a model B may not have
connected: a failed create or an unintended model.

Extract createModelsView(providers, visibility) from the models context
and add useScopedModels(dir), which builds the view from a directory's
providers while sharing the global per-user prefs (visibility, recent,
variant). useProviders now takes an optional directory override. The
create card scopes both to its selected folder and re-seeds/validates the
model when the folder changes, so it can only ever submit a model the
target project can run.

Unit test (createModelsView): the view reflects only the providers it is
given — swapping scope swaps models/find — and honours the shared
visibility map.
Two review concerns (#1143) verified as already-correct, locked with
regression guards rather than speculative code:

- A second automate tool-card jump must focus its own automation. The
  surface is <Show>-gated and remounts on each open, so onMount already
  re-reads the requested id; the test drives the real two-card flow.
- A model picker outside dismiss must leave focus where the pointer went
  (e.g. the composer prompt), not snap back to the trigger. Kobalte's
  native DismissableLayer already keeps focus off the trigger on outside
  interaction; the test guards that the dismiss refactor didn't regress it.
The surface read the pending deep-link automation id once on mount, which
only worked because the lazy <Show> remounts the panel on every open. That
made a reactive signal (requestedAutomationID) load-bearing on an implicit
remount, an easy thing to break later. Track it with createEffect so the
selection applies whether the panel was freshly mounted or already open.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/app/src/pages/automations/automations-surface.tsx (1)

118-122: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard create dialog opening when directory context is missing.

openCreate checks projectID but not directory. If directory is empty, Line 122 still opens AutomationCreateDialog, and the submit path later calls create with invalid context.

Proposed fix
 const openCreate = (template?: AutomationTemplate) => {
   const projectID = props.projectID()
-  if (!projectID) return
   const directory = props.directory()
+  if (!projectID || !directory) return
   dialog.show(() => (
     <AutomationCreateDialog
       directory={directory}
       projectID={projectID}
       template={template}
       onCreated={(definition) => setSelectedID(definition.id)}
     />
   ))
 }
🤖 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 `@packages/app/src/pages/automations/automations-surface.tsx` around lines 118
- 122, openCreate currently guards only projectID but not directory, so
AutomationCreateDialog can open with an empty directory leading to invalid
create calls; update openCreate to fetch directory via props.directory(), return
early (do not call dialog.show) when directory is falsy, and ensure any passed
template handling still respects this guard so the submit path (which calls
create using the directory) never runs without a valid directory; reference the
openCreate function and AutomationCreateDialog to locate where to add the guard.
🤖 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.

Outside diff comments:
In `@packages/app/src/pages/automations/automations-surface.tsx`:
- Around line 118-122: openCreate currently guards only projectID but not
directory, so AutomationCreateDialog can open with an empty directory leading to
invalid create calls; update openCreate to fetch directory via
props.directory(), return early (do not call dialog.show) when directory is
falsy, and ensure any passed template handling still respects this guard so the
submit path (which calls create using the directory) never runs without a valid
directory; reference the openCreate function and AutomationCreateDialog to
locate where to add the guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bc709b3b-3339-41d5-9135-1a166e24a7d3

📥 Commits

Reviewing files that changed from the base of the PR and between 4b2c8f0 and 659e19d.

📒 Files selected for processing (7)
  • packages/app/e2e/automations/automations-panel.spec.ts
  • packages/app/e2e/prompt/prompt-footer-focus.spec.ts
  • packages/app/src/context/models.test.ts
  • packages/app/src/context/models.tsx
  • packages/app/src/hooks/use-providers.ts
  • packages/app/src/pages/automations/automation-create-dialog.tsx
  • packages/app/src/pages/automations/automations-surface.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/app/e2e/automations/automations-panel.spec.ts
  • packages/app/src/pages/automations/automation-create-dialog.tsx

@Astro-Han Astro-Han merged commit 43b8582 into dev Jun 4, 2026
36 checks passed
@Astro-Han Astro-Han deleted the claude/automation-pr7-create branch June 4, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows enhancement New feature or request P2 Medium priority ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant