mirror of
https://github.com/Kong/insomnia.git
synced 2026-11-05 20:43:52 -05:00
fix: auto close modal when deleting local proj workspace
This commit is contained in:
1 parent
25858ff7c8
commit
46d949fe3d
3 files changed
+36
-26
No files matched your search
@@ -1,6 +1,5 @@
|
||||
import type { Project, Workspace } from 'insomnia-data';
|
||||
import { models } from 'insomnia-data';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Button, Dialog, Heading, Label, Modal, ModalOverlay, Radio, RadioGroup } from 'react-aria-components';
|
||||
import { href } from 'react-router';
|
||||
|
||||
@@ -13,38 +12,25 @@ interface Props {
|
||||
workspace: Workspace;
|
||||
project: Project;
|
||||
organizationId: string;
|
||||
// Driven by the host: it closes once the workspace is gone, so the overlay can play its exit animation
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onDeleted?: () => void;
|
||||
}
|
||||
|
||||
export const WorkspaceDeleteModal = ({ workspace, project, organizationId, onClose, onDeleted }: Props) => {
|
||||
export const WorkspaceDeleteModal = ({ workspace, project, organizationId, isOpen, onClose }: Props) => {
|
||||
const deleteWorkspaceFetcher = useWorkspaceDeleteActionFetcher();
|
||||
const workspaceId = workspace._id;
|
||||
const workspaceName = workspace.name;
|
||||
|
||||
// Close once the deletion succeeds (the action redirects, so no error data is returned)
|
||||
const wasSubmitting = useRef(false);
|
||||
useEffect(() => {
|
||||
if (deleteWorkspaceFetcher.state !== 'idle') {
|
||||
wasSubmitting.current = true;
|
||||
} else if (wasSubmitting.current) {
|
||||
wasSubmitting.current = false;
|
||||
if (!deleteWorkspaceFetcher.data?.error) {
|
||||
onDeleted?.();
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
}, [deleteWorkspaceFetcher.state, deleteWorkspaceFetcher.data, onClose, onDeleted]);
|
||||
|
||||
return (
|
||||
<ModalOverlay
|
||||
isOpen
|
||||
onOpenChange={() => onClose()}
|
||||
isOpen={isOpen}
|
||||
onOpenChange={open => !open && onClose()}
|
||||
isDismissable
|
||||
className="fixed top-0 left-0 z-10 flex h-(--visual-viewport-height) w-full items-center justify-center bg-black/30"
|
||||
className="fixed top-0 left-0 z-10 flex h-(--visual-viewport-height) w-full items-center justify-center bg-black/30 transition-opacity duration-150 data-exiting:opacity-0"
|
||||
>
|
||||
<Modal
|
||||
onOpenChange={() => onClose()}
|
||||
onOpenChange={open => !open && onClose()}
|
||||
className="max-h-full w-full max-w-2xl rounded-md border border-solid border-(--hl-sm) bg-(--color-bg) p-(--padding-lg) text-(--color-font)"
|
||||
>
|
||||
<Dialog className="outline-hidden">
|
||||
|
||||
+1
@@ -660,6 +660,7 @@ const ProjectNavigationSidebarInner = (
|
||||
const [shortcutTargetItemId, setShortcutTargetItemId] = useState<string | null>(null);
|
||||
const showRenameModal = useRenameModal();
|
||||
const { showDeleteModal, deleteModal } = useDeleteModal({
|
||||
flatItems,
|
||||
onDeleteProject: projectId => deleteProjectFetcher.submit({ organizationId, projectId }),
|
||||
// Leave focus mode when its collection is deleted, otherwise the view is left empty
|
||||
onWorkspaceDeleted: workspaceId => {
|
||||
|
||||
+28
-5
@@ -1,5 +1,5 @@
|
||||
import { models, services } from 'insomnia-data';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useRequestDeleteActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.delete';
|
||||
import { useRequestGroupDeleteActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request-group.delete';
|
||||
@@ -8,21 +8,42 @@ import { AskModal } from '~/ui/components/modals/ask-modal';
|
||||
import { WorkspaceDeleteModal } from '~/ui/components/modals/workspace-delete-modal';
|
||||
|
||||
import { getRequestNameOrFallback } from './request-node';
|
||||
import type { CollectionChildFlatItem, PinnedRequestFlatItem, ProjectFlatItem, WorkspaceFlatItem } from './types';
|
||||
import type {
|
||||
CollectionChildFlatItem,
|
||||
FlatItem,
|
||||
PinnedRequestFlatItem,
|
||||
ProjectFlatItem,
|
||||
WorkspaceFlatItem,
|
||||
} from './types';
|
||||
|
||||
export type DeleteTargetItem = ProjectFlatItem | WorkspaceFlatItem | CollectionChildFlatItem | PinnedRequestFlatItem;
|
||||
|
||||
interface Options {
|
||||
// Unfiltered sidebar items, used to notice when the workspace being deleted is gone
|
||||
flatItems: FlatItem[];
|
||||
onDeleteProject: (projectId: string) => void;
|
||||
onWorkspaceDeleted?: (workspaceId: string) => void;
|
||||
}
|
||||
|
||||
// Returns a function to open the delete confirmation for projects, workspaces, request groups, and requests,
|
||||
// plus the element that hosts the workspace confirmation, which must be rendered once by the caller.
|
||||
export const useDeleteModal = ({ onDeleteProject, onWorkspaceDeleted }: Options) => {
|
||||
export const useDeleteModal = ({ flatItems, onDeleteProject, onWorkspaceDeleted }: Options) => {
|
||||
const deleteRequestFetcher = useRequestDeleteActionFetcher();
|
||||
const deleteRequestGroupFetcher = useRequestGroupDeleteActionFetcher();
|
||||
// Kept after closing so the modal can play its exit animation
|
||||
const [workspaceToDelete, setWorkspaceToDelete] = useState<WorkspaceFlatItem | null>(null);
|
||||
const [isWorkspaceModalOpen, setIsWorkspaceModalOpen] = useState(false);
|
||||
|
||||
// The workspace disappearing from the sidebar is the signal that the deletion succeeded.
|
||||
// On failure (e.g. a remote error) it stays, so the modal remains open to show the error.
|
||||
const isWorkspaceGone =
|
||||
!!workspaceToDelete && !flatItems.some(i => i.kind === 'workspace' && i.doc._id === workspaceToDelete.doc._id);
|
||||
useEffect(() => {
|
||||
if (isWorkspaceModalOpen && isWorkspaceGone) {
|
||||
setIsWorkspaceModalOpen(false);
|
||||
onWorkspaceDeleted?.(workspaceToDelete.doc._id);
|
||||
}
|
||||
}, [isWorkspaceModalOpen, isWorkspaceGone, workspaceToDelete, onWorkspaceDeleted]);
|
||||
|
||||
const showDeleteModal = (item: DeleteTargetItem) => {
|
||||
if (item.kind === 'project') {
|
||||
@@ -65,6 +86,7 @@ export const useDeleteModal = ({ onDeleteProject, onWorkspaceDeleted }: Options)
|
||||
return;
|
||||
}
|
||||
setWorkspaceToDelete(item);
|
||||
setIsWorkspaceModalOpen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,11 +135,12 @@ export const useDeleteModal = ({ onDeleteProject, onWorkspaceDeleted }: Options)
|
||||
|
||||
const deleteModal = workspaceToDelete && (
|
||||
<WorkspaceDeleteModal
|
||||
key={workspaceToDelete.doc._id}
|
||||
isOpen={isWorkspaceModalOpen}
|
||||
workspace={workspaceToDelete.doc}
|
||||
project={workspaceToDelete.project}
|
||||
organizationId={workspaceToDelete.organizationId}
|
||||
onClose={() => setWorkspaceToDelete(null)}
|
||||
onDeleted={() => onWorkspaceDeleted?.(workspaceToDelete.doc._id)}
|
||||
onClose={() => setIsWorkspaceModalOpen(false)}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user