Prepare v0.1.0 release

This commit is contained in:
2026-06-24 20:00:11 +02:00
parent 934c6f25d8
commit 993f744c19
9 changed files with 134 additions and 113 deletions

View File

@@ -1,6 +1,6 @@
import type { CSSProperties, DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent, ReactNode } from "react";
import { Copy, Download, Folder, FolderOpen, Home, MoveRight, Plus, Trash2, UploadCloud } from "lucide-react";
import { Button, Dialog } from "@govoplan/core-webui";
import { Copy, Download, FolderOpen, Home, MoveRight, Plus, Trash2, UploadCloud } from "lucide-react";
import { Button, Dialog, ExplorerTree, type ExplorerTreeNodeContext } from "@govoplan/core-webui";
import type { ConflictAction, FileSpace, RenameResponse } from "../../../api/files";
import type { ConflictDialogState, FileActionTarget, FileConflictItem, FolderNode, ContextMenuState } from "../types";
import { isPathUnderOrSame, normalizeFolder, treeNodeKey } from "../utils/fileManagerUtils";
@@ -111,80 +111,35 @@ export function FolderTree({
disabled?: boolean;
depth?: number;
}) {
if (nodes.length === 0) return null;
return (
<div className="file-tree-children">
{nodes.map((node) => {
const isActive = activeSpaceId === spaceId && currentFolder === node.path;
<ExplorerTree
nodes={nodes}
getNodeId={(node) => treeNodeKey(spaceId, node.path)}
getNodeLabel={(node) => node.name}
getNodeChildren={(node) => node.children}
activeId={activeSpaceId === spaceId ? treeNodeKey(spaceId, currentFolder) : ""}
expandedIds={expandedKeys}
onOpen={(node) => onOpen(spaceId, node.path)}
onToggle={(node) => onToggle(spaceId, node.path)}
disabled={disabled}
depth={depth}
getNodeWrapClassName={(node) => {
const target = { spaceId, folderPath: node.path };
const isDropTarget = dragDropEnabled && dropTargetKey === `${target.spaceId}:${normalizeFolder(target.folderPath)}`;
const hasChildren = node.children.length > 0;
const isExpanded = expandedKeys.has(treeNodeKey(spaceId, node.path));
return (
<div key={node.path}>
<div
className={`file-tree-node-wrap ${isActive ? "is-active" : ""} ${isDropTarget ? "is-drop-target" : ""}`}
style={{ paddingLeft: `${Math.min(depth * 14, 56)}px` }}
draggable={dragDropEnabled && !disabled}
onDragStart={dragDropEnabled && onDragStartFolder ? (event) => onDragStartFolder(spaceId, node.path, event) : undefined}
onDragEnd={dragDropEnabled ? onDragEndFolder : undefined}
onContextMenu={contextMenuEnabled && onContextMenu ? (event) => onContextMenu(event, spaceId, node.path) : undefined}
onDragOver={dragDropEnabled && onDragOverTarget ? (event) => {
onDragOverTarget(event, target);
if (hasChildren && !isExpanded) onRequestDragExpand?.(spaceId, node.path);
} : undefined}
onDragLeave={dragDropEnabled ? onClearDropState : undefined}
onDrop={dragDropEnabled && onDropOnTarget ? (event) => void onDropOnTarget(event, target) : undefined}
>
<button
type="button"
className="file-tree-toggle"
onClick={(event) => {
event.stopPropagation();
if (hasChildren) onToggle(spaceId, node.path);
}}
disabled={disabled || !hasChildren}
aria-label={`${isExpanded ? "Collapse" : "Expand"} ${node.name}`}
aria-expanded={hasChildren ? isExpanded : undefined}
>
{isExpanded ? <FolderOpen size={15} aria-hidden="true" /> : <Folder size={15} aria-hidden="true" />}
</button>
<button
type="button"
className="file-tree-node"
onClick={() => onOpen(spaceId, node.path)}
disabled={disabled}
>
<span>{node.name}</span>
</button>
</div>
{hasChildren && isExpanded && (
<FolderTree
nodes={node.children}
activeSpaceId={activeSpaceId}
spaceId={spaceId}
currentFolder={currentFolder}
dropTargetKey={dropTargetKey}
expandedKeys={expandedKeys}
onOpen={onOpen}
onToggle={onToggle}
onContextMenu={onContextMenu}
onDragOverTarget={onDragOverTarget}
onDropOnTarget={onDropOnTarget}
onClearDropState={onClearDropState}
onRequestDragExpand={onRequestDragExpand}
onDragStartFolder={onDragStartFolder}
onDragEndFolder={onDragEndFolder}
dragDropEnabled={dragDropEnabled}
contextMenuEnabled={contextMenuEnabled}
disabled={disabled}
depth={depth + 1}
/>
)}
</div>
);
})}
</div>
return dragDropEnabled && dropTargetKey === `${target.spaceId}:${normalizeFolder(target.folderPath)}` ? "is-drop-target" : undefined;
}}
getNodeWrapStyle={(_node, context: ExplorerTreeNodeContext) => ({ paddingLeft: `${Math.min(context.depth * 14, 56)}px` })}
getNodeDraggable={() => dragDropEnabled && !disabled}
onContextMenu={contextMenuEnabled && onContextMenu ? (event, node) => onContextMenu(event, spaceId, node.path) : undefined}
onDragStart={dragDropEnabled && onDragStartFolder ? (event, node) => onDragStartFolder(spaceId, node.path, event) : undefined}
onDragEnd={dragDropEnabled && onDragEndFolder ? () => onDragEndFolder() : undefined}
onDragOver={dragDropEnabled && onDragOverTarget ? (event, node, context) => {
const target = { spaceId, folderPath: node.path };
onDragOverTarget(event, target);
if (context.hasChildren && !context.expanded) onRequestDragExpand?.(spaceId, node.path);
} : undefined}
onDragLeave={dragDropEnabled && onClearDropState ? () => onClearDropState() : undefined}
onDrop={dragDropEnabled && onDropOnTarget ? (event, node) => void onDropOnTarget(event, { spaceId, folderPath: node.path }) : undefined}
/>
);
}