From 3f1e489074ce666565b44e463d9fc93594d0796d Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sun, 17 May 2026 13:14:19 +0200 Subject: [PATCH 1/3] fix(settings): tag deletion hangs (@fehmer) --- frontend/src/ts/collections/results.ts | 52 ++++++++++++++++---------- frontend/src/ts/modals/edit-tag.ts | 2 +- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/frontend/src/ts/collections/results.ts b/frontend/src/ts/collections/results.ts index e3841319f411..803fb0910133 100644 --- a/frontend/src/ts/collections/results.ts +++ b/frontend/src/ts/collections/results.ts @@ -24,16 +24,16 @@ import { queryOptions } from "@tanstack/solid-query"; import { Accessor } from "solid-js"; import Ape from "../ape"; import { SnapshotResult } from "../constants/default-snapshot"; +import { createEffectOn } from "../hooks/effects"; import { queryClient } from "../queries"; import { baseKey } from "../queries/utils/keys"; +import { isAuthenticated } from "../states/core"; +import { getLastResult, setLastResult } from "../states/snapshot"; import { - __nonReactive as tagsNonReactive, reconcileLocalTagPB, saveLocalTagPB, + __nonReactive as tagsNonReactive, } from "./tags"; -import { isAuthenticated } from "../states/core"; -import { createEffectOn } from "../hooks/effects"; -import { getLastResult, setLastResult } from "../states/snapshot"; import { applyIdWorkaround } from "./utils/misc"; export type ResultsQueryState = { @@ -260,6 +260,9 @@ type ActionType = { insertLocalResult: { result: SnapshotResult; }; + deleteLocalTag: { + tagId: string; + }; }; const actions = { @@ -319,6 +322,21 @@ const actions = { resultsCollection.utils.writeInsert(normalizeResult(result)); }, }), + deleteLocalTag: createOptimisticAction({ + onMutate: ({ tagId }) => { + for (const result of [...resultsCollection.values()].filter((it) => + it.tags.includes(tagId), + )) { + resultsCollection.utils.writeUpdate({ + ...result, + tags: result.tags.filter((it) => it !== tagId), + }); + } + }, + mutationFn: async () => { + return true; + }, + }), }; // --- Public API --- export async function updateTags( @@ -382,6 +400,17 @@ export async function insertLocalResult( await transaction.isPersisted.promise; } +export async function deleteLocalTag( + params: ActionType["deleteLocalTag"], +): Promise { + if (!resultsCollection.isReady()) { + //not loaded yet, don't need to update + return; + } + const transtaction = actions.deleteLocalTag(params); + await transtaction.isPersisted.promise; +} + // oxlint-disable-next-line typescript/explicit-function-return-type export function buildResultsQuery(state: ResultsQueryState) { const applyMode2Filter = ( @@ -622,21 +651,6 @@ function buildSettingsResultsQuery( return query; } -export function deleteLocalTag(tagId: string): void { - resultsCollection.utils.writeBatch(() => { - for (const result of [...resultsCollection.values()]) { - if (!result.tags.includes(tagId)) { - continue; - } - - resultsCollection.utils.writeUpdate({ - ...result, - tags: result.tags.filter((it) => it !== tagId), - }); - } - }); -} - export function isResultsReady(): boolean { return resultsCollection.isReady(); } diff --git a/frontend/src/ts/modals/edit-tag.ts b/frontend/src/ts/modals/edit-tag.ts index 08e1cead2b54..b11dfba56456 100644 --- a/frontend/src/ts/modals/edit-tag.ts +++ b/frontend/src/ts/modals/edit-tag.ts @@ -106,7 +106,7 @@ const actionModals: Record = { }; } - deleteLocalTag(tagId); + await deleteLocalTag({ tagId }); void Settings.update(); return { status: "success", message: `Tag removed` }; From 3afbe735f63f10450fce965b1f630f3cfd44e2eb Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Sun, 17 May 2026 14:49:45 +0200 Subject: [PATCH 2/3] Update frontend/src/ts/collections/results.ts Co-authored-by: Leonabcd123 <156839416+Leonabcd123@users.noreply.github.com> --- frontend/src/ts/collections/results.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/ts/collections/results.ts b/frontend/src/ts/collections/results.ts index 803fb0910133..17b034a9bf1e 100644 --- a/frontend/src/ts/collections/results.ts +++ b/frontend/src/ts/collections/results.ts @@ -407,8 +407,8 @@ export async function deleteLocalTag( //not loaded yet, don't need to update return; } - const transtaction = actions.deleteLocalTag(params); - await transtaction.isPersisted.promise; + const transaction = actions.deleteLocalTag(params); + await transaction.isPersisted.promise; } // oxlint-disable-next-line typescript/explicit-function-return-type From 5d7c53e1b17631caa2dd0a737f53494ed006665e Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Tue, 19 May 2026 10:28:59 +0200 Subject: [PATCH 3/3] local only updates --- frontend/src/ts/collections/results.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/ts/collections/results.ts b/frontend/src/ts/collections/results.ts index 17b034a9bf1e..a224008a34d4 100644 --- a/frontend/src/ts/collections/results.ts +++ b/frontend/src/ts/collections/results.ts @@ -316,11 +316,12 @@ const actions = { }), insertLocalResult: createOptimisticAction({ onMutate: ({ result }) => { - resultsCollection.insert(result); - }, - mutationFn: async ({ result }) => { resultsCollection.utils.writeInsert(normalizeResult(result)); }, + mutationFn: async () => { + //we don't sync the changes back to the backend here, it is done already + return; + }, }), deleteLocalTag: createOptimisticAction({ onMutate: ({ tagId }) => { @@ -334,7 +335,8 @@ const actions = { } }, mutationFn: async () => { - return true; + //we do not sync the changes back to the backend + return; }, }), };