Skip to content

Commit 3ef4901

Browse files
committed
fix(workspace): retain feedback for the current refresh
Signed-off-by: song <liusongstep@gmail.com>
1 parent 6af9215 commit 3ef4901

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

‎apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,10 @@ export function PersonalWorkspacePage({
864864
const [lifecycleBusyGoalIds, setLifecycleBusyGoalIds] = useState<ReadonlySet<string>>(() => new Set());
865865
const [quickCompletingTodoIds, setQuickCompletingTodoIds] = useState<ReadonlySet<string>>(() => new Set());
866866
const [refreshState, setRefreshState] = useState<"idle" | "loading" | "done" | "error">("idle");
867+
const refreshResetTimer = useRef<number | null>(null);
868+
useEffect(() => () => {
869+
if (refreshResetTimer.current !== null) window.clearTimeout(refreshResetTimer.current);
870+
}, []);
867871
const [historyRefreshRevision, setHistoryRefreshRevision] = useState(0);
868872
const [sessionProposalIds, setSessionProposalIds] = useState<string[]>([]);
869873
const [managerChannelProposalIds, setManagerChannelProposalIds] = useState<string[]>([]);
@@ -1928,6 +1932,10 @@ export function PersonalWorkspacePage({
19281932

19291933
async function refreshWorkspace() {
19301934
if (!callbacks.onRefresh || refreshState === "loading") return;
1935+
if (refreshResetTimer.current !== null) {
1936+
window.clearTimeout(refreshResetTimer.current);
1937+
refreshResetTimer.current = null;
1938+
}
19311939
setRefreshState("loading");
19321940
try {
19331941
await callbacks.onRefresh();
@@ -1936,7 +1944,10 @@ export function PersonalWorkspacePage({
19361944
} catch {
19371945
setRefreshState("error");
19381946
}
1939-
window.setTimeout(() => setRefreshState("idle"), 1800);
1947+
refreshResetTimer.current = window.setTimeout(() => {
1948+
refreshResetTimer.current = null;
1949+
setRefreshState("idle");
1950+
}, 1800);
19401951
}
19411952

19421953
const settingsPage = settingsOpen ? (

‎examples/personal-workspace-browser/navigation-sorting.mjs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,26 @@ export const navigationSortingScenario = {
446446
if (await page.locator(".personal-digest-card").count()) throw new Error("A first-visit digest repeated attention counts without any new run results");
447447
pass(17, "Manager home omits the empty first-visit digest and redundant Agent worker strip.");
448448

449+
// An earlier completion notice must not clear a newer pending refresh.
450+
await page.clock.install();
451+
await page.clock.pauseAt(await page.evaluate(() => Date.now()));
452+
const refresh = page.getByRole("button", {name: "刷新状态", exact: true});
453+
await refresh.click();
454+
await page.locator(".personal-refresh-control.is-done").waitFor();
455+
await page.clock.runFor(1000);
456+
context.api.nextStatusDelayMs = 4000;
457+
await refresh.click();
458+
await page.locator(".personal-refresh-control.is-loading").waitFor();
459+
await page.clock.runFor(900);
460+
if (!await page.locator(".personal-refresh-control.is-loading").count()) {
461+
throw new Error("An old completion timer cleared a newer pending refresh");
462+
}
463+
await page.locator(".personal-refresh-control.is-done").waitFor();
464+
await page.clock.runFor(1800);
465+
await page.locator(".personal-refresh-control.is-idle").waitFor();
466+
await page.clock.resume();
467+
pass(25, "Refresh feedback belongs to the current request, including an overlapping prior completion timer.");
468+
449469
} finally {
450470
await context.close();
451471
}

0 commit comments

Comments
 (0)