diff --git a/apps/web/app/components/sidebar.tsx b/apps/web/app/components/sidebar.tsx index 83c7b15b3b6..c0a6b42dd33 100644 --- a/apps/web/app/components/sidebar.tsx +++ b/apps/web/app/components/sidebar.tsx @@ -351,7 +351,7 @@ export function Sidebar({ const [mainMemory, setMainMemory] = useState(null); const [dailyLogs, setDailyLogs] = useState([]); const [workspaceTree, setWorkspaceTree] = useState([]); - const [activeProfile, setActiveProfile] = useState("default"); + const [activeWorkspace, setActiveWorkspace] = useState(null); const [loading, setLoading] = useState(true); const toggleSection = (section: SidebarSection) => { @@ -368,19 +368,19 @@ export function Sidebar({ async function load() { setLoading(true); try { - const [webSessionsRes, skillsRes, memoriesRes, workspaceRes, profilesRes] = await Promise.all([ + const [webSessionsRes, skillsRes, memoriesRes, workspaceRes, workspaceListRes] = await Promise.all([ fetch("/api/web-sessions").then((r) => r.json()), fetch("/api/skills").then((r) => r.json()), fetch("/api/memories").then((r) => r.json()), fetch("/api/workspace/tree").then((r) => r.json()).catch(() => ({ tree: [] })), - fetch("/api/profiles").then((r) => r.json()).catch(() => ({ activeProfile: "default" })), + fetch("/api/workspace/list").then((r) => r.json()).catch(() => ({ activeWorkspace: null })), ]); setWebSessions(webSessionsRes.sessions ?? []); setSkills(skillsRes.skills ?? []); setMainMemory(memoriesRes.mainMemory ?? null); setDailyLogs(memoriesRes.dailyLogs ?? []); setWorkspaceTree(workspaceRes.tree ?? []); - setActiveProfile(String(profilesRes.activeProfile || "default")); + setActiveWorkspace((workspaceListRes.activeWorkspace ?? null) as string | null); } catch (err) { console.error("Failed to load sidebar data:", err); } finally { @@ -428,7 +428,9 @@ export function Sidebar({ -

Profile: {activeProfile}

+

+ Workspace: {activeWorkspace ?? "none"} +

{/* Content */} diff --git a/apps/web/app/components/workspace/create-workspace-dialog.tsx b/apps/web/app/components/workspace/create-workspace-dialog.tsx index 731b262d2d8..e8f61ae32e5 100644 --- a/apps/web/app/components/workspace/create-workspace-dialog.tsx +++ b/apps/web/app/components/workspace/create-workspace-dialog.tsx @@ -1,7 +1,6 @@ "use client"; import { useState, useRef, useEffect } from "react"; -import { DirectoryPickerModal } from "./directory-picker-modal"; type CreateWorkspaceDialogProps = { isOpen: boolean; @@ -16,17 +15,9 @@ function shortenPath(p: string): string { .replace(/^[A-Za-z]:[/\\]Users[/\\][^/\\]+/, "~"); } -function pathBasename(p: string): string { - return p.replaceAll("\\", "/").split("/").pop() || p; -} - export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWorkspaceDialogProps) { - const [profileName, setProfileName] = useState(""); - const [customPath, setCustomPath] = useState(""); - const [useCustomPath, setUseCustomPath] = useState(false); - const [showDirPicker, setShowDirPicker] = useState(false); + const [workspaceName, setWorkspaceName] = useState(""); const [seedBootstrap, setSeedBootstrap] = useState(true); - const [copyConfigAuth, setCopyConfigAuth] = useState(true); const [creating, setCreating] = useState(false); const [error, setError] = useState(null); const [result, setResult] = useState<{ workspaceDir: string; seededFiles: string[] } | null>(null); @@ -36,30 +27,26 @@ export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWork // Focus input on open useEffect(() => { if (isOpen) { - setProfileName(""); - setCustomPath(""); - setUseCustomPath(false); - setShowDirPicker(false); - setCopyConfigAuth(true); + setWorkspaceName(""); setError(null); setResult(null); setTimeout(() => inputRef.current?.focus(), 100); } }, [isOpen]); - // Close on Escape (only if dir picker is not open) + // Close on Escape. useEffect(() => { function handleKey(e: KeyboardEvent) { - if (e.key === "Escape" && !showDirPicker) {onClose();} + if (e.key === "Escape") {onClose();} } if (isOpen) { document.addEventListener("keydown", handleKey); return () => document.removeEventListener("keydown", handleKey); } - }, [isOpen, onClose, showDirPicker]); + }, [isOpen, onClose]); const handleCreate = async () => { - const name = profileName.trim(); + const name = workspaceName.trim(); if (!name) { setError("Please enter a workspace name."); return; @@ -74,13 +61,9 @@ export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWork try { const body: Record = { - profile: name, + workspace: name, seedBootstrap, - copyConfigAuth, }; - if (useCustomPath && customPath.trim()) { - body.path = customPath.trim(); - } const res = await fetch("/api/workspace/init", { method: "POST", @@ -196,9 +179,9 @@ export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWork { - setProfileName(e.target.value); + setWorkspaceName(e.target.value); setError(null); }} onKeyDown={(e) => { @@ -216,91 +199,10 @@ export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWork className="text-xs mt-1" style={{ color: "var(--color-text-muted)" }} > - This creates a new profile with its own workspace directory. + This creates a workspace under ~/.openclaw-ironclaw/workspace-{"{name}"}.

- {/* Custom path toggle */} -
- - - {useCustomPath && ( -
- {customPath ? ( -
-
- - - -
-
-

- {pathBasename(customPath)} -

-

- {shortenPath(customPath)} -

-
- - -
- ) : ( - - )} -
- )} -
- {/* Bootstrap toggle */} - - {error && (

- {p.workspaceDir && ( + {workspace.workspaceDir && (