Skip to content

Commit 5525cf4

Browse files
committed
feat: expose snapshot restore planning API
The restore UI needs a target-scoped answer for the snapshot query root and whether original-location restore is available. That decision now belongs to core planning and must account for the selected restore agent platform
1 parent b945d28 commit 5525cf4

15 files changed

Lines changed: 250 additions & 108 deletions

app/client/api-client/@tanstack/react-query.gen.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import { type DefaultError, type InfiniteData, infiniteQueryOptions, queryOptions, type UseMutationOptions } from '@tanstack/react-query';
55

66
import { client } from '../client.gen';
7-
import { browseFilesystem, cancelDoctor, createApiKey, createBackupSchedule, createDesktopSession, createNotificationDestination, createRepository, createVolume, deleteApiKey, deleteBackupSchedule, deleteNotificationDestination, deleteRepository, deleteSnapshot, deleteSnapshots, deleteSsoInvitation, deleteSsoProvider, deleteUserAccount, deleteVolume, downloadResticPassword, dumpSnapshot, getAdminUsers, getApiKeys, getBackupProgress, getBackupSchedule, getBackupScheduleForVolume, getDevPanel, getMirrorCompatibility, getMirrorSyncStatus, getNotificationDestination, getOrgMembers, getPasswordLoginStatus, getPublicSsoProviders, getRegistrationStatus, getRepository, getRepositoryStats, getScheduleMirrors, getScheduleNotifications, getSnapshotDetails, getSsoSettings, getStatus, getSystemInfo, getUpdates, getUserDeletionImpact, getUserSsoInvitations, getVolume, healthCheckVolume, listBackupSchedules, listFiles, listNotificationDestinations, listRcloneRemotes, listRepositories, listSnapshotFiles, listSnapshots, listVolumes, mountVolume, type Options, refreshRepositoryStats, refreshSnapshots, removeOrgMember, reorderBackupSchedules, restoreSnapshot, runBackupNow, runForget, setPasswordLoginStatus, setRegistrationStatus, startDoctor, startInvitationSsoVerification, stopBackup, syncMirror, tagSnapshots, testConnection, testNotificationDestination, unlockRepository, unmountVolume, updateBackupSchedule, updateMemberRole, updateNotificationDestination, updateRepository, updateScheduleMirrors, updateScheduleNotifications, updateSsoProviderAutoLinking, updateVolume } from '../sdk.gen';
8-
import type { BrowseFilesystemData, BrowseFilesystemResponse, CancelDoctorData, CancelDoctorResponse, CreateApiKeyData, CreateApiKeyResponse, CreateBackupScheduleData, CreateBackupScheduleResponse, CreateDesktopSessionData, CreateNotificationDestinationData, CreateNotificationDestinationResponse, CreateRepositoryData, CreateRepositoryResponse, CreateVolumeData, CreateVolumeResponse, DeleteApiKeyData, DeleteBackupScheduleData, DeleteBackupScheduleResponse, DeleteNotificationDestinationData, DeleteNotificationDestinationResponse, DeleteRepositoryData, DeleteRepositoryResponse, DeleteSnapshotData, DeleteSnapshotResponse, DeleteSnapshotsData, DeleteSnapshotsResponse, DeleteSsoInvitationData, DeleteSsoProviderData, DeleteUserAccountData, DeleteVolumeData, DeleteVolumeResponse, DownloadResticPasswordData, DownloadResticPasswordResponse, DumpSnapshotData, DumpSnapshotResponse, GetAdminUsersData, GetAdminUsersResponse, GetApiKeysData, GetApiKeysResponse, GetBackupProgressData, GetBackupProgressResponse, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponse, GetBackupScheduleResponse, GetDevPanelData, GetDevPanelResponse, GetMirrorCompatibilityData, GetMirrorCompatibilityResponse, GetMirrorSyncStatusData, GetMirrorSyncStatusResponse, GetNotificationDestinationData, GetNotificationDestinationResponse, GetOrgMembersData, GetOrgMembersResponse, GetPasswordLoginStatusData, GetPasswordLoginStatusResponse, GetPublicSsoProvidersData, GetPublicSsoProvidersResponse, GetRegistrationStatusData, GetRegistrationStatusResponse, GetRepositoryData, GetRepositoryResponse, GetRepositoryStatsData, GetRepositoryStatsResponse, GetScheduleMirrorsData, GetScheduleMirrorsResponse, GetScheduleNotificationsData, GetScheduleNotificationsResponse, GetSnapshotDetailsData, GetSnapshotDetailsResponse, GetSsoSettingsData, GetSsoSettingsResponse, GetStatusData, GetStatusResponse, GetSystemInfoData, GetSystemInfoResponse, GetUpdatesData, GetUpdatesResponse, GetUserDeletionImpactData, GetUserDeletionImpactResponse, GetUserSsoInvitationsData, GetUserSsoInvitationsResponse, GetVolumeData, GetVolumeResponse, HealthCheckVolumeData, HealthCheckVolumeResponse, ListBackupSchedulesData, ListBackupSchedulesResponse, ListFilesData, ListFilesResponse, ListNotificationDestinationsData, ListNotificationDestinationsResponse, ListRcloneRemotesData, ListRcloneRemotesResponse, ListRepositoriesData, ListRepositoriesResponse, ListSnapshotFilesData, ListSnapshotFilesResponse, ListSnapshotsData, ListSnapshotsResponse, ListVolumesData, ListVolumesResponse, MountVolumeData, MountVolumeResponse, RefreshRepositoryStatsData, RefreshRepositoryStatsResponse, RefreshSnapshotsData, RefreshSnapshotsResponse, RemoveOrgMemberData, ReorderBackupSchedulesData, ReorderBackupSchedulesResponse, RestoreSnapshotData, RestoreSnapshotResponse, RunBackupNowData, RunBackupNowResponse, RunForgetData, RunForgetResponse, SetPasswordLoginStatusData, SetPasswordLoginStatusResponse, SetRegistrationStatusData, SetRegistrationStatusResponse, StartDoctorData, StartDoctorResponse, StartInvitationSsoVerificationData, StopBackupData, StopBackupResponse, SyncMirrorData, SyncMirrorResponse, TagSnapshotsData, TagSnapshotsResponse, TestConnectionData, TestConnectionResponse, TestNotificationDestinationData, TestNotificationDestinationResponse, UnlockRepositoryData, UnlockRepositoryResponse, UnmountVolumeData, UnmountVolumeResponse, UpdateBackupScheduleData, UpdateBackupScheduleResponse, UpdateMemberRoleData, UpdateNotificationDestinationData, UpdateNotificationDestinationResponse, UpdateRepositoryData, UpdateRepositoryResponse, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponse, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponse, UpdateSsoProviderAutoLinkingData, UpdateVolumeData, UpdateVolumeResponse } from '../types.gen';
7+
import { browseFilesystem, cancelDoctor, createApiKey, createBackupSchedule, createDesktopSession, createNotificationDestination, createRepository, createVolume, deleteApiKey, deleteBackupSchedule, deleteNotificationDestination, deleteRepository, deleteSnapshot, deleteSnapshots, deleteSsoInvitation, deleteSsoProvider, deleteUserAccount, deleteVolume, downloadResticPassword, dumpSnapshot, getAdminUsers, getApiKeys, getBackupProgress, getBackupSchedule, getBackupScheduleForVolume, getDevPanel, getMirrorCompatibility, getMirrorSyncStatus, getNotificationDestination, getOrgMembers, getPasswordLoginStatus, getPublicSsoProviders, getRegistrationStatus, getRepository, getRepositoryStats, getScheduleMirrors, getScheduleNotifications, getSnapshotDetails, getSnapshotRestorePlan, getSsoSettings, getStatus, getSystemInfo, getUpdates, getUserDeletionImpact, getUserSsoInvitations, getVolume, healthCheckVolume, listBackupSchedules, listFiles, listNotificationDestinations, listRcloneRemotes, listRepositories, listSnapshotFiles, listSnapshots, listVolumes, mountVolume, type Options, refreshRepositoryStats, refreshSnapshots, removeOrgMember, reorderBackupSchedules, restoreSnapshot, runBackupNow, runForget, setPasswordLoginStatus, setRegistrationStatus, startDoctor, startInvitationSsoVerification, stopBackup, syncMirror, tagSnapshots, testConnection, testNotificationDestination, unlockRepository, unmountVolume, updateBackupSchedule, updateMemberRole, updateNotificationDestination, updateRepository, updateScheduleMirrors, updateScheduleNotifications, updateSsoProviderAutoLinking, updateVolume } from '../sdk.gen';
8+
import type { BrowseFilesystemData, BrowseFilesystemResponse, CancelDoctorData, CancelDoctorResponse, CreateApiKeyData, CreateApiKeyResponse, CreateBackupScheduleData, CreateBackupScheduleResponse, CreateDesktopSessionData, CreateNotificationDestinationData, CreateNotificationDestinationResponse, CreateRepositoryData, CreateRepositoryResponse, CreateVolumeData, CreateVolumeResponse, DeleteApiKeyData, DeleteBackupScheduleData, DeleteBackupScheduleResponse, DeleteNotificationDestinationData, DeleteNotificationDestinationResponse, DeleteRepositoryData, DeleteRepositoryResponse, DeleteSnapshotData, DeleteSnapshotResponse, DeleteSnapshotsData, DeleteSnapshotsResponse, DeleteSsoInvitationData, DeleteSsoProviderData, DeleteUserAccountData, DeleteVolumeData, DeleteVolumeResponse, DownloadResticPasswordData, DownloadResticPasswordResponse, DumpSnapshotData, DumpSnapshotResponse, GetAdminUsersData, GetAdminUsersResponse, GetApiKeysData, GetApiKeysResponse, GetBackupProgressData, GetBackupProgressResponse, GetBackupScheduleData, GetBackupScheduleForVolumeData, GetBackupScheduleForVolumeResponse, GetBackupScheduleResponse, GetDevPanelData, GetDevPanelResponse, GetMirrorCompatibilityData, GetMirrorCompatibilityResponse, GetMirrorSyncStatusData, GetMirrorSyncStatusResponse, GetNotificationDestinationData, GetNotificationDestinationResponse, GetOrgMembersData, GetOrgMembersResponse, GetPasswordLoginStatusData, GetPasswordLoginStatusResponse, GetPublicSsoProvidersData, GetPublicSsoProvidersResponse, GetRegistrationStatusData, GetRegistrationStatusResponse, GetRepositoryData, GetRepositoryResponse, GetRepositoryStatsData, GetRepositoryStatsResponse, GetScheduleMirrorsData, GetScheduleMirrorsResponse, GetScheduleNotificationsData, GetScheduleNotificationsResponse, GetSnapshotDetailsData, GetSnapshotDetailsResponse, GetSnapshotRestorePlanData, GetSnapshotRestorePlanResponse, GetSsoSettingsData, GetSsoSettingsResponse, GetStatusData, GetStatusResponse, GetSystemInfoData, GetSystemInfoResponse, GetUpdatesData, GetUpdatesResponse, GetUserDeletionImpactData, GetUserDeletionImpactResponse, GetUserSsoInvitationsData, GetUserSsoInvitationsResponse, GetVolumeData, GetVolumeResponse, HealthCheckVolumeData, HealthCheckVolumeResponse, ListBackupSchedulesData, ListBackupSchedulesResponse, ListFilesData, ListFilesResponse, ListNotificationDestinationsData, ListNotificationDestinationsResponse, ListRcloneRemotesData, ListRcloneRemotesResponse, ListRepositoriesData, ListRepositoriesResponse, ListSnapshotFilesData, ListSnapshotFilesResponse, ListSnapshotsData, ListSnapshotsResponse, ListVolumesData, ListVolumesResponse, MountVolumeData, MountVolumeResponse, RefreshRepositoryStatsData, RefreshRepositoryStatsResponse, RefreshSnapshotsData, RefreshSnapshotsResponse, RemoveOrgMemberData, ReorderBackupSchedulesData, ReorderBackupSchedulesResponse, RestoreSnapshotData, RestoreSnapshotResponse, RunBackupNowData, RunBackupNowResponse, RunForgetData, RunForgetResponse, SetPasswordLoginStatusData, SetPasswordLoginStatusResponse, SetRegistrationStatusData, SetRegistrationStatusResponse, StartDoctorData, StartDoctorResponse, StartInvitationSsoVerificationData, StopBackupData, StopBackupResponse, SyncMirrorData, SyncMirrorResponse, TagSnapshotsData, TagSnapshotsResponse, TestConnectionData, TestConnectionResponse, TestNotificationDestinationData, TestNotificationDestinationResponse, UnlockRepositoryData, UnlockRepositoryResponse, UnmountVolumeData, UnmountVolumeResponse, UpdateBackupScheduleData, UpdateBackupScheduleResponse, UpdateMemberRoleData, UpdateNotificationDestinationData, UpdateNotificationDestinationResponse, UpdateRepositoryData, UpdateRepositoryResponse, UpdateScheduleMirrorsData, UpdateScheduleMirrorsResponse, UpdateScheduleNotificationsData, UpdateScheduleNotificationsResponse, UpdateSsoProviderAutoLinkingData, UpdateVolumeData, UpdateVolumeResponse } from '../types.gen';
99

