Repository navigation
[Fix] Sidebar stuck on spinner while a large task history loads #2114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2716,8 +2716,11 @@ export class ClineProvider | |
| } | ||
|
|
||
| async getStateToPostToWebview({ includeTaskHistory = true }: GetStateOptions = {}): Promise<ExtensionState> { | ||
| // Ensure the store is initialized before reading task history | ||
| await this.taskHistoryStore.initialized | ||
| // Only wait for the store when task history is requested, so a slow scan of a large | ||
| // history cannot keep the webview from receiving its first state. | ||
| if (includeTaskHistory) { | ||
| await this.taskHistoryStore.initialized | ||
|
Comment on lines
+2721
to
+2722
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: rg -n 'postStateToWebviewWithoutTaskHistory|postStateToWebview\(|updateSettings|includeTaskHistory' src/core/webview/ClineProvider.ts src/core/webview/webviewMessageHandler.ts
sed -n '2700,2760p' src/core/webview/ClineProvider.ts
sed -n '590,620p' src/core/webview/webviewMessageHandler.tsRepository: Zoo-Code-Org/Zoo-Code Length of output: 9534 🏁 Script executed: set -o pipefail
printf '%s\n' '--- updateSettings branch ---'
sed -n '730,785p' src/core/webview/webviewMessageHandler.ts
printf '%s\n' '--- state-post helpers ---'
sed -n '2545,2590p' src/core/webview/ClineProvider.ts
printf '%s\n' '--- state construction and history ---'
sed -n '3045,3170p' src/core/webview/ClineProvider.ts
printf '%s\n' '--- webview state message consumers ---'
rg -n -F --glob '*.{ts,tsx}' -e 'state' -e 'cachedState' webview-ui/src | head -160
printf '%s\n' '--- settings update sender/receiver references ---'
rg -n -F --glob '*.{ts,tsx}' -e 'updateSettings' -e 'postMessage' webview-ui/src/components/settings webview-ui/src | head -220Repository: Zoo-Code-Org/Zoo-Code Length of output: 41857 🏁 Script executed: set -o pipefail
printf '%s\n' '--- complete updateSettings continuation ---'
sed -n '749,875p' src/core/webview/webviewMessageHandler.ts
printf '%s\n' '--- exact webview state handling ---'
sed -n '330,490p' webview-ui/src/context/ExtensionStateContext.tsx
printf '%s\n' '--- settings sender context ---'
sed -n '560,630p' webview-ui/src/components/settings/SettingsView.tsxRepository: Zoo-Code-Org/Zoo-Code Length of output: 13210 🏁 Script executed: set -o pipefail
printf '%s\n' '--- updateSettings response ---'
sed -n '870,892p' src/core/webview/webviewMessageHandler.ts
printf '%s\n' '--- mergeExtensionState implementation ---'
rg -n -F -- 'function mergeExtensionState' webview-ui/src/context/ExtensionStateContext.tsx
sed -n '155,225p' webview-ui/src/context/ExtensionStateContext.tsxRepository: Zoo-Code-Org/Zoo-Code Length of output: 3486 Keep follow-up settings state posts responsive. The initial render is not regressed. However, Use the history-free post while the store is uninitialized. Keep the scheduled full post after initialization. 🐛 Suggested fix-await provider.postStateToWebview()
+await (provider.taskHistoryStore.isInitialized
+ ? provider.postStateToWebview()
+ : provider.postStateToWebviewWithoutTaskHistory())🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| const { | ||
| apiConfiguration, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,6 +128,8 @@ const mockClineProvider = { | |
| }, | ||
| log: vi.fn(), | ||
| postStateToWebview: vi.fn(), | ||
| postStateToWebviewWithoutTaskHistory: vi.fn(), | ||
| taskHistoryStore: { isInitialized: true, initialized: Promise.resolve() }, | ||
| resolveWebviewThemeFixtureProbe: vi.fn(), | ||
| getCurrentTask: vi.fn(), | ||
| getTaskWithId: vi.fn(), | ||
|
|
@@ -3036,3 +3038,42 @@ describe("updateProfileModel", () => { | |
| expect(updateProfileModel).not.toHaveBeenCalled() | ||
| }) | ||
| }) | ||
|
|
||
| describe("webviewMessageHandler - webviewDidLaunch task history", () => { | ||
| function setupLaunch(taskHistoryStore: { isInitialized: boolean; initialized: Promise<void> }) { | ||
| vi.mocked(mockClineProvider.customModesManager.getCustomModes).mockResolvedValue([]) | ||
| const launchProvider = mockClineProvider as unknown as { | ||
| getMcpHub: ReturnType<typeof vi.fn> | ||
| providerSettingsManager: { listConfig: ReturnType<typeof vi.fn> } | ||
| taskHistoryStore: typeof taskHistoryStore | ||
| } | ||
| launchProvider.getMcpHub = vi.fn().mockReturnValue(undefined) | ||
| launchProvider.providerSettingsManager = { listConfig: vi.fn().mockResolvedValue(undefined) } | ||
| launchProvider.taskHistoryStore = taskHistoryStore | ||
| vi.mocked(mockClineProvider.postStateToWebview).mockClear() | ||
| vi.mocked(mockClineProvider.postStateToWebviewWithoutTaskHistory).mockClear() | ||
| } | ||
|
|
||
| it("posts the full state right away once task history is loaded", async () => { | ||
| setupLaunch({ isInitialized: true, initialized: Promise.resolve() }) | ||
|
|
||
| await webviewMessageHandler(mockClineProvider, { type: "webviewDidLaunch" }) | ||
|
|
||
| expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1) | ||
| expect(mockClineProvider.postStateToWebviewWithoutTaskHistory).not.toHaveBeenCalled() | ||
| }) | ||
|
|
||
| it("renders without waiting for a slow task history load, then posts the full state", async () => { | ||
| let finishLoading!: () => void | ||
| const initialized = new Promise<void>((resolve) => (finishLoading = resolve)) | ||
| setupLaunch({ isInitialized: false, initialized }) | ||
|
|
||
| await webviewMessageHandler(mockClineProvider, { type: "webviewDidLaunch" }) | ||
|
|
||
| expect(mockClineProvider.postStateToWebviewWithoutTaskHistory).toHaveBeenCalledTimes(1) | ||
| expect(mockClineProvider.postStateToWebview).not.toHaveBeenCalled() | ||
|
|
||
| finishLoading() | ||
| await vi.waitFor(() => expect(mockClineProvider.postStateToWebview).toHaveBeenCalledTimes(1)) | ||
|
Comment on lines
+3071
to
+3077
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '3030,3090p' src/core/webview/__tests__/webviewMessageHandler.spec.ts
sed -n '2440,2470p' src/core/webview/__tests__/ClineProvider.spec.ts
rg -n 'postStateToWebviewWithoutTaskHistory|webviewDidLaunch|taskHistory:' src/core/webview/__tests__Repository: Zoo-Code-Org/Zoo-Code Length of output: 11206 🏁 Script executed: set -o pipefail
printf '%s\n' '--- handler and symbols ---'
rg -n -F --glob '*.ts' -e 'webviewDidLaunch' -e 'postStateToWebviewWithoutTaskHistory' -e 'getStateToPostToWebview' src/core/webview src/core | head -200
printf '%s\n' '--- launch mock setup ---'
sed -n '80,155p' src/core/webview/__tests__/webviewMessageHandler.spec.ts
printf '%s\n' '--- handler implementation ---'
rg -l -F -- 'case "webviewDidLaunch"' src/core/webview src/core | while read -r f; do echo "FILE $f"; sed -n '/case "webviewDidLaunch"/,/^[[:space:]]*case /p' "$f"; done
printf '%s\n' '--- provider state/post methods ---'
rg -l -F -- 'postStateToWebviewWithoutTaskHistory' src/core/webview | while read -r f; do echo "FILE $f"; rg -n -F -C 12 -- 'postStateToWebviewWithoutTaskHistory' "$f"; done
printf '%s\n' '--- provider launch and post tests ---'
sed -n '1380,1490p' src/core/webview/__tests__/ClineProvider.spec.ts
sed -n '1825,1875p' src/core/webview/__tests__/ClineProvider.spec.ts
printf '%s\n' '--- task-history provider assertions ---'
sed -n '580,635p' src/core/webview/__tests__/ClineProvider.taskHistory.spec.tsRepository: Zoo-Code-Org/Zoo-Code Length of output: 42236 Assert the staged state payloads. The launch tests use 🤖 Prompt for AI Agents |
||
| }) | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: Zoo-Code-Org/Zoo-Code
Length of output: 5764
🏁 Script executed:
Repository: Zoo-Code-Org/Zoo-Code
Length of output: 19706
🏁 Script executed:
Repository: Zoo-Code-Org/Zoo-Code
Length of output: 41856
Assert
isInitializedwhile initialization is pending.Hold the reconciliation scan with a deferred gate, assert
store.isInitializedis stillfalse, then release the gate and assert that it becomestrue. The current test samples only before callinginitialize()and after it returns, so it does not prove the in-flight state. This is required by the test guidance and is more than a nitpick.🤖 Prompt for AI Agents