From 25f2273e246d0a0e83b1ca2593d0ff7642d31080 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 12:56:56 +0100 Subject: [PATCH 01/11] chore(deps): update redis:6.2-alpine docker digest to 46884be (#25839) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- e2e/docker-compose.dev.yml | 2 +- e2e/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/docker-compose.dev.yml b/e2e/docker-compose.dev.yml index cd1d3d4982..14e159ed50 100644 --- a/e2e/docker-compose.dev.yml +++ b/e2e/docker-compose.dev.yml @@ -70,7 +70,7 @@ services: restart: unless-stopped redis: - image: redis:6.2-alpine@sha256:37e002448575b32a599109664107e374c8709546905c372a34d64919043b9ceb + image: redis:6.2-alpine@sha256:46884be93652d02a96a176ccf173d1040bef365c5706aa7b6a1931caec8bfeef database: image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:6f3e9d2c2177af16c2988ff71425d79d89ca630ec2f9c8db03209ab716542338 diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index a33cb6573c..a98a7013a4 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -42,7 +42,7 @@ services: - 2285:2285 redis: - image: redis:6.2-alpine@sha256:37e002448575b32a599109664107e374c8709546905c372a34d64919043b9ceb + image: redis:6.2-alpine@sha256:46884be93652d02a96a176ccf173d1040bef365c5706aa7b6a1931caec8bfeef database: image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:6f3e9d2c2177af16c2988ff71425d79d89ca630ec2f9c8db03209ab716542338 From 23445fdcc113cb33f8246791c3f315163469b39b Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 3 Feb 2026 09:28:29 -0600 Subject: [PATCH 02/11] fix: upload progress bar flickering (#25829) * fix: upload progress bar flickering * pr feedback and more logs --- .../lib/providers/backup/drift_backup.provider.dart | 13 +++++++++---- mobile/lib/services/background_upload.service.dart | 4 ++++ mobile/pubspec.lock | 8 ++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/mobile/lib/providers/backup/drift_backup.provider.dart b/mobile/lib/providers/backup/drift_backup.provider.dart index 2f067fdf67..624c21f158 100644 --- a/mobile/lib/providers/backup/drift_backup.provider.dart +++ b/mobile/lib/providers/backup/drift_backup.provider.dart @@ -259,6 +259,11 @@ class DriftBackupNotifier extends StateNotifier { } Future startForegroundBackup(String userId) async { + // Cancel any existing backup before starting a new one + if (state.cancelToken != null) { + await stopForegroundBackup(); + } + state = state.copyWith(error: BackupError.none); final cancelToken = CancellationToken(); @@ -375,21 +380,21 @@ class DriftBackupNotifier extends StateNotifier { _logger.warning("Skip handleBackupResume (pre-call): notifier disposed"); return; } - _logger.info("Resuming backup tasks..."); + _logger.info("Start background backup sequence"); state = state.copyWith(error: BackupError.none); final tasks = await _backgroundUploadService.getActiveTasks(kBackupGroup); if (!mounted) { _logger.warning("Skip handleBackupResume (post-call): notifier disposed"); return; } - _logger.info("Found ${tasks.length} tasks"); + _logger.info("Found ${tasks.length} pending tasks"); if (tasks.isEmpty) { - _logger.info("Start backup with URLSession"); + _logger.info("No pending tasks, starting new upload"); return _backgroundUploadService.uploadBackupCandidates(userId); } - _logger.info("Tasks to resume: ${tasks.length}"); + _logger.info("Resuming upload ${tasks.length} assets"); return _backgroundUploadService.resume(); } } diff --git a/mobile/lib/services/background_upload.service.dart b/mobile/lib/services/background_upload.service.dart index 4eece142d2..d54a677c24 100644 --- a/mobile/lib/services/background_upload.service.dart +++ b/mobile/lib/services/background_upload.service.dart @@ -164,9 +164,12 @@ class BackgroundUploadService { final candidates = await _backupRepository.getCandidates(userId); if (candidates.isEmpty) { + _logger.info("No new backup candidates found, finishing background upload"); return; } + _logger.info("Found ${candidates.length} backup candidates for background tasks"); + const batchSize = 100; final batch = candidates.take(batchSize).toList(); List tasks = []; @@ -179,6 +182,7 @@ class BackgroundUploadService { } if (tasks.isNotEmpty && !shouldAbortQueuingTasks) { + _logger.info("Enqueuing ${tasks.length} background upload tasks"); await enqueueTasks(tasks); } } diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index d237c02023..c8aa680e07 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -1249,10 +1249,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: @@ -1942,10 +1942,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.7" thumbhash: dependency: "direct main" description: From 8872d2c7aea307a03358aa29b603509dd504dfec Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 3 Feb 2026 10:00:17 -0600 Subject: [PATCH 03/11] chore: remove swift logs (#25857) --- mobile/ios/Runner/Images/LocalImagesImpl.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/mobile/ios/Runner/Images/LocalImagesImpl.swift b/mobile/ios/Runner/Images/LocalImagesImpl.swift index 4f2090443a..3af524f424 100644 --- a/mobile/ios/Runner/Images/LocalImagesImpl.swift +++ b/mobile/ios/Runner/Images/LocalImagesImpl.swift @@ -133,7 +133,6 @@ class LocalImageApiImpl: LocalImageApi { "height": Int64(buffer.height), "rowBytes": Int64(buffer.rowBytes) ])) - print("Successful response for \(requestId)") Self.remove(requestId: requestId) } catch { Self.remove(requestId: requestId) From 94965f6d66638a6aefa706761dc796540555830e Mon Sep 17 00:00:00 2001 From: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:06:26 +0100 Subject: [PATCH 04/11] chore: rework tags sidebar (#25855) --- .../asset-viewer/asset-viewer.svelte | 5 ++ .../asset-viewer/detail-panel-tags.svelte | 66 ++++++++----------- .../timeline/actions/TagAction.svelte | 7 +- web/src/lib/managers/event-manager.svelte.ts | 1 + web/src/lib/modals/AssetTagModal.svelte | 7 +- web/src/lib/services/asset.service.ts | 15 ++++- 6 files changed, 54 insertions(+), 47 deletions(-) diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 6284e207c6..06f4e5a0b2 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -14,6 +14,7 @@ import { eventManager } from '$lib/managers/event-manager.svelte'; import { imageManager } from '$lib/managers/ImageManager.svelte'; import { Route } from '$lib/route'; + import { getAssetActions } from '$lib/services/asset.service'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { ocrManager } from '$lib/stores/ocr.svelte'; import { alwaysLoadOriginalVideo } from '$lib/stores/preferences.store'; @@ -36,6 +37,7 @@ type PersonResponseDto, type StackResponseDto, } from '@immich/sdk'; + import { CommandPaletteDefaultProvider } from '@immich/ui'; import { onDestroy, onMount, untrack } from 'svelte'; import { t } from 'svelte-i18n'; import { fly } from 'svelte/transition'; @@ -426,8 +428,11 @@ !assetViewerManager.isShowEditor && ocrManager.hasOcrData, ); + + const { Tag } = $derived(getAssetActions($t, asset)); + diff --git a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte index cd9b1a40d2..09c4432723 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-tags.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-tags.svelte @@ -1,12 +1,13 @@ - + {#if isOwner && !authManager.isSharedLink}
@@ -42,36 +44,24 @@
{#each tags as tag (tag.id)} -
- + -

- {tag.value} -

-
- - -
+ size="tiny" + class="hover:bg-primary-400" + shape="round" + /> + {/each} - +
{/if} diff --git a/web/src/lib/components/timeline/actions/TagAction.svelte b/web/src/lib/components/timeline/actions/TagAction.svelte index d2235d7c74..dfe24b476b 100644 --- a/web/src/lib/components/timeline/actions/TagAction.svelte +++ b/web/src/lib/components/timeline/actions/TagAction.svelte @@ -20,11 +20,8 @@ const handleTagAssets = async () => { const assets = [...getOwnedAssets()]; - const success = await modalManager.show(AssetTagModal, { assetIds: assets.map(({ id }) => id) }); - - if (success) { - clearSelect(); - } + await modalManager.show(AssetTagModal, { assetIds: assets.map(({ id }) => id) }); + clearSelect(); }; diff --git a/web/src/lib/managers/event-manager.svelte.ts b/web/src/lib/managers/event-manager.svelte.ts index 4825dbc93b..4093413d1a 100644 --- a/web/src/lib/managers/event-manager.svelte.ts +++ b/web/src/lib/managers/event-manager.svelte.ts @@ -37,6 +37,7 @@ export type Events = { AssetsArchive: [string[]]; AssetsDelete: [string[]]; AssetEditsApplied: [string]; + AssetsTag: [string[]]; AlbumAddAssets: []; AlbumUpdate: [AlbumResponseDto]; diff --git a/web/src/lib/modals/AssetTagModal.svelte b/web/src/lib/modals/AssetTagModal.svelte index e541e24b60..00862ce1b1 100644 --- a/web/src/lib/modals/AssetTagModal.svelte +++ b/web/src/lib/modals/AssetTagModal.svelte @@ -1,4 +1,5 @@