feat: implement port forward deletion

This commit is contained in:
2024-12-03 23:34:38 +00:00
parent 62d0633ef1
commit ee857cbbf9
2 changed files with 73 additions and 7 deletions

View File

@@ -1,7 +1,7 @@
import { fetchApi, type ApiError } from "@/api";
import type { QueryStatus } from "@/lib/query";
import { useCallback, useState } from "react";
import useSWR, { useSWRConfig } from "swr";
import useSWR, { mutate, useSWRConfig } from "swr";
import {
type Workspace,
type WorkspacePortMapping,
@@ -200,6 +200,46 @@ function useAddWorkspacePort() {
return { addWorkspacePort, status };
}
function useDeleteWorkspacePort() {
const [status, setStatus] = useState<QueryStatus<ApiError>>({ type: "idle" });
const deleteWorkspacePort = useCallback(
async (workspaceName: string, portName: string) => {
setStatus({ type: "loading" });
try {
await mutate(
"/workspaces",
fetchApi(`/workspaces/${workspaceName}/forwarded-ports/${portName}`, {
method: "DELETE",
}),
{
populateCache: (_, workspaces) =>
workspaces.map(
(it: Workspace): Workspace =>
it.name === workspaceName
? {
...it,
ports: it.ports?.filter(
(port) => port.subdomain !== portName,
),
}
: it,
),
revalidate: false,
throwOnError: true,
},
);
setStatus({ type: "ok" });
} catch (error: unknown) {
setStatus({ type: "error", error: error as ApiError });
}
},
[],
);
return { deleteWorkspacePort, status };
}
function useWorkspaceRuntimes() {
return useSWR(
"/workspace-runtimes",
@@ -215,4 +255,5 @@ export {
useDeleteWorkspace,
useAddWorkspacePort,
useWorkspaceRuntimes,
useDeleteWorkspacePort,
};

View File

@@ -10,13 +10,14 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useToast } from "@/hooks/use-toast";
import { superstructResolver } from "@hookform/resolvers/superstruct";
import { Check, Trash2, X } from "lucide-react";
import { useContext, useId } from "react";
import { useContext, useEffect, useId } from "react";
import { useForm } from "react-hook-form";
import { type Infer, number, object, pattern, size, string } from "superstruct";
import { create } from "zustand";
import { useAddWorkspacePort } from "./api";
import { useAddWorkspacePort, useDeleteWorkspacePort } from "./api";
import { WorkspaceTableRowContext } from "./workspace-table";
interface PortInfoTabStore {
@@ -57,7 +58,7 @@ function PortInfoTableBody() {
<TableCell className="py-0">{subdomain}</TableCell>
<TableCell className="py-0">{port}</TableCell>
<TableCell className="p-0 text-right">
<DeletePortMappingButton />
<DeletePortMappingButton subdomain={subdomain} />
</TableCell>
</TableRow>
))}
@@ -183,10 +184,34 @@ function NewPortMappingRow() {
);
}
function DeletePortMappingButton() {
function DeletePortMappingButton({ subdomain }: { subdomain: string }) {
const { deleteWorkspacePort, status } = useDeleteWorkspacePort();
const { toast } = useToast();
const workspace = useContext(WorkspaceTableRowContext);
const isDeleting = status.type === "loading";
useEffect(() => {
if (status.type === "error") {
toast({
variant: "destructive",
title: "Failed to delete port.",
description: "Unexpected error.",
});
}
}, [status.type, toast]);
async function _deleteWorkspacePort() {
await deleteWorkspacePort(workspace.name, subdomain);
}
return (
<Button variant="ghost" size="icon">
<Trash2 />
<Button
disabled={isDeleting}
variant="ghost"
size="icon"
onClick={_deleteWorkspacePort}
>
{isDeleting ? <LoadingSpinner /> : <Trash2 />}
</Button>
);
}