From dffde8660cace6165751ebe808c7fcc9195ccb76 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:10:13 -0800 Subject: [PATCH 1/9] feat(desktop): add workspace settings section with project/workspace navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new Workspace settings section that allows users to view and edit workspace details including name, branch, path, and scripts configuration. The settings sidebar now shows a hierarchical project/workspace list for easy navigation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../lib/trpc/routers/workspaces/workspaces.ts | 17 +++ .../ConfigFilePreview/ConfigFilePreview.tsx | 62 ++++++++ .../components/ConfigFilePreview/index.ts | 4 + .../SettingsView/SettingsContent.tsx | 2 + .../SettingsView/SettingsSidebar.tsx | 138 +++++++++++++++--- .../WorkspaceSettings/WorkspaceSettings.tsx | 125 ++++++++++++++++ .../SettingsView/WorkspaceSettings/index.ts | 1 + apps/desktop/src/renderer/stores/app-state.ts | 4 +- apps/desktop/src/shared/constants.ts | 9 ++ 9 files changed, 339 insertions(+), 23 deletions(-) create mode 100644 apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx create mode 100644 apps/desktop/src/renderer/components/ConfigFilePreview/index.ts create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/index.ts diff --git a/apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts b/apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts index b55c8bff755..f21d1b71507 100644 --- a/apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts +++ b/apps/desktop/src/lib/trpc/routers/workspaces/workspaces.ts @@ -223,9 +223,26 @@ export const createWorkspacesRouter = () => { ); } + const project = db.data.projects.find( + (p) => p.id === workspace.projectId, + ); + const worktree = db.data.worktrees.find( + (wt) => wt.id === workspace.worktreeId, + ); + return { ...workspace, worktreePath: getWorktreePath(workspace.worktreeId) ?? "", + project: project + ? { + id: project.id, + name: project.name, + mainRepoPath: project.mainRepoPath, + } + : null, + worktree: worktree + ? { branch: worktree.branch, gitStatus: worktree.gitStatus } + : null, }; }), diff --git a/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx b/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx new file mode 100644 index 00000000000..f49fed892d6 --- /dev/null +++ b/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx @@ -0,0 +1,62 @@ +import { Button } from "@superset/ui/button"; +import { cn } from "@superset/ui/utils"; +import { HiArrowTopRightOnSquare } from "react-icons/hi2"; +import { OpenInButton } from "renderer/components/OpenInButton"; +import { + CONFIG_FILE_NAME, + CONFIG_TEMPLATE, + PROJECT_SUPERSET_DIR_NAME, + WEBSITE_URL, +} from "shared/constants"; + +export interface ConfigFilePreviewProps { + projectName: string; + configFilePath?: string; + className?: string; +} + +export function ConfigFilePreview({ + projectName, + configFilePath, + className, +}: ConfigFilePreviewProps) { + const handleLearnMore = () => { + window.open(`${WEBSITE_URL}/scripts`, "_blank"); + }; + + return ( + <> +
+
+ + {projectName}/{PROJECT_SUPERSET_DIR_NAME}/{CONFIG_FILE_NAME} + + +
+ +
+
+						{CONFIG_TEMPLATE}
+					
+
+
+ +
+ +
+ + ); +} diff --git a/apps/desktop/src/renderer/components/ConfigFilePreview/index.ts b/apps/desktop/src/renderer/components/ConfigFilePreview/index.ts new file mode 100644 index 00000000000..e52ac58fc8b --- /dev/null +++ b/apps/desktop/src/renderer/components/ConfigFilePreview/index.ts @@ -0,0 +1,4 @@ +export { + ConfigFilePreview, + type ConfigFilePreviewProps, +} from "./ConfigFilePreview"; diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx index 812e0b84eeb..891f38b75b0 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx @@ -1,6 +1,7 @@ import type { SettingsSection } from "renderer/stores"; import { AppearanceSettings } from "./AppearanceSettings"; import { KeyboardShortcutsSettings } from "./KeyboardShortcutsSettings"; +import { WorkspaceSettings } from "./WorkspaceSettings"; interface SettingsContentProps { activeSection: SettingsSection; @@ -9,6 +10,7 @@ interface SettingsContentProps { export function SettingsContent({ activeSection }: SettingsContentProps) { return (
+ {activeSection === "workspace" && } {activeSection === "appearance" && } {activeSection === "keyboard" && }
diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx index 0bde8d42e11..c6b5ab96ad6 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx @@ -1,9 +1,15 @@ import { cn } from "@superset/ui/utils"; +import { useState } from "react"; import { HiArrowLeft, + HiChevronDown, + HiChevronRight, HiOutlineCommandLine, + HiOutlineFolder, HiOutlinePaintBrush, } from "react-icons/hi2"; +import { trpc } from "renderer/lib/trpc"; +import { useSetActiveWorkspace } from "renderer/react-query/workspaces"; import { type SettingsSection, useCloseSettings } from "renderer/stores"; interface SettingsSidebarProps { @@ -11,11 +17,16 @@ interface SettingsSidebarProps { onSectionChange: (section: SettingsSection) => void; } -const SECTIONS: { +const GENERAL_SECTIONS: { id: SettingsSection; label: string; icon: React.ReactNode; }[] = [ + { + id: "workspace", + label: "Workspace", + icon: , + }, { id: "appearance", label: "Appearance", @@ -33,9 +44,33 @@ export function SettingsSidebar({ onSectionChange, }: SettingsSidebarProps) { const closeSettings = useCloseSettings(); + const { data: groups = [] } = trpc.workspaces.getAllGrouped.useQuery(); + const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); + const setActiveWorkspace = useSetActiveWorkspace(); + const [expandedProjects, setExpandedProjects] = useState>( + () => + new Set(activeWorkspace?.projectId ? [activeWorkspace.projectId] : []), + ); + + const toggleProject = (projectId: string) => { + setExpandedProjects((prev) => { + const next = new Set(prev); + if (next.has(projectId)) { + next.delete(projectId); + } else { + next.add(projectId); + } + return next; + }); + }; + + const handleWorkspaceClick = (workspaceId: string) => { + setActiveWorkspace.mutate({ id: workspaceId }); + onSectionChange("workspace"); + }; return ( -
+
{/* Back button */} - ))} - + {/* Projects & Workspaces */} +
+
+

+ Workspaces +

+ +
+ + {/* General Settings */} +
+

+ General +

+ +
+
); } diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx new file mode 100644 index 00000000000..2ca324ef1ae --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx @@ -0,0 +1,125 @@ +import { Input } from "@superset/ui/input"; +import { + HiOutlineCog6Tooth, + HiOutlineFolder, + HiOutlinePencilSquare, +} from "react-icons/hi2"; +import { LuGitBranch } from "react-icons/lu"; +import { ConfigFilePreview } from "renderer/components/ConfigFilePreview"; +import { trpc } from "renderer/lib/trpc"; +import { useWorkspaceRename } from "renderer/screens/main/components/TopBar/WorkspaceTabs/useWorkspaceRename"; + +export function WorkspaceSettings() { + const { data: activeWorkspace, isLoading } = + trpc.workspaces.getActive.useQuery(); + + const { data: configFilePath } = trpc.config.getConfigFilePath.useQuery( + { projectId: activeWorkspace?.projectId ?? "" }, + { enabled: !!activeWorkspace?.projectId }, + ); + + const rename = useWorkspaceRename( + activeWorkspace?.id ?? "", + activeWorkspace?.name ?? "", + ); + + if (isLoading) { + return ( +
+
+
+
+
+
+ ); + } + + if (!activeWorkspace) { + return ( +
+
+

Workspace

+

+ No active workspace selected +

+
+
+ ); + } + + return ( +
+
+

Workspace

+
+ +
+
+

Name

+ {rename.isRenaming ? ( + rename.setRenameValue(e.target.value)} + onBlur={rename.submitRename} + onKeyDown={rename.handleKeyDown} + className="text-base" + /> + ) : ( + + )} +
+ + {activeWorkspace.worktree && ( +
+

+ + Branch +

+
+

{activeWorkspace.worktree.branch}

+ {activeWorkspace.worktree.gitStatus?.needsRebase && ( + + Needs Rebase + + )} +
+
+ )} + +
+

+ + Path +

+

+ {activeWorkspace.worktreePath} +

+
+ + {activeWorkspace.project && ( +
+
+

+ + Scripts +

+
+ +
+ )} +
+
+ ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/index.ts b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/index.ts new file mode 100644 index 00000000000..52c413ca2c9 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/index.ts @@ -0,0 +1 @@ +export { WorkspaceSettings } from "./WorkspaceSettings"; diff --git a/apps/desktop/src/renderer/stores/app-state.ts b/apps/desktop/src/renderer/stores/app-state.ts index 9fe5264fbf9..b934b577631 100644 --- a/apps/desktop/src/renderer/stores/app-state.ts +++ b/apps/desktop/src/renderer/stores/app-state.ts @@ -2,7 +2,7 @@ import { create } from "zustand"; import { devtools } from "zustand/middleware"; export type AppView = "workspace" | "settings"; -export type SettingsSection = "appearance" | "keyboard"; +export type SettingsSection = "workspace" | "appearance" | "keyboard"; interface AppState { currentView: AppView; @@ -20,7 +20,7 @@ export const useAppStore = create()( (set) => ({ currentView: "workspace", isSettingsTabOpen: false, - settingsSection: "appearance", + settingsSection: "workspace", setView: (view) => { set({ currentView: view }); diff --git a/apps/desktop/src/shared/constants.ts b/apps/desktop/src/shared/constants.ts index a4c759f9712..eb813f2540a 100644 --- a/apps/desktop/src/shared/constants.ts +++ b/apps/desktop/src/shared/constants.ts @@ -21,7 +21,16 @@ export const PORTS = { export const SUPERSET_DIR_NAME = ENVIRONMENT.IS_DEV ? ".superset-dev" : ".superset"; +// Project-level directory name (always .superset, not conditional) +export const PROJECT_SUPERSET_DIR_NAME = ".superset"; export const WORKTREES_DIR_NAME = "worktrees"; +export const CONFIG_FILE_NAME = "config.json"; // Website URL - defaults to production, can be overridden via env var for local dev export const WEBSITE_URL = process.env.WEBSITE_URL || "https://superset.sh"; + +// Config file template +export const CONFIG_TEMPLATE = `{ + "setup": [], + "teardown": [] +}`; From 42fd407340ee4dc879688dd4a96c1136618910c8 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:13:57 -0800 Subject: [PATCH 2/9] feat(desktop): load actual config content in workspace settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show the actual config.json content if it exists, otherwise display the template. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../src/lib/trpc/routers/config/config.ts | 24 ++++++++++++++++++- .../ConfigFilePreview/ConfigFilePreview.tsx | 17 +++++++++++-- .../WorkspaceSettings/WorkspaceSettings.tsx | 1 + 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/config/config.ts b/apps/desktop/src/lib/trpc/routers/config/config.ts index b52eb914cb8..8a925af2252 100644 --- a/apps/desktop/src/lib/trpc/routers/config/config.ts +++ b/apps/desktop/src/lib/trpc/routers/config/config.ts @@ -1,4 +1,4 @@ -import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { db } from "main/lib/db"; import { z } from "zod"; @@ -77,6 +77,28 @@ export const createConfigRouter = () => { } return ensureConfigExists(project.mainRepoPath); }), + + // Get the config file content + getConfigContent: publicProcedure + .input(z.object({ projectId: z.string() })) + .query(({ input }) => { + const project = db.data.projects.find((p) => p.id === input.projectId); + if (!project) { + return { content: null, exists: false }; + } + + const configPath = getConfigPath(project.mainRepoPath); + if (!existsSync(configPath)) { + return { content: null, exists: false }; + } + + try { + const content = readFileSync(configPath, "utf-8"); + return { content, exists: true }; + } catch { + return { content: null, exists: false }; + } + }), }); }; diff --git a/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx b/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx index f49fed892d6..9dfa214bdce 100644 --- a/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx +++ b/apps/desktop/src/renderer/components/ConfigFilePreview/ConfigFilePreview.tsx @@ -2,6 +2,7 @@ import { Button } from "@superset/ui/button"; import { cn } from "@superset/ui/utils"; import { HiArrowTopRightOnSquare } from "react-icons/hi2"; import { OpenInButton } from "renderer/components/OpenInButton"; +import { trpc } from "renderer/lib/trpc"; import { CONFIG_FILE_NAME, CONFIG_TEMPLATE, @@ -10,20 +11,32 @@ import { } from "shared/constants"; export interface ConfigFilePreviewProps { + projectId: string; projectName: string; configFilePath?: string; className?: string; } export function ConfigFilePreview({ + projectId, projectName, configFilePath, className, }: ConfigFilePreviewProps) { + const { data: configData } = trpc.config.getConfigContent.useQuery( + { projectId }, + { enabled: !!projectId }, + ); + const handleLearnMore = () => { window.open(`${WEBSITE_URL}/scripts`, "_blank"); }; + const displayContent = + configData?.exists && configData.content + ? configData.content + : CONFIG_TEMPLATE; + return ( <>
-
-						{CONFIG_TEMPLATE}
+					
+						{displayContent}
 					
diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx index 2ca324ef1ae..38dc9eea2b9 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx @@ -114,6 +114,7 @@ export function WorkspaceSettings() {
From 940ab0f95ae5a64ff50f094e1f4d3f5703d18b37 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:27:23 -0800 Subject: [PATCH 3/9] feat(desktop): add project settings section with scripts configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ProjectSettings component showing project name, repo path, and scripts config - Move scripts/config section from WorkspaceSettings to ProjectSettings - Update SettingsSidebar to show project hierarchy with Project Settings and Workspaces - Workspaces are now shown as children of projects in the settings sidebar 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../ProjectSettings/ProjectSettings.tsx | 80 +++++++++++++++++++ .../SettingsView/ProjectSettings/index.ts | 1 + .../SettingsView/SettingsContent.tsx | 2 + .../SettingsView/SettingsSidebar.tsx | 36 +++++++-- .../WorkspaceSettings/WorkspaceSettings.tsx | 28 +------ apps/desktop/src/renderer/stores/app-state.ts | 8 +- 6 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/ProjectSettings.tsx create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/index.ts diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/ProjectSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/ProjectSettings.tsx new file mode 100644 index 00000000000..4023bd30876 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/ProjectSettings.tsx @@ -0,0 +1,80 @@ +import { HiOutlineCog6Tooth, HiOutlineFolder } from "react-icons/hi2"; +import { ConfigFilePreview } from "renderer/components/ConfigFilePreview"; +import { trpc } from "renderer/lib/trpc"; + +export function ProjectSettings() { + const { data: activeWorkspace, isLoading } = + trpc.workspaces.getActive.useQuery(); + + const { data: configFilePath } = trpc.config.getConfigFilePath.useQuery( + { projectId: activeWorkspace?.projectId ?? "" }, + { enabled: !!activeWorkspace?.projectId }, + ); + + if (isLoading) { + return ( +
+
+
+
+
+
+ ); + } + + if (!activeWorkspace?.project) { + return ( +
+
+

Project

+

+ No active project selected +

+
+
+ ); + } + + const { project } = activeWorkspace; + + return ( +
+
+

Project

+
+ +
+
+

Name

+

{project.name}

+
+ +
+

+ + Repository Path +

+

{project.mainRepoPath}

+
+ +
+
+

+ + Scripts +

+

+ Configure setup and teardown scripts that run when workspaces are + created or deleted. +

+
+ +
+
+
+ ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/index.ts b/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/index.ts new file mode 100644 index 00000000000..46b8b1f5e83 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/ProjectSettings/index.ts @@ -0,0 +1 @@ +export { ProjectSettings } from "./ProjectSettings"; diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx index 891f38b75b0..fa321afb7bd 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsContent.tsx @@ -1,6 +1,7 @@ import type { SettingsSection } from "renderer/stores"; import { AppearanceSettings } from "./AppearanceSettings"; import { KeyboardShortcutsSettings } from "./KeyboardShortcutsSettings"; +import { ProjectSettings } from "./ProjectSettings"; import { WorkspaceSettings } from "./WorkspaceSettings"; interface SettingsContentProps { @@ -10,6 +11,7 @@ interface SettingsContentProps { export function SettingsContent({ activeSection }: SettingsContentProps) { return (
+ {activeSection === "project" && } {activeSection === "workspace" && } {activeSection === "appearance" && } {activeSection === "keyboard" && } diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx index c6b5ab96ad6..d354a68d51e 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx @@ -4,8 +4,8 @@ import { HiArrowLeft, HiChevronDown, HiChevronRight, + HiOutlineCog6Tooth, HiOutlineCommandLine, - HiOutlineFolder, HiOutlinePaintBrush, } from "react-icons/hi2"; import { trpc } from "renderer/lib/trpc"; @@ -22,11 +22,6 @@ const GENERAL_SECTIONS: { label: string; icon: React.ReactNode; }[] = [ - { - id: "workspace", - label: "Workspace", - icon: , - }, { id: "appearance", label: "Appearance", @@ -64,6 +59,12 @@ export function SettingsSidebar({ }); }; + const handleProjectClick = (workspaceId: string) => { + // Set a workspace from this project as active to show project settings + setActiveWorkspace.mutate({ id: workspaceId }); + onSectionChange("project"); + }; + const handleWorkspaceClick = (workspaceId: string) => { setActiveWorkspace.mutate({ id: workspaceId }); onSectionChange("workspace"); @@ -88,7 +89,7 @@ export function SettingsSidebar({

- Workspaces + Projects

); diff --git a/apps/desktop/src/renderer/stores/app-state.ts b/apps/desktop/src/renderer/stores/app-state.ts index b934b577631..c7c92759d74 100644 --- a/apps/desktop/src/renderer/stores/app-state.ts +++ b/apps/desktop/src/renderer/stores/app-state.ts @@ -2,7 +2,11 @@ import { create } from "zustand"; import { devtools } from "zustand/middleware"; export type AppView = "workspace" | "settings"; -export type SettingsSection = "workspace" | "appearance" | "keyboard"; +export type SettingsSection = + | "project" + | "workspace" + | "appearance" + | "keyboard"; interface AppState { currentView: AppView; @@ -20,7 +24,7 @@ export const useAppStore = create()( (set) => ({ currentView: "workspace", isSettingsTabOpen: false, - settingsSection: "workspace", + settingsSection: "project", setView: (view) => { set({ currentView: view }); From 48dd4d25e238512ba2ba8cd2d17948ea1f789945 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:29:41 -0800 Subject: [PATCH 4/9] refactor(desktop): move projects under General section in settings sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../SettingsView/SettingsSidebar.tsx | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx index d354a68d51e..c543a984c85 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx @@ -85,13 +85,31 @@ export function SettingsSidebar({ {/* Settings title */}

Settings

- {/* Projects & Workspaces */}
+ {/* General Settings */}

- Projects + General

- - {/* General Settings */} -
-

- General -

- -
); From b97efc794f6db2b9be747ab2fa5029488c9dd498 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:31:16 -0800 Subject: [PATCH 5/9] refactor(desktop): click project for settings, chevron for expand/collapse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Clicking project name now opens project settings directly - Separate chevron button handles expand/collapse of workspaces - Removed "Project Settings" child item 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../SettingsView/SettingsSidebar.tsx | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx index c543a984c85..1ec826bd04d 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx @@ -4,7 +4,6 @@ import { HiArrowLeft, HiChevronDown, HiChevronRight, - HiOutlineCog6Tooth, HiOutlineCommandLine, HiOutlinePaintBrush, } from "react-icons/hi2"; @@ -113,47 +112,50 @@ export function SettingsSidebar({ {groups.map((group) => (
{/* Project header */} - +
+ + +
- {/* Project Settings & Workspaces */} + {/* Workspaces */} {expandedProjects.has(group.project.id) && (
- {/* Project Settings */} - - - {/* Workspaces */} {group.workspaces.map((workspace) => ( ))} - - {/* Projects under General */} - {groups.map((group) => ( -
- {/* Project header */} -
- - -
- - {/* Workspaces */} - {expandedProjects.has(group.project.id) && ( -
- {group.workspaces.map((workspace) => ( - - ))} -
- )} -
- ))}
+ + {/* Projects */} + {groups.length > 0 && ( +
+

+ Projects +

+ +
+ )}
); From b77432075e454e58a237c4bb4c38bba4670af821 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:41:10 -0800 Subject: [PATCH 7/9] feat(desktop): expand all projects by default in settings sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../main/components/SettingsView/SettingsSidebar.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx index 356995a017b..686891c67bf 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx @@ -1,5 +1,5 @@ import { cn } from "@superset/ui/utils"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { HiArrowLeft, HiChevronDown, @@ -42,10 +42,16 @@ export function SettingsSidebar({ const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); const setActiveWorkspace = useSetActiveWorkspace(); const [expandedProjects, setExpandedProjects] = useState>( - () => - new Set(activeWorkspace?.projectId ? [activeWorkspace.projectId] : []), + new Set(), ); + // Expand all projects by default when groups are loaded + useEffect(() => { + if (groups.length > 0) { + setExpandedProjects(new Set(groups.map((g) => g.project.id))); + } + }, [groups]); + const toggleProject = (projectId: string) => { setExpandedProjects((prev) => { const next = new Set(prev); From 22d2ef3c82e2acd20bc8670f199968e59844d74d Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:53:51 -0800 Subject: [PATCH 8/9] refactor --- .../SettingsView/AppearanceSettings.tsx | 2 +- .../SettingsView/SettingsSidebar.tsx | 199 ------------------ .../{components/ThemeCard => }/ThemeCard.tsx | 0 .../components/ThemeCard/index.ts | 1 - 4 files changed, 1 insertion(+), 201 deletions(-) delete mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx rename apps/desktop/src/renderer/screens/main/components/SettingsView/{components/ThemeCard => }/ThemeCard.tsx (100%) delete mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/index.ts diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/AppearanceSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/AppearanceSettings.tsx index 4360f633cce..f1ce6cf41e1 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/AppearanceSettings.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/AppearanceSettings.tsx @@ -1,6 +1,6 @@ import { useSetTheme, useThemeId, useThemeStore } from "renderer/stores"; import { builtInThemes } from "shared/themes"; -import { ThemeCard } from "./components/ThemeCard"; +import { ThemeCard } from "./ThemeCard"; export function AppearanceSettings() { const activeThemeId = useThemeId(); diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx deleted file mode 100644 index 686891c67bf..00000000000 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { cn } from "@superset/ui/utils"; -import { useEffect, useState } from "react"; -import { - HiArrowLeft, - HiChevronDown, - HiChevronRight, - HiOutlineCommandLine, - HiOutlinePaintBrush, -} from "react-icons/hi2"; -import { trpc } from "renderer/lib/trpc"; -import { useSetActiveWorkspace } from "renderer/react-query/workspaces"; -import { type SettingsSection, useCloseSettings } from "renderer/stores"; - -interface SettingsSidebarProps { - activeSection: SettingsSection; - onSectionChange: (section: SettingsSection) => void; -} - -const GENERAL_SECTIONS: { - id: SettingsSection; - label: string; - icon: React.ReactNode; -}[] = [ - { - id: "appearance", - label: "Appearance", - icon: , - }, - { - id: "keyboard", - label: "Keyboard Shortcuts", - icon: , - }, -]; - -export function SettingsSidebar({ - activeSection, - onSectionChange, -}: SettingsSidebarProps) { - const closeSettings = useCloseSettings(); - const { data: groups = [] } = trpc.workspaces.getAllGrouped.useQuery(); - const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); - const setActiveWorkspace = useSetActiveWorkspace(); - const [expandedProjects, setExpandedProjects] = useState>( - new Set(), - ); - - // Expand all projects by default when groups are loaded - useEffect(() => { - if (groups.length > 0) { - setExpandedProjects(new Set(groups.map((g) => g.project.id))); - } - }, [groups]); - - const toggleProject = (projectId: string) => { - setExpandedProjects((prev) => { - const next = new Set(prev); - if (next.has(projectId)) { - next.delete(projectId); - } else { - next.add(projectId); - } - return next; - }); - }; - - const handleProjectClick = (workspaceId: string) => { - // Set a workspace from this project as active to show project settings - setActiveWorkspace.mutate({ id: workspaceId }); - onSectionChange("project"); - }; - - const handleWorkspaceClick = (workspaceId: string) => { - setActiveWorkspace.mutate({ id: workspaceId }); - onSectionChange("workspace"); - }; - - return ( -
- {/* Back button */} - - - {/* Settings title */} -

Settings

- -
- {/* General Settings */} -
-

- General -

- -
- - {/* Projects */} - {groups.length > 0 && ( -
-

- Projects -

- -
- )} -
-
- ); -} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/ThemeCard.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/ThemeCard.tsx similarity index 100% rename from apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/ThemeCard.tsx rename to apps/desktop/src/renderer/screens/main/components/SettingsView/ThemeCard.tsx diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/index.ts b/apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/index.ts deleted file mode 100644 index 64e6196ee95..00000000000 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/components/ThemeCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ThemeCard } from "./ThemeCard"; From 4d49af519957b9f72ae10166d2784c1cf65d2712 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 2 Dec 2025 17:59:25 -0800 Subject: [PATCH 9/9] fix refactor --- .../SettingsSidebar/GeneralSettings.tsx | 56 ++++++++ .../SettingsSidebar/ProjectsSettings.tsx | 134 ++++++++++++++++++ .../SettingsSidebar/SettingsSidebar.tsx | 44 ++++++ .../SettingsView/SettingsSidebar/index.ts | 1 + .../WorkspaceSettings/WorkspaceSettings.tsx | 17 ++- 5 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/GeneralSettings.tsx create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/ProjectsSettings.tsx create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/SettingsSidebar.tsx create mode 100644 apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/index.ts diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/GeneralSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/GeneralSettings.tsx new file mode 100644 index 00000000000..5224783eb99 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/GeneralSettings.tsx @@ -0,0 +1,56 @@ +import { cn } from "@superset/ui/utils"; +import { HiOutlineCommandLine, HiOutlinePaintBrush } from "react-icons/hi2"; +import type { SettingsSection } from "renderer/stores"; + +interface GeneralSettingsProps { + activeSection: SettingsSection; + onSectionChange: (section: SettingsSection) => void; +} + +const GENERAL_SECTIONS: { + id: SettingsSection; + label: string; + icon: React.ReactNode; +}[] = [ + { + id: "appearance", + label: "Appearance", + icon: , + }, + { + id: "keyboard", + label: "Keyboard Shortcuts", + icon: , + }, +]; + +export function GeneralSettings({ + activeSection, + onSectionChange, +}: GeneralSettingsProps) { + return ( +
+

+ General +

+ +
+ ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/ProjectsSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/ProjectsSettings.tsx new file mode 100644 index 00000000000..ced9cc67b69 --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/ProjectsSettings.tsx @@ -0,0 +1,134 @@ +import { cn } from "@superset/ui/utils"; +import { useEffect, useState } from "react"; +import { HiChevronDown, HiChevronRight } from "react-icons/hi2"; +import { trpc } from "renderer/lib/trpc"; +import { useSetActiveWorkspace } from "renderer/react-query/workspaces"; +import type { SettingsSection } from "renderer/stores"; + +interface ProjectsSettingsProps { + activeSection: SettingsSection; + onSectionChange: (section: SettingsSection) => void; +} + +export function ProjectsSettings({ + activeSection, + onSectionChange, +}: ProjectsSettingsProps) { + const { data: groups = [] } = trpc.workspaces.getAllGrouped.useQuery(); + const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); + const setActiveWorkspace = useSetActiveWorkspace(); + const [expandedProjects, setExpandedProjects] = useState>( + new Set(), + ); + + // Expand all projects by default when groups are loaded + useEffect(() => { + if (groups.length > 0) { + setExpandedProjects(new Set(groups.map((g) => g.project.id))); + } + }, [groups]); + + const toggleProject = (projectId: string) => { + setExpandedProjects((prev) => { + const next = new Set(prev); + if (next.has(projectId)) { + next.delete(projectId); + } else { + next.add(projectId); + } + return next; + }); + }; + + const handleProjectClick = (workspaceId: string) => { + // Set a workspace from this project as active to show project settings + setActiveWorkspace.mutate({ id: workspaceId }); + onSectionChange("project"); + }; + + const handleWorkspaceClick = (workspaceId: string) => { + setActiveWorkspace.mutate({ id: workspaceId }); + onSectionChange("workspace"); + }; + + if (groups.length === 0) { + return null; + } + + return ( +
+

+ Projects +

+ +
+ ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/SettingsSidebar.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/SettingsSidebar.tsx new file mode 100644 index 00000000000..faf5413d66b --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/SettingsSidebar.tsx @@ -0,0 +1,44 @@ +import { HiArrowLeft } from "react-icons/hi2"; +import { type SettingsSection, useCloseSettings } from "renderer/stores"; +import { GeneralSettings } from "./GeneralSettings"; +import { ProjectsSettings } from "./ProjectsSettings"; + +interface SettingsSidebarProps { + activeSection: SettingsSection; + onSectionChange: (section: SettingsSection) => void; +} + +export function SettingsSidebar({ + activeSection, + onSectionChange, +}: SettingsSidebarProps) { + const closeSettings = useCloseSettings(); + + return ( +
+ {/* Back button */} + + + {/* Settings title */} +

Settings

+ +
+ + +
+
+ ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/index.ts b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/index.ts new file mode 100644 index 00000000000..e2563f91cfc --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/SettingsSidebar/index.ts @@ -0,0 +1 @@ +export { SettingsSidebar } from "./SettingsSidebar"; diff --git a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx index 9108ab5667a..1a3a7ac954d 100644 --- a/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx +++ b/apps/desktop/src/renderer/screens/main/components/SettingsView/WorkspaceSettings/WorkspaceSettings.tsx @@ -45,7 +45,12 @@ export function WorkspaceSettings() {
-

Name

+

+ Name +

{rename.isRenaming ? ( rename.setRenameValue(e.target.value)} onBlur={rename.submitRename} - onKeyDown={rename.handleKeyDown} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + e.currentTarget.blur(); + } else { + rename.handleKeyDown(e); + } + }} + aria-labelledby="workspace-name-label" className="text-base" /> ) : (