From 23acae11219a7135e67764692a1e0a1862c26741 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sat, 17 Jan 2026 23:19:17 +0100 Subject: [PATCH] refactor(navigation): use volume id in urls instead of name --- .../api-client/@tanstack/react-query.gen.ts | 2 +- app/client/api-client/sdk.gen.ts | 16 +- app/client/api-client/types.gen.ts | 750 +++++++- app/client/components/volume-file-browser.tsx | 10 +- .../components/create-schedule-form.tsx | 2 +- .../backups/components/schedule-summary.tsx | 2 +- .../repositories/routes/snapshot-details.tsx | 2 +- .../volumes/components/healthchecks-card.tsx | 4 +- .../modules/volumes/routes/create-volume.tsx | 2 +- .../modules/volumes/routes/volume-details.tsx | 20 +- app/client/modules/volumes/routes/volumes.tsx | 2 +- app/client/modules/volumes/tabs/files.tsx | 2 +- app/client/modules/volumes/tabs/info.tsx | 4 +- app/drizzle/0042_watery_liz_osborn.sql | 1 + app/drizzle/meta/0042_snapshot.json | 1628 +++++++++++++++++ app/drizzle/meta/_journal.json | 7 + app/routes.ts | 2 +- app/server/db/schema.ts | 2 +- app/server/jobs/auto-remount.ts | 2 +- app/server/jobs/healthchecks.ts | 4 +- app/server/modules/lifecycle/startup.ts | 4 +- .../modules/volumes/volume.controller.ts | 42 +- app/server/modules/volumes/volume.service.ts | 60 +- 23 files changed, 2461 insertions(+), 109 deletions(-) create mode 100644 app/drizzle/0042_watery_liz_osborn.sql create mode 100644 app/drizzle/meta/0042_snapshot.json diff --git a/app/client/api-client/@tanstack/react-query.gen.ts b/app/client/api-client/@tanstack/react-query.gen.ts index 342f4a36..4709971b 100644 --- a/app/client/api-client/@tanstack/react-query.gen.ts +++ b/app/client/api-client/@tanstack/react-query.gen.ts @@ -1260,7 +1260,7 @@ export const getUpdatesOptions = (options?: Options) => }); /** - * Download the Restic password file for backup recovery. Requires password re-authentication. + * Download the organization's Restic password for backup recovery. Requires organization owner or admin role and password re-authentication. */ export const downloadResticPasswordMutation = ( options?: Partial>, diff --git a/app/client/api-client/sdk.gen.ts b/app/client/api-client/sdk.gen.ts index 835080bd..97befa52 100644 --- a/app/client/api-client/sdk.gen.ts +++ b/app/client/api-client/sdk.gen.ts @@ -179,7 +179,7 @@ export const testConnection = ( */ export const deleteVolume = (options: Options) => (options.client ?? client).delete({ - url: "/api/v1/volumes/{name}", + url: "/api/v1/volumes/{id}", ...options, }); @@ -188,7 +188,7 @@ export const deleteVolume = (options: Opti */ export const getVolume = (options: Options) => (options.client ?? client).get({ - url: "/api/v1/volumes/{name}", + url: "/api/v1/volumes/{id}", ...options, }); @@ -197,7 +197,7 @@ export const getVolume = (options: Options */ export const updateVolume = (options: Options) => (options.client ?? client).put({ - url: "/api/v1/volumes/{name}", + url: "/api/v1/volumes/{id}", ...options, headers: { "Content-Type": "application/json", @@ -210,7 +210,7 @@ export const updateVolume = (options: Opti */ export const mountVolume = (options: Options) => (options.client ?? client).post({ - url: "/api/v1/volumes/{name}/mount", + url: "/api/v1/volumes/{id}/mount", ...options, }); @@ -221,7 +221,7 @@ export const unmountVolume = ( options: Options, ) => (options.client ?? client).post({ - url: "/api/v1/volumes/{name}/unmount", + url: "/api/v1/volumes/{id}/unmount", ...options, }); @@ -232,7 +232,7 @@ export const healthCheckVolume = ( options: Options, ) => (options.client ?? client).post({ - url: "/api/v1/volumes/{name}/health-check", + url: "/api/v1/volumes/{id}/health-check", ...options, }); @@ -241,7 +241,7 @@ export const healthCheckVolume = ( */ export const listFiles = (options: Options) => (options.client ?? client).get({ - url: "/api/v1/volumes/{name}/files", + url: "/api/v1/volumes/{id}/files", ...options, }); @@ -708,7 +708,7 @@ export const getUpdates = (options?: Optio }); /** - * Download the Restic password file for backup recovery. Requires password re-authentication. + * Download the organization's Restic password for backup recovery. Requires organization owner or admin role and password re-authentication. */ export const downloadResticPassword = ( options?: Options, diff --git a/app/client/api-client/types.gen.ts b/app/client/api-client/types.gen.ts index 3cab252d..cd506b9c 100644 --- a/app/client/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -313,10 +313,10 @@ export type TestConnectionResponse = TestConnectionResponses[keyof TestConnectio export type DeleteVolumeData = { body?: never; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}"; + url: "/api/v1/volumes/{id}"; }; export type DeleteVolumeResponses = { @@ -333,10 +333,10 @@ export type DeleteVolumeResponse = DeleteVolumeResponses[keyof DeleteVolumeRespo export type GetVolumeData = { body?: never; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}"; + url: "/api/v1/volumes/{id}"; }; export type GetVolumeErrors = { @@ -485,10 +485,10 @@ export type UpdateVolumeData = { name?: string; }; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}"; + url: "/api/v1/volumes/{id}"; }; export type UpdateVolumeErrors = { @@ -574,10 +574,10 @@ export type UpdateVolumeResponse = UpdateVolumeResponses[keyof UpdateVolumeRespo export type MountVolumeData = { body?: never; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}/mount"; + url: "/api/v1/volumes/{id}/mount"; }; export type MountVolumeResponses = { @@ -595,10 +595,10 @@ export type MountVolumeResponse = MountVolumeResponses[keyof MountVolumeResponse export type UnmountVolumeData = { body?: never; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}/unmount"; + url: "/api/v1/volumes/{id}/unmount"; }; export type UnmountVolumeResponses = { @@ -616,10 +616,10 @@ export type UnmountVolumeResponse = UnmountVolumeResponses[keyof UnmountVolumeRe export type HealthCheckVolumeData = { body?: never; path: { - name: string; + id: string; }; query?: never; - url: "/api/v1/volumes/{name}/health-check"; + url: "/api/v1/volumes/{id}/health-check"; }; export type HealthCheckVolumeErrors = { @@ -644,7 +644,7 @@ export type HealthCheckVolumeResponse = HealthCheckVolumeResponses[keyof HealthC export type ListFilesData = { body?: never; path: { - name: string; + id: string; }; query?: { /** @@ -652,7 +652,7 @@ export type ListFilesData = { */ path?: string; }; - url: "/api/v1/volumes/{name}/files"; + url: "/api/v1/volumes/{id}/files"; }; export type ListFilesResponses = { @@ -725,8 +725,18 @@ export type ListRepositoriesResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -736,8 +746,18 @@ export type ListRepositoriesResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -746,9 +766,19 @@ export type ListRepositoriesResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -757,17 +787,37 @@ export type ListRepositoriesResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -775,18 +825,38 @@ export type ListRepositoriesResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -799,9 +869,19 @@ export type ListRepositoriesResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -828,8 +908,18 @@ export type CreateRepositoryData = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -839,8 +929,18 @@ export type CreateRepositoryData = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -849,9 +949,19 @@ export type CreateRepositoryData = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -860,17 +970,37 @@ export type CreateRepositoryData = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -878,18 +1008,38 @@ export type CreateRepositoryData = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -902,9 +1052,19 @@ export type CreateRepositoryData = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; name: string; compressionMode?: "auto" | "max" | "off"; @@ -993,8 +1153,18 @@ export type GetRepositoryResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -1004,8 +1174,18 @@ export type GetRepositoryResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -1014,9 +1194,19 @@ export type GetRepositoryResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -1025,17 +1215,37 @@ export type GetRepositoryResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -1043,18 +1253,38 @@ export type GetRepositoryResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -1067,9 +1297,19 @@ export type GetRepositoryResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -1123,8 +1363,18 @@ export type UpdateRepositoryResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -1134,8 +1384,18 @@ export type UpdateRepositoryResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -1144,9 +1404,19 @@ export type UpdateRepositoryResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -1155,17 +1425,37 @@ export type UpdateRepositoryResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -1173,18 +1463,38 @@ export type UpdateRepositoryResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -1197,9 +1507,19 @@ export type UpdateRepositoryResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -1470,8 +1790,18 @@ export type ListBackupSchedulesResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -1481,8 +1811,18 @@ export type ListBackupSchedulesResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -1491,9 +1831,19 @@ export type ListBackupSchedulesResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -1502,17 +1852,37 @@ export type ListBackupSchedulesResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -1520,18 +1890,38 @@ export type ListBackupSchedulesResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -1544,9 +1934,19 @@ export type ListBackupSchedulesResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -1762,8 +2162,18 @@ export type GetBackupScheduleResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -1773,8 +2183,18 @@ export type GetBackupScheduleResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -1783,9 +2203,19 @@ export type GetBackupScheduleResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -1794,17 +2224,37 @@ export type GetBackupScheduleResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -1812,18 +2262,38 @@ export type GetBackupScheduleResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -1836,9 +2306,19 @@ export type GetBackupScheduleResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -2035,8 +2515,18 @@ export type GetBackupScheduleForVolumeResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -2046,8 +2536,18 @@ export type GetBackupScheduleForVolumeResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -2056,9 +2556,19 @@ export type GetBackupScheduleForVolumeResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -2067,17 +2577,37 @@ export type GetBackupScheduleForVolumeResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -2085,18 +2615,38 @@ export type GetBackupScheduleForVolumeResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -2109,9 +2659,19 @@ export type GetBackupScheduleForVolumeResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -2516,8 +3076,18 @@ export type GetScheduleMirrorsResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -2527,8 +3097,18 @@ export type GetScheduleMirrorsResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -2537,9 +3117,19 @@ export type GetScheduleMirrorsResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -2548,17 +3138,37 @@ export type GetScheduleMirrorsResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -2566,18 +3176,38 @@ export type GetScheduleMirrorsResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -2590,9 +3220,19 @@ export type GetScheduleMirrorsResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -2646,8 +3286,18 @@ export type UpdateScheduleMirrorsResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accessKeyId: string; @@ -2657,8 +3307,18 @@ export type UpdateScheduleMirrorsResponses = { secretAccessKey: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { accountKey: string; @@ -2667,9 +3327,19 @@ export type UpdateScheduleMirrorsResponses = { container: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; endpointSuffix?: string; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "gcs"; @@ -2678,17 +3348,37 @@ export type UpdateScheduleMirrorsResponses = { projectId: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "local"; name: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rclone"; @@ -2696,18 +3386,38 @@ export type UpdateScheduleMirrorsResponses = { remote: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; } | { backend: "rest"; url: string; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; password?: string; path?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; username?: string; } | { @@ -2720,9 +3430,19 @@ export type UpdateScheduleMirrorsResponses = { skipHostKeyCheck?: boolean; cacert?: string; customPassword?: string; + downloadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; insecureTls?: boolean; isExistingRepository?: boolean; knownHosts?: string; + uploadLimit?: { + unit?: "Gbps" | "Kbps" | "Mbps"; + value?: number; + enabled?: boolean; + }; }; createdAt: number; id: string; @@ -3426,7 +4146,7 @@ export type DownloadResticPasswordData = { export type DownloadResticPasswordResponses = { /** - * Restic password file content + * Organization's Restic password */ 200: string; }; diff --git a/app/client/components/volume-file-browser.tsx b/app/client/components/volume-file-browser.tsx index fc8826f5..9b1dbf83 100644 --- a/app/client/components/volume-file-browser.tsx +++ b/app/client/components/volume-file-browser.tsx @@ -6,7 +6,7 @@ import { useFileBrowser } from "../hooks/use-file-browser"; import { parseError } from "../lib/errors"; type VolumeFileBrowserProps = { - volumeName: string; + volumeId: string; enabled?: boolean; withCheckboxes?: boolean; selectedPaths?: Set; @@ -18,7 +18,7 @@ type VolumeFileBrowserProps = { }; export const VolumeFileBrowser = ({ - volumeName, + volumeId, enabled = true, withCheckboxes = false, selectedPaths, @@ -31,7 +31,7 @@ export const VolumeFileBrowser = ({ const queryClient = useQueryClient(); const { data, isLoading, error } = useQuery({ - ...listFilesOptions({ path: { name: volumeName } }), + ...listFilesOptions({ path: { id: volumeId } }), enabled, }); @@ -41,7 +41,7 @@ export const VolumeFileBrowser = ({ fetchFolder: async (path) => { return await queryClient.ensureQueryData( listFilesOptions({ - path: { name: volumeName }, + path: { id: volumeId }, query: { path }, }), ); @@ -49,7 +49,7 @@ export const VolumeFileBrowser = ({ prefetchFolder: (path) => { void queryClient.prefetchQuery( listFilesOptions({ - path: { name: volumeName }, + path: { id: volumeId }, query: { path }, }), ); diff --git a/app/client/modules/backups/components/create-schedule-form.tsx b/app/client/modules/backups/components/create-schedule-form.tsx index bf78889d..1978c608 100644 --- a/app/client/modules/backups/components/create-schedule-form.tsx +++ b/app/client/modules/backups/components/create-schedule-form.tsx @@ -372,7 +372,7 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }: {
{schedule.name} - + {schedule.volume.name} diff --git a/app/client/modules/repositories/routes/snapshot-details.tsx b/app/client/modules/repositories/routes/snapshot-details.tsx index 2d740d1b..dd31f9a8 100644 --- a/app/client/modules/repositories/routes/snapshot-details.tsx +++ b/app/client/modules/repositories/routes/snapshot-details.tsx @@ -136,7 +136,7 @@ export default function SnapshotDetailsPage({ loaderData }: Route.ComponentProps Volume:

{backupSchedule?.volume.name} diff --git a/app/client/modules/volumes/components/healthchecks-card.tsx b/app/client/modules/volumes/components/healthchecks-card.tsx index 86a3c88e..74157b70 100644 --- a/app/client/modules/volumes/components/healthchecks-card.tsx +++ b/app/client/modules/volumes/components/healthchecks-card.tsx @@ -60,7 +60,7 @@ export const HealthchecksCard = ({ volume }: Props) => { - toggleAutoRemount.mutate({ path: { name: volume.name }, body: { autoRemount: !volume.autoRemount } }) + toggleAutoRemount.mutate({ path: { id: volume.shortId }, body: { autoRemount: !volume.autoRemount } }) } disabled={toggleAutoRemount.isPending} enabledLabel="Enabled" @@ -74,7 +74,7 @@ export const HealthchecksCard = ({ volume }: Props) => { variant="outline" className="mt-4" loading={healthcheck.isPending} - onClick={() => healthcheck.mutate({ path: { name: volume.name } })} + onClick={() => healthcheck.mutate({ path: { id: volume.shortId } })} > Run Health Check diff --git a/app/client/modules/volumes/routes/create-volume.tsx b/app/client/modules/volumes/routes/create-volume.tsx index 46bbec06..8d5bbaca 100644 --- a/app/client/modules/volumes/routes/create-volume.tsx +++ b/app/client/modules/volumes/routes/create-volume.tsx @@ -33,7 +33,7 @@ export default function CreateVolume() { ...createVolumeMutation(), onSuccess: (data) => { toast.success("Volume created successfully"); - void navigate(`/volumes/${data.name}`); + void navigate(`/volumes/${data.shortId}`); }, }); diff --git a/app/client/modules/volumes/routes/volume-details.tsx b/app/client/modules/volumes/routes/volume-details.tsx index f2b3da4a..f5faeb81 100644 --- a/app/client/modules/volumes/routes/volume-details.tsx +++ b/app/client/modules/volumes/routes/volume-details.tsx @@ -41,12 +41,12 @@ const getVolumeStatusVariant = (status: VolumeStatus): "success" | "neutral" | " }; export const handle = { - breadcrumb: (match: Route.MetaArgs) => [{ label: "Volumes", href: "/volumes" }, { label: match.params.name }], + breadcrumb: (match: Route.MetaArgs) => [{ label: "Volumes", href: "/volumes" }, { label: match.params.id }], }; export function meta({ params }: Route.MetaArgs) { return [ - { title: `Zerobyte - ${params.name}` }, + { title: `Zerobyte - ${params.id}` }, { name: "description", content: "View and manage volume details, configuration, and files.", @@ -55,19 +55,19 @@ export function meta({ params }: Route.MetaArgs) { } export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => { - const volume = await getVolume({ path: { name: params.name } }); + const volume = await getVolume({ path: { id: params.id } }); if (volume.data) return volume.data; }; export default function VolumeDetails({ loaderData }: Route.ComponentProps) { - const { name } = useParams<{ name: string }>(); + const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get("tab") || "info"; const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const { data } = useQuery({ - ...getVolumeOptions({ path: { name: name ?? "" } }), + ...getVolumeOptions({ path: { id: id ?? "" } }), initialData: loaderData, }); @@ -110,10 +110,10 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) { const handleConfirmDelete = () => { setShowDeleteConfirm(false); - deleteVol.mutate({ path: { name: name ?? "" } }); + deleteVol.mutate({ path: { id: id ?? "" } }); }; - if (!name) { + if (!id) { return

Volume not found
; } @@ -139,7 +139,7 @@ export default function VolumeDetails({ loaderData }: Route.ComponentProps) {