feat: implement port forward deletion
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
@@ -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>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user