diff --git a/app/client/modules/backups/routes/edit-backup.tsx b/app/client/modules/backups/routes/edit-backup.tsx
new file mode 100644
index 00000000..8aae42c7
--- /dev/null
+++ b/app/client/modules/backups/routes/edit-backup.tsx
@@ -0,0 +1,75 @@
+import { useId } from "react";
+import { useMutation, useSuspenseQuery } from "@tanstack/react-query";
+import { Save, X } from "lucide-react";
+import { toast } from "sonner";
+import { getBackupScheduleOptions, updateBackupScheduleMutation } from "~/client/api-client/@tanstack/react-query.gen";
+import { Button } from "~/client/components/ui/button";
+import { parseError } from "~/client/lib/errors";
+import { useNavigate } from "@tanstack/react-router";
+import { getCronExpression } from "~/utils/utils";
+import { CreateScheduleForm, type BackupScheduleFormValues } from "../components/create-schedule-form";
+
+export function EditBackupPage({ backupId }: { backupId: string }) {
+ const navigate = useNavigate();
+ const formId = useId();
+
+ const { data: schedule } = useSuspenseQuery({
+ ...getBackupScheduleOptions({ path: { shortId: backupId } }),
+ });
+
+ const updateSchedule = useMutation({
+ ...updateBackupScheduleMutation(),
+ onSuccess: () => {
+ toast.success("Backup schedule saved successfully");
+ void navigate({ to: `/backups/${schedule.shortId}` });
+ },
+ onError: (error) => {
+ toast.error("Failed to save backup schedule", {
+ description: parseError(error)?.message,
+ });
+ },
+ });
+
+ const handleSubmit = (formValues: BackupScheduleFormValues) => {
+ const cronExpression = getCronExpression(
+ formValues.frequency,
+ formValues.dailyTime,
+ formValues.weeklyDay,
+ formValues.monthlyDays,
+ formValues.cronExpression,
+ );
+
+ const retentionPolicy: Record
= {};
+ if (formValues.keepLast) retentionPolicy.keepLast = formValues.keepLast;
+ if (formValues.keepHourly) retentionPolicy.keepHourly = formValues.keepHourly;
+ if (formValues.keepDaily) retentionPolicy.keepDaily = formValues.keepDaily;
+ if (formValues.keepWeekly) retentionPolicy.keepWeekly = formValues.keepWeekly;
+ if (formValues.keepMonthly) retentionPolicy.keepMonthly = formValues.keepMonthly;
+ if (formValues.keepYearly) retentionPolicy.keepYearly = formValues.keepYearly;
+
+ updateSchedule.mutate({
+ path: { shortId: schedule.shortId },
+ body: {
+ ...formValues,
+ cronExpression,
+ retentionPolicy: Object.keys(retentionPolicy).length > 0 ? retentionPolicy : undefined,
+ },
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/routeTree.gen.ts b/app/routeTree.gen.ts
index e0a737d3..ca1eb70c 100644
--- a/app/routeTree.gen.ts
+++ b/app/routeTree.gen.ts
@@ -33,6 +33,7 @@ import { Route as dashboardRepositoriesRepositoryIdIndexRouteImport } from './ro
import { Route as dashboardBackupsBackupIdIndexRouteImport } from './routes/(dashboard)/backups/$backupId/index'
import { Route as dashboardSettingsSsoNewRouteImport } from './routes/(dashboard)/settings/sso/new'
import { Route as dashboardRepositoriesRepositoryIdEditRouteImport } from './routes/(dashboard)/repositories/$repositoryId/edit'
+import { Route as dashboardBackupsBackupIdEditRouteImport } from './routes/(dashboard)/backups/$backupId/edit'
import { Route as dashboardRepositoriesRepositoryIdSnapshotIdIndexRouteImport } from './routes/(dashboard)/repositories/$repositoryId/$snapshotId/index'
import { Route as dashboardRepositoriesRepositoryIdSnapshotIdRestoreRouteImport } from './routes/(dashboard)/repositories/$repositoryId/$snapshotId/restore'
import { Route as dashboardBackupsBackupIdSnapshotIdRestoreRouteImport } from './routes/(dashboard)/backups/$backupId/$snapshotId.restore'
@@ -164,6 +165,12 @@ const dashboardRepositoriesRepositoryIdEditRoute =
path: '/repositories/$repositoryId/edit',
getParentRoute: () => dashboardRouteRoute,
} as any)
+const dashboardBackupsBackupIdEditRoute =
+ dashboardBackupsBackupIdEditRouteImport.update({
+ id: '/backups/$backupId/edit',
+ path: '/backups/$backupId/edit',
+ getParentRoute: () => dashboardRouteRoute,
+ } as any)
const dashboardRepositoriesRepositoryIdSnapshotIdIndexRoute =
dashboardRepositoriesRepositoryIdSnapshotIdIndexRouteImport.update({
id: '/repositories/$repositoryId/$snapshotId/',
@@ -202,6 +209,7 @@ export interface FileRoutesByFullPath {
'/repositories/': typeof dashboardRepositoriesIndexRoute
'/settings/': typeof dashboardSettingsIndexRoute
'/volumes/': typeof dashboardVolumesIndexRoute
+ '/backups/$backupId/edit': typeof dashboardBackupsBackupIdEditRoute
'/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute
'/settings/sso/new': typeof dashboardSettingsSsoNewRoute
'/backups/$backupId/': typeof dashboardBackupsBackupIdIndexRoute
@@ -229,6 +237,7 @@ export interface FileRoutesByTo {
'/repositories': typeof dashboardRepositoriesIndexRoute
'/settings': typeof dashboardSettingsIndexRoute
'/volumes': typeof dashboardVolumesIndexRoute
+ '/backups/$backupId/edit': typeof dashboardBackupsBackupIdEditRoute
'/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute
'/settings/sso/new': typeof dashboardSettingsSsoNewRoute
'/backups/$backupId': typeof dashboardBackupsBackupIdIndexRoute
@@ -259,6 +268,7 @@ export interface FileRoutesById {
'/(dashboard)/repositories/': typeof dashboardRepositoriesIndexRoute
'/(dashboard)/settings/': typeof dashboardSettingsIndexRoute
'/(dashboard)/volumes/': typeof dashboardVolumesIndexRoute
+ '/(dashboard)/backups/$backupId/edit': typeof dashboardBackupsBackupIdEditRoute
'/(dashboard)/repositories/$repositoryId/edit': typeof dashboardRepositoriesRepositoryIdEditRoute
'/(dashboard)/settings/sso/new': typeof dashboardSettingsSsoNewRoute
'/(dashboard)/backups/$backupId/': typeof dashboardBackupsBackupIdIndexRoute
@@ -288,6 +298,7 @@ export interface FileRouteTypes {
| '/repositories/'
| '/settings/'
| '/volumes/'
+ | '/backups/$backupId/edit'
| '/repositories/$repositoryId/edit'
| '/settings/sso/new'
| '/backups/$backupId/'
@@ -315,6 +326,7 @@ export interface FileRouteTypes {
| '/repositories'
| '/settings'
| '/volumes'
+ | '/backups/$backupId/edit'
| '/repositories/$repositoryId/edit'
| '/settings/sso/new'
| '/backups/$backupId'
@@ -344,6 +356,7 @@ export interface FileRouteTypes {
| '/(dashboard)/repositories/'
| '/(dashboard)/settings/'
| '/(dashboard)/volumes/'
+ | '/(dashboard)/backups/$backupId/edit'
| '/(dashboard)/repositories/$repositoryId/edit'
| '/(dashboard)/settings/sso/new'
| '/(dashboard)/backups/$backupId/'
@@ -530,6 +543,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof dashboardRepositoriesRepositoryIdEditRouteImport
parentRoute: typeof dashboardRouteRoute
}
+ '/(dashboard)/backups/$backupId/edit': {
+ id: '/(dashboard)/backups/$backupId/edit'
+ path: '/backups/$backupId/edit'
+ fullPath: '/backups/$backupId/edit'
+ preLoaderRoute: typeof dashboardBackupsBackupIdEditRouteImport
+ parentRoute: typeof dashboardRouteRoute
+ }
'/(dashboard)/repositories/$repositoryId/$snapshotId/': {
id: '/(dashboard)/repositories/$repositoryId/$snapshotId/'
path: '/repositories/$repositoryId/$snapshotId'
@@ -595,6 +615,7 @@ interface dashboardRouteRouteChildren {
dashboardRepositoriesIndexRoute: typeof dashboardRepositoriesIndexRoute
dashboardSettingsIndexRoute: typeof dashboardSettingsIndexRoute
dashboardVolumesIndexRoute: typeof dashboardVolumesIndexRoute
+ dashboardBackupsBackupIdEditRoute: typeof dashboardBackupsBackupIdEditRoute
dashboardRepositoriesRepositoryIdEditRoute: typeof dashboardRepositoriesRepositoryIdEditRoute
dashboardSettingsSsoNewRoute: typeof dashboardSettingsSsoNewRoute
dashboardBackupsBackupIdIndexRoute: typeof dashboardBackupsBackupIdIndexRoute
@@ -618,6 +639,7 @@ const dashboardRouteRouteChildren: dashboardRouteRouteChildren = {
dashboardRepositoriesIndexRoute: dashboardRepositoriesIndexRoute,
dashboardSettingsIndexRoute: dashboardSettingsIndexRoute,
dashboardVolumesIndexRoute: dashboardVolumesIndexRoute,
+ dashboardBackupsBackupIdEditRoute: dashboardBackupsBackupIdEditRoute,
dashboardRepositoriesRepositoryIdEditRoute:
dashboardRepositoriesRepositoryIdEditRoute,
dashboardSettingsSsoNewRoute: dashboardSettingsSsoNewRoute,
diff --git a/app/routes/(dashboard)/backups/$backupId/edit.tsx b/app/routes/(dashboard)/backups/$backupId/edit.tsx
new file mode 100644
index 00000000..f74ff57d
--- /dev/null
+++ b/app/routes/(dashboard)/backups/$backupId/edit.tsx
@@ -0,0 +1,41 @@
+import { createFileRoute } from "@tanstack/react-router";
+import { getBackupScheduleOptions, listRepositoriesOptions } from "~/client/api-client/@tanstack/react-query.gen";
+import { EditBackupPage } from "~/client/modules/backups/routes/edit-backup";
+
+export const Route = createFileRoute("/(dashboard)/backups/$backupId/edit")({
+ component: RouteComponent,
+ errorComponent: () => Failed to load backup
,
+ loader: async ({ params, context }) => {
+ const schedule = await context.queryClient.ensureQueryData({
+ ...getBackupScheduleOptions({ path: { shortId: params.backupId } }),
+ });
+
+ await context.queryClient.ensureQueryData({
+ ...listRepositoriesOptions(),
+ });
+
+ return schedule;
+ },
+ staticData: {
+ breadcrumb: (match) => [
+ { label: "Backup Jobs", href: "/backups" },
+ { label: match.loaderData?.name || "Job Details", href: `/backups/${match.params.backupId}` },
+ { label: "Edit" },
+ ],
+ },
+ head: ({ loaderData }) => ({
+ meta: [
+ { title: `Zerobyte - Edit ${loaderData?.name || "Backup Job"}` },
+ {
+ name: "description",
+ content: "Edit backup job configuration and schedule.",
+ },
+ ],
+ }),
+});
+
+function RouteComponent() {
+ const { backupId } = Route.useParams();
+
+ return ;
+}