@futo-org/backups-orchestrator-ui 0.27.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/components/backends/BackendItem.svelte +28 -24
  2. package/dist/components/backends/BackendsList.svelte +33 -34
  3. package/dist/components/backends/BackendsList.svelte.d.ts +1 -0
  4. package/dist/components/backends/dialogs/SelectBackendModal.svelte +44 -55
  5. package/dist/components/backups/BackupItem.svelte +33 -26
  6. package/dist/components/backups/BackupStatus.svelte +200 -0
  7. package/dist/components/backups/BackupStatus.svelte.d.ts +19 -0
  8. package/dist/components/backups/BackupsList.svelte +17 -11
  9. package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +2 -2
  10. package/dist/components/backups/dialogs/SelectRepositoryModal.svelte +26 -36
  11. package/dist/components/backups/dialogs/ViewStatusModal.svelte +175 -0
  12. package/dist/components/backups/dialogs/ViewStatusModal.svelte.d.ts +8 -0
  13. package/dist/components/backups/run-history/RepositoryRunHistory.svelte +23 -12
  14. package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +2 -0
  15. package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +46 -20
  16. package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte +136 -0
  17. package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte.d.ts +8 -0
  18. package/dist/components/backups/run-history/RunHistoryModal.svelte +2 -2
  19. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +22 -10
  20. package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +2 -0
  21. package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +23 -21
  22. package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte +115 -0
  23. package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte.d.ts +9 -0
  24. package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +2 -2
  25. package/dist/components/dashboard/Dashboard.svelte +14 -7
  26. package/dist/components/dashboard/Dashboard.svelte.d.ts +1 -1
  27. package/dist/components/dashboard/DashboardAvgBackupTime.svelte +1 -1
  28. package/dist/components/dashboard/DashboardBackupHealth.svelte +5 -9
  29. package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +1 -1
  30. package/dist/components/dashboard/DashboardCurrentUsage.svelte +1 -1
  31. package/dist/components/dashboard/DashboardDailyBackupTime.svelte +1 -1
  32. package/dist/components/dashboard/DashboardInstall.svelte +1 -1
  33. package/dist/components/dashboard/DashboardRecentBackups.svelte +47 -78
  34. package/dist/components/dashboard/DashboardTotalStored.svelte +1 -1
  35. package/dist/components/integrations/immich/ImmichBackupSettings.svelte +12 -0
  36. package/dist/components/integrations/immich/ImmichBackupSettings.svelte.d.ts +18 -0
  37. package/dist/components/integrations/immich/ImmichBackupsCard.svelte +109 -0
  38. package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +13 -0
  39. package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte +55 -0
  40. package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte.d.ts +10 -0
  41. package/dist/components/integrations/immich/ImmichBackupsPage.svelte +16 -3
  42. package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +8 -1
  43. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +102 -0
  44. package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte.d.ts +8 -0
  45. package/dist/components/integrations/immich/ImmichManageBackup.svelte +53 -14
  46. package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +45 -71
  47. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +123 -82
  48. package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +1 -1
  49. package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte +313 -0
  50. package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte.d.ts +3 -0
  51. package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte +218 -0
  52. package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte.d.ts +3 -0
  53. package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte +207 -0
  54. package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte.d.ts +3 -0
  55. package/dist/components/onboarding/RecoveryKeyDisplay.svelte +34 -20
  56. package/dist/components/onboarding/SampleOnboarding.svelte +57 -38
  57. package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +10 -24
  58. package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte +44 -0
  59. package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte.d.ts +7 -0
  60. package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte +50 -0
  61. package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte.d.ts +7 -0
  62. package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte +45 -0
  63. package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte.d.ts +8 -0
  64. package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte +67 -0
  65. package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte.d.ts +9 -0
  66. package/dist/components/onboarding/steps/OnboardingStepLayout.svelte +58 -0
  67. package/dist/components/onboarding/steps/OnboardingStepLayout.svelte.d.ts +19 -0
  68. package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte +52 -0
  69. package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte.d.ts +18 -0
  70. package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte +33 -0
  71. package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte.d.ts +8 -0
  72. package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte +32 -0
  73. package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +11 -0
  74. package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte +7 -0
  75. package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte.d.ts +18 -0
  76. package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte +46 -0
  77. package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte.d.ts +6 -0
  78. package/dist/components/onboarding/upsell/UpsellModal.svelte +43 -0
  79. package/dist/components/onboarding/upsell/UpsellModal.svelte.d.ts +9 -0
  80. package/dist/components/onboarding/upsell/UpsellPage.svelte +40 -0
  81. package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +14 -0
  82. package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte +58 -0
  83. package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte.d.ts +8 -0
  84. package/dist/components/schedules/RepositoryPicker.svelte +45 -38
  85. package/dist/components/schedules/ScheduleItem.svelte +32 -26
  86. package/dist/components/schedules/ScheduleList.svelte +16 -10
  87. package/dist/components/settings/GlobalSettings.svelte +8 -0
  88. package/dist/components/settings/GlobalSettings.svelte.d.ts +18 -0
  89. package/dist/components/settings/SettingsBackends.svelte +16 -0
  90. package/dist/components/settings/SettingsBackends.svelte.d.ts +18 -0
  91. package/dist/components/settings/SettingsBilling.svelte +69 -0
  92. package/dist/components/settings/SettingsBilling.svelte.d.ts +6 -0
  93. package/dist/components/settings/SettingsNotifications.svelte +47 -0
  94. package/dist/components/settings/SettingsNotifications.svelte.d.ts +6 -0
  95. package/dist/components/test/ImmichTestUi.svelte +143 -27
  96. package/dist/components/test/TestUi.svelte +4 -4
  97. package/dist/components/test/dashboard/ActiveJobs.svelte +2 -2
  98. package/dist/components/test/immich/MockImmichHideBackupsReminder.svelte +12 -0
  99. package/dist/components/test/immich/MockImmichHideBackupsReminder.svelte.d.ts +3 -0
  100. package/dist/components/test/immich/MockImmichPhotos.svelte +36 -0
  101. package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
  102. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
  103. package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
  104. package/dist/components/test/immich/MockImmichServerStatus.svelte +9 -0
  105. package/dist/components/test/immich/MockImmichServerStatus.svelte.d.ts +18 -0
  106. package/dist/components/test/immich/MockImmichSidebar.svelte +20 -0
  107. package/dist/components/test/immich/MockImmichSidebar.svelte.d.ts +7 -0
  108. package/dist/components/test/immich/MockImmichStorageSpace.svelte +25 -0
  109. package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +7 -0
  110. package/dist/components/ui/Accordion.svelte +67 -0
  111. package/dist/components/ui/Accordion.svelte.d.ts +11 -0
  112. package/dist/components/ui/ListToolbar.svelte +60 -0
  113. package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
  114. package/dist/components/ui/PageLayout.svelte +21 -9
  115. package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
  116. package/dist/components/ui/Pagination.svelte +80 -0
  117. package/dist/components/ui/Pagination.svelte.d.ts +8 -0
  118. package/dist/components/ui/PathListField.svelte +17 -14
  119. package/dist/components/ui/StackList.svelte +18 -18
  120. package/dist/components/ui/StackList.svelte.d.ts +6 -27
  121. package/dist/components/ui/StackListItem.svelte +47 -25
  122. package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
  123. package/dist/components/ui/StackListOption.svelte +33 -0
  124. package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
  125. package/dist/components/ui/StackListPlaceholder.svelte +12 -0
  126. package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
  127. package/dist/components/ui/StepNumber.svelte +20 -0
  128. package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
  129. package/dist/components/util/Suspense.svelte +7 -3
  130. package/dist/components/util/YuccaContext.svelte +1 -1
  131. package/dist/events.js +1 -1
  132. package/dist/fetch-client.d.ts +2 -0
  133. package/dist/index.d.ts +6 -1
  134. package/dist/index.js +6 -1
  135. package/dist/services/backend.service.js +3 -0
  136. package/dist/services/immich.integration.service.d.ts +1 -1
  137. package/dist/services/immich.integration.service.js +2 -3
  138. package/dist/services/integrations.service.d.ts +1 -0
  139. package/dist/services/integrations.service.js +2 -1
  140. package/dist/services/log.service.svelte.d.ts +12 -0
  141. package/dist/services/log.service.svelte.js +15 -1
  142. package/dist/services/repository.service.js +9 -3
  143. package/dist/services/runHistory.service.d.ts +1 -1
  144. package/dist/services/runHistory.service.js +5 -4
  145. package/dist/utils/format.d.ts +1 -1
  146. package/dist/utils/format.js +2 -2
  147. package/package.json +3 -3
  148. package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
  149. package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
  150. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
  151. package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
  152. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
  153. package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
  154. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
  155. package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
  156. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
  157. package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
  158. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
  159. package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
  160. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
  161. package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
  162. package/dist/components/util/TimedButton.svelte +0 -37
  163. package/dist/components/util/TimedButton.svelte.d.ts +0 -7
