diff --git a/frontend/src/components/shared/overwrite/index.ts b/frontend/src/components/shared/overwrite/index.ts index efd75784..1cf00ddb 100644 --- a/frontend/src/components/shared/overwrite/index.ts +++ b/frontend/src/components/shared/overwrite/index.ts @@ -1,5 +1,5 @@ export { OverwriteButtons } from './overwrite-buttons'; export { OverwriteDialog } from './overwrite-dialog'; export type { OverwriteConflict } from './overwrite-dialog'; -export { useOverwriteAction } from './use-overwrite-action'; -export type { OverwriteOutcome } from './use-overwrite-action'; +export { useOverwrite } from './use-overwrite'; +export type { OverwriteOutcome } from './use-overwrite'; diff --git a/frontend/src/components/shared/overwrite/use-overwrite-action.ts b/frontend/src/components/shared/overwrite/use-overwrite.ts similarity index 97% rename from frontend/src/components/shared/overwrite/use-overwrite-action.ts rename to frontend/src/components/shared/overwrite/use-overwrite.ts index 2bc8f920..3f1ad8f8 100644 --- a/frontend/src/components/shared/overwrite/use-overwrite-action.ts +++ b/frontend/src/components/shared/overwrite/use-overwrite.ts @@ -30,7 +30,7 @@ const ANONYMOUS_FALLBACK_CONFLICT: OverwriteConflict = { destinationName: 'an item', }; -interface UseOverwriteActionOptions { +interface UseOverwriteOptions { /** * Execute the REST call. Receives the plan + a boolean `force` flag. * Should return a discriminated outcome — see `OverwriteOutcome`. @@ -54,7 +54,7 @@ interface UseOverwriteActionOptions { synthesizeFallbackConflicts?: (plan: TPlan) => OverwriteConflict[]; } -interface UseOverwriteActionResult { +interface UseOverwriteResult { /** Live conflict descriptors. Wire to ``. */ conflicts: OverwriteConflict[]; /** @@ -95,9 +95,7 @@ interface UseOverwriteActionResult { * to wrap them in `useCallback`. This keeps the hook ergonomic at the call * site without sacrificing reference stability for the returned actions. */ -export const useOverwriteAction = ( - options: UseOverwriteActionOptions, -): UseOverwriteActionResult => { +export const useOverwrite = (options: UseOverwriteOptions): UseOverwriteResult => { const [conflicts, setConflicts] = useState([]); const [pendingPlan, setPendingPlan] = useState(null); diff --git a/frontend/src/features/flows/files/flow-files-attach-resources-dialog.tsx b/frontend/src/features/flows/files/flow-files-attach-resources-dialog.tsx index 6511a995..941b806c 100644 --- a/frontend/src/features/flows/files/flow-files-attach-resources-dialog.tsx +++ b/frontend/src/features/flows/files/flow-files-attach-resources-dialog.tsx @@ -2,7 +2,7 @@ import { FolderInput, Search, X } from 'lucide-react'; import { useCallback, useMemo, useState } from 'react'; import { FileManager, type FileNode } from '@/components/shared/file-manager'; -import { OverwriteButtons, OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteButtons, OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Button } from '@/components/ui/button'; import { Dialog, @@ -84,7 +84,7 @@ const FlowFilesAttachResourcesDialogBody = ({ * the backend) and the resource paths (used by preflight against the * flow's existing cache mirror). */ - const overwriteAction = useOverwriteAction({ + const overwriteAction = useOverwrite({ execute: async ({ ids }, force) => attach({ ids: [...ids], shouldOverwrite: force }), findConflicts: ({ resourcePaths }) => findAttachConflicts(resourcePaths, cachedFiles), onSuccess: () => { diff --git a/frontend/src/features/flows/files/flow-files-promote-dialog.tsx b/frontend/src/features/flows/files/flow-files-promote-dialog.tsx index d1930d21..7c1f2c1e 100644 --- a/frontend/src/features/flows/files/flow-files-promote-dialog.tsx +++ b/frontend/src/features/flows/files/flow-files-promote-dialog.tsx @@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteButtons, OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteButtons, OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; @@ -137,7 +137,7 @@ const FlowFilesPromoteDialogForm = ({ files, flowId, onClose }: FlowFilesPromote * with a single atomic batch request. Backend handles `sources[]` in one * DB transaction (all-or-nothing) — no per-source aggregation needed here. */ - const overwriteAction = useOverwriteAction({ + const overwriteAction = useOverwrite({ execute: (plan, force) => promote(plan.sources, plan.destination, force), // Local preflight against the resource library snapshot — flags the // exact destinations already taken so the dialog can name them. diff --git a/frontend/src/features/flows/files/flow-files-pull-dialog.tsx b/frontend/src/features/flows/files/flow-files-pull-dialog.tsx index dd2780e0..744bbc90 100644 --- a/frontend/src/features/flows/files/flow-files-pull-dialog.tsx +++ b/frontend/src/features/flows/files/flow-files-pull-dialog.tsx @@ -7,7 +7,7 @@ import { type FileManagerBulkAction, type FileNode, } from '@/components/shared/file-manager'; -import { OverwriteButtons, OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteButtons, OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Autocomplete, AutocompleteContent, @@ -95,7 +95,7 @@ const getParentContainerPath = (path: string): string => { * is open so closing it discards every transient field without an imperative reset. * * The actual overwrite orchestration (preflight → execute → ConflictDialog - * fallback) is delegated to {@link useOverwriteAction}; this component only + * fallback) is delegated to {@link useOverwrite}; this component only * owns the listing browser UI and the per-action plan derivation. */ const FlowFilesPullDialogForm = ({ cachedFiles, flowId, onClose, onSuccess }: FlowFilesPullDialogFormProps) => { @@ -167,7 +167,7 @@ const FlowFilesPullDialogForm = ({ cachedFiles, flowId, onClose, onSuccess }: Fl * close-on-success — this dialog just provides the plan (paths) and the * three pure helpers (find / execute / synthesize). */ - const overwriteAction = useOverwriteAction({ + const overwriteAction = useOverwrite({ execute: (paths, force) => pull(paths, force), findConflicts: (paths) => findPullConflicts(paths, cachedFiles), onSuccess: onClose, diff --git a/frontend/src/features/resources/resources-copy-dialog.tsx b/frontend/src/features/resources/resources-copy-dialog.tsx index a6f052d3..5c0ebdde 100644 --- a/frontend/src/features/resources/resources-copy-dialog.tsx +++ b/frontend/src/features/resources/resources-copy-dialog.tsx @@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteButtons, OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteButtons, OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; @@ -139,7 +139,7 @@ const ResourcesCopyDialogForm = ({ files, onClose }: ResourcesCopyDialogFormProp * with a single atomic batch request. Backend handles `sources[]` in one * DB transaction (all-or-nothing). */ - const overwriteAction = useOverwriteAction({ + const overwriteAction = useOverwrite({ execute: (plan, force) => copy(plan.sources, plan.destination, force), // Copy never deletes the sources, so collisions with sources are real // conflicts (unlike move). Just intersect targets with existing paths. diff --git a/frontend/src/features/resources/resources-move-dialog.tsx b/frontend/src/features/resources/resources-move-dialog.tsx index b03a85d4..186c3735 100644 --- a/frontend/src/features/resources/resources-move-dialog.tsx +++ b/frontend/src/features/resources/resources-move-dialog.tsx @@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteButtons, OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteButtons, OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; @@ -133,7 +133,7 @@ const ResourcesMoveDialogForm = ({ files, onClose }: ResourcesMoveDialogFormProp * with a single atomic batch request. Backend handles `sources[]` in one * DB transaction (all-or-nothing) — no per-source aggregation needed here. */ - const overwriteAction = useOverwriteAction({ + const overwriteAction = useOverwrite({ execute: (plan, force) => move(plan.sources, plan.destination, force), // Local preflight: filter out targets that match an item we're moving // (those are no-ops, not conflicts) and keep the ones already taken diff --git a/frontend/src/pages/resources/resources.tsx b/frontend/src/pages/resources/resources.tsx index cdfc6918..aa14b002 100644 --- a/frontend/src/pages/resources/resources.tsx +++ b/frontend/src/pages/resources/resources.tsx @@ -24,7 +24,7 @@ import { formatModifiedRelative, } from '@/components/shared/file-manager'; import { HeaderButton } from '@/components/shared/header-button'; -import { OverwriteDialog, useOverwriteAction } from '@/components/shared/overwrite'; +import { OverwriteDialog, useOverwrite } from '@/components/shared/overwrite'; import { Breadcrumb, BreadcrumbItem, BreadcrumbList, BreadcrumbPage } from '@/components/ui/breadcrumb'; import { Button } from '@/components/ui/button'; import { @@ -185,7 +185,7 @@ const Resources = () => { targets: OverwriteConflict[]; } - const dndMoveAction = useOverwriteAction({ + const dndMoveAction = useOverwrite({ execute: (plan, force) => move(plan.sources, plan.destination, force), findConflicts: (plan) => { const movedPaths = new Set(plan.sources);