Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/desktop/src/lib/trpc/routers/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ export const createSettingsRouter = () => {
commands: z.array(z.string()),
projectIds: z.array(z.string()).nullable().optional(),
pinnedToBar: z.boolean().optional(),
useAsWorkspaceRun: z.boolean().optional(),
executionMode: z.enum(EXECUTION_MODES).optional(),
}),
)
Expand Down Expand Up @@ -437,6 +438,7 @@ export const createSettingsRouter = () => {
commands: z.array(z.string()).optional(),
projectIds: z.array(z.string()).nullable().optional(),
pinnedToBar: z.boolean().optional(),
useAsWorkspaceRun: z.boolean().optional(),
executionMode: z.enum(EXECUTION_MODES).optional(),
}),
}),
Expand All @@ -462,6 +464,8 @@ export const createSettingsRouter = () => {
preset.projectIds = normalizePresetProjectIds(input.patch.projectIds);
if (input.patch.pinnedToBar !== undefined)
preset.pinnedToBar = input.patch.pinnedToBar;
if (input.patch.useAsWorkspaceRun !== undefined)
preset.useAsWorkspaceRun = input.patch.useAsWorkspaceRun;
if (input.patch.executionMode !== undefined)
preset.executionMode = input.patch.executionMode;

Expand Down
113 changes: 70 additions & 43 deletions apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {
projects,
settings,
workspaceSections,
workspaces,
worktrees,
} from "@superset/local-db";
import { TRPCError } from "@trpc/server";
import { eq, isNotNull, isNull } from "drizzle-orm";
import { localDb } from "main/lib/local-db";
import { selectWorkspaceRunDefinition } from "shared/workspace-run-definition";
import { z } from "zod";
import { publicProcedure, router } from "../../..";
import {
normalizeTerminalPresets,
type PresetWithUnknownMode,
} from "../../settings/preset-execution-mode";
import { getWorkspace } from "../utils/db-helpers";
import { getProjectChildItems } from "../utils/project-children-order";
import { loadSetupConfig } from "../utils/setup";
Expand All @@ -17,6 +23,64 @@ import { getWorkspacePath } from "../utils/worktree";

type WorktreePathMap = Map<string, string>;

function getTerminalPresetsForWorkspaceRun() {
const row = localDb.select().from(settings).get();
return normalizeTerminalPresets(
(row?.terminalPresets ?? []) as PresetWithUnknownMode[],
);
}

function getWorkspaceRunDefinition(workspaceId: string) {
const workspace = localDb
.select()
.from(workspaces)
.where(eq(workspaces.id, workspaceId))
.get();
if (!workspace) {
throw new TRPCError({
code: "NOT_FOUND",
message: `Workspace ${workspaceId} not found`,
});
}

const project = localDb
.select()
.from(projects)
.where(eq(projects.id, workspace.projectId))
.get();
if (!project) {
return null;
}

const worktree = workspace.worktreeId
? localDb
.select()
.from(worktrees)
.where(eq(worktrees.id, workspace.worktreeId))
.get()
: null;

const worktreePath =
workspace.type === "worktree" && worktree?.path
? worktree.path
: workspace.type === "branch"
? project.mainRepoPath
: undefined;

const config = loadSetupConfig({
mainRepoPath: project.mainRepoPath,
worktreePath,
projectId: project.id,
});

return selectWorkspaceRunDefinition({
presets: getTerminalPresetsForWorkspaceRun(),
configRunCommands: config?.run,
configCwd: config?.cwd,
projectId: project.id,
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/** Returns workspace IDs in sidebar visual order (by project.tabOrder, then ungrouped workspaces, then sections by tabOrder). */
function getWorkspacesInVisualOrder(): string[] {
const activeProjects = localDb
Expand Down Expand Up @@ -302,51 +366,14 @@ export const createQueryProcedures = () => {
getResolvedRunCommands: publicProcedure
.input(z.object({ workspaceId: z.string() }))
.query(({ input }) => {
const workspace = localDb
.select()
.from(workspaces)
.where(eq(workspaces.id, input.workspaceId))
.get();
if (!workspace) {
throw new TRPCError({
code: "NOT_FOUND",
message: `Workspace ${input.workspaceId} not found`,
});
}

const project = localDb
.select()
.from(projects)
.where(eq(projects.id, workspace.projectId))
.get();
if (!project) {
return { commands: [] };
}

const worktree = workspace.worktreeId
? localDb
.select()
.from(worktrees)
.where(eq(worktrees.id, workspace.worktreeId))
.get()
: null;

const worktreePath =
workspace.type === "worktree" && worktree?.path
? worktree.path
: workspace.type === "branch"
? project.mainRepoPath
: undefined;

const config = loadSetupConfig({
mainRepoPath: project.mainRepoPath,
worktreePath,
projectId: project.id,
});

const definition = getWorkspaceRunDefinition(input.workspaceId);
return {
commands: config?.run ?? [],
commands: definition?.commands ?? [],
};
}),

getWorkspaceRunDefinition: publicProcedure
.input(z.object({ workspaceId: z.string() }))
.query(({ input }) => getWorkspaceRunDefinition(input.workspaceId)),
});
};
20 changes: 20 additions & 0 deletions apps/desktop/src/lib/trpc/routers/workspaces/utils/setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,26 @@ describe("run config", () => {
expect(config).toBeNull();
});

test("validates cwd field must be non-empty", () => {
writeFileSync(
join(MAIN_REPO, ".superset", "config.json"),
JSON.stringify({ cwd: " ", run: ["bun dev"] }),
);

const config = loadSetupConfig({ mainRepoPath: MAIN_REPO });
expect(config).toBeNull();
});

test("normalizes configured cwd", () => {
writeFileSync(
join(MAIN_REPO, ".superset", "config.json"),
JSON.stringify({ cwd: " packages/web ", run: ["bun dev"] }),
);

const config = loadSetupConfig({ mainRepoPath: MAIN_REPO });
expect(config?.cwd).toBe("packages/web");
});

test("local config can override run commands", () => {
writeFileSync(
join(MAIN_REPO, ".superset", "config.json"),
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop/src/lib/trpc/routers/workspaces/utils/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ function readConfigFile(configPath: string): SetupConfig | null {
throw new Error("'run' field must be an array of strings");
}

if (parsed.cwd !== undefined) {
if (typeof parsed.cwd !== "string" || parsed.cwd.trim().length === 0) {
throw new Error("'cwd' field must be a non-empty string");
}
parsed.cwd = parsed.cwd.trim();
}

return parsed;
} catch (error) {
console.error(
Expand Down Expand Up @@ -124,6 +131,7 @@ function mergeBaseConfigs(
setup: override.setup ?? base.setup,
teardown: override.teardown ?? base.teardown,
run: override.run ?? base.run,
cwd: override.cwd ?? base.cwd,
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/renderer/lib/project-scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export async function invalidateProjectScriptQueries(
await Promise.all([
utils.config.getConfigContent.invalidate({ projectId }),
utils.config.shouldShowSetupCard.invalidate({ projectId }),
utils.workspaces.getWorkspaceRunDefinition.invalidate(),
utils.workspaces.getResolvedRunCommands.invalidate(),
]);
}
10 changes: 10 additions & 0 deletions apps/desktop/src/renderer/react-query/presets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ function useCreateTerminalPreset(
await utils.settings.getTerminalPresets.invalidate();
await utils.settings.getWorkspaceCreationPresets.invalidate();
await utils.settings.getNewTabPresets.invalidate();
await utils.workspaces.getWorkspaceRunDefinition.invalidate();
await utils.workspaces.getResolvedRunCommands.invalidate();
await options?.onSuccess?.(...args);
},
});
Expand All @@ -33,6 +35,8 @@ function useUpdateTerminalPreset(
await utils.settings.getTerminalPresets.invalidate();
await utils.settings.getWorkspaceCreationPresets.invalidate();
await utils.settings.getNewTabPresets.invalidate();
await utils.workspaces.getWorkspaceRunDefinition.invalidate();
await utils.workspaces.getResolvedRunCommands.invalidate();
await options?.onSuccess?.(...args);
},
});
Expand All @@ -51,6 +55,8 @@ function useDeleteTerminalPreset(
await utils.settings.getTerminalPresets.invalidate();
await utils.settings.getWorkspaceCreationPresets.invalidate();
await utils.settings.getNewTabPresets.invalidate();
await utils.workspaces.getWorkspaceRunDefinition.invalidate();
await utils.workspaces.getResolvedRunCommands.invalidate();
await options?.onSuccess?.(...args);
},
});
Expand All @@ -69,6 +75,8 @@ function useSetPresetAutoApply(
await utils.settings.getTerminalPresets.invalidate();
await utils.settings.getWorkspaceCreationPresets.invalidate();
await utils.settings.getNewTabPresets.invalidate();
await utils.workspaces.getWorkspaceRunDefinition.invalidate();
await utils.workspaces.getResolvedRunCommands.invalidate();
await options?.onSuccess?.(...args);
},
});
Expand All @@ -87,6 +95,8 @@ function useReorderTerminalPresets(
await utils.settings.getTerminalPresets.invalidate();
await utils.settings.getWorkspaceCreationPresets.invalidate();
await utils.settings.getNewTabPresets.invalidate();
await utils.workspaces.getWorkspaceRunDefinition.invalidate();
await utils.workspaces.getResolvedRunCommands.invalidate();
await options?.onSuccess?.(...args);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ export const WorkspaceRunButton = memo(function WorkspaceRunButton({
workspaceId,
worktreePath,
});
const { data: runConfig } =
electronTrpc.workspaces.getResolvedRunCommands.useQuery(
const { data: runDefinition } =
electronTrpc.workspaces.getWorkspaceRunDefinition.useQuery(
{ workspaceId },
{ enabled: !!workspaceId },
);
const hasRunCommand = (runConfig?.commands ?? []).some(
const hasRunCommand = (runDefinition?.commands ?? []).some(
(command) => command.trim().length > 0,
);

Expand All @@ -73,13 +73,20 @@ export const WorkspaceRunButton = memo(function WorkspaceRunButton({
]);

const handleConfigureClick = useCallback(() => {
if (runDefinition?.source === "terminal-preset") {
void navigate({
to: "/settings/terminal",
search: { editPresetId: runDefinition.presetId },
});
return;
}
if (!projectId) return;
setSettingsSearchQuery("scripts");
void navigate({
to: "/settings/projects/$projectId",
params: { projectId },
});
}, [navigate, projectId, setSettingsSearchQuery]);
}, [navigate, projectId, runDefinition, setSettingsSearchQuery]);

Comment thread
coderabbitai[bot] marked this conversation as resolved.
const handleForceStopClick = useCallback(() => {
void forceStopWorkspaceRun();
Expand Down Expand Up @@ -167,7 +174,9 @@ export const WorkspaceRunButton = memo(function WorkspaceRunButton({
)}
<DropdownMenuItem onClick={handleConfigureClick}>
<HiMiniCog6Tooth className="mr-2 size-4" />
Configure
{runDefinition?.source === "terminal-preset"
? "Edit Run Preset"
: "Configure"}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import {
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import { useNavigate } from "@tanstack/react-router";
import { Eye, EyeOff, Settings } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
type ReactNode,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { HiMiniCommandLine } from "react-icons/hi2";
import { useIsDarkTheme } from "renderer/assets/app-icons/preset-icons";
import { HotkeyMenuShortcut } from "renderer/components/HotkeyMenuShortcut";
Expand All @@ -27,6 +33,7 @@ interface V2PresetsBarProps {
executePreset: (preset: V2TerminalPresetRow) => void | Promise<void>;
showPresetsBar: boolean;
onToggleShowPresetsBar: (enabled: boolean) => void;
trailing?: ReactNode;
}

// Co-located to keep v2 self-contained. Mirrors the v1 array in
Expand Down Expand Up @@ -68,6 +75,7 @@ export function V2PresetsBar({
executePreset,
showPresetsBar,
onToggleShowPresetsBar,
trailing,
}: V2PresetsBarProps) {
const navigate = useNavigate();
const isDark = useIsDarkTheme();
Expand Down Expand Up @@ -194,14 +202,18 @@ export function V2PresetsBar({

return (
<div
className="flex h-8 min-w-0 shrink-0 items-center gap-0.5 overflow-x-auto overflow-y-hidden border-b border-border bg-background px-2"
className="flex h-8 min-w-0 shrink-0 items-center gap-0.5 overflow-x-auto overflow-y-hidden border-b border-border/60 bg-background px-2"
style={{ scrollbarWidth: "none" }}
>
<DropdownMenu>
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-6 shrink-0">
<Button
variant="ghost"
size="icon"
className="size-6 shrink-0 text-muted-foreground hover:text-foreground"
>
<Settings className="size-3.5" />
</Button>
</DropdownMenuTrigger>
Expand Down Expand Up @@ -269,6 +281,9 @@ export function V2PresetsBar({
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{visiblePresets.length > 0 ? (
<div className="mx-1 h-3.5 w-px shrink-0 bg-border/60" />
) : null}
{visiblePresets.map(({ preset }, visibleIndex) => {
const hotkeyId = PRESET_HOTKEY_IDS[visibleIndex];
return (
Expand All @@ -286,6 +301,9 @@ export function V2PresetsBar({
/>
);
})}
{trailing ? (
<div className="ml-auto shrink-0 pl-1">{trailing}</div>
) : null}
</div>
);
}
Loading
Loading