From 4d2e4ff5bfc39863eaf2dec9826c5ae39c933416 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Fri, 15 May 2026 09:50:08 +0700 Subject: [PATCH] refactor(frontend): consolidate overwrite and unsaved-changes into module folders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group the overwrite trio (OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction) into components/shared/overwrite/ — they cross-import the OverwriteConflict type and 12 consumers always pull from the same logical module. Same pattern for the unsaved-changes pair: move the dialog from components/shared/ and the UI-agnostic guard hook from hooks/ into components/shared/unsaved-changes/. Each folder ships an index.ts so consumers reach the module through one import path. --- frontend/src/components/shared/overwrite/index.ts | 5 +++++ .../shared/{ => overwrite}/overwrite-confirm-dialog.tsx | 0 .../shared/{ => overwrite}/overwrite-cta-buttons.tsx | 0 .../shared/{ => overwrite}/use-overwrite-action.ts | 2 +- frontend/src/components/shared/unsaved-changes/index.ts | 4 ++++ .../shared/{ => unsaved-changes}/unsaved-changes-dialog.tsx | 0 .../shared/unsaved-changes}/use-unsaved-changes-guard.ts | 0 .../flows/files/flow-files-attach-resources-dialog.tsx | 4 +--- frontend/src/features/flows/files/flow-files-conflicts.ts | 2 +- .../src/features/flows/files/flow-files-promote-dialog.tsx | 6 ++---- .../src/features/flows/files/flow-files-pull-dialog.tsx | 4 +--- .../features/flows/files/use-flow-files-attach-resources.ts | 2 +- frontend/src/features/flows/files/use-flow-files-promote.ts | 2 +- frontend/src/features/flows/files/use-flow-files-pull.ts | 2 +- frontend/src/features/knowledges/knowledge-form.tsx | 3 +-- frontend/src/features/resources/resources-copy-dialog.tsx | 6 ++---- frontend/src/features/resources/resources-move-dialog.tsx | 6 ++---- frontend/src/features/resources/use-resources-copy.ts | 2 +- frontend/src/features/resources/use-resources-move.ts | 2 +- frontend/src/pages/resources/resources.tsx | 5 ++--- 20 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 frontend/src/components/shared/overwrite/index.ts rename frontend/src/components/shared/{ => overwrite}/overwrite-confirm-dialog.tsx (100%) rename frontend/src/components/shared/{ => overwrite}/overwrite-cta-buttons.tsx (100%) rename frontend/src/components/shared/{ => overwrite}/use-overwrite-action.ts (98%) create mode 100644 frontend/src/components/shared/unsaved-changes/index.ts rename frontend/src/components/shared/{ => unsaved-changes}/unsaved-changes-dialog.tsx (100%) rename frontend/src/{hooks => components/shared/unsaved-changes}/use-unsaved-changes-guard.ts (100%) diff --git a/frontend/src/components/shared/overwrite/index.ts b/frontend/src/components/shared/overwrite/index.ts new file mode 100644 index 00000000..f94d348f --- /dev/null +++ b/frontend/src/components/shared/overwrite/index.ts @@ -0,0 +1,5 @@ +export { OverwriteConfirmDialog } from './overwrite-confirm-dialog'; +export type { OverwriteConflict } from './overwrite-confirm-dialog'; +export { OverwriteCtaButtons } from './overwrite-cta-buttons'; +export { useOverwriteAction } from './use-overwrite-action'; +export type { OverwriteOutcome } from './use-overwrite-action'; diff --git a/frontend/src/components/shared/overwrite-confirm-dialog.tsx b/frontend/src/components/shared/overwrite/overwrite-confirm-dialog.tsx similarity index 100% rename from frontend/src/components/shared/overwrite-confirm-dialog.tsx rename to frontend/src/components/shared/overwrite/overwrite-confirm-dialog.tsx diff --git a/frontend/src/components/shared/overwrite-cta-buttons.tsx b/frontend/src/components/shared/overwrite/overwrite-cta-buttons.tsx similarity index 100% rename from frontend/src/components/shared/overwrite-cta-buttons.tsx rename to frontend/src/components/shared/overwrite/overwrite-cta-buttons.tsx diff --git a/frontend/src/components/shared/use-overwrite-action.ts b/frontend/src/components/shared/overwrite/use-overwrite-action.ts similarity index 98% rename from frontend/src/components/shared/use-overwrite-action.ts rename to frontend/src/components/shared/overwrite/use-overwrite-action.ts index 06a59520..0b1da399 100644 --- a/frontend/src/components/shared/use-overwrite-action.ts +++ b/frontend/src/components/shared/overwrite/use-overwrite-action.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useRef, useState } from 'react'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from './overwrite-confirm-dialog'; /** * Discriminated outcome of a server action that supports an overwrite flag. diff --git a/frontend/src/components/shared/unsaved-changes/index.ts b/frontend/src/components/shared/unsaved-changes/index.ts new file mode 100644 index 00000000..410ee2e5 --- /dev/null +++ b/frontend/src/components/shared/unsaved-changes/index.ts @@ -0,0 +1,4 @@ +export { UnsavedChangesDialog } from './unsaved-changes-dialog'; +export type { UnsavedChangesDialogProps } from './unsaved-changes-dialog'; +export { useUnsavedChangesGuard } from './use-unsaved-changes-guard'; +export type { UnsavedChangesGuard, UseUnsavedChangesGuardArgs } from './use-unsaved-changes-guard'; diff --git a/frontend/src/components/shared/unsaved-changes-dialog.tsx b/frontend/src/components/shared/unsaved-changes/unsaved-changes-dialog.tsx similarity index 100% rename from frontend/src/components/shared/unsaved-changes-dialog.tsx rename to frontend/src/components/shared/unsaved-changes/unsaved-changes-dialog.tsx diff --git a/frontend/src/hooks/use-unsaved-changes-guard.ts b/frontend/src/components/shared/unsaved-changes/use-unsaved-changes-guard.ts similarity index 100% rename from frontend/src/hooks/use-unsaved-changes-guard.ts rename to frontend/src/components/shared/unsaved-changes/use-unsaved-changes-guard.ts 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 9c9538c9..d7902075 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,9 +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 { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { OverwriteCtaButtons } from '@/components/shared/overwrite-cta-buttons'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction } from '@/components/shared/overwrite'; import { Button } from '@/components/ui/button'; import { Dialog, diff --git a/frontend/src/features/flows/files/flow-files-conflicts.ts b/frontend/src/features/flows/files/flow-files-conflicts.ts index eb1ea58e..a793fb36 100644 --- a/frontend/src/features/flows/files/flow-files-conflicts.ts +++ b/frontend/src/features/flows/files/flow-files-conflicts.ts @@ -1,5 +1,5 @@ import type { FileNode } from '@/components/shared/file-manager'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from '@/components/shared/overwrite'; import { CONTAINER_PATH_PREFIX, RESOURCES_PATH_PREFIX } from './flow-files-constants'; 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 f6f6e3b8..6a7fab68 100644 --- a/frontend/src/features/flows/files/flow-files-promote-dialog.tsx +++ b/frontend/src/features/flows/files/flow-files-promote-dialog.tsx @@ -4,11 +4,9 @@ import { useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { OverwriteCtaButtons } from '@/components/shared/overwrite-cta-buttons'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction } 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'; 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 b305f90a..76025e07 100644 --- a/frontend/src/features/flows/files/flow-files-pull-dialog.tsx +++ b/frontend/src/features/flows/files/flow-files-pull-dialog.tsx @@ -7,9 +7,7 @@ import { type FileManagerBulkAction, type FileNode, } from '@/components/shared/file-manager'; -import { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { OverwriteCtaButtons } from '@/components/shared/overwrite-cta-buttons'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction } from '@/components/shared/overwrite'; import { Autocomplete, AutocompleteContent, diff --git a/frontend/src/features/flows/files/use-flow-files-attach-resources.ts b/frontend/src/features/flows/files/use-flow-files-attach-resources.ts index c1adaee8..f276e491 100644 --- a/frontend/src/features/flows/files/use-flow-files-attach-resources.ts +++ b/frontend/src/features/flows/files/use-flow-files-attach-resources.ts @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; -import type { OverwriteOutcome } from '@/components/shared/use-overwrite-action'; +import type { OverwriteOutcome } from '@/components/shared/overwrite'; import { resourceIdsToWire } from '@/features/resources/resources-rest'; import { api, getApiErrorMessage, getApiErrorStatusCode } from '@/lib/axios'; diff --git a/frontend/src/features/flows/files/use-flow-files-promote.ts b/frontend/src/features/flows/files/use-flow-files-promote.ts index 6145e346..32ccacbb 100644 --- a/frontend/src/features/flows/files/use-flow-files-promote.ts +++ b/frontend/src/features/flows/files/use-flow-files-promote.ts @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; import { z } from 'zod'; -import type { OverwriteOutcome } from '@/components/shared/use-overwrite-action'; +import type { OverwriteOutcome } from '@/components/shared/overwrite'; import type { RestResourceList } from '@/features/resources/resources-rest'; import { pluralizeItems } from '@/features/resources/resources-utils'; diff --git a/frontend/src/features/flows/files/use-flow-files-pull.ts b/frontend/src/features/flows/files/use-flow-files-pull.ts index 96773a9d..5ddf32f9 100644 --- a/frontend/src/features/flows/files/use-flow-files-pull.ts +++ b/frontend/src/features/flows/files/use-flow-files-pull.ts @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; -import type { OverwriteOutcome } from '@/components/shared/use-overwrite-action'; +import type { OverwriteOutcome } from '@/components/shared/overwrite'; import { api, getApiErrorMessage, getApiErrorStatusCode } from '@/lib/axios'; diff --git a/frontend/src/features/knowledges/knowledge-form.tsx b/frontend/src/features/knowledges/knowledge-form.tsx index 16e4f03d..77787d64 100644 --- a/frontend/src/features/knowledges/knowledge-form.tsx +++ b/frontend/src/features/knowledges/knowledge-form.tsx @@ -12,12 +12,11 @@ import type { } from '@/graphql/types'; import { HeaderButton } from '@/components/shared/header-button'; -import { UnsavedChangesDialog } from '@/components/shared/unsaved-changes-dialog'; +import { UnsavedChangesDialog, useUnsavedChangesGuard } from '@/components/shared/unsaved-changes'; import { Form } from '@/components/ui/form'; import { Spinner } from '@/components/ui/spinner'; import { KnowledgeAnswerType, KnowledgeDocType, KnowledgeGuideType } from '@/graphql/types'; import { useBreakpoint } from '@/hooks/use-breakpoint'; -import { useUnsavedChangesGuard } from '@/hooks/use-unsaved-changes-guard'; import { Log } from '@/lib/log'; import { KnowledgeFormLayoutDesktop, KnowledgeFormLayoutMobile } from './knowledge-form-layout'; diff --git a/frontend/src/features/resources/resources-copy-dialog.tsx b/frontend/src/features/resources/resources-copy-dialog.tsx index 34898a55..7052251d 100644 --- a/frontend/src/features/resources/resources-copy-dialog.tsx +++ b/frontend/src/features/resources/resources-copy-dialog.tsx @@ -4,11 +4,9 @@ import { useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { OverwriteCtaButtons } from '@/components/shared/overwrite-cta-buttons'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction } 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'; diff --git a/frontend/src/features/resources/resources-move-dialog.tsx b/frontend/src/features/resources/resources-move-dialog.tsx index 16ebe857..585515fe 100644 --- a/frontend/src/features/resources/resources-move-dialog.tsx +++ b/frontend/src/features/resources/resources-move-dialog.tsx @@ -4,11 +4,9 @@ import { useEffect, useMemo } from 'react'; import { useForm } from 'react-hook-form'; import type { FileNode } from '@/components/shared/file-manager'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from '@/components/shared/overwrite'; -import { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { OverwriteCtaButtons } from '@/components/shared/overwrite-cta-buttons'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, OverwriteCtaButtons, useOverwriteAction } 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'; diff --git a/frontend/src/features/resources/use-resources-copy.ts b/frontend/src/features/resources/use-resources-copy.ts index f72b768d..f8d69e6c 100644 --- a/frontend/src/features/resources/use-resources-copy.ts +++ b/frontend/src/features/resources/use-resources-copy.ts @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; import { z } from 'zod'; -import type { OverwriteOutcome } from '@/components/shared/use-overwrite-action'; +import type { OverwriteOutcome } from '@/components/shared/overwrite'; import { api, getApiErrorMessage, getApiErrorStatusCode } from '@/lib/axios'; diff --git a/frontend/src/features/resources/use-resources-move.ts b/frontend/src/features/resources/use-resources-move.ts index fcddc711..9b44fb04 100644 --- a/frontend/src/features/resources/use-resources-move.ts +++ b/frontend/src/features/resources/use-resources-move.ts @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'; import { toast } from 'sonner'; import { z } from 'zod'; -import type { OverwriteOutcome } from '@/components/shared/use-overwrite-action'; +import type { OverwriteOutcome } from '@/components/shared/overwrite'; import { api, getApiErrorMessage, getApiErrorStatusCode } from '@/lib/axios'; diff --git a/frontend/src/pages/resources/resources.tsx b/frontend/src/pages/resources/resources.tsx index 0afe1225..1f61d040 100644 --- a/frontend/src/pages/resources/resources.tsx +++ b/frontend/src/pages/resources/resources.tsx @@ -2,7 +2,7 @@ import { ChevronDown, Copy, FileSymlink, Folder, FolderPlus, FolderUp, Loader2, import { useCallback, useMemo, useState } from 'react'; import { toast } from 'sonner'; -import type { OverwriteConflict } from '@/components/shared/overwrite-confirm-dialog'; +import type { OverwriteConflict } from '@/components/shared/overwrite'; import ConfirmationDialog from '@/components/shared/confirmation-dialog'; import { @@ -24,8 +24,7 @@ import { formatModifiedRelative, } from '@/components/shared/file-manager'; import { HeaderButton } from '@/components/shared/header-button'; -import { OverwriteConfirmDialog } from '@/components/shared/overwrite-confirm-dialog'; -import { useOverwriteAction } from '@/components/shared/use-overwrite-action'; +import { OverwriteConfirmDialog, useOverwriteAction } from '@/components/shared/overwrite'; import { Breadcrumb, BreadcrumbItem, BreadcrumbList, BreadcrumbPage } from '@/components/ui/breadcrumb'; import { Button } from '@/components/ui/button'; import {