1010
export type QueryKey<TOptions extends Options> = [
1111
Pick<TOptions, 'baseUrl' | 'body' | 'headers' | 'path' | 'query'> & {
@@ -811,6 +811,24 @@ export const getSnapshotDetailsOptions = (options: Options<GetSnapshotDetailsDat
811811
queryKey: getSnapshotDetailsQueryKey(options)
812812
});
813813

814+
export const getSnapshotRestorePlanQueryKey = (options: Options<GetSnapshotRestorePlanData>) => createQueryKey('getSnapshotRestorePlan', options);
815+
816+
/**
817+
* Get a target-scoped restore plan for a snapshot
818+
*/
819+
export const getSnapshotRestorePlanOptions = (options: Options<GetSnapshotRestorePlanData>) => queryOptions<GetSnapshotRestorePlanResponse, DefaultError, GetSnapshotRestorePlanResponse, ReturnType<typeof getSnapshotRestorePlanQueryKey>>({
820+
queryFn: async ({ queryKey, signal }) => {
821+
const { data } = await getSnapshotRestorePlan({
822+
...options,
823+
...queryKey[0],
824+
signal,
825+
throwOnError: true
826+
});
827+
return data;
828+
},
829+
queryKey: getSnapshotRestorePlanQueryKey(options)
830+
});
831+
814832
export const listSnapshotFilesQueryKey = (options: Options<ListSnapshotFilesData>) => createQueryKey('listSnapshotFiles', options);
815833

816834
/**

app/client/api-client/client/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export type { QuerySerializerOptions } from "../core/bodySerializer.gen";
66
export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer } from "../core/bodySerializer.gen";
77
export { buildClientParams } from "../core/params.gen";
88
export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen";
9+
export type { ServerSentEventsResult } from "../core/serverSentEvents.gen";
10+
export type { ClientMeta } from "../core/types.gen";
911
export { createClient } from "./client.gen";
1012
export type {
1113
Client,

app/client/api-client/client/utils.gen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'
1515
export const createQuerySerializer = <T = unknown>({
1616
parameters = {},
1717
...args
18-
}: QuerySerializerOptions = {}) => {
19-
const querySerializer = (queryParams: T) => {
18+
}: QuerySerializerOptions = {}): ((queryParams: T) => string) => {
19+
const querySerializer = (queryParams: T): string => {
2020
const search: string[] = [];
2121
if (queryParams && typeof queryParams === 'object') {
2222
for (const name in queryParams) {

app/client/api-client/core/auth.gen.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ export interface Auth {
1010
* @default 'header'
1111
*/
1212
in?: 'header' | 'query' | 'cookie';
13+
/**
14+
* A unique identifier for the security scheme.
15+
*
16+
* Defined only when there are multiple security schemes whose `Auth`
17+
* shape would otherwise be identical.
18+
*/
19+
key?: string;
1320
/**
1421
* Header or query parameter name.
1522
*

app/client/api-client/core/params.gen.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type KeyMap = Map<
6363
}
6464
>;
6565

66-
const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
66+
function buildKeyMap(fields: FieldsConfig, map?: KeyMap): KeyMap {
6767
if (!map) {
6868
map = new Map();
6969
}
@@ -86,7 +86,7 @@ const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
8686
}
8787

8888
return map;
89-
};
89+
}
9090

9191
interface Params {
9292
body: unknown;
@@ -95,16 +95,18 @@ interface Params {
9595
query: Record<string, unknown>;
9696
}
9797

98-
const stripEmptySlots = (params: Params) => {
98+
type ParamsSlotMap = Record<Slot, unknown>;
99+
100+
function stripEmptySlots(params: ParamsSlotMap): void {
99101
for (const [slot, value] of Object.entries(params)) {
100102
if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) {
101103
delete params[slot as Slot];
102104
}
103105
}
104-
};
106+
}
105107

106-
export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => {
107-
const params: Params = {
108+
export function buildClientParams(args: ReadonlyArray<unknown>, fields: FieldsConfig): Params {
109+
const params: ParamsSlotMap = {
108110
body: Object.create(null),
109111
headers: Object.create(null),
110112
path: Object.create(null),
@@ -166,5 +168,5 @@ export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsCo
166168

167169
stripEmptySlots(params);
168170

169-
return params;
170-
};
171+
return params as Params;
172+
}

app/client/api-client/core/pathSerializer.gen.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ interface SerializePrimitiveParam extends SerializePrimitiveOptions {
2626
value: string;
2727
}
2828

29-
export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
29+
export const separatorArrayExplode = (style: ArraySeparatorStyle): '.' | ';' | ',' | '&' => {
3030
switch (style) {
3131
case 'label':
3232
return '.';
@@ -39,7 +39,7 @@ export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
3939
}
4040
};
4141

42-
export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
42+
export const separatorArrayNoExplode = (style: ArraySeparatorStyle): ',' | '|' | '%20' => {
4343
switch (style) {
4444
case 'form':
4545
return ',';
@@ -52,7 +52,7 @@ export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
5252
}
5353
};
5454

55-
export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
55+
export const separatorObjectExplode = (style: ObjectSeparatorStyle): '.' | ';' | ',' | '&' => {
5656
switch (style) {
5757
case 'label':
5858
return '.';
@@ -73,7 +73,7 @@ export const serializeArrayParam = ({
7373
value,
7474
}: SerializeOptions<ArraySeparatorStyle> & {
7575
value: unknown[];
76-
}) => {
76+
}): string => {
7777
if (!explode) {
7878
const joinedValues = (
7979
allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
@@ -111,7 +111,7 @@ export const serializePrimitiveParam = ({
111111
allowReserved,
112112
name,
113113
value,
114-
}: SerializePrimitiveParam) => {
114+
}: SerializePrimitiveParam): string => {
115115
if (value === undefined || value === null) {
116116
return '';
117117
}
@@ -135,7 +135,7 @@ export const serializeObjectParam = ({
135135
}: SerializeOptions<ObjectSeparatorStyle> & {
136136
value: Record<string, unknown> | Date;
137137
valueOnly?: boolean;
138-
}) => {
138+
}): string => {
139139
if (value instanceof Date) {
140140
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
141141
}

app/client/api-client/core/queryKeySerializer.gen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type JsonValue =
1515
/**
1616
* Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes.
1717
*/
18-
export const queryKeyJsonReplacer = (_key: string, value: unknown) => {
18+
export const queryKeyJsonReplacer = (_key: string, value: unknown): unknown | undefined => {
1919
if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
2020
return undefined;
2121
}

app/client/api-client/core/types.gen.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ export interface Config {
9292
responseValidator?: (data: unknown) => Promise<unknown>;
9393
}
9494

95+
/**
96+
* Arbitrary metadata passed through the `meta` request option.
97+
*/
98+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
99+
export interface ClientMeta {}
100+
95101
type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
96102
? true
97103
: [T] extends [never | undefined]

app/client/api-client/core/utils.gen.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ export interface PathSerializer {
1414
url: string;
1515
}
1616

17-
export const PATH_PARAM_RE = /\{[^{}]+\}/g;
17+
export const PATH_PARAM_RE: RegExp = /\{[^{}]+\}/g;
1818

19-
export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
19+
export const defaultPathSerializer = ({ path, url: _url }: PathSerializer): string => {
2020
let url = _url;
2121
const matches = _url.match(PATH_PARAM_RE);
2222
if (matches) {
@@ -95,7 +95,7 @@ export const getUrl = ({
9595
query?: Record<string, unknown>;
9696
querySerializer: QuerySerializer;
9797
url: string;
98-
}) => {
98+
}): string => {
9999
const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
100100
let url = (baseUrl ?? '') + pathUrl;
101101
if (path) {
@@ -115,7 +115,7 @@ export function getValidRequestBody(options: {
115115
body?: unknown;
116116
bodySerializer?: BodySerializer | null;
117117
serializedBody?: unknown;
118-
}) {
118+
}): unknown {
119119
const hasBody = options.body !== undefined;
120120
const isSerializedBody = hasBody && options.bodySerializer;
121121

app/client/api-client/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export {
4141
getScheduleMirrors,
4242
getScheduleNotifications,
4343
getSnapshotDetails,
44+
getSnapshotRestorePlan,
4445
getSsoSettings,
4546
getStatus,
4647
getSystemInfo,
@@ -209,6 +210,9 @@ export type {
209210
GetSnapshotDetailsData,
210211
GetSnapshotDetailsResponse,
211212
GetSnapshotDetailsResponses,
213+
GetSnapshotRestorePlanData,
214+
GetSnapshotRestorePlanResponse,
215+
GetSnapshotRestorePlanResponses,
212216
GetSsoSettingsData,
213217
GetSsoSettingsResponse,
214218
GetSsoSettingsResponses,

0 commit comments

Comments
 (0)