diff --git a/src/renderer/components/team/useClaudeLogsController.ts b/src/renderer/components/team/useClaudeLogsController.ts index 6237c700..25b2bc87 100644 --- a/src/renderer/components/team/useClaudeLogsController.ts +++ b/src/renderer/components/team/useClaudeLogsController.ts @@ -514,7 +514,7 @@ export function useClaudeLogsController( }; void fetchLogs({ queueIfBusy: true }); - const id = window.setInterval(() => void fetchLogs(), POLL_MS); + const id = window.setInterval(() => void fetchLogs({ queueIfBusy: true }), POLL_MS); return () => { cancelled = true; window.clearInterval(id); diff --git a/src/renderer/components/ui/MemberSelect.tsx b/src/renderer/components/ui/MemberSelect.tsx index 1ece6e05..7c1d23a7 100644 --- a/src/renderer/components/ui/MemberSelect.tsx +++ b/src/renderer/components/ui/MemberSelect.tsx @@ -46,8 +46,8 @@ export const MemberSelect = ({ size = 'sm', disabled = false, className, - searchPlaceholder = 'Search members...', - emptyMessage = 'No members found.', + searchPlaceholder, + emptyMessage, getMemberLabel, getMemberDescription, ariaLabel, diff --git a/test/renderer/components/team/useClaudeLogsController.test.tsx b/test/renderer/components/team/useClaudeLogsController.test.tsx index e0c34a99..e70c8877 100644 --- a/test/renderer/components/team/useClaudeLogsController.test.tsx +++ b/test/renderer/components/team/useClaudeLogsController.test.tsx @@ -92,6 +92,7 @@ describe('useClaudeLogsController enabled option', () => { afterEach(() => { document.body.innerHTML = ''; + vi.useRealTimers(); vi.clearAllMocks(); vi.unstubAllGlobals(); }); @@ -170,6 +171,46 @@ describe('useClaudeLogsController enabled option', () => { }); }); + it('queues interval-driven polls when the current request is still in flight', async () => { + vi.useFakeTimers(); + const firstRequest = createDeferred(); + controllerState.getClaudeLogs + .mockReturnValueOnce(firstRequest.promise) + .mockResolvedValue(createLogsResponse('interval fresh lead')); + const host = document.createElement('div'); + document.body.appendChild(host); + const root = createRoot(host); + + await act(async () => { + root.render(React.createElement(ControllerHarness, { enabled: true })); + await Promise.resolve(); + }); + expect(controllerState.getClaudeLogs).toHaveBeenCalledTimes(1); + + await act(async () => { + vi.advanceTimersByTime(2000); + await Promise.resolve(); + }); + expect(controllerState.getClaudeLogs).toHaveBeenCalledTimes(1); + + await act(async () => { + firstRequest.resolve(createLogsResponse('stale lead')); + await Promise.resolve(); + await Promise.resolve(); + }); + + expect(controllerState.getClaudeLogs).toHaveBeenCalledTimes(2); + expect(controllerState.getClaudeLogs).toHaveBeenLastCalledWith('demo-team', { + offset: 0, + limit: 100, + }); + + await act(async () => { + root.unmount(); + await Promise.resolve(); + }); + }); + it('does not run a queued lead fetch after being disabled again', async () => { const firstRequest = createDeferred(); controllerState.getClaudeLogs diff --git a/test/renderer/components/ui/MemberSelect.test.tsx b/test/renderer/components/ui/MemberSelect.test.tsx index 50bb4b63..248e2e1b 100644 --- a/test/renderer/components/ui/MemberSelect.test.tsx +++ b/test/renderer/components/ui/MemberSelect.test.tsx @@ -112,20 +112,16 @@ describe('MemberSelect', () => { searchPlaceholder="Search log sources..." emptyMessage="No log sources found." ariaLabel="Log source" - getMemberLabel={(candidate) => - candidate.name === 'team-lead' - ? 'Lead' - : candidate.removedAt - ? `${candidate.name} (removed)` - : candidate.name - } - getMemberDescription={(candidate) => - candidate.name === 'team-lead' - ? 'Team Lead' - : candidate.removedAt - ? 'Removed' - : 'Reviewer' - } + getMemberLabel={(candidate) => { + if (candidate.name === 'team-lead') return 'Lead'; + if (candidate.removedAt) return `${candidate.name} (removed)`; + return candidate.name; + }} + getMemberDescription={(candidate) => { + if (candidate.name === 'team-lead') return 'Team Lead'; + if (candidate.removedAt) return 'Removed'; + return 'Reviewer'; + }} /> ); await flush();