diff --git a/src/App.tsx b/src/App.tsx
index 2f428ea9e..796a7378b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -91,6 +91,7 @@ function MainApp() {
connectWorkspace,
markWorkspaceConnected,
updateWorkspaceSettings,
+ removeWorkspace,
hasLoaded,
refreshWorkspaces,
} = useWorkspaces({ onDebug: addDebugEntry });
@@ -355,6 +356,9 @@ function MainApp() {
onDeleteThread={(workspaceId, threadId) => {
removeThread(workspaceId, threadId);
}}
+ onDeleteWorkspace={(workspaceId) => {
+ void removeWorkspace(workspaceId);
+ }}
/>
void;
onSelectThread: (workspaceId: string, threadId: string) => void;
onDeleteThread: (workspaceId: string, threadId: string) => void;
+ onDeleteWorkspace: (workspaceId: string) => void;
};
export function Sidebar({
@@ -41,6 +42,7 @@ export function Sidebar({
onToggleWorkspaceCollapse,
onSelectThread,
onDeleteThread,
+ onDeleteWorkspace,
}: SidebarProps) {
const [expandedWorkspaces, setExpandedWorkspaces] = useState(
new Set(),
@@ -69,6 +71,22 @@ export function Sidebar({
await menu.popup(position, window);
}
+ async function showWorkspaceMenu(
+ event: React.MouseEvent,
+ workspaceId: string,
+ ) {
+ event.preventDefault();
+ event.stopPropagation();
+ const deleteItem = await MenuItem.new({
+ text: "Delete",
+ action: () => onDeleteWorkspace(workspaceId),
+ });
+ const menu = await Menu.new({ items: [deleteItem] });
+ const window = getCurrentWindow();
+ const position = new LogicalPosition(event.clientX, event.clientY);
+ await menu.popup(position, window);
+ }
+
const usagePercent = accountRateLimits?.primary?.usedPercent;
const globalUsagePercent = accountRateLimits?.secondary?.usedPercent;
const credits = accountRateLimits?.credits ?? null;
@@ -150,6 +168,7 @@ export function Sidebar({
role="button"
tabIndex={0}
onClick={() => onSelectWorkspace(entry.id)}
+ onContextMenu={(event) => showWorkspaceMenu(event, entry.id)}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
diff --git a/src/hooks/useWorkspaces.ts b/src/hooks/useWorkspaces.ts
index a7e061621..460185da2 100644
--- a/src/hooks/useWorkspaces.ts
+++ b/src/hooks/useWorkspaces.ts
@@ -1,11 +1,13 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import type { DebugEntry } from "../types";
import type { WorkspaceInfo, WorkspaceSettings } from "../types";
+import { ask } from "@tauri-apps/plugin-dialog";
import {
addWorkspace as addWorkspaceService,
connectWorkspace as connectWorkspaceService,
listWorkspaces,
pickWorkspacePath,
+ removeWorkspace as removeWorkspaceService,
updateWorkspaceSettings as updateWorkspaceSettingsService,
} from "../services/tauri";
@@ -149,6 +151,48 @@ export function useWorkspaces(options: UseWorkspacesOptions = {}) {
}
}
+ async function removeWorkspace(workspaceId: string) {
+ const workspace = workspaces.find((entry) => entry.id === workspaceId);
+ const workspaceName = workspace?.name || "this workspace";
+
+ const confirmed = await ask(
+ `Are you sure you want to delete "${workspaceName}"?\n\nThis will remove the workspace from CodexMonitor.`,
+ {
+ title: "Delete Workspace",
+ kind: "warning",
+ okLabel: "Delete",
+ cancelLabel: "Cancel",
+ },
+ );
+
+ if (!confirmed) {
+ return;
+ }
+
+ onDebug?.({
+ id: `${Date.now()}-client-remove-workspace`,
+ timestamp: Date.now(),
+ source: "client",
+ label: "workspace/remove",
+ payload: { workspaceId },
+ });
+ try {
+ await removeWorkspaceService(workspaceId);
+ setWorkspaces((prev) => prev.filter((entry) => entry.id !== workspaceId));
+ setActiveWorkspaceId((prev) => (prev === workspaceId ? null : prev));
+ await refreshWorkspaces();
+ } catch (error) {
+ onDebug?.({
+ id: `${Date.now()}-client-remove-workspace-error`,
+ timestamp: Date.now(),
+ source: "error",
+ label: "workspace/remove error",
+ payload: error instanceof Error ? error.message : String(error),
+ });
+ throw error;
+ }
+ }
+
return {
workspaces,
activeWorkspace,
@@ -158,6 +202,7 @@ export function useWorkspaces(options: UseWorkspacesOptions = {}) {
connectWorkspace,
markWorkspaceConnected,
updateWorkspaceSettings,
+ removeWorkspace,
hasLoaded,
refreshWorkspaces,
};
diff --git a/src/services/tauri.ts b/src/services/tauri.ts
index de9146b28..ad279273f 100644
--- a/src/services/tauri.ts
+++ b/src/services/tauri.ts
@@ -29,6 +29,10 @@ export async function updateWorkspaceSettings(
return invoke("update_workspace_settings", { id, settings });
}
+export async function removeWorkspace(id: string): Promise {
+ return invoke("remove_workspace", { id });
+}
+
export async function connectWorkspace(id: string): Promise {
return invoke("connect_workspace", { id });
}