Skip to content

Chat renders twice (wrong workspace then correct) when opening a chat in a different workspace #79

Description

@chhotu-claw

Summary

Opening a chat that lives in a different workspace (e.g. clicking it in the sidebar) renders the chat twice: it first opens in the current (wrong) workspace, then re-renders in the correct workspace once the switch completes. Visible as a double-load / flash of the chat window on every cross-workspace navigation.

Steps to reproduce

  1. Open a chat in workspace A.
  2. In the sidebar, click a chat that belongs to workspace B.
  3. The chat window loads, briefly against workspace A, then loads again under workspace B.

Expected

A single render: switch to workspace B, then open the chat in B.

Root cause

In src/routes/+page.svelte, the URL-driven workspace effect both reads and writes lastLoadedPath, which is $state:

let lastLoadedPath = $state<string | null>(null);

$effect(() => {
    const workspacePath = $page.url.searchParams.get('workspace');
    ...
    if (workspacePath && workspacePath !== lastLoadedPath) {
        lastLoadedPath = workspacePath;            // (1) synchronous write to $state
        loadWorkspace(workspacePath).then(async () => {
            ...
            processIntentParams();                 // (3) correct: runs after load
        });
    } else if (workspacePath && workspacePath === lastLoadedPath) {
        processIntentParams();                     // (2) runs immediately
    }
    ...
});

Writing lastLoadedPath at (1) re-triggers the effect synchronously (it's reactive state the effect reads). On that re-run workspacePath === lastLoadedPath, so branch (2) calls processIntentParams() immediately — but loadWorkspace() from the first run is still in flight, so currentWorkspace is still the old workspace. The openChat intent is therefore applied against the wrong workspace (render #1). When loadWorkspace() resolves, the workspace switches and (3) opens the chat again in the correct workspace (render #2).

Suggested fix

Only process intents in the immediate branch when the target workspace is actually current; otherwise let the in-flight loadWorkspace().then() handle it:

} else if (workspacePath && workspacePath === lastLoadedPath) {
    if (get(currentWorkspace)?.path === workspacePath) processIntentParams();
}

This preserves the fast path for same-workspace navigation (chat-to-chat within the current workspace) while preventing intents from being applied against a stale workspace during a cross-workspace switch. Single render in all cases.

(Making lastLoadedPath a plain let instead of $state also resolves it, by removing the spurious self-retrigger — but the guard is the smaller, more targeted change.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions