feat: ui redesign (pt. 1)

This commit is contained in:
izzy 2026-08-06 13:58:02 +01:00
parent a8c1c0cc5a
commit f5745b474a
No known key found for this signature in database
13 changed files with 144 additions and 190 deletions

View file

@ -26,7 +26,7 @@
"devDependencies": {
"@eslint/js": "^10.0.0",
"@faker-js/faker": "^10.1.0",
"@futo-org/backups-orchestrator-ui": "0.22.1",
"@futo-org/backups-orchestrator-ui": "0.28.0",
"@immich/cli": "workspace:*",
"@immich/e2e-auth-server": "workspace:*",
"@immich/sdk": "workspace:*",

View file

@ -60,7 +60,7 @@ test.describe('Yucca Backups', () => {
test.setTimeout(30_000);
await utils.setAuthCookies(context, admin.accessToken);
await page.goto('/backups');
await page.goto('/admin/backups');
const dialog = page.getByRole('dialog');
await expect(dialog.filter({ hasText: 'Backup options' })).toBeVisible();
@ -81,7 +81,7 @@ test.describe('Yucca Backups', () => {
test.setTimeout(60_000);
await utils.setAuthCookies(context, admin.accessToken);
await page.goto('/backups/repositories');
await page.goto('/admin/backups/repositories');
const backupNow = page.getByRole('button', { name: 'Backup Now' });
await expect(backupNow).toBeVisible();

View file

@ -19608,6 +19608,9 @@
"name": {
"type": "string"
},
"paused": {
"type": "boolean"
},
"retentionPolicy": {
"allOf": [
{
@ -20639,12 +20642,20 @@
"name": {
"type": "string"
},
"siteCode": {
"nullable": true,
"type": "string"
},
"snapshots": {
"items": {
"$ref": "#/components/schemas/SnapshotDto"
},
"type": "array"
},
"storageClusterCode": {
"nullable": true,
"type": "string"
},
"worm": {
"type": "boolean"
}
@ -20653,7 +20664,9 @@
"id",
"metrics",
"name",
"siteCode",
"snapshots",
"storageClusterCode",
"worm"
],
"type": "object"
@ -21001,6 +21014,14 @@
"name": {
"type": "string"
},
"siteCode": {
"nullable": true,
"type": "string"
},
"storageClusterCode": {
"nullable": true,
"type": "string"
},
"worm": {
"type": "boolean"
}
@ -21009,6 +21030,8 @@
"id",
"metrics",
"name",
"siteCode",
"storageClusterCode",
"worm"
],
"type": "object"
@ -23798,6 +23821,10 @@
},
"type": "array"
},
"site": {
"description": "Internal site code from environment metadata",
"type": "string"
},
"worm": {
"type": "boolean"
}
@ -23943,6 +23970,9 @@
],
"nullable": true,
"type": "object"
},
"worm": {
"type": "boolean"
}
},
"type": "object"

174
pnpm-lock.yaml generated
View file

@ -112,8 +112,8 @@ importers:
specifier: ^10.1.0
version: 10.5.0
'@futo-org/backups-orchestrator-ui':
specifier: 0.22.1
version: 0.22.1(svelte@5.56.5(@typescript-eslint/types@8.64.0))
specifier: 0.28.0
version: 0.28.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@immich/cli':
specifier: workspace:*
version: link:../packages/cli
@ -404,8 +404,8 @@ importers:
specifier: 2.0.0-rc13
version: 2.0.0-rc13
'@futo-org/backups-orchestrator-api':
specifier: 0.22.1
version: 0.22.1(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@nestjs/platform-socket.io@11.1.28)(@nestjs/schedule@6.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28))(@nestjs/websockets@11.1.28)(reflect-metadata@0.2.2)
specifier: 0.28.0
version: 0.28.0(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@nestjs/platform-socket.io@11.1.28)(@nestjs/schedule@6.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28))(@nestjs/swagger@11.4.5(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@typescript/typescript6@6.0.2)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2))(@nestjs/websockets@11.1.28)(reflect-metadata@0.2.2)
'@immich/plugin-sdk':
specifier: workspace:*
version: link:../packages/plugin-sdk
@ -787,7 +787,7 @@ importers:
version: 1.5.9(@swc/core@1.15.43(@swc/helpers@0.5.23))(rollup@4.62.0)
vite-tsconfig-paths:
specifier: ^6.0.0
version: 6.1.1(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@1.21.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
version: 6.1.1(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
vitest:
specifier: ^3.0.0
version: 3.2.7(@types/debug@4.1.13)(@types/node@24.13.3)(happy-dom@20.10.6)(jiti@1.21.7)(jsdom@26.1.0(canvas@3.2.3))(lightningcss@1.33.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
@ -798,8 +798,8 @@ importers:
specifier: ^3.0.0
version: 3.5.15
'@futo-org/backups-orchestrator-ui':
specifier: 0.22.1
version: 0.22.1(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
specifier: 0.28.0
version: 0.28.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@immich/justified-layout-wasm':
specifier: ^0.4.3
version: 0.4.3
@ -807,8 +807,8 @@ importers:
specifier: workspace:*
version: link:../packages/sdk
'@immich/ui':
specifier: ^0.83.0
version: 0.83.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
specifier: ^0.85.0
version: 0.85.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@mapbox/mapbox-gl-rtl-text':
specifier: 0.4.0
version: 0.4.0
@ -2907,20 +2907,21 @@ packages:
resolution: {integrity: sha512-YTVITFGN0/24PxzXrwqCgnyd7njDuzp5ZvaCx5nq/jg55kUYd94Nj8UTchBdBofi/L0nwRfjGOg0E41d2u9T1w==}
engines: {node: '>=6'}
'@futo-org/backups-api-client@0.22.1':
resolution: {integrity: sha512-8w1kLyV2gPADGMjrpLvK1IIo7SQLz0TQZ/KoGojnT3Txzj7Im2CPlKsjXM/f9CrYo2czFIy2iWImq/Yi0iOyGw==}
'@futo-org/backups-api-client@0.28.0':
resolution: {integrity: sha512-YWu1LJpYa3cmJTXnEN8GuVbPTyEKjP1x2QMyYvpMwG+X0Mje2t4mlTwXUOhnBo3tp7PN/GG4v6lBxOTGohGllA==}
'@futo-org/backups-orchestrator-api@0.22.1':
resolution: {integrity: sha512-+/3z+uUkx8oQMHv4PlRWiAWhp33YExJjhQeVEVYgwb5kkltJMIEcXamckWxr7r/t5eRCXqbvGvqr67Bu7XD78w==}
'@futo-org/backups-orchestrator-api@0.28.0':
resolution: {integrity: sha512-Zrk7LtOBDVauLX2kBGnVc+2+tC2cT4Rh6psiiM/evZJXYlMF3NUljIGWPKCLPmkTYctl5zYVRZ43LLRVWryDNQ==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
'@nestjs/platform-socket.io': ^11.0.0
'@nestjs/schedule': ^6.0.0
'@nestjs/swagger': ^11.0.0
'@nestjs/websockets': ^11.0.0
'@futo-org/backups-orchestrator-ui@0.22.1':
resolution: {integrity: sha512-8wmjcVSQBKzKT/64sVu2Ih6ro34px+hLCuGZSArewCRolbguSfKsY6m8rAqcBnhCYmVoE6G0zxqLPHWLZqV91w==}
'@futo-org/backups-orchestrator-ui@0.28.0':
resolution: {integrity: sha512-f1ZvypMrbo84oXSsQ39G+bbYbhs4VIMXRQJVztvq7eXESwPGk5GA3DNArhhssDQe1uxnmeWRuE+T9iInSGBW1g==}
peerDependencies:
svelte: ^5.0.0
@ -3140,18 +3141,8 @@ packages:
resolution: {integrity: sha512-O1SJ+BbeFVsUTF4af1MfagJZM+lPgLjI8lQ3SZNjpo8SGJReSbUl2ii03OKuGni/G0yp2GnRLpOTNSHYGtVrcg==}
hasBin: true
'@immich/svelte-markdown-preprocess@0.1.0':
resolution: {integrity: sha512-jgSOJEGLPKEXQCNRI4r4YUayeM2b0ZYLdzgKGl891jZBhOQIetlY7rU44kPpV1AA3/8wGDwNFKduIQZZ/qJYzg==}
peerDependencies:
svelte: ^5.0.0
'@immich/ui@0.59.0':
resolution: {integrity: sha512-7yxvyhhd99T0AHhjMakp7c/U4n0jGAmRO5xpncsRASRvqZve/LAibjr6N5FJc5IAd222DROTMLn6imsxVfqfvg==}
peerDependencies:
svelte: ^5.0.0
'@immich/ui@0.83.0':
resolution: {integrity: sha512-Xh3R3yhn8/Qyq8lGWIiVmturA+dHXtmW/h++AGb2UAwS/58qu7ssocO/HWIamaSpkgjPGotlWpPIpUJq1zh9FQ==}
'@immich/ui@0.85.0':
resolution: {integrity: sha512-KCAEtVGexZ1G+nuT25bv1QS6Rc2wOlLymp4qDBZVqMxu3o3RWpUzafRHvZt5g4FnlAgfHZdXAIHVVrhJzkrlDA==}
peerDependencies:
'@sveltejs/kit': ^2.13.0
svelte: ^5.0.0
@ -6872,6 +6863,7 @@ packages:
cron-parser@4.9.0:
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
engines: {node: '>=12.0.0'}
deprecated: v4 is no longer maintained, upgrade to v5
cron-validate@1.5.3:
resolution: {integrity: sha512-jcu8g/3wZL8OBr4MkEcbeIdLpM8pp5Y6UoOlRktcJG3WjgpifijR0s26Yac7ywR0gC2ABtevOsz5mlD3l3gzwA==}
@ -8108,6 +8100,10 @@ packages:
resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==}
engines: {node: '>=18'}
fuse.js@7.5.0:
resolution: {integrity: sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==}
engines: {node: '>=10'}
gauge@3.0.2:
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
engines: {node: '>=10'}
@ -15974,19 +15970,20 @@ snapshots:
dependencies:
'@fortawesome/fontawesome-common-types': 7.2.0
'@futo-org/backups-api-client@0.22.1':
'@futo-org/backups-api-client@0.28.0':
dependencies:
'@oazapfts/runtime': 1.2.0
'@futo-org/backups-orchestrator-api@0.22.1(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@nestjs/platform-socket.io@11.1.28)(@nestjs/schedule@6.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28))(@nestjs/websockets@11.1.28)(reflect-metadata@0.2.2)':
'@futo-org/backups-orchestrator-api@0.28.0(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@nestjs/platform-socket.io@11.1.28)(@nestjs/schedule@6.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28))(@nestjs/swagger@11.4.5(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@typescript/typescript6@6.0.2)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2))(@nestjs/websockets@11.1.28)(reflect-metadata@0.2.2)':
dependencies:
'@futo-org/backups-api-client': 0.22.1
'@futo-org/backups-api-client': 0.28.0
'@futo-org/restic-wrapper': 1.3.1
'@nestjs/common': 11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.28(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.28)(@nestjs/websockets@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/event-emitter': 3.1.0(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)
'@nestjs/platform-socket.io': 11.1.28(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.28)(rxjs@7.8.2)
'@nestjs/schedule': 6.1.3(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)
'@nestjs/swagger': 11.4.5(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@typescript/typescript6@6.0.2)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)
'@nestjs/websockets': 11.1.28(@nestjs/common@11.1.28(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.28)(@nestjs/platform-socket.io@11.1.28)(reflect-metadata@0.2.2)(rxjs@7.8.2)
better-sqlite3: 12.9.0
class-validator: 0.14.4
@ -16001,35 +15998,17 @@ snapshots:
rxjs: 7.8.2
socket.io: 4.8.3
tail: 2.2.6
zod: 4.3.6
transitivePeerDependencies:
- bufferutil
- reflect-metadata
- supports-color
- utf-8-validate
'@futo-org/backups-orchestrator-ui@0.22.1(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
'@futo-org/backups-orchestrator-ui@0.28.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
'@futo-org/backups-api-client': 0.22.1
'@immich/ui': 0.59.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@mdi/js': 7.4.47
'@oazapfts/runtime': 1.2.0
'@tanstack/svelte-query': 6.1.28(svelte@5.56.5(@typescript-eslint/types@8.64.0))
cron-validate: 1.5.3
cronstrue: 3.14.0
lodash.debounce: 4.0.8
luxon: 3.7.2
socket.io-client: 4.8.3
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
transitivePeerDependencies:
- '@sveltejs/kit'
- bufferutil
- supports-color
- utf-8-validate
'@futo-org/backups-orchestrator-ui@0.22.1(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
'@futo-org/backups-api-client': 0.22.1
'@immich/ui': 0.59.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@futo-org/backups-api-client': 0.28.0
'@immich/ui': 0.85.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@mdi/js': 7.4.47
'@oazapfts/runtime': 1.2.0
'@tanstack/svelte-query': 6.1.28(svelte@5.56.5(@typescript-eslint/types@8.64.0))
@ -16211,48 +16190,13 @@ snapshots:
pg-connection-string: 2.14.0
postgres: 3.4.9
'@immich/svelte-markdown-preprocess@0.1.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
'@immich/ui@0.59.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
'@immich/svelte-markdown-preprocess': 0.1.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@internationalized/date': 3.12.2
'@mdi/js': 7.4.47
bits-ui: 2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
luxon: 3.7.2
simple-icons: 16.26.0
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
svelte-highlight: 7.11.0
tailwind-merge: 3.6.0
tailwind-variants: 3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.2)
tailwindcss: 4.3.2
transitivePeerDependencies:
- '@sveltejs/kit'
'@immich/ui@0.59.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
'@immich/svelte-markdown-preprocess': 0.1.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))
'@internationalized/date': 3.12.2
'@mdi/js': 7.4.47
bits-ui: 2.18.1(@internationalized/date@3.12.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))
luxon: 3.7.2
simple-icons: 16.26.0
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
svelte-highlight: 7.11.0
tailwind-merge: 3.6.0
tailwind-variants: 3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.2)
tailwindcss: 4.3.2
transitivePeerDependencies:
- '@sveltejs/kit'
'@immich/ui@0.83.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
'@immich/ui@0.85.0(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))':
dependencies:
'@internationalized/date': 3.12.2
'@mdi/js': 7.4.47
'@sveltejs/kit': 2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
bits-ui: 2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(svelte@5.56.5(@typescript-eslint/types@8.64.0))
fuse.js: 7.5.0
luxon: 3.7.2
simple-icons: 16.26.0
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
@ -19569,19 +19513,6 @@ snapshots:
transitivePeerDependencies:
- '@sveltejs/kit'
bits-ui@2.18.1(@internationalized/date@3.12.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0)):
dependencies:
'@floating-ui/core': 1.7.5
'@floating-ui/dom': 1.7.6
'@internationalized/date': 3.12.2
esm-env: 1.2.2
runed: 0.35.1(svelte@5.56.5(@typescript-eslint/types@8.64.0))
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
svelte-toolbelt: 0.10.6(svelte@5.56.5(@typescript-eslint/types@8.64.0))
tabbable: 6.5.0
transitivePeerDependencies:
- '@sveltejs/kit'
bl@4.1.0:
dependencies:
buffer: 5.7.1
@ -21744,6 +21675,8 @@ snapshots:
function-timeout@1.0.2: {}
fuse.js@7.5.0: {}
gauge@3.0.2:
dependencies:
aproba: 2.1.0
@ -25569,13 +25502,6 @@ snapshots:
optionalDependencies:
'@sveltejs/kit': 2.69.3(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)))(@typescript/typescript6@6.0.2)(svelte@5.56.5(@typescript-eslint/types@8.64.0))(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
runed@0.35.1(svelte@5.56.5(@typescript-eslint/types@8.64.0)):
dependencies:
dequal: 2.0.3
esm-env: 1.2.2
lz-string: 1.5.0
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
rw@1.3.3: {}
rxjs@7.8.1:
@ -26279,15 +26205,6 @@ snapshots:
transitivePeerDependencies:
- '@sveltejs/kit'
svelte-toolbelt@0.10.6(svelte@5.56.5(@typescript-eslint/types@8.64.0)):
dependencies:
clsx: 2.1.1
runed: 0.35.1(svelte@5.56.5(@typescript-eslint/types@8.64.0))
style-to-object: 1.0.14
svelte: 5.56.5(@typescript-eslint/types@8.64.0)
transitivePeerDependencies:
- '@sveltejs/kit'
svelte@5.56.5(@typescript-eslint/types@8.64.0):
dependencies:
'@jridgewell/remapping': 2.3.5
@ -27058,12 +26975,12 @@ snapshots:
- tsx
- yaml
vite-tsconfig-paths@6.1.1(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@1.21.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)):
vite-tsconfig-paths@6.1.1(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(@typescript/typescript6@6.0.2)
vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@1.21.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
vite: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
transitivePeerDependencies:
- supports-color
- typescript
@ -27086,23 +27003,6 @@ snapshots:
tsx: 4.23.1
yaml: 2.9.0
vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@1.21.7)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0):
dependencies:
lightningcss: 1.33.0
picomatch: 4.0.5
postcss: 8.5.19
rolldown: 1.1.5
tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 24.13.3
esbuild: 0.28.1
fsevents: 2.3.3
jiti: 1.21.7
sass: 1.101.0
terser: 5.49.0
tsx: 4.23.1
yaml: 2.9.0
vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0):
dependencies:
lightningcss: 1.33.0

