Skip to content

Commit 00fc1a9

Browse files
authored
Merge pull request #1440 from Dokploy/1120-rebuild-database
feat(databases): add database rebuild functionality
2 parents c5272aa + 624eedd commit 00fc1a9

File tree

19 files changed

+370
-93
lines changed

19 files changed

+370
-93
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import {
2+
AlertDialog,
3+
AlertDialogAction,
4+
AlertDialogCancel,
5+
AlertDialogContent,
6+
AlertDialogDescription,
7+
AlertDialogFooter,
8+
AlertDialogHeader,
9+
AlertDialogTitle,
10+
AlertDialogTrigger,
11+
} from "@/components/ui/alert-dialog";
12+
import { Button } from "@/components/ui/button";
13+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
14+
import { api } from "@/utils/api";
15+
import { DatabaseIcon, AlertTriangle } from "lucide-react";
16+
import { toast } from "sonner";
17+
18+
interface Props {
19+
id: string;
20+
type: "postgres" | "mysql" | "mariadb" | "mongo" | "redis";
21+
}
22+
23+
export const RebuildDatabase = ({ id, type }: Props) => {
24+
const utils = api.useUtils();
25+
26+
const mutationMap = {
27+
postgres: () => api.postgres.rebuild.useMutation(),
28+
mysql: () => api.mysql.rebuild.useMutation(),
29+
mariadb: () => api.mariadb.rebuild.useMutation(),
30+
mongo: () => api.mongo.rebuild.useMutation(),
31+
redis: () => api.redis.rebuild.useMutation(),
32+
};
33+
34+
const { mutateAsync, isLoading } = mutationMap[type]();
35+
36+
const handleRebuild = async () => {
37+
try {
38+
await mutateAsync({
39+
postgresId: type === "postgres" ? id : "",
40+
mysqlId: type === "mysql" ? id : "",
41+
mariadbId: type === "mariadb" ? id : "",
42+
mongoId: type === "mongo" ? id : "",
43+
redisId: type === "redis" ? id : "",
44+
});
45+
toast.success("Database rebuilt successfully");
46+
await utils.invalidate();
47+
} catch (error) {
48+
toast.error("Error rebuilding database", {
49+
description: error instanceof Error ? error.message : "Unknown error",
50+
});
51+
}
52+
};
53+
54+
return (
55+
<Card className="bg-background border-destructive/50">
56+
<CardHeader>
57+
<CardTitle className="text-xl flex items-center gap-2">
58+
<AlertTriangle className="h-5 w-5 text-destructive" />
59+
Danger Zone
60+
</CardTitle>
61+
</CardHeader>
62+
<CardContent>
63+
<div className="flex flex-col gap-4">
64+
<div className="flex flex-col gap-2">
65+
<h3 className="text-base font-semibold">Rebuild Database</h3>
66+
<p className="text-sm text-muted-foreground">
67+
This action will completely reset your database to its initial
68+
state. All data, tables, and configurations will be removed.
69+
</p>
70+
</div>
71+
<AlertDialog>
72+
<AlertDialogTrigger asChild>
73+
<Button
74+
variant="outline"
75+
className="w-full border-destructive/50 hover:bg-destructive/10 hover:text-destructive text-destructive"
76+
>
77+
<DatabaseIcon className="mr-2 h-4 w-4" />
78+
Rebuild Database
79+
</Button>
80+
</AlertDialogTrigger>
81+
<AlertDialogContent>
82+
<AlertDialogHeader>
83+
<AlertDialogTitle className="flex items-center gap-2">
84+
<AlertTriangle className="h-5 w-5 text-destructive" />
85+
Are you absolutely sure?
86+
</AlertDialogTitle>
87+
<AlertDialogDescription className="space-y-2">
88+
<p>This action will:</p>
89+
<ul className="list-disc list-inside space-y-1">
90+
<li>Stop the current database service</li>
91+
<li>Delete all existing data and volumes</li>
92+
<li>Reset to the default configuration</li>
93+
<li>Restart the service with a clean state</li>
94+
</ul>
95+
<p className="font-medium text-destructive mt-4">
96+
This action cannot be undone.
97+
</p>
98+
</AlertDialogDescription>
99+
</AlertDialogHeader>
100+
<AlertDialogFooter>
101+
<AlertDialogCancel>Cancel</AlertDialogCancel>
102+
<AlertDialogAction
103+
onClick={handleRebuild}
104+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
105+
disabled={isLoading}
106+
>
107+
{isLoading ? "Rebuilding..." : "Yes, rebuild database"}
108+
</AlertDialogAction>
109+
</AlertDialogFooter>
110+
</AlertDialogContent>
111+
</AlertDialog>
112+
</div>
113+
</CardContent>
114+
</Card>
115+
);
116+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
2+
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
3+
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
4+
import { RebuildDatabase } from "./rebuild-database";
5+
6+
interface Props {
7+
id: string;
8+
type: "postgres" | "mysql" | "mariadb" | "mongo" | "redis";
9+
}
10+
11+
export const ShowDatabaseAdvancedSettings = ({ id, type }: Props) => {
12+
return (
13+
<div className="flex w-full flex-col gap-5">
14+
<ShowCustomCommand id={id} type={type} />
15+
<ShowVolumes id={id} type={type} />
16+
<ShowResources id={id} type={type} />
17+
<RebuildDatabase id={id} type={type} />
18+
</div>
19+
);
20+
};

apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
2-
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
31
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
42
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
53
import { DeleteService } from "@/components/dashboard/compose/delete-service";
@@ -10,7 +8,7 @@ import { ShowInternalMariadbCredentials } from "@/components/dashboard/mariadb/g
108
import { UpdateMariadb } from "@/components/dashboard/mariadb/update-mariadb";
119
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
1210
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
13-
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
11+
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
1412
import { MariadbIcon } from "@/components/icons/data-tools-icons";
1513
import { ProjectLayout } from "@/components/layouts/project-layout";
1614
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
@@ -278,11 +276,10 @@ const Mariadb = (
278276
</TabsContent>
279277
<TabsContent value="advanced">
280278
<div className="flex flex-col gap-4 pt-2.5">
281-
<div className="flex w-full flex-col gap-5">
282-
<ShowCustomCommand id={mariadbId} type="mariadb" />
283-
<ShowVolumes id={mariadbId} type="mariadb" />
284-
<ShowResources id={mariadbId} type="mariadb" />
285-
</div>
279+
<ShowDatabaseAdvancedSettings
280+
id={mariadbId}
281+
type="mariadb"
282+
/>
286283
</div>
287284
</TabsContent>
288285
</Tabs>

apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
2-
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
31
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
42
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
53
import { DeleteService } from "@/components/dashboard/compose/delete-service";
@@ -10,7 +8,7 @@ import { ShowInternalMongoCredentials } from "@/components/dashboard/mongo/gener
108
import { UpdateMongo } from "@/components/dashboard/mongo/update-mongo";
119
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
1210
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
13-
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
11+
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
1412
import { MongodbIcon } from "@/components/icons/data-tools-icons";
1513
import { ProjectLayout } from "@/components/layouts/project-layout";
1614
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
@@ -279,11 +277,7 @@ const Mongo = (
279277
</TabsContent>
280278
<TabsContent value="advanced">
281279
<div className="flex flex-col gap-4 pt-2.5">
282-
<div className="flex w-full flex-col gap-5 ">
283-
<ShowCustomCommand id={mongoId} type="mongo" />
284-
<ShowVolumes id={mongoId} type="mongo" />
285-
<ShowResources id={mongoId} type="mongo" />
286-
</div>
280+
<ShowDatabaseAdvancedSettings id={mongoId} type="mongo" />
287281
</div>
288282
</TabsContent>
289283
</Tabs>

apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
2-
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
31
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
42
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
53
import { DeleteService } from "@/components/dashboard/compose/delete-service";
@@ -10,7 +8,7 @@ import { ShowExternalMysqlCredentials } from "@/components/dashboard/mysql/gener
108
import { ShowGeneralMysql } from "@/components/dashboard/mysql/general/show-general-mysql";
119
import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-internal-mysql-credentials";
1210
import { UpdateMysql } from "@/components/dashboard/mysql/update-mysql";
13-
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
11+
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
1412
import { MysqlIcon } from "@/components/icons/data-tools-icons";
1513
import { ProjectLayout } from "@/components/layouts/project-layout";
1614
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
@@ -236,33 +234,9 @@ const MySql = (
236234
/>
237235
) : (
238236
<>
239-
{/* {monitoring?.enabledFeatures && (
240-
<div className="flex flex-row border w-fit p-4 rounded-lg items-center gap-2">
241-
<Label className="text-muted-foreground">
242-
Change Monitoring
243-
</Label>
244-
<Switch
245-
checked={toggleMonitoring}
246-
onCheckedChange={setToggleMonitoring}
247-
/>
248-
</div>
249-
)}
250-
251-
{toggleMonitoring ? (
252-
<ContainerPaidMonitoring
253-
appName={data?.appName || ""}
254-
baseUrl={`http://${monitoring?.serverIp}:${monitoring?.metricsConfig?.server?.port}`}
255-
token={
256-
monitoring?.metricsConfig?.server?.token || ""
257-
}
258-
/>
259-
) : (
260-
<div> */}
261237
<ContainerFreeMonitoring
262238
appName={data?.appName || ""}
263239
/>
264-
{/* </div> */}
265-
{/* )} */}
266240
</>
267241
)}
268242
</div>
@@ -283,11 +257,10 @@ const MySql = (
283257
</TabsContent>
284258
<TabsContent value="advanced">
285259
<div className="flex flex-col gap-4 pt-2.5">
286-
<div className="flex w-full flex-col gap-5">
287-
<ShowCustomCommand id={mysqlId} type="mysql" />
288-
<ShowVolumes id={mysqlId} type="mysql" />
289-
<ShowResources id={mysqlId} type="mysql" />
290-
</div>
260+
<ShowDatabaseAdvancedSettings
261+
id={mysqlId}
262+
type="mysql"
263+
/>
291264
</div>
292265
</TabsContent>
293266
</Tabs>

apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
2-
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
31
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
42
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
53
import { DeleteService } from "@/components/dashboard/compose/delete-service";
64
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
75
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
86
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
9-
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
107
import { ShowExternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-external-postgres-credentials";
118
import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres";
129
import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials";
@@ -15,6 +12,7 @@ import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
1512
import { ProjectLayout } from "@/components/layouts/project-layout";
1613
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
1714
import { StatusTooltip } from "@/components/shared/status-tooltip";
15+
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
1816
import { Badge } from "@/components/ui/badge";
1917
import {
2018
Card,
@@ -235,33 +233,9 @@ const Postgresql = (
235233
/>
236234
) : (
237235
<>
238-
{/* {monitoring?.enabledFeatures && (
239-
<div className="flex flex-row border w-fit p-4 rounded-lg items-center gap-2">
240-
<Label className="text-muted-foreground">
241-
Change Monitoring
242-
</Label>
243-
<Switch
244-
checked={toggleMonitoring}
245-
onCheckedChange={setToggleMonitoring}
246-
/>
247-
</div>
248-
)}
249-
250-
{toggleMonitoring ? (
251-
<ContainerPaidMonitoring
252-
appName={data?.appName || ""}
253-
baseUrl={`http://${monitoring?.serverIp}:${monitoring?.metricsConfig?.server?.port}`}
254-
token={
255-
monitoring?.metricsConfig?.server?.token || ""
256-
}
257-
/>
258-
) : (
259-
<div> */}
260236
<ContainerFreeMonitoring
261237
appName={data?.appName || ""}
262238
/>
263-
{/* </div> */}
264-
{/* )} */}
265239
</>
266240
)}
267241
</div>
@@ -282,11 +256,10 @@ const Postgresql = (
282256
</TabsContent>
283257
<TabsContent value="advanced">
284258
<div className="flex flex-col gap-4 pt-2.5">
285-
<div className="flex w-full flex-col gap-5 ">
286-
<ShowCustomCommand id={postgresId} type="postgres" />
287-
<ShowVolumes id={postgresId} type="postgres" />
288-
<ShowResources id={postgresId} type="postgres" />
289-
</div>
259+
<ShowDatabaseAdvancedSettings
260+
id={postgresId}
261+
type="postgres"
262+
/>
290263
</div>
291264
</TabsContent>
292265
</Tabs>

apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
2-
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
31
import { ShowEnvironment } from "@/components/dashboard/application/environment/show-enviroment";
42
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
53
import { DeleteService } from "@/components/dashboard/compose/delete-service";
64
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
75
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
8-
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
96
import { ShowExternalRedisCredentials } from "@/components/dashboard/redis/general/show-external-redis-credentials";
107
import { ShowGeneralRedis } from "@/components/dashboard/redis/general/show-general-redis";
118
import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/general/show-internal-redis-credentials";
129
import { UpdateRedis } from "@/components/dashboard/redis/update-redis";
10+
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
1311
import { RedisIcon } from "@/components/icons/data-tools-icons";
1412
import { ProjectLayout } from "@/components/layouts/project-layout";
1513
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
@@ -272,11 +270,7 @@ const Redis = (
272270
</TabsContent>
273271
<TabsContent value="advanced">
274272
<div className="flex flex-col gap-4 pt-2.5">
275-
<div className="flex w-full flex-col gap-5 ">
276-
<ShowCustomCommand id={redisId} type="redis" />
277-
<ShowVolumes id={redisId} type="redis" />
278-
<ShowResources id={redisId} type="redis" />
279-
</div>
273+
<ShowDatabaseAdvancedSettings id={redisId} type="redis" />
280274
</div>
281275
</TabsContent>
282276
</Tabs>

apps/dokploy/server/api/routers/mariadb.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
apiSaveEnvironmentVariablesMariaDB,
99
apiSaveExternalPortMariaDB,
1010
apiUpdateMariaDB,
11+
apiRebuildMariadb,
1112
mariadb as mariadbTable,
1213
} from "@/server/db/schema";
1314
import { cancelJobs } from "@/server/utils/backup";
@@ -34,7 +35,7 @@ import { observable } from "@trpc/server/observable";
3435
import { z } from "zod";
3536
import { eq } from "drizzle-orm";
3637
import { db } from "@/server/db";
37-
38+
import { rebuildDatabase } from "@dokploy/server";
3839
export const mariadbRouter = createTRPCRouter({
3940
create: protectedProcedure
4041
.input(apiCreateMariaDB)
@@ -369,4 +370,18 @@ export const mariadbRouter = createTRPCRouter({
369370

370371
return updatedMariadb;
371372
}),
373+
rebuild: protectedProcedure
374+
.input(apiRebuildMariadb)
375+
.mutation(async ({ input, ctx }) => {
376+
const mariadb = await findMariadbById(input.mariadbId);
377+
if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
378+
throw new TRPCError({
379+
code: "UNAUTHORIZED",
380+
message: "You are not authorized to rebuild this MariaDB database",
381+
});
382+
}
383+
384+
await rebuildDatabase(mariadb.mariadbId, "mariadb");
385+
return true;
386+
}),
372387
});

0 commit comments

Comments
 (0)