diff --git a/apps/desktop/src/lib/trpc/routers/settings/index.ts b/apps/desktop/src/lib/trpc/routers/settings/index.ts
index 4676a7d9ed9..d9ff55e10b7 100644
--- a/apps/desktop/src/lib/trpc/routers/settings/index.ts
+++ b/apps/desktop/src/lib/trpc/routers/settings/index.ts
@@ -1,6 +1,7 @@
import {
BRANCH_PREFIX_MODES,
EXECUTION_MODES,
+ FILE_OPEN_MODES,
settings,
TERMINAL_LINK_BEHAVIORS,
type TerminalPreset,
@@ -12,6 +13,7 @@ import { localDb } from "main/lib/local-db";
import {
DEFAULT_AUTO_APPLY_DEFAULT_PRESET,
DEFAULT_CONFIRM_ON_QUIT,
+ DEFAULT_FILE_OPEN_MODE,
DEFAULT_TERMINAL_LINK_BEHAVIOR,
} from "shared/constants";
import { DEFAULT_RINGTONE_ID, RINGTONES } from "shared/ringtones";
@@ -362,6 +364,26 @@ export const createSettingsRouter = () => {
return { success: true };
}),
+ getFileOpenMode: publicProcedure.query(() => {
+ const row = getSettings();
+ return row.fileOpenMode ?? DEFAULT_FILE_OPEN_MODE;
+ }),
+
+ setFileOpenMode: publicProcedure
+ .input(z.object({ mode: z.enum(FILE_OPEN_MODES) }))
+ .mutation(({ input }) => {
+ localDb
+ .insert(settings)
+ .values({ id: 1, fileOpenMode: input.mode })
+ .onConflictDoUpdate({
+ target: settings.id,
+ set: { fileOpenMode: input.mode },
+ })
+ .run();
+
+ return { success: true };
+ }),
+
getAutoApplyDefaultPreset: publicProcedure.query(() => {
const row = getSettings();
return row.autoApplyDefaultPreset ?? DEFAULT_AUTO_APPLY_DEFAULT_PRESET;
diff --git a/apps/desktop/src/renderer/hooks/useFileOpenMode/index.ts b/apps/desktop/src/renderer/hooks/useFileOpenMode/index.ts
new file mode 100644
index 00000000000..9c7ae61741c
--- /dev/null
+++ b/apps/desktop/src/renderer/hooks/useFileOpenMode/index.ts
@@ -0,0 +1 @@
+export { useFileOpenMode } from "./useFileOpenMode";
diff --git a/apps/desktop/src/renderer/hooks/useFileOpenMode/useFileOpenMode.ts b/apps/desktop/src/renderer/hooks/useFileOpenMode/useFileOpenMode.ts
new file mode 100644
index 00000000000..e0c31713af7
--- /dev/null
+++ b/apps/desktop/src/renderer/hooks/useFileOpenMode/useFileOpenMode.ts
@@ -0,0 +1,6 @@
+import { electronTrpc } from "renderer/lib/electron-trpc";
+
+export function useFileOpenMode() {
+ const { data } = electronTrpc.settings.getFileOpenMode.useQuery();
+ return data ?? "split-pane";
+}
diff --git a/apps/desktop/src/renderer/routes/_authenticated/settings/behavior/components/BehaviorSettings/BehaviorSettings.tsx b/apps/desktop/src/renderer/routes/_authenticated/settings/behavior/components/BehaviorSettings/BehaviorSettings.tsx
index f28e73c8ef1..81b9846a302 100644
--- a/apps/desktop/src/renderer/routes/_authenticated/settings/behavior/components/BehaviorSettings/BehaviorSettings.tsx
+++ b/apps/desktop/src/renderer/routes/_authenticated/settings/behavior/components/BehaviorSettings/BehaviorSettings.tsx
@@ -1,4 +1,4 @@
-import type { BranchPrefixMode } from "@superset/local-db";
+import type { BranchPrefixMode, FileOpenMode } from "@superset/local-db";
import { Input } from "@superset/ui/input";
import { Label } from "@superset/ui/label";
import {
@@ -40,6 +40,10 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
SETTING_ITEM_ID.BEHAVIOR_TELEMETRY,
visibleItems,
);
+ const showFileOpenMode = isItemVisible(
+ SETTING_ITEM_ID.BEHAVIOR_FILE_OPEN_MODE,
+ visibleItems,
+ );
const utils = electronTrpc.useUtils();
@@ -160,6 +164,25 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
});
};
+ const { data: fileOpenMode, isLoading: isFileOpenModeLoading } =
+ electronTrpc.settings.getFileOpenMode.useQuery();
+ const setFileOpenMode = electronTrpc.settings.setFileOpenMode.useMutation({
+ onMutate: async ({ mode }) => {
+ await utils.settings.getFileOpenMode.cancel();
+ const previous = utils.settings.getFileOpenMode.getData();
+ utils.settings.getFileOpenMode.setData(undefined, mode);
+ return { previous };
+ },
+ onError: (_err, _vars, context) => {
+ if (context?.previous !== undefined) {
+ utils.settings.getFileOpenMode.setData(undefined, context.previous);
+ }
+ },
+ onSettled: () => {
+ utils.settings.getFileOpenMode.invalidate();
+ },
+ });
+
const previewPrefix =
resolveBranchPrefix({
mode: branchPrefix?.mode ?? "none",
@@ -276,6 +299,32 @@ export function BehaviorSettings({ visibleItems }: BehaviorSettingsProps) {
)}
+ {showFileOpenMode && (
+
diff --git a/apps/desktop/src/renderer/routes/_authenticated/settings/utils/settings-search/settings-search.ts b/apps/desktop/src/renderer/routes/_authenticated/settings/utils/settings-search/settings-search.ts
index cb611ce0951..b69f8c9093e 100644
--- a/apps/desktop/src/renderer/routes/_authenticated/settings/utils/settings-search/settings-search.ts
+++ b/apps/desktop/src/renderer/routes/_authenticated/settings/utils/settings-search/settings-search.ts
@@ -24,6 +24,7 @@ export const SETTING_ITEM_ID = {
BEHAVIOR_DELETE_LOCAL_BRANCH: "behavior-delete-local-branch",
BEHAVIOR_BRANCH_PREFIX: "behavior-branch-prefix",
BEHAVIOR_TELEMETRY: "behavior-telemetry",
+ BEHAVIOR_FILE_OPEN_MODE: "behavior-file-open-mode",
TERMINAL_PRESETS: "terminal-presets",
TERMINAL_QUICK_ADD: "terminal-quick-add",
@@ -364,6 +365,25 @@ export const SETTINGS_ITEMS: SettingsItem[] = [
"disable",
],
},
+ {
+ id: SETTING_ITEM_ID.BEHAVIOR_FILE_OPEN_MODE,
+ section: "behavior",
+ title: "File open mode",
+ description:
+ "Choose how files open when clicked in the file tree or changes view",
+ keywords: [
+ "file",
+ "open",
+ "mode",
+ "split",
+ "pane",
+ "tab",
+ "new tab",
+ "split pane",
+ "viewer",
+ "behavior",
+ ],
+ },
{
id: SETTING_ITEM_ID.TERMINAL_PRESETS,
section: "terminal",
diff --git a/apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx b/apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
index 034c42ec157..b6f640764f6 100644
--- a/apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
+++ b/apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
@@ -5,6 +5,7 @@ import { useParams } from "@tanstack/react-router";
import { useCallback } from "react";
import { LuDiff } from "react-icons/lu";
import { HotkeyTooltipContent } from "renderer/components/HotkeyTooltipContent";
+import { useFileOpenMode } from "renderer/hooks/useFileOpenMode";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { useSidebarStore } from "renderer/stores";
import { useChangesStore } from "renderer/stores/changes";
@@ -46,6 +47,7 @@ export function SidebarControl() {
);
const addFileViewerPane = useTabsStore((s) => s.addFileViewerPane);
+ const fileOpenMode = useFileOpenMode();
const trpcUtils = electronTrpc.useUtils();
const invalidateFileContent = useCallback(
@@ -92,6 +94,7 @@ export function SidebarControl() {
diffCategory: category,
oldPath: firstFile.oldPath,
isPinned: false,
+ openInNewTab: fileOpenMode === "new-tab",
});
invalidateFileContent(firstFile.path);
}
@@ -102,6 +105,7 @@ export function SidebarControl() {
selectFile,
addFileViewerPane,
invalidateFileContent,
+ fileOpenMode,
]);
const handleClick = useCallback(() => {
diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useFileLinkClick.ts b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useFileLinkClick.ts
index e1fdc40edb4..04c1beaa04b 100644
--- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useFileLinkClick.ts
+++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useFileLinkClick.ts
@@ -1,5 +1,6 @@
import { toast } from "@superset/ui/sonner";
import { useCallback } from "react";
+import { useFileOpenMode } from "renderer/hooks/useFileOpenMode";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { electronTrpcClient as trpcClient } from "renderer/lib/trpc-client";
import { useTabsStore } from "renderer/stores/tabs/store";
@@ -25,6 +26,7 @@ export function useFileLinkClick({
workspaceCwd,
}: UseFileLinkClickOptions): UseFileLinkClickReturn {
const addFileViewerPane = useTabsStore((s) => s.addFileViewerPane);
+ const fileOpenMode = useFileOpenMode();
// Query terminal link behavior setting
const { data: terminalLinkBehavior } =
@@ -85,12 +87,23 @@ export function useFileLinkClick({
});
return;
}
- addFileViewerPane(workspaceId, { filePath, line, column });
+ addFileViewerPane(workspaceId, {
+ filePath,
+ line,
+ column,
+ openInNewTab: fileOpenMode === "new-tab",
+ });
} else {
openInExternalEditor();
}
},
- [terminalLinkBehavior, workspaceId, workspaceCwd, addFileViewerPane],
+ [
+ terminalLinkBehavior,
+ workspaceId,
+ workspaceCwd,
+ addFileViewerPane,
+ fileOpenMode,
+ ],
);
return {
diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/FilesView/FilesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/FilesView/FilesView.tsx
index a7f288e1075..49ddbf20d16 100644
--- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/FilesView/FilesView.tsx
+++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/FilesView/FilesView.tsx
@@ -14,6 +14,7 @@ import {
import { useParams } from "@tanstack/react-router";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { LuFile, LuFolder } from "react-icons/lu";
+import { useFileOpenMode } from "renderer/hooks/useFileOpenMode";
import { electronTrpc } from "renderer/lib/electron-trpc";
import { useFileExplorerStore } from "renderer/stores/file-explorer";
import { useTabsStore } from "renderer/stores/tabs/store";
@@ -148,6 +149,7 @@ export function FilesView() {
});
const addFileViewerPane = useTabsStore((s) => s.addFileViewerPane);
+ const fileOpenMode = useFileOpenMode();
const openFileInEditorMutation =
electronTrpc.external.openFileInEditor.useMutation();
@@ -162,9 +164,10 @@ export function FilesView() {
if (!workspaceId || !worktreePath || entry.isDirectory) return;
addFileViewerPane(workspaceId, {
filePath: entry.relativePath,
+ openInNewTab: fileOpenMode === "new-tab",
});
},
- [workspaceId, worktreePath, addFileViewerPane],
+ [workspaceId, worktreePath, addFileViewerPane, fileOpenMode],
);
const handleOpenInEditor = useCallback(
diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/index.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/index.tsx
index 624a9b93bbc..9bad05da004 100644
--- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/index.tsx
+++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/RightSidebar/index.tsx
@@ -11,6 +11,7 @@ import {
LuX,
} from "react-icons/lu";
import { HotkeyTooltipContent } from "renderer/components/HotkeyTooltipContent";
+import { useFileOpenMode } from "renderer/hooks/useFileOpenMode";
import { electronTrpc } from "renderer/lib/electron-trpc";
import {
RightSidebarTab,
@@ -101,6 +102,7 @@ export function RightSidebar() {
};
const addFileViewerPane = useTabsStore((s) => s.addFileViewerPane);
+ const fileOpenMode = useFileOpenMode();
const trpcUtils = electronTrpc.useUtils();
const { scrollToFile } = useScrollContext();
@@ -135,10 +137,17 @@ export function RightSidebar() {
diffCategory: category,
commitHash,
oldPath: file.oldPath,
+ openInNewTab: fileOpenMode === "new-tab",
});
invalidateFileContent(file.path);
},
- [workspaceId, worktreePath, addFileViewerPane, invalidateFileContent],
+ [
+ workspaceId,
+ worktreePath,
+ addFileViewerPane,
+ invalidateFileContent,
+ fileOpenMode,
+ ],
);
const handleFileScrollTo = useCallback(
diff --git a/apps/desktop/src/renderer/stores/tabs/store.ts b/apps/desktop/src/renderer/stores/tabs/store.ts
index a2da770dcaf..8304ebc90d4 100644
--- a/apps/desktop/src/renderer/stores/tabs/store.ts
+++ b/apps/desktop/src/renderer/stores/tabs/store.ts
@@ -682,6 +682,48 @@ export const useTabsStore = create()(
}
// No reusable pane found, create a new one
+ if (options.openInNewTab) {
+ const workspaceId = activeTab.workspaceId;
+ const newTabId = generateId("tab");
+ const newPane = createFileViewerPane(newTabId, options);
+
+ const newTab = {
+ id: newTabId,
+ workspaceId,
+ name: newPane.name,
+ layout: newPane.id as MosaicNode,
+ createdAt: Date.now(),
+ };
+
+ const currentActiveId = state.activeTabIds[workspaceId];
+ const historyStack = state.tabHistoryStacks[workspaceId] || [];
+ const newHistoryStack = currentActiveId
+ ? [
+ currentActiveId,
+ ...historyStack.filter((id) => id !== currentActiveId),
+ ]
+ : historyStack;
+
+ set({
+ tabs: [...state.tabs, newTab],
+ panes: { ...state.panes, [newPane.id]: newPane },
+ activeTabIds: {
+ ...state.activeTabIds,
+ [workspaceId]: newTab.id,
+ },
+ focusedPaneIds: {
+ ...state.focusedPaneIds,
+ [newTab.id]: newPane.id,
+ },
+ tabHistoryStacks: {
+ ...state.tabHistoryStacks,
+ [workspaceId]: newHistoryStack,
+ },
+ });
+
+ return newPane.id;
+ }
+
const newPane = createFileViewerPane(activeTab.id, options);
const newLayout: MosaicNode = {
diff --git a/apps/desktop/src/renderer/stores/tabs/types.ts b/apps/desktop/src/renderer/stores/tabs/types.ts
index d0cd41fd981..3870758c7cb 100644
--- a/apps/desktop/src/renderer/stores/tabs/types.ts
+++ b/apps/desktop/src/renderer/stores/tabs/types.ts
@@ -57,6 +57,8 @@ export interface AddFileViewerPaneOptions {
column?: number;
/** If true, opens pinned (permanent). If false/undefined, opens in preview mode (can be replaced) */
isPinned?: boolean;
+ /** If true, opens in a new tab instead of splitting the current tab */
+ openInNewTab?: boolean;
}
/**
diff --git a/apps/desktop/src/shared/constants.ts b/apps/desktop/src/shared/constants.ts
index 2eadec60637..c6186fc627b 100644
--- a/apps/desktop/src/shared/constants.ts
+++ b/apps/desktop/src/shared/constants.ts
@@ -53,6 +53,7 @@ export const MOCK_ORG_ID = "mock-org-id";
// Default user preference values
export const DEFAULT_CONFIRM_ON_QUIT = true;
export const DEFAULT_TERMINAL_LINK_BEHAVIOR = "external-editor" as const;
+export const DEFAULT_FILE_OPEN_MODE = "split-pane" as const;
export const DEFAULT_AUTO_APPLY_DEFAULT_PRESET = true;
export const DEFAULT_TELEMETRY_ENABLED = true;
diff --git a/packages/local-db/drizzle/0020_add_file_open_mode_setting.sql b/packages/local-db/drizzle/0020_add_file_open_mode_setting.sql
new file mode 100644
index 00000000000..1866465ce0e
--- /dev/null
+++ b/packages/local-db/drizzle/0020_add_file_open_mode_setting.sql
@@ -0,0 +1 @@
+ALTER TABLE `settings` ADD `file_open_mode` text;
\ No newline at end of file
diff --git a/packages/local-db/drizzle/meta/0020_snapshot.json b/packages/local-db/drizzle/meta/0020_snapshot.json
new file mode 100644
index 00000000000..be74644589f
--- /dev/null
+++ b/packages/local-db/drizzle/meta/0020_snapshot.json
@@ -0,0 +1,1078 @@
+{
+ "version": "6",
+ "dialect": "sqlite",
+ "id": "3ff0af35-7fc1-4e36-8012-b113e7a91372",
+ "prevId": "732c942c-5f01-451f-a6cf-92c38b434076",
+ "tables": {
+ "organization_members": {
+ "name": "organization_members",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "organization_members_organization_id_idx": {
+ "name": "organization_members_organization_id_idx",
+ "columns": [
+ "organization_id"
+ ],
+ "isUnique": false
+ },
+ "organization_members_user_id_idx": {
+ "name": "organization_members_user_id_idx",
+ "columns": [
+ "user_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "organization_members_organization_id_organizations_id_fk": {
+ "name": "organization_members_organization_id_organizations_id_fk",
+ "tableFrom": "organization_members",
+ "tableTo": "organizations",
+ "columnsFrom": [
+ "organization_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "organization_members_user_id_users_id_fk": {
+ "name": "organization_members_user_id_users_id_fk",
+ "tableFrom": "organization_members",
+ "tableTo": "users",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "organizations": {
+ "name": "organizations",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "clerk_org_id": {
+ "name": "clerk_org_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "github_org": {
+ "name": "github_org",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "avatar_url": {
+ "name": "avatar_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "organizations_clerk_org_id_unique": {
+ "name": "organizations_clerk_org_id_unique",
+ "columns": [
+ "clerk_org_id"
+ ],
+ "isUnique": true
+ },
+ "organizations_slug_unique": {
+ "name": "organizations_slug_unique",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": true
+ },
+ "organizations_slug_idx": {
+ "name": "organizations_slug_idx",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": false
+ },
+ "organizations_clerk_org_id_idx": {
+ "name": "organizations_clerk_org_id_idx",
+ "columns": [
+ "clerk_org_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "projects": {
+ "name": "projects",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "main_repo_path": {
+ "name": "main_repo_path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "color": {
+ "name": "color",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "tab_order": {
+ "name": "tab_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_opened_at": {
+ "name": "last_opened_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "config_toast_dismissed": {
+ "name": "config_toast_dismissed",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "default_branch": {
+ "name": "default_branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "github_owner": {
+ "name": "github_owner",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "branch_prefix_mode": {
+ "name": "branch_prefix_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "branch_prefix_custom": {
+ "name": "branch_prefix_custom",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "hide_image": {
+ "name": "hide_image",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "projects_main_repo_path_idx": {
+ "name": "projects_main_repo_path_idx",
+ "columns": [
+ "main_repo_path"
+ ],
+ "isUnique": false
+ },
+ "projects_last_opened_at_idx": {
+ "name": "projects_last_opened_at_idx",
+ "columns": [
+ "last_opened_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "settings": {
+ "name": "settings",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false,
+ "default": 1
+ },
+ "last_active_workspace_id": {
+ "name": "last_active_workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_used_app": {
+ "name": "last_used_app",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "terminal_presets": {
+ "name": "terminal_presets",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "terminal_presets_initialized": {
+ "name": "terminal_presets_initialized",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "selected_ringtone_id": {
+ "name": "selected_ringtone_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "active_organization_id": {
+ "name": "active_organization_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "confirm_on_quit": {
+ "name": "confirm_on_quit",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "terminal_link_behavior": {
+ "name": "terminal_link_behavior",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "persist_terminal": {
+ "name": "persist_terminal",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": true
+ },
+ "auto_apply_default_preset": {
+ "name": "auto_apply_default_preset",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "branch_prefix_mode": {
+ "name": "branch_prefix_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "branch_prefix_custom": {
+ "name": "branch_prefix_custom",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "notification_sounds_muted": {
+ "name": "notification_sounds_muted",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "delete_local_branch": {
+ "name": "delete_local_branch",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "file_open_mode": {
+ "name": "file_open_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "tasks": {
+ "name": "tasks",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "status_color": {
+ "name": "status_color",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "status_type": {
+ "name": "status_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "status_position": {
+ "name": "status_position",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "priority": {
+ "name": "priority",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "repository_id": {
+ "name": "repository_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "assignee_id": {
+ "name": "assignee_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "creator_id": {
+ "name": "creator_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "estimate": {
+ "name": "estimate",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "due_date": {
+ "name": "due_date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "labels": {
+ "name": "labels",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "branch": {
+ "name": "branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "pr_url": {
+ "name": "pr_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "external_provider": {
+ "name": "external_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "external_key": {
+ "name": "external_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "external_url": {
+ "name": "external_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "last_synced_at": {
+ "name": "last_synced_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "sync_error": {
+ "name": "sync_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "tasks_slug_unique": {
+ "name": "tasks_slug_unique",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": true
+ },
+ "tasks_slug_idx": {
+ "name": "tasks_slug_idx",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": false
+ },
+ "tasks_organization_id_idx": {
+ "name": "tasks_organization_id_idx",
+ "columns": [
+ "organization_id"
+ ],
+ "isUnique": false
+ },
+ "tasks_assignee_id_idx": {
+ "name": "tasks_assignee_id_idx",
+ "columns": [
+ "assignee_id"
+ ],
+ "isUnique": false
+ },
+ "tasks_status_idx": {
+ "name": "tasks_status_idx",
+ "columns": [
+ "status"
+ ],
+ "isUnique": false
+ },
+ "tasks_created_at_idx": {
+ "name": "tasks_created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "tasks_organization_id_organizations_id_fk": {
+ "name": "tasks_organization_id_organizations_id_fk",
+ "tableFrom": "tasks",
+ "tableTo": "organizations",
+ "columnsFrom": [
+ "organization_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "tasks_assignee_id_users_id_fk": {
+ "name": "tasks_assignee_id_users_id_fk",
+ "tableFrom": "tasks",
+ "tableTo": "users",
+ "columnsFrom": [
+ "assignee_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "tasks_creator_id_users_id_fk": {
+ "name": "tasks_creator_id_users_id_fk",
+ "tableFrom": "tasks",
+ "tableTo": "users",
+ "columnsFrom": [
+ "creator_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "clerk_id": {
+ "name": "clerk_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "avatar_url": {
+ "name": "avatar_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "users_clerk_id_unique": {
+ "name": "users_clerk_id_unique",
+ "columns": [
+ "clerk_id"
+ ],
+ "isUnique": true
+ },
+ "users_email_unique": {
+ "name": "users_email_unique",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ },
+ "users_email_idx": {
+ "name": "users_email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": false
+ },
+ "users_clerk_id_idx": {
+ "name": "users_clerk_id_idx",
+ "columns": [
+ "clerk_id"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "workspaces": {
+ "name": "workspaces",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "project_id": {
+ "name": "project_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "worktree_id": {
+ "name": "worktree_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "branch": {
+ "name": "branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "tab_order": {
+ "name": "tab_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "last_opened_at": {
+ "name": "last_opened_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "is_unread": {
+ "name": "is_unread",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": false
+ },
+ "is_unnamed": {
+ "name": "is_unnamed",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false,
+ "default": false
+ },
+ "deleting_at": {
+ "name": "deleting_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "workspaces_project_id_idx": {
+ "name": "workspaces_project_id_idx",
+ "columns": [
+ "project_id"
+ ],
+ "isUnique": false
+ },
+ "workspaces_worktree_id_idx": {
+ "name": "workspaces_worktree_id_idx",
+ "columns": [
+ "worktree_id"
+ ],
+ "isUnique": false
+ },
+ "workspaces_last_opened_at_idx": {
+ "name": "workspaces_last_opened_at_idx",
+ "columns": [
+ "last_opened_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "workspaces_project_id_projects_id_fk": {
+ "name": "workspaces_project_id_projects_id_fk",
+ "tableFrom": "workspaces",
+ "tableTo": "projects",
+ "columnsFrom": [
+ "project_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "workspaces_worktree_id_worktrees_id_fk": {
+ "name": "workspaces_worktree_id_worktrees_id_fk",
+ "tableFrom": "workspaces",
+ "tableTo": "worktrees",
+ "columnsFrom": [
+ "worktree_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ },
+ "worktrees": {
+ "name": "worktrees",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "project_id": {
+ "name": "project_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "path": {
+ "name": "path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "branch": {
+ "name": "branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "base_branch": {
+ "name": "base_branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "autoincrement": false
+ },
+ "git_status": {
+ "name": "git_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ },
+ "github_status": {
+ "name": "github_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "autoincrement": false
+ }
+ },
+ "indexes": {
+ "worktrees_project_id_idx": {
+ "name": "worktrees_project_id_idx",
+ "columns": [
+ "project_id"
+ ],
+ "isUnique": false
+ },
+ "worktrees_branch_idx": {
+ "name": "worktrees_branch_idx",
+ "columns": [
+ "branch"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "worktrees_project_id_projects_id_fk": {
+ "name": "worktrees_project_id_projects_id_fk",
+ "tableFrom": "worktrees",
+ "tableTo": "projects",
+ "columnsFrom": [
+ "project_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "checkConstraints": {}
+ }
+ },
+ "views": {},
+ "enums": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ },
+ "internal": {
+ "indexes": {}
+ }
+}
\ No newline at end of file
diff --git a/packages/local-db/drizzle/meta/_journal.json b/packages/local-db/drizzle/meta/_journal.json
index d6ac4a2497b..60394526996 100644
--- a/packages/local-db/drizzle/meta/_journal.json
+++ b/packages/local-db/drizzle/meta/_journal.json
@@ -141,6 +141,13 @@
"when": 1770438863796,
"tag": "0019_add_hide_image_to_projects",
"breakpoints": true
+ },
+ {
+ "idx": 20,
+ "version": "6",
+ "when": 1770754481921,
+ "tag": "0020_add_file_open_mode_setting",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/packages/local-db/src/schema/schema.ts b/packages/local-db/src/schema/schema.ts
index 74757311d4d..8ca558f826c 100644
--- a/packages/local-db/src/schema/schema.ts
+++ b/packages/local-db/src/schema/schema.ts
@@ -4,6 +4,7 @@ import { v4 as uuidv4 } from "uuid";
import type {
BranchPrefixMode,
ExternalApp,
+ FileOpenMode,
GitHubStatus,
GitStatus,
TerminalLinkBehavior,
@@ -157,6 +158,7 @@ export const settings = sqliteTable("settings", {
mode: "boolean",
}),
deleteLocalBranch: integer("delete_local_branch", { mode: "boolean" }),
+ fileOpenMode: text("file_open_mode").$type(),
});
export type InsertSettings = typeof settings.$inferInsert;
diff --git a/packages/local-db/src/schema/zod.ts b/packages/local-db/src/schema/zod.ts
index be05a5d5e74..59b1972f32e 100644
--- a/packages/local-db/src/schema/zod.ts
+++ b/packages/local-db/src/schema/zod.ts
@@ -128,3 +128,7 @@ export const BRANCH_PREFIX_MODES = [
] as const;
export type BranchPrefixMode = (typeof BRANCH_PREFIX_MODES)[number];
+
+export const FILE_OPEN_MODES = ["split-pane", "new-tab"] as const;
+
+export type FileOpenMode = (typeof FILE_OPEN_MODES)[number];