Add virtual folder system that surfaces Skills, Memories, and Chat sessions in the workspace sidebar alongside real dench files. Rearchitect the home page into a landing hub and move the ChatPanel into the workspace as the default view. New API route — virtual-file: - apps/web/app/api/workspace/virtual-file/route.ts: new GET/POST API that resolves virtual paths (~skills/*, ~memories/*) to absolute filesystem paths in ~/.openclaw/skills/ d ~/.openclaw/workspace/. Includes path traversal protection and directory allowlisting. Tree API — virtual folder builders: - apps/web/app/api/workspace/tree/route.ts: add `virtual` field to TreeNode type. Add ildSkillsVirtualFolder() scanning ~/.openclaw/skills/ and ~/.openclaw/workspace/skills/ with SKILL.md frontmatter parsing (name + emoji). Add buildMemoriesVirtualFolder() scanning MEMORY.md and daily logs from ~/.openclaw/workspace/memory/. Virtual folders are appended after real workspace entries and are also returned when no dench root exists. File manager tree — virtual node awareness: - apps/web/app/components/workspace/file-manager-tree.tsx: add isVirtualNode() helper and RESERVED_FOLDER_NAMES set (Chats, Skills, Memories). Virtual nodes show a lock badge, disable drag-and-drop, block rename/delete, and reject reserved names during create/rename. Add ChatBubbleIcon for ~chats/ paths. Markdown editor — virtual path routing: - apps/web/app/components/workspace/markdown-editor.tsx: save to /api/workspace/virtual-file for paths starting with ~ instead of the regular /api/workspace/file endpoint. Home page redesign: - apps/web/app/page.tsx: replace the chat-first layout (SidebarhatPanel) with a branded landing page showing the OpenClaw Dench heading, tagline, and a single "Open Workspace" CTA linking to /workspace. Workspace page — unified layout with integrated chat: - apps/web/app/workspace/page.tsx: ChatPanel is now the default main view when no file is selected. Add session fetching from /api/web-sessions and build an enhanced tree with a virtual "Chats" folder listing all sessions. Clicking ~chats/<id> loads the session; clicking ~chats starts a new one. Add isVirtualPath()/fileApiUrl() helpers for virtual file reads. Add a "Back to chat" button in the top bar alongside the chat sidebar toggle. Sidebar + empty-state cosmetic updates: - apps/web/app/components/workspace/workspace-sidebar.tsx: rename BackIcon to HomeIcon (house SVG), change label from "Back to Chat" to "Home". - apps/web/app/components/workspace/empty-state.tsx: update link text from "Back to Chat" to "Back to Home".
120 lines
3.4 KiB
TypeScript
120 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
export function EmptyState({ workspaceExists }: { workspaceExists: boolean }) {
|
|
return (
|
|
<div className="flex flex-col items-center justify-center h-full gap-6 px-8">
|
|
{/* Icon */}
|
|
<div
|
|
className="w-20 h-20 rounded-2xl flex items-center justify-center"
|
|
style={{
|
|
background: "var(--color-surface)",
|
|
border: "1px solid var(--color-border)",
|
|
}}
|
|
>
|
|
<svg
|
|
width="40"
|
|
height="40"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
style={{ color: "var(--color-text-muted)", opacity: 0.5 }}
|
|
>
|
|
<rect width="7" height="7" x="3" y="3" rx="1" />
|
|
<rect width="7" height="7" x="14" y="3" rx="1" />
|
|
<rect width="7" height="7" x="14" y="14" rx="1" />
|
|
<rect width="7" height="7" x="3" y="14" rx="1" />
|
|
</svg>
|
|
</div>
|
|
|
|
{/* Text */}
|
|
<div className="text-center max-w-md">
|
|
<h2
|
|
className="text-lg font-semibold mb-2"
|
|
style={{ color: "var(--color-text)" }}
|
|
>
|
|
{workspaceExists
|
|
? "Workspace is empty"
|
|
: "No workspace found"}
|
|
</h2>
|
|
<p
|
|
className="text-sm leading-relaxed"
|
|
style={{ color: "var(--color-text-muted)" }}
|
|
>
|
|
{workspaceExists ? (
|
|
<>
|
|
The Dench workspace exists but has no knowledge tree yet.
|
|
Ask the CRM agent to create objects and documents to populate it.
|
|
</>
|
|
) : (
|
|
<>
|
|
The Dench workspace directory was not found. To initialize it,
|
|
start a conversation with the CRM agent and it will create the
|
|
workspace structure automatically.
|
|
</>
|
|
)}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Hint */}
|
|
<div
|
|
className="flex items-center gap-2 px-4 py-3 rounded-lg text-sm"
|
|
style={{
|
|
background: "var(--color-surface)",
|
|
border: "1px solid var(--color-border)",
|
|
color: "var(--color-text-muted)",
|
|
}}
|
|
>
|
|
<svg
|
|
width="16"
|
|
height="16"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
style={{ color: "var(--color-accent)", flexShrink: 0 }}
|
|
>
|
|
<circle cx="12" cy="12" r="10" />
|
|
<path d="M12 16v-4" />
|
|
<path d="M12 8h.01" />
|
|
</svg>
|
|
<span>
|
|
Expected location:{" "}
|
|
<code
|
|
className="px-1.5 py-0.5 rounded text-xs"
|
|
style={{ background: "var(--color-bg)" }}
|
|
>
|
|
~/.openclaw/workspace/dench/
|
|
</code>
|
|
</span>
|
|
</div>
|
|
|
|
{/* Back link */}
|
|
<a
|
|
href="/"
|
|
className="flex items-center gap-2 text-sm mt-2 transition-colors"
|
|
style={{ color: "var(--color-accent)" }}
|
|
>
|
|
<svg
|
|
width="16"
|
|
height="16"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
>
|
|
<path d="m12 19-7-7 7-7" />
|
|
<path d="M19 12H5" />
|
|
</svg>
|
|
Back to Home
|
|
</a>
|
|
</div>
|
|
);
|
|
}
|