View file

@ -37,7 +37,7 @@
},
"dependencies": {
"@extism/extism": "2.0.0-rc13",
"@futo-org/backups-orchestrator-api": "0.22.1",
"@futo-org/backups-orchestrator-api": "0.28.0",
"@immich/plugin-sdk": "workspace:*",
"@immich/sql-tools": "^0.5.1",
"@nestjs/bullmq": "^11.0.1",

View file

@ -25,10 +25,10 @@
},
"dependencies": {
"@formatjs/icu-messageformat-parser": "^3.0.0",
"@futo-org/backups-orchestrator-ui": "0.22.1",
"@futo-org/backups-orchestrator-ui": "0.28.0",
"@immich/justified-layout-wasm": "^0.4.3",
"@immich/sdk": "workspace:*",
"@immich/ui": "^0.83.0",
"@immich/ui": "^0.85.0",
"@mapbox/mapbox-gl-rtl-text": "0.4.0",
"@mdi/js": "^7.4.47",
"@noble/hashes": "^2.2.0",

View file

@ -2,16 +2,25 @@
import BreadcrumbActionPage from '$lib/components/BreadcrumbActionPage.svelte';
import NavigationBar from '$lib/components/shared-components/navigation-bar/NavigationBar.svelte';
import BottomInfo from '$lib/components/shared-components/side-bar/BottomInfo.svelte';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { Route } from '$lib/route';
import { sidebarStore } from '$lib/stores/sidebar.svelte';
import type { HeaderButtonActionItem } from '$lib/types';
import { AppShell, AppShellHeader, AppShellSidebar, MenuItemType, NavbarItem, type BreadcrumbItem } from '@immich/ui';
import { mdiAccountMultipleOutline, mdiBookshelf, mdiCog, mdiServer, mdiTrayFull, mdiWrench } from '@mdi/js';
import {
mdiAccountMultipleOutline,
mdiBookshelf,
mdiCloudUploadOutline,
mdiCog,
mdiServer,
mdiTrayFull,
mdiWrench,
} from '@mdi/js';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
type Props = {
breadcrumbs: BreadcrumbItem[];
breadcrumbs?: BreadcrumbItem[];
actions?: Array<HeaderButtonActionItem | MenuItemType>;
children?: Snippet;
};
@ -28,6 +37,9 @@
class="flex h-full flex-col justify-between gap-2 border-none shadow-none"
>
<div class="flex flex-col gap-1 pe-4 pt-8">
{#if featureFlagsManager.value.backups}
<NavbarItem title="Backups" href={Route.backups()} icon={mdiCloudUploadOutline} />
{/if}
<NavbarItem title={$t('users')} href={Route.users()} icon={mdiAccountMultipleOutline} />
<NavbarItem title={$t('external_libraries')} href={Route.libraries()} icon={mdiBookshelf} />
<NavbarItem title={$t('admin.queues')} href={Route.queues()} icon={mdiTrayFull} />
@ -41,7 +53,13 @@
</div>
</AppShellSidebar>
<BreadcrumbActionPage {breadcrumbs} {actions}>
{@render children?.()}
</BreadcrumbActionPage>
{#if breadcrumbs}
<BreadcrumbActionPage {breadcrumbs} {actions}>
{@render children?.()}
</BreadcrumbActionPage>
{:else}
<div class="flex h-full flex-col">
{@render children?.()}
</div>
{/if}
</AppShell>

View file

@ -14,7 +14,6 @@
mdiAccountOutline,
mdiArchiveArrowDown,
mdiArchiveArrowDownOutline,
mdiBackupRestore,
mdiFolderOutline,
mdiHeart,
mdiHeartOutline,
@ -97,10 +96,6 @@
<NavbarItem title={$t('folders')} href={Route.folders()} icon={{ icon: mdiFolderOutline, flipped: true }} />
{/if}
{#if featureFlagsManager.value.backups && authManager.user.isAdmin}
<NavbarItem title="Backups" href={Route.backups()} icon={mdiBackupRestore} />
{/if}
<NavbarItem title={$t('utilities')} href={Route.utilities()} icon={mdiToolboxOutline} activeIcon={mdiToolbox} />
<NavbarItem

View file

@ -149,7 +149,7 @@ export const Route = {
viewWorkflow: ({ id }: { id: string }) => `/workflows/${id}`,
// backups
backups: () => '/backups',
backups: () => '/admin/backups',
// queues
queues: () => '/admin/queues',

View file

@ -1,31 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import {
ImmichBackupsPage,
orchestrationApiProvider,
sdk,
setProvider,
YuccaContext,
} from '@futo-org/backups-orchestrator-ui';
import type { PageData } from './$types';
import UserPageLayout from '$lib/components/layouts/UserPageLayout.svelte';
interface Props {
data: PageData;
}
let { data }: Props = $props();
sdk.defaults.baseUrl = globalThis.location.origin;
setProvider(orchestrationApiProvider);
</script>
<svelte:head>
<title>{data.meta.title}</title>
</svelte:head>
<YuccaContext baseUrl={globalThis.location.origin}>
<UserPageLayout>
<ImmichBackupsPage onExit={() => goto('/')} />
</UserPageLayout>
</YuccaContext>

View file

@ -0,0 +1,42 @@
<script lang="ts">
import {
ImmichBackupsPage,
orchestrationApiProvider,
sdk,
setProvider,
YuccaContext,
} from '@futo-org/backups-orchestrator-ui';
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
sdk.defaults.baseUrl = location.origin;
setProvider(orchestrationApiProvider);
const questions = [
{
title: 'What gets backed up?',
answer: 'TODO',
},
{
title: 'Where is my data stored?',
answer: 'TODO',
},
{
title: 'Can I restore to a new server?',
answer: 'TODO',
},
{
title: 'What happens if I need more storage?',
answer: 'TODO',
},
{
title: 'Can I cancel at any time?',
answer: 'TODO',
},
];
</script>
<YuccaContext baseUrl={location.origin}>
<AdminPageLayout>
<ImmichBackupsPage price="$1" includedStorage="0gb" {questions} />
</AdminPageLayout>
</YuccaContext>

View file

@ -2,7 +2,7 @@ import { authenticate } from '$lib/utils/auth';
import type { PageLoad } from './$types';
export const load = (async ({ url }) => {
await authenticate(url);
await authenticate(url, { admin: true });
return {
meta: {

View file

@ -7,7 +7,7 @@
import { maintenanceStore } from '$lib/stores/maintenance.store';
import { MaintenanceAction } from '@immich/sdk';
import { Button, Heading, Link, ProgressBar, Scrollable, Text } from '@immich/ui';
import { YuccaContext, ViewLogModal } from '@futo-org/backups-orchestrator-ui';
import { YuccaContext, ViewStatusModal } from '@futo-org/backups-orchestrator-ui';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@ -44,7 +44,7 @@
);
</script>
<YuccaContext baseUrl={globalThis.location.origin}>
<YuccaContext baseUrl={location.origin}>
<AuthPageLayout
withHeader={$status?.action === MaintenanceAction.Start || $status?.action === MaintenanceAction.End}
withBackdrop={$status?.action === MaintenanceAction.Start}
@ -72,8 +72,8 @@
<Text>{$t('maintenance_task_rollback')}</Text>
{/if}
{/if}
{:else if $status?.action === MaintenanceAction.Rollback}
<ViewLogModal logId={$status!.yuccaLogId} onClose={() => void 0} />
{:else if $status?.action === MaintenanceAction.Rollback && $status.yuccaLogId}
<ViewStatusModal logId={$status.yuccaLogId} onClose={() => void 0} />
{:else if $status?.action === MaintenanceAction.SelectDatabaseRestore && $auth}
<MaintenanceRestoreFlow {end} expectedVersion={data.expectedVersion} />
{:else}