feat: add cleanup cache on deployments

This commit is contained in:
Mauricio Siu
2025-01-19 00:57:42 -06:00
parent 089274492d
commit 25a8df567e
24 changed files with 13380 additions and 53 deletions

View File

@@ -133,7 +133,9 @@ export const AddTemplate = ({ projectId }: Props) => {
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn("w-full sm:w-[200px] justify-between !bg-input")}
className={cn(
"w-full sm:w-[200px] justify-between !bg-input",
)}
>
{isLoadingTags
? "Loading...."

View File

@@ -118,14 +118,16 @@ export const UserNav = () => {
</DropdownMenuItem>
)}
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
router.push("/dashboard/settings/server");
}}
>
Settings
</DropdownMenuItem>
{data?.rol === "admin" && (
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
router.push("/dashboard/settings");
}}
>
Settings
</DropdownMenuItem>
)}
</>
) : (
<>

View File

@@ -0,0 +1 @@
ALTER TABLE "admin" ADD COLUMN "enableCleanupCache" boolean DEFAULT true NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE "admin" RENAME COLUMN "enableCleanupCache" TO "cleanupCacheOnDeployments";

View File

@@ -0,0 +1,3 @@
ALTER TABLE "admin" RENAME COLUMN "cleanupCacheOnDeployments" TO "cleanupCacheApplications";--> statement-breakpoint
ALTER TABLE "admin" ADD COLUMN "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "admin" ADD COLUMN "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -400,6 +400,27 @@
"when": 1736789918294,
"tag": "0056_majestic_skaar",
"breakpoints": true
},
{
"idx": 57,
"version": "6",
"when": 1737266192013,
"tag": "0057_oval_ken_ellis",
"breakpoints": true
},
{
"idx": 58,
"version": "6",
"when": 1737266560950,
"tag": "0058_cultured_warpath",
"breakpoints": true
},
{
"idx": 59,
"version": "6",
"when": 1737268325181,
"tag": "0059_public_speed",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,220 @@
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { DialogFooter } from "@/components/ui/dialog";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Switch } from "@/components/ui/switch";
import { appRouter } from "@/server/api/root";
import { api } from "@/utils/api";
import { validateRequest } from "@dokploy/server";
import { zodResolver } from "@hookform/resolvers/zod";
import { createServerSideHelpers } from "@trpc/react-query/server";
import { Settings } from "lucide-react";
import type { GetServerSidePropsContext } from "next";
import React, { useEffect, type ReactElement } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import superjson from "superjson";
import { z } from "zod";
const settings = z.object({
cleanCacheOnApplications: z.boolean(),
cleanCacheOnCompose: z.boolean(),
cleanCacheOnPreviews: z.boolean(),
});
type SettingsType = z.infer<typeof settings>;
const Page = () => {
const { data, refetch } = api.admin.one.useQuery();
const { mutateAsync, isLoading, isError, error } =
api.admin.update.useMutation();
const form = useForm<SettingsType>({
defaultValues: {
cleanCacheOnApplications: false,
cleanCacheOnCompose: false,
cleanCacheOnPreviews: false,
},
resolver: zodResolver(settings),
});
useEffect(() => {
form.reset({
cleanCacheOnApplications: data?.cleanupCacheApplications || false,
cleanCacheOnCompose: data?.cleanupCacheOnCompose || false,
cleanCacheOnPreviews: data?.cleanupCacheOnPreviews || false,
});
}, [form, form.reset, form.formState.isSubmitSuccessful, data]);
const onSubmit = async (values: SettingsType) => {
await mutateAsync({
cleanupCacheApplications: values.cleanCacheOnApplications,
cleanupCacheOnCompose: values.cleanCacheOnCompose,
cleanupCacheOnPreviews: values.cleanCacheOnPreviews,
})
.then(() => {
toast.success("Settings updated");
refetch();
})
.catch(() => {
toast.error("Something went wrong");
});
};
return (
<div className="w-full">
<Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-5xl mx-auto">
<div className="rounded-xl bg-background shadow-md ">
<CardHeader className="">
<CardTitle className="text-xl flex flex-row gap-2">
<Settings className="size-6 text-muted-foreground self-center" />
Settings
</CardTitle>
<CardDescription>Manage your Dokploy settings</CardDescription>
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
</CardHeader>
<CardContent className="space-y-2 py-8 border-t">
<Form {...form}>
<form
id="hook-form-add-security"
onSubmit={form.handleSubmit(onSubmit)}
className="grid w-full gap-2"
>
<FormField
control={form.control}
name="cleanCacheOnApplications"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between p-3 mt-4 border rounded-lg shadow-sm">
<div className="space-y-0.5">
<FormLabel>Clean Cache on Applications</FormLabel>
<FormDescription>
Clean the cache after every deployment
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="cleanCacheOnPreviews"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between p-3 mt-4 border rounded-lg shadow-sm">
<div className="space-y-0.5">
<FormLabel>Clean Cache on Previews</FormLabel>
<FormDescription>
Clean the cache after every deployment
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="cleanCacheOnCompose"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between p-3 mt-4 border rounded-lg shadow-sm">
<div className="space-y-0.5">
<FormLabel>Clean Cache on Compose</FormLabel>
<FormDescription>
Clean the cache after every deployment
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<DialogFooter>
<Button
isLoading={isLoading}
form="hook-form-add-security"
type="submit"
>
Update
</Button>
</DialogFooter>
</form>
</Form>
</CardContent>
</div>
</Card>
</div>
);
};
export default Page;
Page.getLayout = (page: ReactElement) => {
return <DashboardLayout metaName="Server">{page}</DashboardLayout>;
};
export async function getServerSideProps(
ctx: GetServerSidePropsContext<{ serviceId: string }>,
) {
const { req, res } = ctx;
const { user, session } = await validateRequest(ctx.req, ctx.res);
if (!user) {
return {
redirect: {
permanent: true,
destination: "/",
},
};
}
if (user.rol === "user") {
return {
redirect: {
permanent: true,
destination: "/dashboard/settings/profile",
},
};
}
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {
req: req as any,
res: res as any,
db: null as any,
session: session,
user: user,
},
transformer: superjson,
});
await helpers.auth.get.prefetch();
return {
props: {
trpcState: helpers.dehydrate(),
},
};
}

View File

@@ -239,7 +239,10 @@ export const projectRouter = createTRPCRouter({
}
}),
});
function buildServiceFilter(fieldName: AnyPgColumn, accessedServices: string[]) {
function buildServiceFilter(
fieldName: AnyPgColumn,
accessedServices: string[],
) {
return accessedServices.length > 0
? sql`${fieldName} IN (${sql.join(
accessedServices.map((serviceId) => sql`${serviceId}`),

View File

@@ -101,7 +101,7 @@
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
@@ -110,16 +110,16 @@
::-webkit-scrollbar {
width: 0.3125rem;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(var(--border));
border-radius: 0.3125rem;
}
* {
scrollbar-width: thin;
scrollbar-color: hsl(var(--border)) transparent;

View File

@@ -1269,7 +1269,8 @@ export const templates: TemplateData[] = [
},
tags: ["cloud", "networking", "security", "tunnel"],
load: () => import("./cloudflared/index").then((m) => m.generate),
},{
},
{
id: "couchdb",
name: "CouchDB",
version: "latest",