Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
|
|
import { useState, useCallback, useRef, useEffect } from "react";
|
|
|
|
|
|
import {
|
|
|
|
|
|
DndContext,
|
|
|
|
|
|
DragOverlay,
|
|
|
|
|
|
useDraggable,
|
|
|
|
|
|
useDroppable,
|
|
|
|
|
|
closestCenter,
|
|
|
|
|
|
type DragStartEvent,
|
|
|
|
|
|
type DragEndEvent,
|
|
|
|
|
|
type DragOverEvent,
|
|
|
|
|
|
PointerSensor,
|
|
|
|
|
|
useSensor,
|
|
|
|
|
|
useSensors,
|
|
|
|
|
|
} from "@dnd-kit/core";
|
|
|
|
|
|
import { ContextMenu, type ContextMenuAction, type ContextMenuTarget } from "./context-menu";
|
|
|
|
|
|
import { InlineRename, RENAME_SHAKE_STYLE } from "./inline-rename";
|
|
|
|
|
|
|
|
|
|
|
|
// --- Types ---
|
|
|
|
|
|
|
|
|
|
|
|
export type TreeNode = {
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
path: string;
|
|
|
|
|
|
type: "object" | "document" | "folder" | "file" | "database" | "report";
|
|
|
|
|
|
icon?: string;
|
|
|
|
|
|
defaultView?: "table" | "kanban";
|
|
|
|
|
|
children?: TreeNode[];
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
/** When true, the node represents a virtual folder/file outside the real workspace (e.g. Skills, Memories). CRUD ops are disabled. */
|
|
|
|
|
|
virtual?: boolean;
|
2026-02-21 14:39:55 -08:00
|
|
|
|
/** True when the entry is a symbolic link / shortcut. */
|
|
|
|
|
|
symlink?: boolean;
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
/** Folder names reserved for virtual sections -- cannot be created/renamed to. */
|
|
|
|
|
|
const RESERVED_FOLDER_NAMES = new Set(["Chats", "Skills", "Memories"]);
|
|
|
|
|
|
|
|
|
|
|
|
/** Check if a node (or any of its ancestors) is virtual. Paths starting with ~ are always virtual. */
|
|
|
|
|
|
function isVirtualNode(node: TreeNode): boolean {
|
|
|
|
|
|
return !!node.virtual || node.path.startsWith("~");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
type FileManagerTreeProps = {
|
|
|
|
|
|
tree: TreeNode[];
|
|
|
|
|
|
activePath: string | null;
|
|
|
|
|
|
onSelect: (node: TreeNode) => void;
|
|
|
|
|
|
onRefresh: () => void;
|
|
|
|
|
|
compact?: boolean;
|
2026-02-13 15:16:36 -08:00
|
|
|
|
/** Parent directory path for ".." navigation. Null when at filesystem root or in workspace mode without browsing. */
|
|
|
|
|
|
parentDir?: string | null;
|
|
|
|
|
|
/** Callback when user clicks ".." to navigate up. */
|
|
|
|
|
|
onNavigateUp?: () => void;
|
|
|
|
|
|
/** Current browse directory (absolute path), or null when in workspace mode. */
|
|
|
|
|
|
browseDir?: string | null;
|
2026-02-13 19:24:24 -08:00
|
|
|
|
/** Absolute path of the workspace root. Nodes matching this path are rendered as a special non-collapsible workspace entry point. */
|
|
|
|
|
|
workspaceRoot?: string | null;
|
2026-02-15 23:42:13 -08:00
|
|
|
|
/** Called when a node is dragged and dropped outside the tree onto an external drop target (e.g. chat input). */
|
|
|
|
|
|
onExternalDrop?: (node: TreeNode) => void;
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// --- System file detection (client-side mirror) ---
|
|
|
|
|
|
|
2026-02-15 23:00:25 -08:00
|
|
|
|
/** Always protected regardless of depth. */
|
|
|
|
|
|
const ALWAYS_SYSTEM_PATTERNS = [
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
/^\.object\.yaml$/,
|
|
|
|
|
|
/\.wal$/,
|
|
|
|
|
|
/\.tmp$/,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
2026-02-15 23:00:25 -08:00
|
|
|
|
/** Only protected at the workspace root (no "/" in the relative path). */
|
|
|
|
|
|
const ROOT_ONLY_SYSTEM_PATTERNS = [
|
|
|
|
|
|
/^workspace\.duckdb/,
|
|
|
|
|
|
/^workspace_context\.yaml$/,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
function isSystemFile(path: string): boolean {
|
|
|
|
|
|
const base = path.split("/").pop() ?? "";
|
2026-02-15 23:00:25 -08:00
|
|
|
|
if (ALWAYS_SYSTEM_PATTERNS.some((p) => p.test(base))) {return true;}
|
|
|
|
|
|
const isRoot = !path.includes("/");
|
|
|
|
|
|
return isRoot && ROOT_ONLY_SYSTEM_PATTERNS.some((p) => p.test(base));
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Icons (inline SVG, zero-dep) ---
|
|
|
|
|
|
|
|
|
|
|
|
function FolderIcon({ open }: { open?: boolean }) {
|
2026-02-19 22:50:34 -08:00
|
|
|
|
return (
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={open ? "/icons/folder-open.png" : "/icons/folder.png"}
|
|
|
|
|
|
alt=""
|
|
|
|
|
|
width={16}
|
|
|
|
|
|
height={16}
|
|
|
|
|
|
draggable={false}
|
|
|
|
|
|
style={{ flexShrink: 0 }}
|
|
|
|
|
|
/>
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function TableIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<path d="M12 3v18" /><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M3 15h18" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function KanbanIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<rect width="6" height="14" x="2" y="5" rx="1" /><rect width="6" height="10" x="9" y="5" rx="1" /><rect width="6" height="16" x="16" y="3" rx="1" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function DocumentIcon() {
|
|
|
|
|
|
return (
|
2026-02-19 22:50:34 -08:00
|
|
|
|
<img src="/icons/document.png" alt="" width={16} height={16} draggable={false} style={{ flexShrink: 0, filter: "drop-shadow(0 0.5px 1.5px rgba(0,0,0,0.2))" }} />
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function FileIcon() {
|
|
|
|
|
|
return (
|
2026-02-19 22:50:34 -08:00
|
|
|
|
<img src="/icons/document.png" alt="" width={16} height={16} draggable={false} style={{ flexShrink: 0, filter: "drop-shadow(0 0.5px 1.5px rgba(0,0,0,0.2))" }} />
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function DatabaseIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<ellipse cx="12" cy="5" rx="9" ry="3" /><path d="M3 5V19A9 3 0 0 0 21 19V5" /><path d="M3 12A9 3 0 0 0 21 12" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ReportIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<line x1="12" x2="12" y1="20" y2="10" /><line x1="18" x2="18" y1="20" y2="4" /><line x1="6" x2="6" y1="20" y2="14" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
function ChatBubbleIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
function LockBadge() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.4 }}>
|
|
|
|
|
|
<rect width="18" height="11" x="3" y="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-21 14:39:55 -08:00
|
|
|
|
function SymlinkBadge() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ opacity: 0.55 }}>
|
|
|
|
|
|
<path d="m9 18 6-6-6-6" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
function ChevronIcon({ open }: { open: boolean }) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
|
|
|
|
|
|
style={{ transform: open ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 150ms ease" }}>
|
|
|
|
|
|
<path d="m9 18 6-6-6-6" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 19:24:24 -08:00
|
|
|
|
function WorkspaceGridIcon() {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<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>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
function NodeIcon({ node, open }: { node: TreeNode; open?: boolean }) {
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
// Chat items use the chat bubble icon
|
|
|
|
|
|
if (node.path.startsWith("~chats/") || node.path === "~chats") {
|
|
|
|
|
|
return <ChatBubbleIcon />;
|
|
|
|
|
|
}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
switch (node.type) {
|
|
|
|
|
|
case "object":
|
|
|
|
|
|
return node.defaultView === "kanban" ? <KanbanIcon /> : <TableIcon />;
|
|
|
|
|
|
case "document":
|
|
|
|
|
|
return <DocumentIcon />;
|
|
|
|
|
|
case "folder":
|
|
|
|
|
|
return <FolderIcon open={open} />;
|
|
|
|
|
|
case "database":
|
|
|
|
|
|
return <DatabaseIcon />;
|
|
|
|
|
|
case "report":
|
|
|
|
|
|
return <ReportIcon />;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return <FileIcon />;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function typeColor(node: TreeNode): string {
|
|
|
|
|
|
switch (node.type) {
|
|
|
|
|
|
case "object": return "var(--color-accent)";
|
|
|
|
|
|
case "document": return "#60a5fa";
|
|
|
|
|
|
case "database": return "#c084fc";
|
|
|
|
|
|
case "report": return "#22c55e";
|
|
|
|
|
|
default: return "var(--color-text-muted)";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- API helpers ---
|
|
|
|
|
|
|
|
|
|
|
|
async function apiRename(path: string, newName: string) {
|
|
|
|
|
|
const res = await fetch("/api/workspace/rename", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ path, newName }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function apiDelete(path: string) {
|
|
|
|
|
|
const res = await fetch("/api/workspace/file", {
|
|
|
|
|
|
method: "DELETE",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ path }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function apiMove(sourcePath: string, destinationDir: string) {
|
|
|
|
|
|
const res = await fetch("/api/workspace/move", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ sourcePath, destinationDir }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function apiDuplicate(path: string) {
|
|
|
|
|
|
const res = await fetch("/api/workspace/copy", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ path }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function apiMkdir(path: string) {
|
|
|
|
|
|
const res = await fetch("/api/workspace/mkdir", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ path }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function apiCreateFile(path: string, content: string = "") {
|
|
|
|
|
|
const res = await fetch("/api/workspace/file", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ path, content }),
|
|
|
|
|
|
});
|
|
|
|
|
|
return res.json();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Confirm dialog ---
|
|
|
|
|
|
|
|
|
|
|
|
function ConfirmDialog({
|
|
|
|
|
|
message,
|
|
|
|
|
|
onConfirm,
|
|
|
|
|
|
onCancel,
|
|
|
|
|
|
}: {
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
onConfirm: () => void;
|
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
|
}) {
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
function handleKey(e: KeyboardEvent) {
|
|
|
|
|
|
if (e.key === "Escape") {onCancel();}
|
|
|
|
|
|
if (e.key === "Enter") {onConfirm();}
|
|
|
|
|
|
}
|
|
|
|
|
|
document.addEventListener("keydown", handleKey);
|
|
|
|
|
|
return () => document.removeEventListener("keydown", handleKey);
|
|
|
|
|
|
}, [onConfirm, onCancel]);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="fixed inset-0 z-[10000] flex items-center justify-center" style={{ background: "rgba(0,0,0,0.5)" }}>
|
|
|
|
|
|
<div className="rounded-xl p-5 max-w-sm w-full shadow-2xl border" style={{ background: "var(--color-surface)", borderColor: "var(--color-border)" }}>
|
|
|
|
|
|
<p className="text-sm mb-4" style={{ color: "var(--color-text)" }}>{message}</p>
|
|
|
|
|
|
<div className="flex justify-end gap-2">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={onCancel}
|
|
|
|
|
|
className="px-3 py-1.5 rounded-md text-sm"
|
|
|
|
|
|
style={{ color: "var(--color-text-muted)", background: "var(--color-surface-hover)" }}
|
|
|
|
|
|
>
|
|
|
|
|
|
Cancel
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={onConfirm}
|
|
|
|
|
|
className="px-3 py-1.5 rounded-md text-sm text-white"
|
|
|
|
|
|
style={{ background: "#ef4444" }}
|
|
|
|
|
|
>
|
|
|
|
|
|
Delete
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- New item prompt ---
|
|
|
|
|
|
|
|
|
|
|
|
function NewItemPrompt({
|
|
|
|
|
|
kind,
|
|
|
|
|
|
parentPath,
|
|
|
|
|
|
onSubmit,
|
|
|
|
|
|
onCancel,
|
|
|
|
|
|
}: {
|
|
|
|
|
|
kind: "file" | "folder";
|
|
|
|
|
|
parentPath: string;
|
|
|
|
|
|
onSubmit: (name: string) => void;
|
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
|
}) {
|
|
|
|
|
|
const [value, setValue] = useState(kind === "file" ? "untitled.md" : "new-folder");
|
|
|
|
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const el = inputRef.current;
|
|
|
|
|
|
if (!el) {return;}
|
|
|
|
|
|
el.focus();
|
|
|
|
|
|
if (kind === "file") {
|
|
|
|
|
|
const dot = value.lastIndexOf(".");
|
|
|
|
|
|
el.setSelectionRange(0, dot > 0 ? dot : value.length);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
el.select();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="fixed inset-0 z-[10000] flex items-center justify-center" style={{ background: "rgba(0,0,0,0.5)" }}>
|
|
|
|
|
|
<div className="rounded-xl p-5 max-w-sm w-full shadow-2xl border" style={{ background: "var(--color-surface)", borderColor: "var(--color-border)" }}>
|
|
|
|
|
|
<p className="text-sm mb-3 font-medium" style={{ color: "var(--color-text)" }}>
|
|
|
|
|
|
New {kind} in <span style={{ color: "var(--color-accent)" }}>{parentPath || "/"}</span>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<input
|
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={value}
|
|
|
|
|
|
onChange={(e) => setValue(e.target.value)}
|
|
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
|
|
if (e.key === "Enter") {onSubmit(value.trim());}
|
|
|
|
|
|
if (e.key === "Escape") {onCancel();}
|
|
|
|
|
|
}}
|
|
|
|
|
|
className="w-full px-3 py-2 rounded-md text-sm outline-none border"
|
|
|
|
|
|
style={{ background: "var(--color-bg)", color: "var(--color-text)", borderColor: "var(--color-border)" }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="flex justify-end gap-2 mt-3">
|
|
|
|
|
|
<button type="button" onClick={onCancel} className="px-3 py-1.5 rounded-md text-sm" style={{ color: "var(--color-text-muted)", background: "var(--color-surface-hover)" }}>
|
|
|
|
|
|
Cancel
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button type="button" onClick={() => onSubmit(value.trim())} className="px-3 py-1.5 rounded-md text-sm text-white" style={{ background: "var(--color-accent)" }}>
|
|
|
|
|
|
Create
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Draggable + Droppable Node ---
|
|
|
|
|
|
|
|
|
|
|
|
function DraggableNode({
|
|
|
|
|
|
node,
|
|
|
|
|
|
depth,
|
|
|
|
|
|
activePath,
|
|
|
|
|
|
selectedPath,
|
|
|
|
|
|
onSelect,
|
|
|
|
|
|
onNodeSelect,
|
|
|
|
|
|
expandedPaths,
|
|
|
|
|
|
onToggleExpand,
|
|
|
|
|
|
renamingPath,
|
|
|
|
|
|
onStartRename,
|
|
|
|
|
|
onCommitRename,
|
|
|
|
|
|
onCancelRename,
|
|
|
|
|
|
onContextMenu,
|
|
|
|
|
|
compact,
|
|
|
|
|
|
dragOverPath,
|
2026-02-13 19:24:24 -08:00
|
|
|
|
workspaceRoot,
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
}: {
|
|
|
|
|
|
node: TreeNode;
|
|
|
|
|
|
depth: number;
|
|
|
|
|
|
activePath: string | null;
|
|
|
|
|
|
selectedPath: string | null;
|
|
|
|
|
|
onSelect: (node: TreeNode) => void;
|
|
|
|
|
|
onNodeSelect: (path: string) => void;
|
|
|
|
|
|
expandedPaths: Set<string>;
|
|
|
|
|
|
onToggleExpand: (path: string) => void;
|
|
|
|
|
|
renamingPath: string | null;
|
|
|
|
|
|
onStartRename: (path: string) => void;
|
|
|
|
|
|
onCommitRename: (newName: string) => void;
|
|
|
|
|
|
onCancelRename: () => void;
|
|
|
|
|
|
onContextMenu: (e: React.MouseEvent, node: TreeNode) => void;
|
|
|
|
|
|
compact?: boolean;
|
|
|
|
|
|
dragOverPath: string | null;
|
2026-02-13 19:24:24 -08:00
|
|
|
|
workspaceRoot?: string | null;
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
}) {
|
2026-02-13 19:24:24 -08:00
|
|
|
|
// Workspace root in browse mode: non-expandable entry point back to workspace
|
|
|
|
|
|
const isWorkspaceRoot = !!workspaceRoot && node.path === workspaceRoot;
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const hasChildren = node.children && node.children.length > 0;
|
2026-02-13 19:24:24 -08:00
|
|
|
|
const isExpandable = isWorkspaceRoot ? false : (hasChildren || node.type === "folder" || node.type === "object");
|
|
|
|
|
|
const isExpanded = isWorkspaceRoot ? false : expandedPaths.has(node.path);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const isActive = activePath === node.path;
|
|
|
|
|
|
const isSelected = selectedPath === node.path;
|
|
|
|
|
|
const isRenaming = renamingPath === node.path;
|
|
|
|
|
|
const isSysFile = isSystemFile(node.path);
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
const isVirtual = isVirtualNode(node);
|
2026-02-13 19:24:24 -08:00
|
|
|
|
const isProtected = isSysFile || isVirtual || isWorkspaceRoot;
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const isDragOver = dragOverPath === node.path && isExpandable;
|
|
|
|
|
|
|
|
|
|
|
|
const { attributes, listeners, setNodeRef: setDragRef, isDragging } = useDraggable({
|
|
|
|
|
|
id: `drag-${node.path}`,
|
|
|
|
|
|
data: { node },
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
disabled: isProtected,
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const { setNodeRef: setDropRef, isOver } = useDroppable({
|
|
|
|
|
|
id: `drop-${node.path}`,
|
|
|
|
|
|
data: { node },
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
disabled: !isExpandable || isVirtual,
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const handleClick = useCallback(() => {
|
|
|
|
|
|
onNodeSelect(node.path);
|
|
|
|
|
|
onSelect(node);
|
|
|
|
|
|
if (isExpandable) {
|
|
|
|
|
|
onToggleExpand(node.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [node, isExpandable, onSelect, onNodeSelect, onToggleExpand]);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDoubleClick = useCallback(() => {
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
if (!isProtected) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
onStartRename(node.path);
|
|
|
|
|
|
}
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
}, [node.path, isProtected, onStartRename]);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
|
|
|
|
|
|
const handleContextMenu = useCallback(
|
|
|
|
|
|
(e: React.MouseEvent) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
onNodeSelect(node.path);
|
|
|
|
|
|
onContextMenu(e, node);
|
|
|
|
|
|
},
|
|
|
|
|
|
[node, onNodeSelect, onContextMenu],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Merge drag + drop refs
|
|
|
|
|
|
const mergedRef = useCallback(
|
|
|
|
|
|
(el: HTMLElement | null) => {
|
|
|
|
|
|
setDragRef(el);
|
|
|
|
|
|
setDropRef(el);
|
|
|
|
|
|
},
|
|
|
|
|
|
[setDragRef, setDropRef],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const showDropHighlight = (isOver || isDragOver) && isExpandable;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div style={{ opacity: isDragging ? 0.4 : 1 }}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref={mergedRef}
|
|
|
|
|
|
{...attributes}
|
|
|
|
|
|
{...listeners}
|
|
|
|
|
|
role="treeitem"
|
|
|
|
|
|
tabIndex={-1}
|
2026-02-13 18:06:59 -08:00
|
|
|
|
draggable={!isProtected}
|
|
|
|
|
|
onDragStart={(e) => {
|
|
|
|
|
|
// Native HTML5 drag for cross-component drops (e.g. into chat editor).
|
|
|
|
|
|
// Coexists with @dnd-kit which uses pointer events for intra-tree reordering.
|
|
|
|
|
|
e.dataTransfer.setData(
|
|
|
|
|
|
"application/x-file-mention",
|
|
|
|
|
|
JSON.stringify({ name: node.name, path: node.path }),
|
|
|
|
|
|
);
|
|
|
|
|
|
e.dataTransfer.setData("text/plain", node.path);
|
|
|
|
|
|
e.dataTransfer.effectAllowed = "copy";
|
|
|
|
|
|
}}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
onClick={handleClick}
|
|
|
|
|
|
onDoubleClick={handleDoubleClick}
|
|
|
|
|
|
onContextMenu={handleContextMenu}
|
|
|
|
|
|
className="w-full flex items-center gap-1.5 py-1 px-2 rounded-md text-left text-sm transition-colors duration-100 cursor-pointer select-none"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
paddingLeft: `${depth * 16 + 8}px`,
|
2026-02-13 19:24:24 -08:00
|
|
|
|
background: isWorkspaceRoot
|
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
|
|
|
|
? "var(--color-accent-light)"
|
2026-02-13 19:24:24 -08:00
|
|
|
|
: showDropHighlight
|
|
|
|
|
|
? "var(--color-accent-light)"
|
|
|
|
|
|
: isSelected
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
? "var(--color-surface-hover)"
|
2026-02-13 19:24:24 -08:00
|
|
|
|
: isActive
|
|
|
|
|
|
? "var(--color-surface-hover)"
|
|
|
|
|
|
: "transparent",
|
|
|
|
|
|
color: isWorkspaceRoot
|
|
|
|
|
|
? "var(--color-accent)"
|
|
|
|
|
|
: isActive || isSelected ? "var(--color-text)" : "var(--color-text-muted)",
|
|
|
|
|
|
outline: isWorkspaceRoot
|
|
|
|
|
|
? "1.5px solid var(--color-accent)"
|
|
|
|
|
|
: showDropHighlight ? "1px dashed var(--color-accent)" : "none",
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
outlineOffset: "-1px",
|
2026-02-13 19:24:24 -08:00
|
|
|
|
borderRadius: isWorkspaceRoot ? "8px" : "6px",
|
|
|
|
|
|
marginTop: isWorkspaceRoot ? "2px" : undefined,
|
|
|
|
|
|
marginBottom: isWorkspaceRoot ? "2px" : undefined,
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
}}
|
|
|
|
|
|
onMouseEnter={(e) => {
|
2026-02-13 19:24:24 -08:00
|
|
|
|
if (isWorkspaceRoot) {
|
|
|
|
|
|
(e.currentTarget as HTMLElement).style.opacity = "0.8";
|
|
|
|
|
|
} else if (!isActive && !isSelected && !showDropHighlight) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
(e.currentTarget as HTMLElement).style.background = "var(--color-surface-hover)";
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
onMouseLeave={(e) => {
|
2026-02-13 19:24:24 -08:00
|
|
|
|
if (isWorkspaceRoot) {
|
|
|
|
|
|
(e.currentTarget as HTMLElement).style.opacity = "1";
|
|
|
|
|
|
} else if (!isActive && !isSelected && !showDropHighlight) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
(e.currentTarget as HTMLElement).style.background = "transparent";
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-02-13 19:24:24 -08:00
|
|
|
|
{/* Expand/collapse chevron – intercept click so it only toggles without navigating */}
|
|
|
|
|
|
<span
|
|
|
|
|
|
className="flex-shrink-0 w-4 h-4 flex items-center justify-center"
|
|
|
|
|
|
style={{ opacity: isExpandable ? 1 : 0, cursor: isExpandable ? "pointer" : undefined }}
|
|
|
|
|
|
onClick={isExpandable ? (e) => { e.stopPropagation(); onToggleExpand(node.path); } : undefined}
|
|
|
|
|
|
>
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
{isExpandable && <ChevronIcon open={isExpanded} />}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Icon */}
|
2026-02-13 19:24:24 -08:00
|
|
|
|
<span className="flex-shrink-0 flex items-center" style={{ color: isWorkspaceRoot ? "var(--color-accent)" : typeColor(node) }}>
|
|
|
|
|
|
{isWorkspaceRoot ? <WorkspaceGridIcon /> : <NodeIcon node={node} open={isExpanded} />}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Label or rename input */}
|
|
|
|
|
|
{isRenaming ? (
|
|
|
|
|
|
<InlineRename
|
|
|
|
|
|
currentName={node.name}
|
|
|
|
|
|
onCommit={onCommitRename}
|
|
|
|
|
|
onCancel={onCancelRename}
|
|
|
|
|
|
/>
|
|
|
|
|
|
) : (
|
2026-02-19 22:50:34 -08:00
|
|
|
|
<span className="truncate flex-1">{node.name}</span>
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-13 19:24:24 -08:00
|
|
|
|
{/* Workspace badge for the workspace root entry point */}
|
|
|
|
|
|
{isWorkspaceRoot && (
|
|
|
|
|
|
<span className="text-[10px] px-1.5 py-0.5 rounded-full flex-shrink-0 font-medium"
|
|
|
|
|
|
style={{ background: "var(--color-accent)", color: "white" }}>
|
|
|
|
|
|
workspace
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Lock badge for system/virtual files (skip for workspace root -- it has its own badge) */}
|
|
|
|
|
|
{isProtected && !isWorkspaceRoot && !compact && (
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
<span className="flex-shrink-0 ml-1">
|
|
|
|
|
|
<LockBadge />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-21 14:39:55 -08:00
|
|
|
|
{/* Symlink indicator */}
|
|
|
|
|
|
{node.symlink && !compact && (
|
|
|
|
|
|
<span className="flex-shrink-0 ml-0.5" title="Symbolic link" style={{ color: "var(--color-text-muted)" }}>
|
|
|
|
|
|
<SymlinkBadge />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
{/* Type badge for objects */}
|
|
|
|
|
|
{node.type === "object" && (
|
|
|
|
|
|
<span className="text-[10px] px-1.5 py-0.5 rounded-full flex-shrink-0"
|
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
|
|
|
|
style={{ background: "var(--color-accent-light)", color: "var(--color-accent)" }}>
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
{node.defaultView === "kanban" ? "board" : "table"}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Children */}
|
|
|
|
|
|
{isExpanded && hasChildren && (
|
|
|
|
|
|
<div className="relative" style={{
|
|
|
|
|
|
borderLeft: depth > 0 ? "1px solid var(--color-border)" : "none",
|
|
|
|
|
|
marginLeft: `${depth * 16 + 16}px`,
|
|
|
|
|
|
}}>
|
|
|
|
|
|
{node.children!.map((child) => (
|
|
|
|
|
|
<DraggableNode
|
|
|
|
|
|
key={child.path}
|
|
|
|
|
|
node={child}
|
|
|
|
|
|
depth={depth + 1}
|
|
|
|
|
|
activePath={activePath}
|
|
|
|
|
|
selectedPath={selectedPath}
|
|
|
|
|
|
onSelect={onSelect}
|
|
|
|
|
|
onNodeSelect={onNodeSelect}
|
|
|
|
|
|
expandedPaths={expandedPaths}
|
|
|
|
|
|
onToggleExpand={onToggleExpand}
|
|
|
|
|
|
renamingPath={renamingPath}
|
|
|
|
|
|
onStartRename={onStartRename}
|
|
|
|
|
|
onCommitRename={onCommitRename}
|
|
|
|
|
|
onCancelRename={onCancelRename}
|
|
|
|
|
|
onContextMenu={onContextMenu}
|
|
|
|
|
|
compact={compact}
|
|
|
|
|
|
dragOverPath={dragOverPath}
|
2026-02-13 19:24:24 -08:00
|
|
|
|
workspaceRoot={workspaceRoot}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
/>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 23:00:25 -08:00
|
|
|
|
// --- Root drop zone (allows dropping items back to the top level) ---
|
|
|
|
|
|
|
|
|
|
|
|
function RootDropZone({ isDragging }: { isDragging: boolean }) {
|
|
|
|
|
|
const { setNodeRef, isOver } = useDroppable({
|
|
|
|
|
|
id: "drop-__root__",
|
|
|
|
|
|
data: { rootDrop: true },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const showHighlight = isOver && isDragging;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref={setNodeRef}
|
|
|
|
|
|
className="flex-1 min-h-[48px]"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
margin: isDragging ? "4px 8px" : undefined,
|
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
|
border: showHighlight ? "1.5px dashed var(--color-accent)" : isDragging ? "1.5px dashed var(--color-border)" : "1.5px dashed transparent",
|
|
|
|
|
|
background: showHighlight ? "var(--color-accent-light)" : "transparent",
|
|
|
|
|
|
transition: "all 150ms ease",
|
|
|
|
|
|
display: "flex",
|
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{isDragging && (
|
|
|
|
|
|
<span className="text-[11px] select-none" style={{ color: showHighlight ? "var(--color-accent)" : "var(--color-text-muted)", opacity: showHighlight ? 1 : 0.6 }}>
|
|
|
|
|
|
Drop here to move to root
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
// --- Drag Overlay ---
|
|
|
|
|
|
|
|
|
|
|
|
function DragOverlayContent({ node }: { node: TreeNode }) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm shadow-lg border"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
background: "var(--color-surface)",
|
|
|
|
|
|
borderColor: "var(--color-border)",
|
|
|
|
|
|
color: "var(--color-text)",
|
|
|
|
|
|
pointerEvents: "none",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span style={{ color: typeColor(node) }}>
|
|
|
|
|
|
<NodeIcon node={node} />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span>{node.name}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Helper: find node by path ---
|
|
|
|
|
|
|
|
|
|
|
|
function findNode(tree: TreeNode[], path: string): TreeNode | null {
|
|
|
|
|
|
for (const n of tree) {
|
|
|
|
|
|
if (n.path === path) {return n;}
|
|
|
|
|
|
if (n.children) {
|
|
|
|
|
|
const found = findNode(n.children, path);
|
|
|
|
|
|
if (found) {return found;}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Helper: get parent path ---
|
|
|
|
|
|
|
|
|
|
|
|
function parentPath(path: string): string {
|
|
|
|
|
|
const parts = path.split("/");
|
|
|
|
|
|
parts.pop();
|
|
|
|
|
|
return parts.join("/") || ".";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Flatten tree for keyboard navigation ---
|
|
|
|
|
|
|
|
|
|
|
|
function flattenVisible(tree: TreeNode[], expanded: Set<string>): TreeNode[] {
|
|
|
|
|
|
const result: TreeNode[] = [];
|
|
|
|
|
|
function walk(nodes: TreeNode[]) {
|
|
|
|
|
|
for (const n of nodes) {
|
|
|
|
|
|
result.push(n);
|
|
|
|
|
|
if (n.children && expanded.has(n.path)) {
|
|
|
|
|
|
walk(n.children);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
walk(tree);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Main Exported Component ---
|
|
|
|
|
|
|
2026-02-15 23:42:13 -08:00
|
|
|
|
export function FileManagerTree({ tree, activePath, onSelect, onRefresh, compact, parentDir, onNavigateUp, browseDir: _browseDir, workspaceRoot, onExternalDrop }: FileManagerTreeProps) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const [expandedPaths, setExpandedPaths] = useState<Set<string>>(() => new Set());
|
|
|
|
|
|
const [selectedPath, setSelectedPath] = useState<string | null>(null);
|
|
|
|
|
|
const [renamingPath, setRenamingPath] = useState<string | null>(null);
|
|
|
|
|
|
const [dragOverPath, setDragOverPath] = useState<string | null>(null);
|
|
|
|
|
|
const [activeNode, setActiveNode] = useState<TreeNode | null>(null);
|
|
|
|
|
|
|
2026-02-15 23:42:13 -08:00
|
|
|
|
// Track pointer position during @dnd-kit drags for cross-component drops.
|
2026-02-15 23:54:05 -08:00
|
|
|
|
// Installed synchronously in handleDragStart (not useEffect) to avoid
|
|
|
|
|
|
// missing early pointer moves. Capture-phase on window fires before
|
|
|
|
|
|
// @dnd-kit's own document-level listener.
|
2026-02-15 23:42:13 -08:00
|
|
|
|
const pointerPosRef = useRef({ x: 0, y: 0 });
|
2026-02-15 23:54:05 -08:00
|
|
|
|
const pointerListenerRef = useRef<((e: PointerEvent) => void) | null>(null);
|
2026-02-15 23:42:13 -08:00
|
|
|
|
|
2026-02-15 23:54:05 -08:00
|
|
|
|
const installPointerTracker = useCallback(() => {
|
|
|
|
|
|
const handler = (e: PointerEvent) => {
|
2026-02-15 23:42:13 -08:00
|
|
|
|
pointerPosRef.current = { x: e.clientX, y: e.clientY };
|
|
|
|
|
|
|
|
|
|
|
|
// Toggle visual drop indicator on external chat drop target
|
|
|
|
|
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
|
|
|
|
const target = el?.closest("[data-chat-drop-target]") as HTMLElement | null;
|
|
|
|
|
|
const prev = document.querySelector("[data-drag-hover]");
|
|
|
|
|
|
if (target && !target.hasAttribute("data-drag-hover")) {
|
|
|
|
|
|
target.setAttribute("data-drag-hover", "");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (prev && prev !== target) {
|
|
|
|
|
|
prev.removeAttribute("data-drag-hover");
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-02-15 23:54:05 -08:00
|
|
|
|
pointerListenerRef.current = handler;
|
|
|
|
|
|
window.addEventListener("pointermove", handler, true);
|
|
|
|
|
|
}, []);
|
2026-02-15 23:42:13 -08:00
|
|
|
|
|
2026-02-15 23:54:05 -08:00
|
|
|
|
const removePointerTracker = useCallback(() => {
|
|
|
|
|
|
if (pointerListenerRef.current) {
|
|
|
|
|
|
window.removeEventListener("pointermove", pointerListenerRef.current, true);
|
|
|
|
|
|
pointerListenerRef.current = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
document.querySelector("[data-drag-hover]")?.removeAttribute("data-drag-hover");
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// Clean up on unmount
|
|
|
|
|
|
useEffect(() => removePointerTracker, [removePointerTracker]);
|
2026-02-15 23:42:13 -08:00
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
// Context menu state
|
|
|
|
|
|
const [ctxMenu, setCtxMenu] = useState<{ x: number; y: number; target: ContextMenuTarget } | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
// Confirm dialog
|
|
|
|
|
|
const [confirmDelete, setConfirmDelete] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
// New item prompt
|
|
|
|
|
|
const [newItemPrompt, setNewItemPrompt] = useState<{ kind: "file" | "folder"; parentPath: string } | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
2026-02-12 09:04:34 -08:00
|
|
|
|
// Auto-expand first level on mount.
|
|
|
|
|
|
// Keep ~skills and ~memories collapsed by default; always expand ~chats.
|
|
|
|
|
|
const collapsedByDefault = new Set(["~skills", "~memories"]);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (tree.length > 0 && expandedPaths.size === 0) {
|
|
|
|
|
|
const initial = new Set<string>();
|
|
|
|
|
|
for (const node of tree) {
|
2026-02-12 09:04:34 -08:00
|
|
|
|
if (collapsedByDefault.has(node.path)) {continue;}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
if (node.children && node.children.length > 0) {
|
|
|
|
|
|
initial.add(node.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
setExpandedPaths(initial);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [tree]);
|
|
|
|
|
|
|
|
|
|
|
|
const handleToggleExpand = useCallback((path: string) => {
|
|
|
|
|
|
setExpandedPaths((prev) => {
|
|
|
|
|
|
const next = new Set(prev);
|
|
|
|
|
|
if (next.has(path)) {next.delete(path);}
|
|
|
|
|
|
else {next.add(path);}
|
|
|
|
|
|
return next;
|
|
|
|
|
|
});
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// DnD sensors -- require 8px movement before dragging starts (prevents accidental drags on click)
|
|
|
|
|
|
const sensors = useSensors(
|
|
|
|
|
|
useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDragStart = useCallback((event: DragStartEvent) => {
|
|
|
|
|
|
const data = event.active.data.current as { node: TreeNode } | undefined;
|
2026-02-15 23:54:05 -08:00
|
|
|
|
if (data?.node) {
|
|
|
|
|
|
setActiveNode(data.node);
|
|
|
|
|
|
installPointerTracker();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [installPointerTracker]);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
|
|
|
|
|
|
const handleDragOver = useCallback((event: DragOverEvent) => {
|
2026-02-15 23:00:25 -08:00
|
|
|
|
const overData = event.over?.data.current as { node?: TreeNode; rootDrop?: boolean } | undefined;
|
|
|
|
|
|
if (overData?.rootDrop) {
|
|
|
|
|
|
setDragOverPath("__root__");
|
|
|
|
|
|
} else if (overData?.node) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
setDragOverPath(overData.node.path);
|
|
|
|
|
|
// Auto-expand folders on drag hover (300ms delay)
|
|
|
|
|
|
const path = overData.node.path;
|
|
|
|
|
|
if (overData.node.type === "folder" || overData.node.type === "object") {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
setExpandedPaths((prev) => {
|
|
|
|
|
|
if (prev.has(path)) {return prev;}
|
|
|
|
|
|
const next = new Set(prev);
|
|
|
|
|
|
next.add(path);
|
|
|
|
|
|
return next;
|
|
|
|
|
|
});
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setDragOverPath(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDragEnd = useCallback(
|
|
|
|
|
|
async (event: DragEndEvent) => {
|
|
|
|
|
|
setActiveNode(null);
|
|
|
|
|
|
setDragOverPath(null);
|
2026-02-15 23:54:05 -08:00
|
|
|
|
removePointerTracker();
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
|
|
|
|
|
|
const activeData = event.active.data.current as { node: TreeNode } | undefined;
|
|
|
|
|
|
|
2026-02-15 23:00:25 -08:00
|
|
|
|
if (!activeData?.node) {return;}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
|
|
|
|
|
|
const source = activeData.node;
|
2026-02-15 23:00:25 -08:00
|
|
|
|
|
2026-02-15 23:54:05 -08:00
|
|
|
|
// Check for external drop targets FIRST (e.g. chat input).
|
|
|
|
|
|
// closestCenter always returns a droppable even when the pointer is
|
|
|
|
|
|
// far outside the tree, so we can't rely on `event.over === null`.
|
|
|
|
|
|
if (onExternalDrop) {
|
|
|
|
|
|
const { x, y } = pointerPosRef.current;
|
|
|
|
|
|
const el = document.elementFromPoint(x, y);
|
|
|
|
|
|
if (el?.closest("[data-chat-drop-target]")) {
|
|
|
|
|
|
onExternalDrop(source);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const overData = event.over?.data.current as { node?: TreeNode; rootDrop?: boolean } | undefined;
|
|
|
|
|
|
|
2026-02-15 23:00:25 -08:00
|
|
|
|
// Drop onto root level
|
|
|
|
|
|
if (overData?.rootDrop) {
|
|
|
|
|
|
// Already at root? No-op
|
|
|
|
|
|
if (parentPath(source.path) === ".") {return;}
|
|
|
|
|
|
const result = await apiMove(source.path, ".");
|
|
|
|
|
|
if (result.ok) {
|
|
|
|
|
|
onRefresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-15 23:54:05 -08:00
|
|
|
|
if (!overData?.node) {return;}
|
2026-02-15 23:00:25 -08:00
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const target = overData.node;
|
|
|
|
|
|
|
|
|
|
|
|
// Only drop onto expandable targets (folders/objects)
|
|
|
|
|
|
if (target.type !== "folder" && target.type !== "object") {return;}
|
|
|
|
|
|
|
|
|
|
|
|
// Prevent dropping into self or children
|
|
|
|
|
|
if (target.path === source.path || target.path.startsWith(source.path + "/")) {return;}
|
|
|
|
|
|
|
|
|
|
|
|
// Prevent no-op moves (already in same parent)
|
|
|
|
|
|
if (parentPath(source.path) === target.path) {return;}
|
|
|
|
|
|
|
|
|
|
|
|
const result = await apiMove(source.path, target.path);
|
|
|
|
|
|
if (result.ok) {
|
|
|
|
|
|
onRefresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-02-15 23:54:05 -08:00
|
|
|
|
[onRefresh, onExternalDrop, removePointerTracker],
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDragCancel = useCallback(() => {
|
|
|
|
|
|
setActiveNode(null);
|
|
|
|
|
|
setDragOverPath(null);
|
2026-02-15 23:54:05 -08:00
|
|
|
|
removePointerTracker();
|
|
|
|
|
|
}, [removePointerTracker]);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
|
|
|
|
|
|
// Context menu handlers
|
|
|
|
|
|
const handleContextMenu = useCallback((e: React.MouseEvent, node: TreeNode) => {
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
const isSys = isSystemFile(node.path) || isVirtualNode(node);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const isFolder = node.type === "folder" || node.type === "object";
|
|
|
|
|
|
setCtxMenu({
|
|
|
|
|
|
x: e.clientX,
|
|
|
|
|
|
y: e.clientY,
|
|
|
|
|
|
target: {
|
|
|
|
|
|
kind: isFolder ? "folder" : "file",
|
|
|
|
|
|
path: node.path,
|
|
|
|
|
|
name: node.name,
|
|
|
|
|
|
isSystem: isSys,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleEmptyContextMenu = useCallback((e: React.MouseEvent) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
setCtxMenu({
|
|
|
|
|
|
x: e.clientX,
|
|
|
|
|
|
y: e.clientY,
|
|
|
|
|
|
target: { kind: "empty" },
|
|
|
|
|
|
});
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleContextMenuAction = useCallback(
|
|
|
|
|
|
async (action: ContextMenuAction) => {
|
|
|
|
|
|
const target = ctxMenu?.target;
|
|
|
|
|
|
if (!target) {return;}
|
|
|
|
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
|
|
case "open": {
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
const node = findNode(tree, target.path);
|
|
|
|
|
|
if (node) {onSelect(node);}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "rename": {
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
setRenamingPath(target.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "duplicate": {
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
await apiDuplicate(target.path);
|
|
|
|
|
|
onRefresh();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "copy": {
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
await navigator.clipboard.writeText(target.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "delete": {
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
setConfirmDelete(target.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "newFile": {
|
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
|
|
|
|
const parent = target.kind === "folder" ? target.path : target.kind === "file" ? parentPath(target.path) : "";
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
setNewItemPrompt({ kind: "file", parentPath: parent });
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "newFolder": {
|
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
|
|
|
|
const parent = target.kind === "folder" ? target.path : target.kind === "file" ? parentPath(target.path) : "";
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
setNewItemPrompt({ kind: "folder", parentPath: parent });
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "getInfo": {
|
|
|
|
|
|
// Future: show info panel. For now, copy path.
|
|
|
|
|
|
if (target.kind !== "empty") {
|
|
|
|
|
|
await navigator.clipboard.writeText(target.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
[ctxMenu, tree, onSelect, onRefresh],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Rename handlers
|
|
|
|
|
|
const handleCommitRename = useCallback(
|
|
|
|
|
|
async (newName: string) => {
|
|
|
|
|
|
if (!renamingPath) {return;}
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
// Block reserved folder names
|
|
|
|
|
|
if (RESERVED_FOLDER_NAMES.has(newName)) {
|
|
|
|
|
|
alert(`"${newName}" is a reserved name and cannot be used.`);
|
|
|
|
|
|
setRenamingPath(null);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const result = await apiRename(renamingPath, newName);
|
|
|
|
|
|
setRenamingPath(null);
|
|
|
|
|
|
if (result.ok) {onRefresh();}
|
|
|
|
|
|
},
|
|
|
|
|
|
[renamingPath, onRefresh],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const handleCancelRename = useCallback(() => {
|
|
|
|
|
|
setRenamingPath(null);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// Delete confirm
|
|
|
|
|
|
const handleConfirmDelete = useCallback(async () => {
|
|
|
|
|
|
if (!confirmDelete) {return;}
|
|
|
|
|
|
const result = await apiDelete(confirmDelete);
|
|
|
|
|
|
setConfirmDelete(null);
|
|
|
|
|
|
if (result.ok) {onRefresh();}
|
|
|
|
|
|
}, [confirmDelete, onRefresh]);
|
|
|
|
|
|
|
|
|
|
|
|
// New item submit
|
|
|
|
|
|
const handleNewItemSubmit = useCallback(
|
|
|
|
|
|
async (name: string) => {
|
|
|
|
|
|
if (!newItemPrompt || !name) {return;}
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
|
|
|
|
|
|
// Block reserved folder names
|
|
|
|
|
|
if (RESERVED_FOLDER_NAMES.has(name)) {
|
|
|
|
|
|
alert(`"${name}" is a reserved name and cannot be used.`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
const fullPath = newItemPrompt.parentPath ? `${newItemPrompt.parentPath}/${name}` : name;
|
|
|
|
|
|
|
|
|
|
|
|
if (newItemPrompt.kind === "folder") {
|
|
|
|
|
|
await apiMkdir(fullPath);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await apiCreateFile(fullPath, "");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setNewItemPrompt(null);
|
|
|
|
|
|
onRefresh();
|
|
|
|
|
|
|
|
|
|
|
|
// Auto-expand parent
|
|
|
|
|
|
setExpandedPaths((prev) => {
|
|
|
|
|
|
const next = new Set(prev);
|
|
|
|
|
|
next.add(newItemPrompt.parentPath);
|
|
|
|
|
|
return next;
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
[newItemPrompt, onRefresh],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Keyboard shortcuts
|
|
|
|
|
|
const handleKeyDown = useCallback(
|
|
|
|
|
|
(e: React.KeyboardEvent) => {
|
|
|
|
|
|
// Don't capture keyboard events when renaming
|
|
|
|
|
|
if (renamingPath) {return;}
|
|
|
|
|
|
|
|
|
|
|
|
const flat = flattenVisible(tree, expandedPaths);
|
|
|
|
|
|
const curIdx = flat.findIndex((n) => n.path === selectedPath);
|
|
|
|
|
|
const curNode = curIdx >= 0 ? flat[curIdx] : null;
|
|
|
|
|
|
|
|
|
|
|
|
switch (e.key) {
|
|
|
|
|
|
case "ArrowDown": {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
const next = curIdx < flat.length - 1 ? flat[curIdx + 1] : flat[0];
|
|
|
|
|
|
if (next) {setSelectedPath(next.path);}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "ArrowUp": {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
const prev = curIdx > 0 ? flat[curIdx - 1] : flat[flat.length - 1];
|
|
|
|
|
|
if (prev) {setSelectedPath(prev.path);}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "ArrowRight": {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
if (curNode && (curNode.type === "folder" || curNode.type === "object")) {
|
|
|
|
|
|
setExpandedPaths((p) => new Set([...p, curNode.path]));
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "ArrowLeft": {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
if (curNode && expandedPaths.has(curNode.path)) {
|
|
|
|
|
|
setExpandedPaths((p) => {
|
|
|
|
|
|
const n = new Set(p);
|
|
|
|
|
|
n.delete(curNode.path);
|
|
|
|
|
|
return n;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "Enter": {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
if (curNode) {
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
const curProtected = isSystemFile(curNode.path) || isVirtualNode(curNode);
|
|
|
|
|
|
if (e.shiftKey || curProtected) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
onSelect(curNode);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setRenamingPath(curNode.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "F2": {
|
|
|
|
|
|
e.preventDefault();
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
if (curNode && !isSystemFile(curNode.path) && !isVirtualNode(curNode)) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
setRenamingPath(curNode.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case "Backspace":
|
|
|
|
|
|
case "Delete": {
|
Dench workspace: virtual folders (Skills, Memories, Chats), landing page, and unified workspace layout
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".
2026-02-11 22:09:59 -08:00
|
|
|
|
if (curNode && !isSystemFile(curNode.path) && !isVirtualNode(curNode)) {
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
setConfirmDelete(curNode.path);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default: {
|
|
|
|
|
|
// Cmd+key shortcuts
|
|
|
|
|
|
if (e.metaKey || e.ctrlKey) {
|
|
|
|
|
|
if (e.key === "c" && curNode) {
|
|
|
|
|
|
e.preventDefault();
|
2026-02-13 15:52:13 -08:00
|
|
|
|
void navigator.clipboard.writeText(curNode.path);
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
} else if (e.key === "d" && curNode && !isSystemFile(curNode.path)) {
|
|
|
|
|
|
e.preventDefault();
|
2026-02-13 15:52:13 -08:00
|
|
|
|
void apiDuplicate(curNode.path).then(() => onRefresh());
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
} else if (e.key === "n") {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
const parent = curNode
|
|
|
|
|
|
? curNode.type === "folder" || curNode.type === "object"
|
|
|
|
|
|
? curNode.path
|
|
|
|
|
|
: parentPath(curNode.path)
|
feat(web): full UI redesign with light/dark theme, TanStack data tables, media rendering, and gateway-routed agent execution
Overhaul the Dench web app with a comprehensive visual redesign and several
major feature additions across the chat interface, workspace, and agent
runtime layer.
Theme & Design System
- Replace the dark-only palette with a full light/dark theme system that
respects system preference via localStorage + inline script (no FOUC).
- Introduce new design tokens: glassmorphism surfaces, semantic colors
(success/warning/error/info), object-type chip palettes, and a tiered
shadow scale (sm/md/lg/xl).
- Add Instrument Serif + Inter via Google Fonts for a refined typographic
hierarchy; headings use the serif face, body uses Inter.
- Rebrand UI from "Ironclaw" to "Dench" across the landing page and
metadata.
Chat & Chain-of-Thought
- Rewrite the chain-of-thought component with inline media detection and
rendering — images, video, audio, and PDFs referenced in agent output
are now displayed directly in the conversation thread.
- Add status indicator parts (e.g. "Preparing response...",
"Optimizing session context...") that render as subtle activity badges
instead of verbose reasoning blocks.
- Integrate react-markdown with remark-gfm for proper markdown rendering
in assistant messages (tables, strikethrough, autolinks, etc.).
- Improve report-block splitting and lazy-loaded ReportCard rendering.
Workspace
- Introduce @tanstack/react-table for the object table, replacing the
hand-rolled table with full column sorting, fuzzy filtering via
match-sorter-utils, row selection, and bulk actions.
- Add a new media viewer component for in-workspace image/video/PDF
preview.
- New API routes: bulk-delete entries, field management (CRUD + reorder),
raw-file serving endpoint for media assets.
- Redesign workspace sidebar, empty state, and entry detail modal with
the new theme tokens and improved layout.
Agent Runtime
- Switch web agent execution from --local to gateway-routed mode so
concurrent chat threads share the gateway's lane-based concurrency
system, eliminating cross-process file-lock contention.
- Advertise "tool-events" capability during WebSocket handshake so the
gateway streams tool start/update/result events to the UI.
- Add new agent callback hooks: onLifecycleStart, onCompactionStart/End,
and onToolUpdate for richer real-time feedback.
- Forward media URLs emitted by agent events into the chat stream.
Dependencies
- Add @tanstack/match-sorter-utils and @tanstack/react-table to the web
app.
Published as ironclaw@2026.2.10-1.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 11:17:23 -08:00
|
|
|
|
: "";
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
if (e.shiftKey) {
|
|
|
|
|
|
setNewItemPrompt({ kind: "folder", parentPath: parent });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setNewItemPrompt({ kind: "file", parentPath: parent });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
[tree, expandedPaths, selectedPath, renamingPath, onSelect, onRefresh],
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (tree.length === 0) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="px-4 py-6 text-center text-sm"
|
|
|
|
|
|
style={{ color: "var(--color-text-muted)" }}
|
|
|
|
|
|
onContextMenu={handleEmptyContextMenu}
|
|
|
|
|
|
>
|
|
|
|
|
|
No files in workspace
|
|
|
|
|
|
{ctxMenu && (
|
|
|
|
|
|
<ContextMenu
|
|
|
|
|
|
x={ctxMenu.x}
|
|
|
|
|
|
y={ctxMenu.y}
|
|
|
|
|
|
target={ctxMenu.target}
|
|
|
|
|
|
onAction={handleContextMenuAction}
|
|
|
|
|
|
onClose={() => setCtxMenu(null)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{newItemPrompt && (
|
|
|
|
|
|
<NewItemPrompt
|
|
|
|
|
|
kind={newItemPrompt.kind}
|
|
|
|
|
|
parentPath={newItemPrompt.parentPath}
|
|
|
|
|
|
onSubmit={handleNewItemSubmit}
|
|
|
|
|
|
onCancel={() => setNewItemPrompt(null)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<DndContext
|
|
|
|
|
|
sensors={sensors}
|
|
|
|
|
|
collisionDetection={closestCenter}
|
|
|
|
|
|
onDragStart={handleDragStart}
|
|
|
|
|
|
onDragOver={handleDragOver}
|
|
|
|
|
|
onDragEnd={handleDragEnd}
|
|
|
|
|
|
onDragCancel={handleDragCancel}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
ref={containerRef}
|
2026-02-15 23:00:25 -08:00
|
|
|
|
className="py-1 outline-none flex flex-col min-h-full"
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
tabIndex={0}
|
|
|
|
|
|
role="tree"
|
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
|
onContextMenu={handleEmptyContextMenu}
|
|
|
|
|
|
>
|
2026-02-13 15:16:36 -08:00
|
|
|
|
{/* ".." navigation entry for browsing up */}
|
|
|
|
|
|
{parentDir != null && onNavigateUp && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
role="treeitem"
|
|
|
|
|
|
tabIndex={-1}
|
|
|
|
|
|
onClick={onNavigateUp}
|
|
|
|
|
|
className="w-full flex items-center gap-1.5 py-1 px-2 rounded-md text-left text-sm transition-colors duration-100 cursor-pointer select-none"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
paddingLeft: "8px",
|
|
|
|
|
|
color: "var(--color-text-muted)",
|
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
|
}}
|
|
|
|
|
|
onMouseEnter={(e) => {
|
|
|
|
|
|
(e.currentTarget as HTMLElement).style.background = "var(--color-surface-hover)";
|
|
|
|
|
|
}}
|
|
|
|
|
|
onMouseLeave={(e) => {
|
|
|
|
|
|
(e.currentTarget as HTMLElement).style.background = "transparent";
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="flex-shrink-0 w-4 h-4 flex items-center justify-center">
|
|
|
|
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
|
|
|
<path d="m15 18-6-6 6-6" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="flex-shrink-0 flex items-center" style={{ color: "var(--color-text-muted)" }}>
|
|
|
|
|
|
<FolderIcon />
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="truncate flex-1">..</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
{tree.map((node) => (
|
|
|
|
|
|
<DraggableNode
|
|
|
|
|
|
key={node.path}
|
|
|
|
|
|
node={node}
|
|
|
|
|
|
depth={0}
|
|
|
|
|
|
activePath={activePath}
|
|
|
|
|
|
selectedPath={selectedPath}
|
|
|
|
|
|
onSelect={onSelect}
|
|
|
|
|
|
onNodeSelect={setSelectedPath}
|
|
|
|
|
|
expandedPaths={expandedPaths}
|
|
|
|
|
|
onToggleExpand={handleToggleExpand}
|
|
|
|
|
|
renamingPath={renamingPath}
|
|
|
|
|
|
onStartRename={setRenamingPath}
|
|
|
|
|
|
onCommitRename={handleCommitRename}
|
|
|
|
|
|
onCancelRename={handleCancelRename}
|
|
|
|
|
|
onContextMenu={handleContextMenu}
|
|
|
|
|
|
compact={compact}
|
|
|
|
|
|
dragOverPath={dragOverPath}
|
2026-02-13 19:24:24 -08:00
|
|
|
|
workspaceRoot={workspaceRoot}
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
/>
|
|
|
|
|
|
))}
|
2026-02-15 23:00:25 -08:00
|
|
|
|
{/* Root-level drop zone: fills remaining space so items can be moved to root */}
|
|
|
|
|
|
<RootDropZone isDragging={!!activeNode} />
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-15 23:54:05 -08:00
|
|
|
|
{/* Drag overlay (ghost) — pointer-events:none so elementFromPoint sees through it */}
|
|
|
|
|
|
<DragOverlay dropAnimation={null} style={{ pointerEvents: "none" }}>
|
Dench workspace: file manager, relation resolution, and chat refactor
File Manager & Filesystem Operations:
- Add FileManagerTree component with drag-and-drop (dnd-kit), inline
rename, right-click context menu, and compact sidebar mode
- Add context-menu component (open, new file/folder, rename, duplicate,
copy, paste, move, delete) rendered via portal
- Add InlineRename component with validation and shake-on-error animation
- Add useWorkspaceWatcher hook with SSE live-reload and polling fallback
- Add API routes: mkdir, rename, copy, move, watch (SSE file-change
events), and DELETE on /api/workspace/file with system-file protection
- Add safeResolveNewPath and isSystemFile helpers to workspace lib
- Replace inline WorkspaceTreeNode in sidebar with shared FileManagerTree
(compact mode), add workspace refresh callback
Object Relation Resolution:
- Resolve relation fields to human-readable display labels server-side
(resolveRelationLabels, resolveDisplayField helpers)
- Add reverse relation discovery (findReverseRelations) — surfaces
incoming links from other objects
- Add display_field column migration (idempotent ALTER TABLE) and
PATCH /api/workspace/objects/[name]/display-field endpoint
- Enrich object API response with relationLabels, reverseRelations,
effectiveDisplayField, and related_object_name per field
- Add RelationCell, RelationChip, ReverseRelationCell, LinkIcon
components to object-table with clickable cross-object navigation
- Add relation label rendering to kanban cards
- Extract ObjectView component in workspace page with display-field
selector dropdown and relation/reverse-relation badge counts
Chat Panel Extraction:
- Extract chat logic from page.tsx into standalone ChatPanel component
with forwardRef/useImperativeHandle for session control
- ChatPanel supports file-scoped sessions (filePath param) and
context-aware file chat sidebar
- Simplify page.tsx to thin orchestrator delegating to ChatPanel
- Add filePath filter to GET /api/web-sessions for scoped session lists
Dependencies:
- Add @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
- Add duckdbExec and parseRelationValue to workspace lib
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 19:22:53 -08:00
|
|
|
|
{activeNode ? <DragOverlayContent node={activeNode} /> : null}
|
|
|
|
|
|
</DragOverlay>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Context menu */}
|
|
|
|
|
|
{ctxMenu && (
|
|
|
|
|
|
<ContextMenu
|
|
|
|
|
|
x={ctxMenu.x}
|
|
|
|
|
|
y={ctxMenu.y}
|
|
|
|
|
|
target={ctxMenu.target}
|
|
|
|
|
|
onAction={handleContextMenuAction}
|
|
|
|
|
|
onClose={() => setCtxMenu(null)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Delete confirmation dialog */}
|
|
|
|
|
|
{confirmDelete && (
|
|
|
|
|
|
<ConfirmDialog
|
|
|
|
|
|
message={`Are you sure you want to delete "${confirmDelete.split("/").pop()}"? This action cannot be undone.`}
|
|
|
|
|
|
onConfirm={handleConfirmDelete}
|
|
|
|
|
|
onCancel={() => setConfirmDelete(null)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* New file/folder prompt */}
|
|
|
|
|
|
{newItemPrompt && (
|
|
|
|
|
|
<NewItemPrompt
|
|
|
|
|
|
kind={newItemPrompt.kind}
|
|
|
|
|
|
parentPath={newItemPrompt.parentPath}
|
|
|
|
|
|
onSubmit={handleNewItemSubmit}
|
|
|
|
|
|
onCancel={() => setNewItemPrompt(null)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Inject animation styles */}
|
|
|
|
|
|
<style>{RENAME_SHAKE_STYLE}</style>
|
|
|
|
|
|
</DndContext>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|