mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-06 14:35:26 +02:00
feat: implement volume backup management functionality
- Added components for handling and displaying volume backups in the dashboard. - Created API routes for managing volume backups, including create, update, delete, and list operations. - Introduced database schema for volume backups, including necessary fields and relationships. - Updated the application to integrate volume backup features into the service management interface.
This commit is contained in:
@@ -33,3 +33,4 @@ export * from "./ai";
|
||||
export * from "./account";
|
||||
export * from "./schedule";
|
||||
export * from "./rollbacks";
|
||||
export * from "./volume-backups";
|
||||
|
||||
110
packages/server/src/db/schema/volume-backups.ts
Normal file
110
packages/server/src/db/schema/volume-backups.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { serviceType } from "./mount";
|
||||
import { applications } from "./application";
|
||||
import { mongo } from "./mongo";
|
||||
import { mysql } from "./mysql";
|
||||
import { redis } from "./redis";
|
||||
import { compose } from "./compose";
|
||||
import { postgres } from "./postgres";
|
||||
import { mariadb } from "./mariadb";
|
||||
import { destinations } from "./destination";
|
||||
|
||||
export const volumeBackupType = pgEnum("volumeBackupType", ["bind", "volume"]);
|
||||
|
||||
export const volumeBackups = pgTable("volume_backup", {
|
||||
volumeBackupId: text("volumeBackupId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
name: text("name").notNull(),
|
||||
type: volumeBackupType("type").notNull().default("volume"),
|
||||
volumeName: text("volumeName"),
|
||||
hostPath: text("hostPath"),
|
||||
prefix: text("prefix").notNull(),
|
||||
serviceType: serviceType("serviceType").notNull().default("application"),
|
||||
turnOff: boolean("turnOff").notNull().default(false),
|
||||
cronExpression: text("cronExpression").notNull(),
|
||||
keepLatestCount: integer("keepLatestCount"),
|
||||
enabled: boolean("enabled"),
|
||||
applicationId: text("applicationId").references(
|
||||
() => applications.applicationId,
|
||||
{
|
||||
onDelete: "cascade",
|
||||
},
|
||||
),
|
||||
postgresId: text("postgresId").references(() => postgres.postgresId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
mariadbId: text("mariadbId").references(() => mariadb.mariadbId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
mongoId: text("mongoId").references(() => mongo.mongoId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
mysqlId: text("mysqlId").references(() => mysql.mysqlId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
redisId: text("redisId").references(() => redis.redisId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
composeId: text("composeId").references(() => compose.composeId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
destinationId: text("destinationId")
|
||||
.notNull()
|
||||
.references(() => destinations.destinationId, { onDelete: "cascade" }),
|
||||
});
|
||||
|
||||
export type VolumeBackup = typeof volumeBackups.$inferSelect;
|
||||
|
||||
export const volumeBackupsRelations = relations(volumeBackups, ({ one }) => ({
|
||||
application: one(applications, {
|
||||
fields: [volumeBackups.applicationId],
|
||||
references: [applications.applicationId],
|
||||
}),
|
||||
postgres: one(postgres, {
|
||||
fields: [volumeBackups.postgresId],
|
||||
references: [postgres.postgresId],
|
||||
}),
|
||||
mariadb: one(mariadb, {
|
||||
fields: [volumeBackups.mariadbId],
|
||||
references: [mariadb.mariadbId],
|
||||
}),
|
||||
mongo: one(mongo, {
|
||||
fields: [volumeBackups.mongoId],
|
||||
references: [mongo.mongoId],
|
||||
}),
|
||||
mysql: one(mysql, {
|
||||
fields: [volumeBackups.mysqlId],
|
||||
references: [mysql.mysqlId],
|
||||
}),
|
||||
redis: one(redis, {
|
||||
fields: [volumeBackups.redisId],
|
||||
references: [redis.redisId],
|
||||
}),
|
||||
compose: one(compose, {
|
||||
fields: [volumeBackups.composeId],
|
||||
references: [compose.composeId],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const createVolumeBackupSchema = createInsertSchema(
|
||||
volumeBackups,
|
||||
).extend({
|
||||
volumeName: z.string().min(1),
|
||||
});
|
||||
|
||||
export const updateVolumeBackupSchema = createVolumeBackupSchema.extend({
|
||||
volumeBackupId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiFindOneVolumeBackup = z.object({
|
||||
volumeBackupId: z.string().min(1),
|
||||
});
|
||||
@@ -10,6 +10,7 @@ export * from "./services/mysql";
|
||||
export * from "./services/backup";
|
||||
export * from "./services/cluster";
|
||||
export * from "./services/settings";
|
||||
export * from "./services/volume-backups";
|
||||
export * from "./services/docker";
|
||||
export * from "./services/destination";
|
||||
export * from "./services/deployment";
|
||||
|
||||
51
packages/server/src/services/volume-backups.ts
Normal file
51
packages/server/src/services/volume-backups.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import {
|
||||
type createVolumeBackupSchema,
|
||||
type updateVolumeBackupSchema,
|
||||
volumeBackups,
|
||||
} from "../db/schema";
|
||||
import { db } from "../db";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import type { z } from "zod";
|
||||
|
||||
export const findVolumeBackupById = async (volumeBackupId: string) => {
|
||||
const volumeBackup = await db.query.volumeBackups.findFirst({
|
||||
where: eq(volumeBackups.volumeBackupId, volumeBackupId),
|
||||
});
|
||||
|
||||
if (!volumeBackup) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Volume backup not found",
|
||||
});
|
||||
}
|
||||
|
||||
return volumeBackup;
|
||||
};
|
||||
|
||||
export const createVolumeBackup = async (
|
||||
volumeBackup: z.infer<typeof createVolumeBackupSchema>,
|
||||
) => {
|
||||
const newVolumeBackup = await db
|
||||
.insert(volumeBackups)
|
||||
.values(volumeBackup)
|
||||
.returning();
|
||||
|
||||
return newVolumeBackup;
|
||||
};
|
||||
|
||||
export const removeVolumeBackup = async (volumeBackupId: string) => {
|
||||
await db
|
||||
.delete(volumeBackups)
|
||||
.where(eq(volumeBackups.volumeBackupId, volumeBackupId));
|
||||
};
|
||||
|
||||
export const updateVolumeBackup = async (
|
||||
volumeBackupId: string,
|
||||
volumeBackup: z.infer<typeof updateVolumeBackupSchema>,
|
||||
) => {
|
||||
await db
|
||||
.update(volumeBackups)
|
||||
.set(volumeBackup)
|
||||
.where(eq(volumeBackups.volumeBackupId, volumeBackupId));
|
||||
};
|
||||
Reference in New Issue
Block a user