From 012cb741ad2b60cf463af595812ee57c22ced270 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Fri, 8 May 2026 15:39:03 +0700 Subject: [PATCH] refactor(file-manager): chevron drill-in, responsive bulk bar and tri-state toggle fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - File manager core: - Chevron click on folder rows now drills in via `onOpenDirectory` (when set), matching the existing double-click / Enter semantics. Consumers that don't wire the prop keep the legacy expand/collapse behaviour, so flow-files / resources trees stay unchanged. - Bulk actions bar wraps and collapses to icon-only buttons (Cancel included) on small viewports so the bar stays usable on mobile. - Fix tri-state subtree toggle requiring two clicks when the directory's own path was never in the selection (e.g. user ticked children one-by-one). \`toggleSubtreeOnSet\` now accepts an optional \`rootPath\` and ignores it for the "all selected?" check, mirroring what \`computeDirSelectionState\` shows on the visible checkbox. Covered by new regression tests in \`file-manager-utils.test.ts\`. - Built-in icons swapped: copy-path uses \`ClipboardCopy\` instead of \`Copy\`; bulk \"Save as resources\" uses \`FolderOutput\` instead of \`BookmarkPlus\`. - Pull dialog: flatten the container listing (\`name\` as \`path\`, absolute path in \`id\`) so the chevron / double-click drill into real subfolders instead of toggling a synthetic \`work/\` wrapper that has no meaningful navigation target. Selection is mapped back to absolute paths via a name → absolute lookup before pulling. - Resources page: drop the focus-derived \`currentDir\` plumbing — toolbar mkdir / upload always target the library root, row context menu loses \"Upload files here\" and renames \"New folder here\" to \"New folder\". Page wraps in \`h-[calc(100dvh-3rem)]\` so the bulk bar stays inside the viewport. Tooltips simplified accordingly. - Flow files toolbar: replace the standalone Info icon with rich per-button tooltips that explain where each gesture lands (/work/uploads, /work/resources, separate Container snapshot area); upload button uses the standard \`Upload\` glyph. - Attach resources dialog: switch the ad-hoc footer to a proper \`DialogFooter\` with responsive layout, tighten the dialog title. - \`Dialog\` / \`Sheet\` footers always apply the inter-button gap, not only at the \`sm+\` breakpoint. Co-authored-by: Cursor --- .../file-manager/file-manager-actions.tsx | 6 +- .../file-manager-bulk-actions-bar.tsx | 14 ++- .../shared/file-manager/file-manager-row.tsx | 17 ++- .../shared/file-manager/file-manager-types.ts | 19 ++- .../file-manager/file-manager-utils.test.ts | 90 ++++++++++++++ .../shared/file-manager/file-manager-utils.ts | 42 ++++++- frontend/src/components/ui/dialog.tsx | 2 +- frontend/src/components/ui/sheet.tsx | 2 +- .../flow-files-attach-resources-dialog.tsx | 25 ++-- .../flows/files/flow-files-pull-dialog.tsx | 82 ++++++++++--- .../src/features/flows/files/flow-files.tsx | 56 ++++----- frontend/src/pages/resources/resources.tsx | 113 +++++------------- 12 files changed, 299 insertions(+), 169 deletions(-) diff --git a/frontend/src/components/shared/file-manager/file-manager-actions.tsx b/frontend/src/components/shared/file-manager/file-manager-actions.tsx index a2712fc0..04c1afba 100644 --- a/frontend/src/components/shared/file-manager/file-manager-actions.tsx +++ b/frontend/src/components/shared/file-manager/file-manager-actions.tsx @@ -1,4 +1,4 @@ -import { BookmarkPlus, ClipboardCopy, Copy, Download, FileSymlink, Trash2 } from 'lucide-react'; +import { ClipboardCopy, Copy, Download, FileSymlink, FolderOutput, Trash2 } from 'lucide-react'; import type { FileManagerAction, FileManagerBulkAction, FileNode } from './file-manager-types'; @@ -29,7 +29,7 @@ export const downloadAction = ( /** Built-in copy-path action. */ export const copyPathAction = (onCopyPath: (file: FileNode) => void): FileManagerAction => ({ appliesToDirs: true, - icon: Copy, + icon: ClipboardCopy, id: '__builtin_copy_path', label: 'Copy path', onSelect: onCopyPath, @@ -148,7 +148,7 @@ export const bulkPromoteAction = ( onPromote: (files: FileNode[]) => void, options: { label?: string; overflow?: boolean } = {}, ): FileManagerBulkAction => ({ - icon: BookmarkPlus, + icon: FolderOutput, id: '__builtin_bulk_promote', label: options.label ?? 'Save as resources', onSelect: onPromote, diff --git a/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx b/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx index 4041811c..8efac7a8 100644 --- a/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx +++ b/frontend/src/components/shared/file-manager/file-manager-bulk-actions-bar.tsx @@ -1,4 +1,4 @@ -import { MoreHorizontal } from 'lucide-react'; +import { MoreHorizontal, X } from 'lucide-react'; import { type ComponentType, useCallback, useMemo, useState } from 'react'; import ConfirmationDialog from '@/components/shared/confirmation-dialog'; @@ -136,15 +136,18 @@ export const FileManagerBulkActionsBar = ({ return ( <> -
+
{selectedText} -
+
{inlineActions.map(({ action, isDisabled }) => ( @@ -221,12 +224,13 @@ const BulkActionButton = ({ action, isDisabled, onClick }: BulkActionButtonProps const Icon = action.icon as ComponentType<{ className?: string }> | undefined; const button = ( ); diff --git a/frontend/src/components/shared/file-manager/file-manager-row.tsx b/frontend/src/components/shared/file-manager/file-manager-row.tsx index 6192e0f1..ffc7737d 100644 --- a/frontend/src/components/shared/file-manager/file-manager-row.tsx +++ b/frontend/src/components/shared/file-manager/file-manager-row.tsx @@ -153,9 +153,7 @@ const buildVisibleActions = ( actions: readonly FileManagerAction[], file: FileManagerInternalNode, ): FileManagerAction[] => - actions.filter((action) => - file.isDir ? action.appliesToDirs === true : action.appliesToFiles !== false, - ); + actions.filter((action) => (file.isDir ? action.appliesToDirs === true : action.appliesToFiles !== false)); const FileManagerRowImpl = ({ actions, @@ -425,7 +423,18 @@ const FileManagerRowImpl = ({