feat(desktop): apply default terminal preset when creating workspaces#948
Conversation
When creating a new workspace, the default terminal preset is now applied alongside any project setup scripts. This handles four cases: - Both setup script and default preset: creates separate terminal tabs - Only setup script: creates terminal with setup commands - Only default preset: creates terminal from preset (with parallel support) - Neither: shows config toast as before
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughThe PR threads default terminal preset data from local settings through workspace creation: backend exposes a defaultPreset in setup commands; creation hooks store it in pending setup; init effects create terminals (single- or multi-pane) and run initial commands according to setup script and preset combinations. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Frontend as CreateWorkspace Hook
participant Backend as trpc.getSetupCommands
participant Store as WorkspaceInitStore
participant Effects as WorkspaceInitEffects
participant Terminal as Tab/Terminal Manager
User->>Frontend: request create workspace
Frontend->>Backend: fetch setup commands (+ defaultPreset)
Backend-->>Frontend: projectId, initialCommands, defaultPreset
Frontend->>Store: addPendingTerminalSetup(projectId, initialCommands, defaultPreset)
Frontend->>Store: updateProgress(ready)
Effects->>Store: detect ready pending setup
Effects->>Effects: decide flow (setup+preset / setup only / preset only / neither)
alt setup script + preset
Effects->>Terminal: create setup terminal (tab)
Effects->>Terminal: create preset terminal (single or multi-pane)
Effects->>Terminal: attach / run initialCommands
else setup script only
Effects->>Terminal: create setup terminal
Effects->>Terminal: attach / run initialCommands
else preset only
Effects->>Terminal: create preset terminal (single or multi-pane)
Effects->>Terminal: attach / run initialCommands
else neither
Effects->>User: show configuration toast with action
end
Terminal-->>Effects: success / error
Effects->>Store: cleanup pending/processing state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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: 1
🤖 Fix all issues with AI agents
In `@apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts`:
- Around line 38-41: The current use of
electronTrpc.settings.getDefaultPreset.useQuery() (data: defaultPreset) can be
undefined when the mutation's onSuccess runs, causing the preset to be lost;
update the workspace creation flow (the mutation's onSuccess handler in
useCreateWorkspace) to synchronously fetch the preset when needed by calling
await utils.settings.getDefaultPreset.fetch() instead of relying on
defaultPreset from useQuery(), then use the fetched value (falling back to null
only after the fetch) when calling apply/setup functions so the preset is
applied reliably.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx (1)
49-74: Prefer params object for the new helper.
This keeps the API self-documenting and aligns with the repo’s function-parameter guideline.As per coding guidelines, prefer params objects for functions with 2+ arguments.♻️ Suggested refactor
- const createPresetTerminal = useCallback( - ( - workspaceId: string, - preset: NonNullable<PendingTerminalSetup["defaultPreset"]>, - ) => { + const createPresetTerminal = useCallback( + ({ + workspaceId, + preset, + }: { + workspaceId: string; + preset: NonNullable<PendingTerminalSetup["defaultPreset"]>; + }) => { const isParallel = preset.executionMode === "parallel" && preset.commands.length > 1; ... }, [addTab, addTabWithMultiplePanes, renameTab], );- createPresetTerminal(setup.workspaceId, setup.defaultPreset); + createPresetTerminal({ workspaceId: setup.workspaceId, preset: setup.defaultPreset });- createPresetTerminal(setup.workspaceId, setup.defaultPreset); + createPresetTerminal({ workspaceId: setup.workspaceId, preset: setup.defaultPreset });Also applies to: 94-95, 167-168
| // Query default preset to include in terminal setup | ||
| const { data: defaultPreset } = | ||
| electronTrpc.settings.getDefaultPreset.useQuery(); | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.tsRepository: superset-sh/superset
Length of output: 2250
🏁 Script executed:
wc -l apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.tsRepository: superset-sh/superset
Length of output: 137
🏁 Script executed:
# Check if there are other similar files in the workspaces directory
fd . apps/desktop/src/renderer/react-query/workspaces/ -type fRepository: superset-sh/superset
Length of output: 234
🏁 Script executed:
# Check the addPendingTerminalSetup implementation to understand if it's sync
rg "addPendingTerminalSetup" apps/desktop/src/renderer/stores/ -A 5Repository: superset-sh/superset
Length of output: 1057
🏁 Script executed:
# Check trpc-electron setup
rg "electronTrpc" apps/desktop/src/renderer/lib/ -lRepository: superset-sh/superset
Length of output: 201
🏁 Script executed:
# Search for fetch() usage with getDefaultPreset
rg "getDefaultPreset" apps/desktop/src/renderer/ -B 2 -A 2Repository: superset-sh/superset
Length of output: 2129
🏁 Script executed:
# Check if utils.fetch pattern is used elsewhere
rg "utils\." apps/desktop/src/renderer/react-query/ -A 2 | head -50Repository: superset-sh/superset
Length of output: 4399
🏁 Script executed:
cat -n apps/desktop/src/renderer/react-query/workspaces/useCreateBranchWorkspace.ts | head -70Repository: superset-sh/superset
Length of output: 2224
🏁 Script executed:
# Check if fetch() method exists on settings.getDefaultPreset
rg "settings\.getDefaultPreset" apps/desktop/src/ -B 2 -A 5Repository: superset-sh/superset
Length of output: 3290
🏁 Script executed:
# Check what getSetupCommands returns to see the pattern
rg "getSetupCommands" apps/desktop/src/ -B 3 -A 3Repository: superset-sh/superset
Length of output: 3580
🏁 Script executed:
# Check the backend route definition for workspaces.create to see what it returns
fd . apps -name "*.ts" -path "*/server/*" | xargs rg -l "workspaces.*create" | head -5Repository: superset-sh/superset
Length of output: 573
🏁 Script executed:
# Look for the router definition for these queries
rg "getSetupCommands|getDefaultPreset" apps/desktop/src/server/ -B 2 -A 5Repository: superset-sh/superset
Length of output: 128
🏁 Script executed:
# Find the server-side trpc router files
fd "init.ts" apps/desktop/src/lib/trpc/routers/workspaces/procedures/Repository: superset-sh/superset
Length of output: 127
🏁 Script executed:
# Check the init.ts file to see getSetupCommands and getDefaultPreset definitions
cat -n apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.tsRepository: superset-sh/superset
Length of output: 4580
🏁 Script executed:
# Find settings router
fd . apps/desktop/src/lib/trpc/routers/ -name "*.ts" -type fRepository: superset-sh/superset
Length of output: 294
🏁 Script executed:
# Find settings router definition
find apps/desktop/src/lib/trpc/routers -name "*settings*" -type fRepository: superset-sh/superset
Length of output: 46
🏁 Script executed:
# Search for getDefaultPreset in router definitions
rg "getDefaultPreset" apps/desktop/src/lib/trpc/Repository: superset-sh/superset
Length of output: 369
🏁 Script executed:
# Check the settings router definition
cat -n apps/desktop/src/lib/trpc/routers/settings/index.tsRepository: superset-sh/superset
Length of output: 10830
Handle race condition where defaultPreset query may not resolve before workspace creation succeeds.
useQuery() initializes as undefined, and since the mutation's onSuccess callback fires independently of the query resolution, defaultPreset ?? null will coerce to null if the query hasn't resolved yet, preventing the preset from being applied. Use await utils.settings.getDefaultPreset.fetch() to resolve the preset on demand when needed.
✅ Suggested fix
onSuccess: async (data, ...rest) => {
// Set optimistic progress before navigation to prevent "Setup incomplete" flash
if (data.isInitializing) {
const optimisticProgress: WorkspaceInitProgress = {
workspaceId: data.workspace.id,
projectId: data.projectId,
step: "pending",
message: "Preparing...",
};
updateProgress(optimisticProgress);
}
+ const resolvedPreset =
+ defaultPreset === undefined
+ ? await utils.settings.getDefaultPreset.fetch()
+ : defaultPreset;
+
addPendingTerminalSetup({
workspaceId: data.workspace.id,
projectId: data.projectId,
initialCommands: data.initialCommands,
- defaultPreset: defaultPreset ?? null,
+ defaultPreset: resolvedPreset ?? null,
});🤖 Prompt for AI Agents
In `@apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts`
around lines 38 - 41, The current use of
electronTrpc.settings.getDefaultPreset.useQuery() (data: defaultPreset) can be
undefined when the mutation's onSuccess runs, causing the preset to be lost;
update the workspace creation flow (the mutation's onSuccess handler in
useCreateWorkspace) to synchronously fetch the preset when needed by calling
await utils.settings.getDefaultPreset.fetch() instead of relying on
defaultPreset from useQuery(), then use the fetched value (falling back to null
only after the fetch) when calling apply/setup functions so the preset is
applied reliably.
When creating workspaces, the client-side useQuery for default preset may not have resolved yet, causing the preset to be stored as null and never applied. Now we always fetch from getSetupCommands when the preset is undefined in pending setup, ensuring it's applied even on first-run or slow settings load.
Adds a new "Auto-apply default preset" toggle in Terminal settings that controls whether the default preset is automatically applied when creating new workspaces. Enabled by default to maintain current behavior. - Add autoApplyDefaultPreset column to settings table - Add tRPC procedures for get/set - Add UI toggle in Terminal settings - Check setting in WorkspaceInitEffects before applying preset
When both setup script and default preset exist, the preset now runs in a split pane within the same tab as the setup script, rather than in a separate tab. When only the preset exists (no setup script), it still creates its own tab with parallel panes if configured.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/react-query/workspaces/useCreateBranchWorkspace.ts`:
- Around line 25-44: The utils.workspaces.getSetupCommands.fetch call in the
onSuccess path can throw and block navigation; wrap that fetch in a try/catch
and fall back to null setupData on error, log a contextual message (including
workspaceId/projectId) when the fetch fails, then call addPendingTerminalSetup
with nulls and still create the readyProgress and call updateProgress so the
flow completes; update the onSuccess handler around
utils.workspaces.getSetupCommands.fetch, add the catch/log, and ensure
addPendingTerminalSetup and updateProgress are always invoked even when
setupData is null.
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx (1)
40-173: Prefer object params for helper callbacks.
Positional args in createPresetTerminal and handleTerminalSetup make call sites harder to extend; switch to a params object and update callers. As per coding guidelines, prefer object parameters for functions with 2+ params.♻️ Suggested refactor
- const createPresetTerminal = useCallback( - ( - workspaceId: string, - preset: NonNullable<PendingTerminalSetup["defaultPreset"]>, - ) => { + const createPresetTerminal = useCallback( + ({ + workspaceId, + preset, + }: { + workspaceId: string; + preset: NonNullable<PendingTerminalSetup["defaultPreset"]>; + }) => { @@ - const handleTerminalSetup = useCallback( - (setup: PendingTerminalSetup, onComplete: () => void) => { + const handleTerminalSetup = useCallback( + ({ + setup, + onComplete, + }: { + setup: PendingTerminalSetup; + onComplete: () => void; + }) => { @@ - createPresetTerminal(setup.workspaceId, setup.defaultPreset); + createPresetTerminal({ + workspaceId: setup.workspaceId, + preset: setup.defaultPreset, + }); @@ - createPresetTerminal(setup.workspaceId, setup.defaultPreset); + createPresetTerminal({ + workspaceId: setup.workspaceId, + preset: setup.defaultPreset, + }); @@ - handleTerminalSetup(completeSetup, () => { - removePendingTerminalSetup(workspaceId); - clearProgress(workspaceId); - processingRef.current.delete(workspaceId); - }); + handleTerminalSetup({ + setup: completeSetup, + onComplete: () => { + removePendingTerminalSetup(workspaceId); + clearProgress(workspaceId); + processingRef.current.delete(workspaceId); + }, + }); @@ - handleTerminalSetup(setup, () => { - removePendingTerminalSetup(workspaceId); - clearProgress(workspaceId); - processingRef.current.delete(workspaceId); - }); + handleTerminalSetup({ + setup, + onComplete: () => { + removePendingTerminalSetup(workspaceId); + clearProgress(workspaceId); + processingRef.current.delete(workspaceId); + }, + }); @@ - handleTerminalSetup(fetchedSetup, () => { - clearProgress(workspaceId); - processingRef.current.delete(workspaceId); - }); + handleTerminalSetup({ + setup: fetchedSetup, + onComplete: () => { + clearProgress(workspaceId); + processingRef.current.delete(workspaceId); + }, + });Also applies to: 197-220, 258-260
…gation If the fetch throws, the mutation's onSuccess rejects and the user never navigates to the newly created workspace. Add a catch with a null fallback so the flow still completes. WorkspaceInitEffects has its own fallback fetch for missing preset data.
…ng tab Add addPanesToTab function to create multiple split panes in an existing tab, allowing parallel presets to run commands concurrently instead of sequentially in a single pane.
Summary
Test plan