diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2OpenInMenuButton/V2OpenInMenuButton.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2OpenInMenuButton/V2OpenInMenuButton.tsx index 2e1091ec1f8..d7c94dac4e3 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2OpenInMenuButton/V2OpenInMenuButton.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2OpenInMenuButton/V2OpenInMenuButton.tsx @@ -8,7 +8,9 @@ import { import { toast } from "@superset/ui/sonner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { cn } from "@superset/ui/utils"; -import { useCallback, useMemo, useState } from "react"; +import { eq } from "@tanstack/db"; +import { useLiveQuery } from "@tanstack/react-db"; +import { useCallback, useMemo } from "react"; import { HiChevronDown } from "react-icons/hi2"; import { getAppOption, @@ -16,41 +18,49 @@ import { } from "renderer/components/OpenInExternalDropdown"; import { HotkeyLabel, useHotkey, useHotkeyDisplay } from "renderer/hotkeys"; import { electronTrpc } from "renderer/lib/electron-trpc"; +import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState"; import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider"; import { useThemeStore } from "renderer/stores"; interface V2OpenInMenuButtonProps { worktreePath: string; branch: string; - workspaceId: string; + projectId: string; } export function V2OpenInMenuButton({ worktreePath, branch, - workspaceId, + projectId, }: V2OpenInMenuButtonProps) { const collections = useCollections(); + const { ensureProjectInSidebar } = useDashboardSidebarState(); const activeTheme = useThemeStore((state) => state.activeTheme); - const localState = collections.v2WorkspaceLocalState.get(workspaceId); - const [defaultApp, setDefaultApp] = useState( - (localState?.defaultOpenInApp as ExternalApp) ?? "finder", + const { data: sidebarProjectRows = [] } = useLiveQuery( + (q) => + q + .from({ sp: collections.v2SidebarProjects }) + .where(({ sp }) => eq(sp.projectId, projectId)) + .select(({ sp }) => ({ defaultOpenInApp: sp.defaultOpenInApp })), + [collections, projectId], ); + const resolvedApp: ExternalApp = + (sidebarProjectRows[0]?.defaultOpenInApp as ExternalApp | null) ?? "finder"; - const handleDefaultAppChange = useCallback( + const persistDefaultApp = useCallback( (app: ExternalApp) => { - setDefaultApp(app); - collections.v2WorkspaceLocalState.update(workspaceId, (draft) => { + ensureProjectInSidebar(projectId); + collections.v2SidebarProjects.update(projectId, (draft) => { draft.defaultOpenInApp = app; }); }, - [collections, workspaceId], + [collections, ensureProjectInSidebar, projectId], ); const openInApp = electronTrpc.external.openInApp.useMutation({ onSuccess: (_data, variables) => { - handleDefaultAppChange(variables.app); + persistDefaultApp(variables.app); }, onError: (error) => toast.error(`Failed to open: ${error.message}`), }); @@ -60,8 +70,8 @@ export function V2OpenInMenuButton({ }); const currentApp = useMemo( - () => getAppOption(defaultApp) ?? null, - [defaultApp], + () => getAppOption(resolvedApp) ?? null, + [resolvedApp], ); const openInDisplay = useHotkeyDisplay("OPEN_IN_APP"); const copyPathDisplay = useHotkeyDisplay("COPY_PATH"); @@ -72,8 +82,8 @@ export function V2OpenInMenuButton({ const handleOpenInEditor = useCallback(() => { if (openInApp.isPending || copyPath.isPending) return; - openInApp.mutate({ path: worktreePath, app: defaultApp }); - }, [worktreePath, defaultApp, openInApp, copyPath.isPending]); + openInApp.mutate({ path: worktreePath, app: resolvedApp }); + }, [worktreePath, resolvedApp, openInApp, copyPath.isPending]); const handleOpenInOtherApp = useCallback( (appId: ExternalApp) => { @@ -162,12 +172,12 @@ export function V2OpenInMenuButton({ { if ( - appId !== defaultApp || + appId !== resolvedApp || !showOpenInShortcut || group === "jetbrains" ) { diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2WorkspaceOpenInButton/V2WorkspaceOpenInButton.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2WorkspaceOpenInButton/V2WorkspaceOpenInButton.tsx index 269367c3ada..eab12edd4d6 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2WorkspaceOpenInButton/V2WorkspaceOpenInButton.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/V2WorkspaceOpenInButton/V2WorkspaceOpenInButton.tsx @@ -27,6 +27,7 @@ export function V2WorkspaceOpenInButton({ .select(({ workspaces, hosts }) => ({ id: workspaces.id, branch: workspaces.branch, + projectId: workspaces.projectId, hostMachineId: hosts?.machineId ?? null, })), [collections, workspaceId], @@ -56,7 +57,7 @@ export function V2WorkspaceOpenInButton({ ); } diff --git a/apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts b/apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts index c42fcaaae96..4ed51e6103d 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts @@ -10,6 +10,7 @@ export const dashboardSidebarProjectSchema = z.object({ createdAt: persistedDateSchema, isCollapsed: z.boolean().default(false), tabOrder: z.number().int().default(0), + defaultOpenInApp: z.string().nullable().default(null), }); const paneWorkspaceStateSchema = z.custom>(); @@ -39,7 +40,6 @@ export const workspaceLocalStateSchema = z.object({ }), paneLayout: paneWorkspaceStateSchema, rightSidebarOpen: z.boolean().default(false), - defaultOpenInApp: z.string().nullable().default(null), viewedFiles: z.array(z.string()).default([]), });