feat: add prevent dialog when leaving a terminal

This commit is contained in:
190km
2024-12-05 23:39:03 +01:00
parent 7fe8cd03bf
commit b9faf4bd1a
2 changed files with 201 additions and 123 deletions

View File

@@ -1,56 +1,94 @@
import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogHeader, DialogFooter,
DialogTitle, DialogHeader,
DialogTrigger, DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useState } from "react";
const Terminal = dynamic( const Terminal = dynamic(
() => import("./docker-terminal").then((e) => e.DockerTerminal), () => import("./docker-terminal").then((e) => e.DockerTerminal),
{ {
ssr: false, ssr: false,
}, }
); );
interface Props { interface Props {
containerId: string; containerId: string;
serverId?: string; serverId?: string;
children?: React.ReactNode; children?: React.ReactNode;
} }
export const DockerTerminalModal = ({ export const DockerTerminalModal = ({
children, children,
containerId, containerId,
serverId, serverId,
}: Props) => { }: Props) => {
return ( const [mainDialogOpen, setMainDialogOpen] = useState(false);
<Dialog> const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
<DialogTrigger asChild>
<DropdownMenuItem
className="w-full cursor-pointer space-x-3"
onSelect={(e) => e.preventDefault()}
>
{children}
</DropdownMenuItem>
</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-7xl">
<DialogHeader>
<DialogTitle>Docker Terminal</DialogTitle>
<DialogDescription>
Easy way to access to docker container
</DialogDescription>
</DialogHeader>
<Terminal const handleMainDialogOpenChange = (open: boolean) => {
id="terminal" if (!open) {
containerId={containerId} setConfirmDialogOpen(true);
serverId={serverId || ""} } else {
/> setMainDialogOpen(true);
</DialogContent> }
</Dialog> };
);
const handleConfirm = () => {
setConfirmDialogOpen(false);
setMainDialogOpen(false);
};
const handleCancel = () => {
setConfirmDialogOpen(false);
};
return (
<Dialog open={mainDialogOpen} onOpenChange={handleMainDialogOpenChange}>
<DialogTrigger asChild>
<DropdownMenuItem
className="w-full cursor-pointer space-x-3"
onSelect={(e) => e.preventDefault()}
>
{children}
</DropdownMenuItem>
</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-7xl">
<DialogHeader>
<DialogTitle>Docker Terminal</DialogTitle>
<DialogDescription>
Easy way to access to docker container
</DialogDescription>
</DialogHeader>
<Terminal
id="terminal"
containerId={containerId}
serverId={serverId || ""}
/>
<Dialog open={confirmDialogOpen} onOpenChange={setConfirmDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure you want to close the terminal?</DialogTitle>
<DialogDescription>
By clicking the confirm button, the terminal will be closed.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={handleCancel}>
Cancel
</Button>
<Button onClick={handleConfirm}>Confirm</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</DialogContent>
</Dialog>
);
}; };

View File

@@ -1,20 +1,22 @@
import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogDescription, DialogDescription,
DialogHeader, DialogFooter,
DialogTitle, DialogHeader,
DialogTrigger, DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
SelectGroup, SelectGroup,
SelectItem, SelectItem,
SelectLabel, SelectLabel,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { Loader2 } from "lucide-react"; import { Loader2 } from "lucide-react";
@@ -23,80 +25,118 @@ import type React from "react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
const Terminal = dynamic( const Terminal = dynamic(
() => () =>
import("@/components/dashboard/docker/terminal/docker-terminal").then( import("@/components/dashboard/docker/terminal/docker-terminal").then(
(e) => e.DockerTerminal, (e) => e.DockerTerminal
), ),
{ {
ssr: false, ssr: false,
}, }
); );
interface Props { interface Props {
appName: string; appName: string;
children?: React.ReactNode; children?: React.ReactNode;
serverId?: string; serverId?: string;
} }
export const DockerTerminalModal = ({ children, appName, serverId }: Props) => { export const DockerTerminalModal = ({ children, appName, serverId }: Props) => {
const { data, isLoading } = api.docker.getContainersByAppNameMatch.useQuery( const { data, isLoading } = api.docker.getContainersByAppNameMatch.useQuery(
{ {
appName, appName,
serverId, serverId,
}, },
{ {
enabled: !!appName, enabled: !!appName,
}, }
); );
const [containerId, setContainerId] = useState<string | undefined>(); const [containerId, setContainerId] = useState<string | undefined>();
const [mainDialogOpen, setMainDialogOpen] = useState(false);
const [confirmDialogOpen, setConfirmDialogOpen] = useState(false);
useEffect(() => { const handleMainDialogOpenChange = (open: boolean) => {
if (data && data?.length > 0) { if (!open) {
setContainerId(data[0]?.containerId); setConfirmDialogOpen(true);
} } else {
}, [data]); setMainDialogOpen(true);
return ( }
<Dialog> };
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="max-h-[85vh] overflow-y-auto sm:max-w-7xl"> const handleConfirm = () => {
<DialogHeader> setConfirmDialogOpen(false);
<DialogTitle>Docker Terminal</DialogTitle> setMainDialogOpen(false);
<DialogDescription> };
Easy way to access to docker container
</DialogDescription> const handleCancel = () => {
</DialogHeader> setConfirmDialogOpen(false);
<Label>Select a container to view logs</Label> };
<Select onValueChange={setContainerId} value={containerId}>
<SelectTrigger> useEffect(() => {
{isLoading ? ( if (data && data?.length > 0) {
<div className="flex flex-row gap-2 items-center justify-center text-sm text-muted-foreground"> setContainerId(data[0]?.containerId);
<span>Loading...</span> }
<Loader2 className="animate-spin size-4" /> }, [data]);
</div>
) : ( return (
<SelectValue placeholder="Select a container" /> <Dialog open={mainDialogOpen} onOpenChange={handleMainDialogOpenChange}>
)} <DialogTrigger asChild>{children}</DialogTrigger>
</SelectTrigger> <DialogContent className="max-h-[85vh] overflow-y-auto sm:max-w-7xl">
<SelectContent> <DialogHeader>
<SelectGroup> <DialogTitle>Docker Terminal</DialogTitle>
{data?.map((container) => ( <DialogDescription>
<SelectItem Easy way to access to docker container
key={container.containerId} </DialogDescription>
value={container.containerId} </DialogHeader>
> <Label>Select a container to view logs</Label>
{container.name} ({container.containerId}) {container.state} <Select onValueChange={setContainerId} value={containerId}>
</SelectItem> <SelectTrigger>
))} {isLoading ? (
<SelectLabel>Containers ({data?.length})</SelectLabel> <div className="flex flex-row gap-2 items-center justify-center text-sm text-muted-foreground">
</SelectGroup> <span>Loading...</span>
</SelectContent> <Loader2 className="animate-spin size-4" />
</Select> </div>
<Terminal ) : (
serverId={serverId || ""} <SelectValue placeholder="Select a container" />
id="terminal" )}
containerId={containerId || "select-a-container"} </SelectTrigger>
/> <SelectContent>
</DialogContent> <SelectGroup>
</Dialog> {data?.map((container) => (
); <SelectItem
key={container.containerId}
value={container.containerId}
>
{container.name} ({container.containerId}) {container.state}
</SelectItem>
))}
<SelectLabel>Containers ({data?.length})</SelectLabel>
</SelectGroup>
</SelectContent>
</Select>
<Terminal
serverId={serverId || ""}
id="terminal"
containerId={containerId || "select-a-container"}
/>
<Dialog open={confirmDialogOpen} onOpenChange={setConfirmDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>
Are you sure you want to close the terminal?
</DialogTitle>
<DialogDescription>
By clicking the confirm button, the terminal will be closed.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={handleCancel}>
Cancel
</Button>
<Button onClick={handleConfirm}>Confirm</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</DialogContent>
</Dialog>
);
}; };