Skip to content

feat(desktop): apply default terminal preset when creating workspaces#948

Merged
Kitenite merged 8 commits into
mainfrom
new-workspace-preset
Jan 26, 2026
Merged

feat(desktop): apply default terminal preset when creating workspaces#948
Kitenite merged 8 commits into
mainfrom
new-workspace-preset

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 26, 2026

Summary

  • When creating a new workspace, the user's default terminal preset is now automatically applied alongside any project setup scripts
  • When both setup script and preset exist, they run in split panes within the same tab
  • When only the preset exists, it creates a new tab (with parallel panes if configured)
  • Handles both regular workspaces and branch workspaces consistently
  • Added a new "Auto-apply default preset" setting in Terminal settings to disable this behavior

Test plan

  • Create a new workspace with both a setup script and a default preset configured - verify both run in split panes in the same tab
  • Create a new workspace with only a default preset (no setup script) - verify preset creates its own tab
  • Create a new workspace with only a setup script (no default preset) - verify setup script runs
  • Create a new workspace with neither - verify config toast appears
  • Create a branch workspace with a default preset - verify preset is applied
  • Test preset with parallel execution mode (without setup script) - verify split panes are created
  • Disable "Auto-apply default preset" in Terminal settings - verify preset is NOT applied on workspace creation

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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 26, 2026

Warning

Rate limit exceeded

@Kitenite has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📝 Walkthrough

Walkthrough

The 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

Cohort / File(s) Summary
Backend: setup commands
apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts
Added getDefaultPreset() and surfaced defaultPreset in getSetupCommands() response.
Workspace creation hooks
apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts, apps/desktop/src/renderer/react-query/workspaces/useCreateBranchWorkspace.ts
Hooks now propagate defaultPreset into addPendingTerminalSetup() and use workspace-init flow instead of direct tab creation/invalidations.
Workspace init store
apps/desktop/src/renderer/stores/workspace-init.ts
PendingTerminalSetup now includes `defaultPreset?: TerminalPreset
Init effects & terminal setup
apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
New createPresetTerminal() helper using addTabWithMultiplePanes for parallel presets; expanded handleTerminalSetup() to handle: setup+preset, setup-only, preset-only, neither; adds tab renaming, improved error toast with “Open Terminal” action, and on-demand fetch of setup data when needed.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • saddlepaddle

Poem

🐰
I hopped through presets, soft and bright,
Linking setups in the quiet night,
Tabs unfurl in pane-fed rows,
Commands hum where the warm shell glows,
A tiny rabbit cheers the init flows.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: applying default terminal presets when creating workspaces, which is the core feature across all modified files.
Description check ✅ Passed The description provides a clear summary of changes, comprehensive test plan, and context; it covers the main objective, testing scenarios, and additional notes as expected.

✏️ 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.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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.

♻️ 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 });
As per coding guidelines, prefer params objects for functions with 2+ arguments.

Also applies to: 94-95, 167-168

Comment on lines +38 to +41
// Query default preset to include in terminal setup
const { data: defaultPreset } =
electronTrpc.settings.getDefaultPreset.useQuery();

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts

Repository: superset-sh/superset

Length of output: 2250


🏁 Script executed:

wc -l apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts

Repository: 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 f

Repository: 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 5

Repository: superset-sh/superset

Length of output: 1057


🏁 Script executed:

# Check trpc-electron setup
rg "electronTrpc" apps/desktop/src/renderer/lib/ -l

Repository: superset-sh/superset

Length of output: 201


🏁 Script executed:

# Search for fetch() usage with getDefaultPreset
rg "getDefaultPreset" apps/desktop/src/renderer/ -B 2 -A 2

Repository: 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 -50

Repository: superset-sh/superset

Length of output: 4399


🏁 Script executed:

cat -n apps/desktop/src/renderer/react-query/workspaces/useCreateBranchWorkspace.ts | head -70

Repository: 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 5

Repository: 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 3

Repository: 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 -5

Repository: 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 5

Repository: 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.ts

Repository: superset-sh/superset

Length of output: 4580


🏁 Script executed:

# Find settings router
fd . apps/desktop/src/lib/trpc/routers/ -name "*.ts" -type f

Repository: superset-sh/superset

Length of output: 294


🏁 Script executed:

# Find settings router definition
find apps/desktop/src/lib/trpc/routers -name "*settings*" -type f

Repository: 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.ts

Repository: 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.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 26, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ✅ Electric Fly.io app

Thank you for your contribution! 🎉

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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

Comment thread apps/desktop/src/renderer/react-query/workspaces/useCreateBranchWorkspace.ts Outdated
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant