From f8321d926fa33dc3ba57d43719e903e16eae452c Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Tue, 1 Sep 2026 05:13:31 +0800 Subject: [PATCH] fix: refresh recent connections once connections are loaded The Recent strip was computed from get().connections which is still empty while loadAll() is in flight on app startup, so cached recent IDs got filtered out and the strip could appear empty/flaky until a remount. loadAll now refreshes recents after connections populate. --- desktop/src/stores/connectionStore.test.ts | 27 ++++++++++++++++++++++ desktop/src/stores/connectionStore.ts | 3 +++ 2 files changed, 30 insertions(+) diff --git a/desktop/src/stores/connectionStore.test.ts b/desktop/src/stores/connectionStore.test.ts index e134110..f0cfc0d 100644 --- a/desktop/src/stores/connectionStore.test.ts +++ b/desktop/src/stores/connectionStore.test.ts @@ -225,6 +225,33 @@ describe("favorites / recents / move-selection", () => { expect(commands.recordRecentConnection).toHaveBeenCalledWith("c1"); }); + it("loadAll refreshes recents once connections are known (startup race fix)", async () => { + const conn = makeConn({ id: "c1", name: "Prod" }); + vi.spyOn(commands, "getConnections").mockResolvedValue([conn]); + vi.spyOn(commands, "getFolders").mockResolvedValue([]); + vi.spyOn(commands, "getTags").mockResolvedValue([]); + vi.spyOn(commands, "getRecentConnections").mockResolvedValue([ + { connection_id: "c1", opened_at: "2026-08-02T00:00:00Z" }, + ]); + + // Simulate the app-shell mount: loadAll fires and populates connections. + await useConnectionStore.getState().loadAll(); + + // The recent strip must now show the connection that was opened previously. + expect(commands.getRecentConnections).toHaveBeenCalledWith(8); + expect(useConnectionStore.getState().recent).toEqual([conn]); + }); + + it("loadRecent maps cached recent ids against the current connection list", async () => { + const conn = makeConn({ id: "c1", name: "Prod" }); + useConnectionStore.setState({ connections: [conn] }); + vi.spyOn(commands, "getRecentConnections").mockResolvedValue([ + { connection_id: "c1", opened_at: "2026-08-02T00:00:00Z" }, + ]); + await useConnectionStore.getState().loadRecent(); + expect(useConnectionStore.getState().recent).toEqual([conn]); + }); + describe("duplicateConnection", () => { it("copies fields with a '(copy)' name and favorite false", async () => { const src = makeConn({ id: "c1", name: "Prod", folder_id: "f1", tag_ids: ["t1"], favorite: true }); diff --git a/desktop/src/stores/connectionStore.ts b/desktop/src/stores/connectionStore.ts index 04e28b7..3e856c2 100644 --- a/desktop/src/stores/connectionStore.ts +++ b/desktop/src/stores/connectionStore.ts @@ -46,6 +46,9 @@ export const useConnectionStore = create((set, get) => ({ set((s) => ({ connections: [...s.connections].sort((a, b) => Number(b.favorite) - Number(a.favorite)) })); // Also load tag order get().loadTagOrder(); + // Refresh recents once connections are known so the recent strip is not + // computed against an empty list (avoids a startup race with loadRecent). + get().loadRecent().catch(() => {}); } catch (e) { set({ loading: false, error: e instanceof Error ? e.message : String(e) }); } -- 2.54.0