refactor(frontend): rename useOverwriteAction to useOverwrite

Inside `components/shared/overwrite/` the folder name already supplies
context, so the `-action` suffix is redundant — same principle that
turned overwrite-confirm-dialog into overwrite-dialog. Rename file
use-overwrite-action.ts → use-overwrite.ts, export useOverwriteAction
→ useOverwrite, and the internal UseOverwriteAction* prop/result types
to match. The shape lines up with the project's verb-noun action-hook
convention (useResourcesCopy, useResourcesMove).
This commit is contained in:
Sergey Kozyrenko
2026-05-15 10:09:48 +07:00
parent 90eba577b2
commit d8e84d0df7
8 changed files with 18 additions and 20 deletions
@@ -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';
@@ -30,7 +30,7 @@ const ANONYMOUS_FALLBACK_CONFLICT: OverwriteConflict = {
destinationName: 'an item',
};
interface UseOverwriteActionOptions<TPlan> {
interface UseOverwriteOptions<TPlan> {
/**
* Execute the REST call. Receives the plan + a boolean `force` flag.
* Should return a discriminated outcome see `OverwriteOutcome`.
@@ -54,7 +54,7 @@ interface UseOverwriteActionOptions<TPlan> {
synthesizeFallbackConflicts?: (plan: TPlan) => OverwriteConflict[];
}
interface UseOverwriteActionResult<TPlan> {
interface UseOverwriteResult<TPlan> {
/** Live conflict descriptors. Wire to `<OverwriteDialog conflicts={…} />`. */
conflicts: OverwriteConflict[];
/**
@@ -95,9 +95,7 @@ interface UseOverwriteActionResult<TPlan> {
* 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 = <TPlan>(
options: UseOverwriteActionOptions<TPlan>,
): UseOverwriteActionResult<TPlan> => {
export const useOverwrite = <TPlan>(options: UseOverwriteOptions<TPlan>): UseOverwriteResult<TPlan> => {
const [conflicts, setConflicts] = useState<OverwriteConflict[]>([]);
const [pendingPlan, setPendingPlan] = useState<null | TPlan>(null);
@@ -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<AttachPlan>({
const overwriteAction = useOverwrite<AttachPlan>({
execute: async ({ ids }, force) => attach({ ids: [...ids], shouldOverwrite: force }),
findConflicts: ({ resourcePaths }) => findAttachConflicts(resourcePaths, cachedFiles),
onSuccess: () => {
@@ -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<PromotePlan>({
const overwriteAction = useOverwrite<PromotePlan>({
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.
@@ -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<readonly string[]>({
const overwriteAction = useOverwrite<readonly string[]>({
execute: (paths, force) => pull(paths, force),
findConflicts: (paths) => findPullConflicts(paths, cachedFiles),
onSuccess: onClose,
@@ -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<CopyPlan>({
const overwriteAction = useOverwrite<CopyPlan>({
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.
@@ -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<MovePlan>({
const overwriteAction = useOverwrite<MovePlan>({
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
+2 -2
View File
@@ -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<DndMovePlan>({
const dndMoveAction = useOverwrite<DndMovePlan>({
execute: (plan, force) => move(plan.sources, plan.destination, force),
findConflicts: (plan) => {
const movedPaths = new Set(plan.sources);