feat: backup schedule creation form

This commit is contained in:
Nicolas Meienberger
2025-10-28 22:34:56 +01:00
parent 37a22b260f
commit d1c1adaba7
14 changed files with 746 additions and 610 deletions

View File

@@ -5,6 +5,7 @@ import {
createBackupScheduleDto,
deleteBackupScheduleDto,
getBackupScheduleDto,
getBackupScheduleForVolumeDto,
listBackupSchedulesDto,
runBackupNowDto,
updateBackupScheduleBody,
@@ -25,6 +26,12 @@ export const backupScheduleController = new Hono()
return c.json({ schedule }, 200);
})
.get("/volume/:volumeId", getBackupScheduleForVolumeDto, async (c) => {
const volumeId = c.req.param("volumeId");
const schedule = await backupsService.getScheduleForVolume(Number(volumeId));
return c.json(schedule, 200);
})
.post("/", createBackupScheduleDto, validator("json", createBackupScheduleBody), async (c) => {
const body = c.req.valid("json");

View File

@@ -16,14 +16,12 @@ export type RetentionPolicy = typeof retentionPolicySchema.infer;
const backupScheduleSchema = type({
id: "number",
volumeId: "number",
volumeName: "string",
repositoryId: "string",
repositoryName: "string",
enabled: "boolean",
cronExpression: "string",
retentionPolicy: retentionPolicySchema.or("null"),
excludePatterns: "string[]",
includePatterns: "string[]",
excludePatterns: "string[] | null",
includePatterns: "string[] | null",
lastBackupAt: "number | null",
lastBackupStatus: "'success' | 'error' | null",
lastBackupError: "string | null",
@@ -66,7 +64,7 @@ export const getBackupScheduleResponse = type({
schedule: backupScheduleSchema,
});
export type GetBackupScheduleResponseDto = typeof getBackupScheduleResponse.infer;
export type GetBackupScheduleDto = typeof getBackupScheduleResponse.infer;
export const getBackupScheduleDto = describeRoute({
description: "Get a backup schedule by ID",
@@ -84,6 +82,26 @@ export const getBackupScheduleDto = describeRoute({
},
});
export const getBackupScheduleForVolumeResponse = backupScheduleSchema.or("null");
export type GetBackupScheduleForVolumeResponseDto = typeof getBackupScheduleForVolumeResponse.infer;
export const getBackupScheduleForVolumeDto = describeRoute({
description: "Get a backup schedule for a specific volume",
tags: ["Backups"],
operationId: "getBackupScheduleForVolume",
responses: {
200: {
description: "Backup schedule details for the volume",
content: {
"application/json": {
schema: resolver(getBackupScheduleForVolumeResponse),
},
},
},
},
});
/**
* Create a new backup schedule
*/
@@ -105,6 +123,8 @@ export const createBackupScheduleResponse = type({
schedule: backupScheduleSchema,
});
export type CreateBackupScheduleDto = typeof createBackupScheduleResponse.infer;
export const createBackupScheduleDto = describeRoute({
description: "Create a new backup schedule for a volume",
operationId: "createBackupSchedule",

View File

@@ -247,6 +247,14 @@ const getSchedulesToExecute = async () => {
return schedulesToRun;
};
const getScheduleForVolume = async (volumeId: number) => {
const schedule = await db.query.backupSchedulesTable.findFirst({
where: eq(backupSchedulesTable.volumeId, volumeId),
});
return schedule ?? null;
};
export const backupsService = {
listSchedules,
getSchedule,
@@ -255,4 +263,5 @@ export const backupsService = {
deleteSchedule,
executeBackup,
getSchedulesToExecute,
getScheduleForVolume,
};

View File

@@ -3,6 +3,7 @@ import { type } from "arktype";
import { describeRoute, resolver } from "hono-openapi";
const volumeSchema = type({
id: "number",
name: "string",
path: "string",
type: type.valueOf(BACKEND_TYPES),