@@ -1,13 +1,12 @@
1
- import ImmichConfigureBackup from '../components/integrations/immich/ImmichConfigureBackup.svelte';
2
1
  import BackupsRecoveryKeyModal from '../components/onboarding/dialogs/BackupsRecoveryKeyModal.svelte';
3
2
  import { modalManager } from '@immich/ui';
4
3
  import { mdiCloudUploadOutline, mdiCogOutline, mdiKeyOutline } from '@mdi/js';
5
4
  import { handleCreateBackup } from './repository.service';
6
- export const getBackupPageActions = (repositoryId) => {
5
+ export const getBackupPageActions = (repositoryId, onConfigure) => {
7
6
  const Configure = {
8
7
  title: 'Configure',
9
8
  icon: mdiCogOutline,
10
- onAction: () => modalManager.show(ImmichConfigureBackup, {}),
9
+ onAction: onConfigure,
11
10
  };
12
11
  const ViewRecoveryKey = {
13
12
  title: 'View recovery key',
@@ -1,5 +1,6 @@
1
1
  import { SocketEvent } from '../events';
2
2
  import { type ConfigureImmichIntegrationRequestDto, type IntegrationsResponseDto } from '../fetch-client';
3
+ export declare const IMMICH_DEFAULT_CRON = "0 3 * * *";
3
4
  export declare const integrationsKeys: {
4
5
  all: readonly ["integrations"];
5
6
  };
@@ -3,6 +3,7 @@ import { configureImmichIntegration, getIntegrations, } from '../fetch-client';
3
3
  import { queryClient } from '../query-client';
4
4
  import { handleError } from '../utils/handle-error';
5
5
  import { createMutation, createQuery } from '@tanstack/svelte-query';
6
+ export const IMMICH_DEFAULT_CRON = '0 3 * * *';
6
7
  export const integrationsKeys = {
7
8
  all: ['integrations'],
8
9
  };
@@ -28,7 +29,7 @@ export const useConfigureImmichDefaults = () => createMutation(() => ({
28
29
  await configureImmichIntegration({
29
30
  name: 'Immich',
30
31
  worm: false,
31
- cron: '0 3 * * *',
32
+ cron: IMMICH_DEFAULT_CRON,
32
33
  dataFolders: immichState.dataFolders,
33
34
  backupConfiguration: true,
34
35
  libraries: 'all',
@@ -32,6 +32,14 @@ type LogEvent = SummaryEvent | {
32
32
  } | {
33
33
  message_type: 'raw';
34
34
  message: string;
35
+ } | {
36
+ message_type: 'yucca_prune_kept';
37
+ id: string;
38
+ time: string;
39
+ } | {
40
+ message_type: 'yucca_prune_removed';
41
+ id: string;
42
+ time: string;
35
43
  } | {
36
44
  message_type: 'status';
37
45
  percent_done: number;
@@ -50,6 +58,10 @@ export declare function createLogObserver(logId: string): {
50
58
  readonly errors: string[];
51
59
  readonly events: LogEvent[];
52
60
  readonly summary: SummaryEvent | undefined;
61
+ readonly pruned: {
62
+ kept: number;
63
+ removed: number;
64
+ };
53
65
  destroy(): void;
54
66
  };
55
67
  export {};
@@ -18,6 +18,7 @@ export function createLogObserver(logId) {
18
18
  errors: [],
19
19
  events: [],
20
20
  summary: undefined,
21
+ pruned: { kept: 0, removed: 0 },
21
22
  });
22
23
  const buffer = [];
23
24
  const flush = debounce(() => {
@@ -68,13 +69,23 @@ export function createLogObserver(logId) {
68
69
  flush.flush();
69
70
  break;
70
71
  }
72
+ case 'yucca_prune_kept': {
73
+ state.pruned.kept++;
74
+ flush();
75
+ break;
76
+ }
77
+ case 'yucca_prune_removed': {
78
+ state.pruned.removed++;
79
+ flush();
80
+ break;
81
+ }
71
82
  default: {
72
83
  flush();
73
84
  break;
74
85
  }
75
86
  }
76
87
  };
77
- const source = new EventSource(new URL(`/api/yucca/logs/${logId}/stream`, defaults.baseUrl));
88
+ const source = new EventSource(`${defaults.baseUrl}/api/yucca/logs/${logId}/stream`);
78
89
  source.addEventListener('message', ({ data }) => onEvent(JSON.parse(data)));
79
90
  return {
80
91
  get status() {
@@ -89,6 +100,9 @@ export function createLogObserver(logId) {
89
100
  get summary() {
90
101
  return state.summary;
91
102
  },
103
+ get pruned() {
104
+ return state.pruned;
105
+ },
92
106
  destroy() {
93
107
  flush.cancel();
94
108
  source.close();
@@ -1,7 +1,7 @@
1
1
  import { sdk } from '..';
2
2
  import ConfigureRepositoryModal from '../components/backups/dialogs/ConfigureRepositoryModal.svelte';
3
3
  import ImportRepositoryModal from '../components/backups/dialogs/ImportRepositoryModal.svelte';
4
- import ViewLogModal from '../components/backups/dialogs/ViewLogModal.svelte';
4
+ import ViewStatusModal from '../components/backups/dialogs/ViewStatusModal.svelte';
5
5
  import MetricsHistoryModal from '../components/backups/metrics-history/MetricsHistoryModal.svelte';
6
6
  import RunHistoryModal from '../components/backups/run-history/RunHistoryModal.svelte';
7
7
  import SnapshotsListModal from '../components/backups/snapshots-list/SnapshotsListModal.svelte';
@@ -84,7 +84,10 @@ export const handleCreateBackup = async (id) => {
84
84
  try {
85
85
  toastManager.info('Started backup');
86
86
  const response = await sdk.createBackup(id);
87
- void modalManager.open(ViewLogModal, { logId: response.logId });
87
+ void modalManager.open(ViewStatusModal, {
88
+ logId: response.logId,
89
+ onRetry: () => void handleCreateBackup(id),
90
+ });
88
91
  return response;
89
92
  }
90
93
  catch (error) {
@@ -96,7 +99,10 @@ export const handlePruneRepository = async (id) => {
96
99
  try {
97
100
  toastManager.info('Cleaning up old backups');
98
101
  const response = await sdk.pruneRepository(id);
99
- void modalManager.open(ViewLogModal, { logId: response.logId });
102
+ void modalManager.open(ViewStatusModal, {
103
+ logId: response.logId,
104
+ onRetry: () => void handlePruneRepository(id),
105
+ });
100
106
  return response;
101
107
  }
102
108
  catch (error) {
@@ -8,7 +8,7 @@ export declare const runHistoryKeys: {
8
8
  export declare const runKeys: {
9
9
  byId: (id: string) => readonly ["run", string];
10
10
  };
11
- export declare const useRunHistory: (repositoryId: string) => import("@tanstack/svelte-query").CreateQueryResult<sdk.RunDto[], Error>;
11
+ export declare const useRunHistory: (repositoryId: () => string | undefined) => import("@tanstack/svelte-query").CreateQueryResult<sdk.RunDto[], Error>;
12
12
  export declare const useRun: (logId: string) => import("@tanstack/svelte-query").CreateQueryResult<sdk.RunDto, Error>;
13
13
  export declare const useRunEventHandler: () => {
14
14
  onRunCreate(event: SocketEvent<{
@@ -1,5 +1,5 @@
1
1
  import { sdk } from '..';
2
- import ViewLogModal from '../components/backups/dialogs/ViewLogModal.svelte';
2
+ import ViewStatusModal from '../components/backups/dialogs/ViewStatusModal.svelte';
3
3
  import { SocketEvent } from '../events';
4
4
  import { getRun, getRunHistory } from '../fetch-client';
5
5
  import { queryClient } from '../query-client';
@@ -13,8 +13,9 @@ export const runKeys = {
13
13
  byId: (id) => ['run', id],
14
14
  };
15
15
  export const useRunHistory = (repositoryId) => createQuery(() => ({
16
- queryKey: runHistoryKeys.byRepository(repositoryId),
17
- queryFn: () => getRunHistory(repositoryId).then(({ runs }) => runs.toSorted((a, b) => b.start.localeCompare(a.start))),
16
+ queryKey: runHistoryKeys.byRepository(repositoryId() ?? ''),
17
+ queryFn: () => getRunHistory(repositoryId()).then(({ runs }) => runs.toSorted((a, b) => b.start.localeCompare(a.start))),
18
+ enabled: repositoryId() !== undefined,
18
19
  }), () => queryClient);
19
20
  export const useRun = (logId) => createQuery(() => ({
20
21
  queryKey: runKeys.byId(logId),
@@ -48,7 +49,7 @@ export const handleGetRunHistory = async (id) => {
48
49
  export const getRunActions = (run) => {
49
50
  const ViewLog = {
50
51
  title: 'View Log',
51
- onAction: () => void modalManager.open(ViewLogModal, { logId: run.id }),
52
+ onAction: () => void modalManager.open(ViewStatusModal, { logId: run.id }),
52
53
  };
53
54
  return { ViewLog };
54
55
  };
@@ -1,2 +1,2 @@
1
- export declare const formatDuration: (ms: number) => string;
1
+ export declare const formatDuration: (ms: number, unitDisplay?: "narrow" | "long") => string;
2
2
  export declare const humanizeBackupPath: (path: string) => string;
@@ -1,11 +1,11 @@
1
1
  import { Duration } from 'luxon';
2
- export const formatDuration = (ms) => {
2
+ export const formatDuration = (ms, unitDisplay = 'narrow') => {
3
3
  const seconds = Math.round(ms / 1000);
4
4
  return seconds < 1
5
5
  ? '<1s'
6
6
  : Duration.fromMillis(seconds * 1000)
7
7
  .rescale()
8
- .toHuman({ unitDisplay: 'narrow' });
8
+ .toHuman({ unitDisplay });
9
9
  };
10
10
  const IMMICH_FOLDER_LABELS = {
11
11
  upload: 'Photos and videos',
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@futo-org/backups-orchestrator-ui",
3
3
  "repository": "https://github.com/immich-app/yucca",
4
4
  "description": "Backups orchestrator (UI library)",
5
- "version": "0.27.0",
5
+ "version": "0.30.0",
6
6
  "license": "Source First License 1.1",
7
7
  "files": [
8
8
  "dist",
@@ -55,7 +55,7 @@
55
55
  "svelte"
56
56
  ],
57
57
  "dependencies": {
58
- "@immich/ui": "^0.59.0",
58
+ "@immich/ui": "^0.85.0",
59
59
  "@mdi/js": "^7.4.47",
60
60
  "@oazapfts/runtime": "^1.1.0",
61
61
  "@tanstack/svelte-query": "^6.1.3",
@@ -64,7 +64,7 @@
64
64
  "lodash.debounce": "^4.0.8",
65
65
  "luxon": "^3.7.2",
66
66
  "socket.io-client": "^4.8.3",
67
- "@futo-org/backups-api-client": "^0.27.0"
67
+ "@futo-org/backups-api-client": "^0.30.0"
68
68
  },
69
69
  "scripts": {
70
70
  "dev": "vite dev --port 5174",
@@ -1,208 +0,0 @@
1
- <script lang="ts">
2
- import OnEvents from "../../util/OnEvents.svelte";
3
- import RelativeTime from "../../util/RelativeTime.svelte";
4
- import { options } from "../../../options";
5
- import { createLogObserver } from "../../../services/log.service.svelte";
6
- import { useRun, useRunEventHandler } from "../../../services/runHistory.service";
7
- import { formatDuration } from "../../../utils/format";
8
- import {
9
- Alert,
10
- FormatBytes,
11
- Heading,
12
- Modal,
13
- ModalBody,
14
- ProgressBar,
15
- Scrollable,
16
- Stack,
17
- Text,
18
- } from "@immich/ui";
19
- import { DateTime } from "luxon";
20
- import { onDestroy } from "svelte";
21
-
22
- type Props = {
23
- logId: string;
24
- onClose: () => void;
25
- };
26
-
27
- let { logId, onClose }: Props = $props();
28
-
29
- const advanced = options.advanced;
30
- // svelte-ignore state_referenced_locally
31
- const log = createLogObserver(logId);
32
- // svelte-ignore state_referenced_locally
33
- const runQuery = useRun(logId);
34
- const run = $derived(runQuery.data);
35
- const { onRunUpdate } = useRunEventHandler();
36
-
37
- let now = $state(DateTime.now());
38
- const tick = setInterval(() => (now = DateTime.now()), 1000);
39
-
40
- onDestroy(() => {
41
- clearInterval(tick);
42
- log.destroy();
43
- });
44
-
45
- const running = $derived(run?.status === "incomplete");
46
- const duration = $derived(
47
- run
48
- ? formatDuration(
49
- (run.end ? DateTime.fromISO(run.end) : now).toMillis() -
50
- DateTime.fromISO(run.start).toMillis(),
51
- )
52
- : "",
53
- );
54
- </script>
55
-
56
- <OnEvents {onRunUpdate} />
57
-
58
- <Modal
59
- title={run?.type === "restore"
60
- ? "Restore Log"
61
- : run?.type === "forget"
62
- ? "Prune Log"
63
- : "Backup Log"}
64
- size="giant"
65
- {onClose}
66
- >
67
- <ModalBody>
68
- <Stack gap={5}>
69
- <Stack gap={1}>
70
- {#if !run}
71
- <Heading size="medium">Connecting…</Heading>
72
- {:else if run.status === "incomplete"}
73
- <Heading size="medium">
74
- {#if run.type === "restore"}Restoring{:else if run.type === "forget"}Pruning{:else}Backing
75
- up{/if} &middot; {Math.round(log.status.progress * 100)}%
76
- </Heading>
77
- {:else if run.status === "failed"}
78
- <Heading size="medium" color="danger">
79
- {#if run.type === "restore"}Restore{:else if run.type === "forget"}Prune{:else}Backup{/if}
80
- failed after {duration}
81
- </Heading>
82
- {:else if log.errors.length > 0}
83
- <Heading size="medium" color="warning">
84
- {#if run.type === "restore"}Restored{:else if run.type === "forget"}Pruned{:else}Backed
85
- up{/if} in {duration} &middot; {log.errors.length} error{log
86
- .errors.length === 1
87
- ? ""
88
- : "s"}
89
- </Heading>
90
- {:else}
91
- <Heading size="medium" color="success">
92
- {#if run.type === "restore"}Restored{:else if run.type === "forget"}Pruned{:else}Backed
93
- up{/if} in {duration}
94
- </Heading>
95
- {/if}
96
-
97
- {#if run}
98
- <Text color="secondary">
99
- Started <RelativeTime time={run.start} />
100
- </Text>
101
- {/if}
102
- </Stack>
103
-
104
- {#if running}
105
- <ProgressBar progress={log.status.progress} size="large">
106
- {#if log.status.text}
107
- <Text
108
- size="small"
109
- class={log.status.progress > 0.5 ? "text-light" : "text-dark"}
110
- >
111
- {log.status.text}
112
- </Text>
113
- {/if}
114
- </ProgressBar>
115
- {/if}
116
-
117
- {#if log.errors.length > 0}
118
- <Stack gap={2}>
119
- <Alert color="danger">{log.errors[0]}</Alert>
120
- {#if log.errors.length > 1}
121
- <Scrollable class="max-h-32">
122
- <Stack gap={1}>
123
- {#each log.errors.slice(1) as error}
124
- <Alert color="danger">{error}</Alert>
125
- {/each}
126
- </Stack>
127
- </Scrollable>
128
- {/if}
129
- </Stack>
130
- {/if}
131
-
132
- {#if log.summary && run?.type !== "forget"}
133
- <Stack gap={1}>
134
- {#if run?.type === "restore"}
135
- <Text>
136
- {(log.summary.files_restored ?? 0).toLocaleString()} restored
137
- {#if log.summary.files_skipped}
138
- &middot; {log.summary.files_skipped.toLocaleString()} skipped
139
- {/if}
140
- {#if log.summary.files_deleted}
141
- &middot; {log.summary.files_deleted.toLocaleString()} deleted
142
- {/if}
143
- </Text>
144
- {#if log.summary.bytes_restored !== undefined}
145
- <Text color="secondary">
146
- Restored <FormatBytes bytes={log.summary.bytes_restored} />
147
- {#if log.summary.total_bytes !== undefined}
148
- of
149
- <FormatBytes
150
- bytes={Math.max(
151
- log.summary.bytes_restored,
152
- log.summary.total_bytes,
153
- )}
154
- />
155
- {/if}
156
- </Text>
157
- {/if}
158
- {:else}
159
- <Text>
160
- {(log.summary.files_new ?? 0).toLocaleString()} new &middot;
161
- {(log.summary.files_changed ?? 0).toLocaleString()} changed &middot;
162
- {(log.summary.files_unmodified ?? 0).toLocaleString()} unchanged
163
- </Text>
164
- {#if log.summary.data_added !== undefined}
165
- <Text color="secondary">
166
- Added <FormatBytes bytes={log.summary.data_added} />
167
- {#if log.summary.total_bytes_processed !== undefined}
168
- of
169
- <FormatBytes
170
- bytes={Math.max(
171
- log.summary.data_added,
172
- log.summary.total_bytes_processed,
173
- )}
174
- /> processed
175
- {/if}
176
- </Text>
177
- {/if}
178
- {/if}
179
- </Stack>
180
- {/if}
181
-
182
- {#if running}
183
- <Stack gap={1} class="h-20 overflow-hidden">
184
- {#each log.status.currentFiles.slice(0, 3) as file}
185
- <Text size="small" color="secondary" class="truncate" title={file}>
186
- {file}
187
- </Text>
188
- {/each}
189
- </Stack>
190
- {/if}
191
-
192
- {#if $advanced}
193
- <Stack gap={1}>
194
- <Heading size="small">Event Log</Heading>
195
- <Scrollable class="h-80 overflow-x-hidden">
196
- <Stack gap={1}>
197
- {#each log.events as event}
198
- <Text size="tiny" class="font-mono select-all">
199
- {JSON.stringify(event)}
200
- </Text>
201
- {/each}
202
- </Stack>
203
- </Scrollable>
204
- </Stack>
205
- {/if}
206
- </Stack>
207
- </ModalBody>
208
- </Modal>
@@ -1,7 +0,0 @@
1
- type Props = {
2
- logId: string;
3
- onClose: () => void;
4
- };
5
- declare const ViewLogModal: import("svelte").Component<Props, {}, "">;
6
- type ViewLogModal = ReturnType<typeof ViewLogModal>;
7
- export default ViewLogModal;