Skip to content

Commit

Permalink
support delete instance
Browse files Browse the repository at this point in the history
  • Loading branch information
moeakwak committed Apr 29, 2024
1 parent 9522d54 commit 777786a
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 10 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
Expand Down
40 changes: 40 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 49 additions & 6 deletions src/app/(panel)/admin/instances/instance-info-card-admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,46 @@ import { TRPCClientError } from "@trpc/client";
import { type ServiceInstance } from "@/schema/serviceInstance.schema";
import { popupChatGPTShareInstanceConfigDetails } from "./chatgpt-share-config-popup";
import { useRouter } from "next/navigation";
import { popup } from "@/components/popup";
import { Checkbox } from "@/components/ui/checkbox";

interface Props extends React.HTMLAttributes<HTMLFormElement> {
instance: ServiceInstance;
className?: string;
}

export function DeleteInstance({ instanceId, closePopup }: { instanceId: string; closePopup: () => void }) {
const router = useRouter();
const deleteMutation = api.serviceInstance.delete.useMutation();
const [deleteLogs, setDeleteLogs] = React.useState(false);

return (
<div className="space-y-4">
<div className="flex items-center space-x-2">
<Checkbox checked={deleteLogs} onCheckedChange={() => setDeleteLogs((current) => !current)} />
<label
htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Delete logs associated with this instance
</label>
</div>
<FunctionButton
variant={"destructive"}
className="my-2 w-full"
onClick={async () => {
await deleteMutation.mutateAsync({ id: instanceId, deleteLogs });
closePopup();
toast.success("Instance has been deleted.");
router.refresh();
}}
>
Confirm
</FunctionButton>
</div>
);
}

export function AdminInstanceInfoCard({ instance, className }: Props) {
const router = useRouter();
const grantMutation = api.serviceInstance.grantToAllActiveUsers.useMutation();
Expand All @@ -38,10 +72,6 @@ export function AdminInstanceInfoCard({ instance, className }: Props) {
}
};

const unpublish = async (instanceId: string) => {
toast.info("Unpublishing is not implemented yet.");
};

return (
<InstanceInfoCard instance={instance} className={className}>
<div className="flex w-full flex-row items-center justify-between">
Expand All @@ -55,9 +85,9 @@ export function AdminInstanceInfoCard({ instance, className }: Props) {
<FunctionButton className="lt-md:w-full" variant={"outline"} onClick={() => grantToAll(instance.id)}>
Publish To All Active Users
</FunctionButton>
<FunctionButton variant={"outline"} onClick={() => unpublish(instance.id)}>
{/* <FunctionButton variant={"outline"} onClick={() => unpublish(instance.id)}>
Unpublish
</FunctionButton>
</FunctionButton> */}
<Button onClick={() => popupChatGPTShareInstanceConfigDetails({ url: instance.url ?? "", id: instance.id })}>
<Icons.eye className="mr-2 h-4 w-4" />
View Config
Expand All @@ -66,6 +96,19 @@ export function AdminInstanceInfoCard({ instance, className }: Props) {
<Icons.pencil className="mr-2 h-4 w-4" />
Edit
</Button>
<FunctionButton
className="lt-md:w-full"
variant={"destructive"}
onClick={async () => {
popup({
title: `Delete Instance`,
description: `Delete instance ${instance.name} from database. This will delete all associated user data.`,
content: (closePopup) => <DeleteInstance instanceId={instance.id} closePopup={closePopup} />,
});
}}
>
Delete
</FunctionButton>
</div>
</div>
</InstanceInfoCard>
Expand Down
33 changes: 33 additions & 0 deletions src/components/ui/popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client"

import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"

import { cn } from "@/lib/utils"

const Popover = PopoverPrimitive.Root

const PopoverTrigger = PopoverPrimitive.Trigger

const PopoverAnchor = PopoverPrimitive.Anchor

const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName

export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
16 changes: 12 additions & 4 deletions src/server/api/routers/serviceInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
ServiceInstanceUpdateSchema,
ServiceInstanceWithToken,
} from "@/schema/serviceInstance.schema";
import { serviceInstances, userInstanceAbilities, users } from "@/server/db/schema";
import { resourceUsageLogs, serviceInstances, userInstanceAbilities, users } from "@/server/db/schema";
import { createCUID } from "@/lib/cuid";
import { and, eq } from "drizzle-orm";

Expand Down Expand Up @@ -107,9 +107,17 @@ export const serviceInstanceRouter = createTRPCRouter({
return ServiceInstanceSchema.parse(result);
}),

delete: adminProcedure.input(ServiceInstanceSchema.pick({ id: true })).mutation(async ({ ctx, input }) => {
await ctx.db.delete(serviceInstances).where(eq(serviceInstances.id, input.id));
}),
delete: adminProcedure
.input(ServiceInstanceSchema.pick({ id: true }).merge(z.object({ deleteLogs: z.boolean() })))
.mutation(async ({ ctx, input }) => {
await ctx.db.transaction(async (tx) => {
await tx.delete(userInstanceAbilities).where(eq(userInstanceAbilities.instanceId, input.id));
await tx.delete(serviceInstances).where(eq(serviceInstances.id, input.id));
if (input.deleteLogs) {
await tx.delete(resourceUsageLogs).where(eq(resourceUsageLogs.instanceId, input.id));
}
});
}),

verifyUserAbility: publicProcedure
.input(
Expand Down

0 comments on commit 777786a

Please sign in to comment.