Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,132 +5,50 @@ import {
} from "./githubQueryPolicy";

describe("getGitHubStatusQueryPolicy", () => {
test("enables focus-only refresh for the active changes sidebar diffs view", () => {
expect(
getGitHubStatusQueryPolicy("changes-sidebar", {
hasWorkspaceId: true,
isActive: true,
isReviewTabActive: false,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: true,
staleTime: 0,
});
});

test("enables polling for the active changes sidebar review view", () => {
expect(
getGitHubStatusQueryPolicy("changes-sidebar", {
hasWorkspaceId: true,
isActive: true,
isReviewTabActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: 10_000,
refetchOnWindowFocus: true,
staleTime: 10_000,
});
});

test("disables changes sidebar status when the surface is inactive", () => {
expect(
getGitHubStatusQueryPolicy("changes-sidebar", {
hasWorkspaceId: true,
isActive: false,
isReviewTabActive: true,
}),
).toEqual({
enabled: false,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 10_000,
});
});

test("keeps the workspace page active without interval polling", () => {
expect(
getGitHubStatusQueryPolicy("workspace-page", {
hasWorkspaceId: true,
isActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 300_000,
});
});

test("keeps hover-card surfaces lazy without focus refresh", () => {
expect(
getGitHubStatusQueryPolicy("workspace-hover-card", {
hasWorkspaceId: true,
isActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 300_000,
});
});

test("keeps workspace list items cheaper than full-page PR surfaces", () => {
expect(
getGitHubStatusQueryPolicy("workspace-list-item", {
hasWorkspaceId: true,
isActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 30_000,
});
});

test("disables passive hover surfaces when they are not visible", () => {
expect(
getGitHubStatusQueryPolicy("workspace-row", {
hasWorkspaceId: true,
isActive: false,
}),
).toEqual({
enabled: false,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 300_000,
});
test("active surfaces poll every 10s", () => {
for (const surface of ["changes-sidebar", "workspace-page"] as const) {
expect(
getGitHubStatusQueryPolicy(surface, {
hasWorkspaceId: true,
isActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: 10_000,
refetchOnWindowFocus: true,
staleTime: 10_000,
});
}
});

test("hover surfaces rely on staleTime debounce, no polling", () => {
for (const surface of [
"workspace-list-item",
"workspace-row",
"workspace-hover-card",
] as const) {
expect(
getGitHubStatusQueryPolicy(surface, {
hasWorkspaceId: true,
isActive: true,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 10_000,
});
}
});
});

describe("getGitHubPRCommentsQueryPolicy", () => {
test("fetches review comments without polling when changes is open on diffs", () => {
test("polls every 30s when active with a pull request", () => {
expect(
getGitHubPRCommentsQueryPolicy({
hasWorkspaceId: true,
hasActivePullRequest: true,
isActive: true,
isReviewTabActive: false,
}),
).toEqual({
enabled: true,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 30_000,
});
});

test("polls review comments while the review tab is active", () => {
expect(
getGitHubPRCommentsQueryPolicy({
hasWorkspaceId: true,
hasActivePullRequest: true,
isActive: true,
isReviewTabActive: true,
}),
).toEqual({
enabled: true,
Expand All @@ -139,20 +57,4 @@ describe("getGitHubPRCommentsQueryPolicy", () => {
staleTime: 30_000,
});
});

test("disables comments when there is no active pull request", () => {
expect(
getGitHubPRCommentsQueryPolicy({
hasWorkspaceId: true,
hasActivePullRequest: false,
isActive: true,
isReviewTabActive: true,
}),
).toEqual({
enabled: false,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: 30_000,
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
const ACTIVE_GITHUB_STATUS_STALE_TIME_MS = 10_000;
const ACTIVE_GITHUB_STATUS_REFETCH_INTERVAL_MS = 10_000;
const WORKSPACE_LIST_ITEM_GITHUB_STATUS_STALE_TIME_MS = 30_000;
const PASSIVE_GITHUB_STATUS_STALE_TIME_MS = 5 * 60 * 1000;
export const GITHUB_STATUS_STALE_TIME_MS = 10_000;
const GITHUB_STATUS_REFETCH_INTERVAL_MS = 10_000;
const GITHUB_PR_COMMENTS_STALE_TIME_MS = 30_000;
const GITHUB_PR_COMMENTS_REFETCH_INTERVAL_MS = 30_000;

Expand All @@ -22,81 +20,51 @@ export interface GitHubQueryPolicy {
interface GitHubStatusQueryPolicyOptions {
hasWorkspaceId: boolean;
isActive?: boolean;
isReviewTabActive?: boolean;
}

interface GitHubPRCommentsQueryPolicyOptions {
hasWorkspaceId: boolean;
hasActivePullRequest: boolean;
isActive?: boolean;
isReviewTabActive?: boolean;
}

const HOVER_SURFACES: ReadonlySet<GitHubStatusQuerySurface> = new Set([
"workspace-list-item",
"workspace-row",
"workspace-hover-card",
]);

/**
* Centralizes GitHub query behavior so passive hover surfaces stay cheap while
* active workspace surfaces still revalidate when they become relevant again.
* Active surfaces (changes-sidebar, workspace-page) poll every 10s.
* Hover surfaces don't poll — callers trigger refetch on hover, debounced by staleTime.
*/
export function getGitHubStatusQueryPolicy(
surface: GitHubStatusQuerySurface,
{
hasWorkspaceId,
isActive = true,
isReviewTabActive = false,
}: GitHubStatusQueryPolicyOptions,
{ hasWorkspaceId, isActive = true }: GitHubStatusQueryPolicyOptions,
): GitHubQueryPolicy {
const isEnabled = hasWorkspaceId && isActive;
const isHover = HOVER_SURFACES.has(surface);

switch (surface) {
case "changes-sidebar":
return {
enabled: isEnabled,
refetchInterval:
isEnabled && isReviewTabActive
? ACTIVE_GITHUB_STATUS_REFETCH_INTERVAL_MS
: false,
refetchOnWindowFocus: isEnabled,
staleTime: isReviewTabActive ? ACTIVE_GITHUB_STATUS_STALE_TIME_MS : 0,
};
case "workspace-page":
return {
enabled: isEnabled,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: PASSIVE_GITHUB_STATUS_STALE_TIME_MS,
};
case "workspace-list-item":
return {
enabled: isEnabled,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: WORKSPACE_LIST_ITEM_GITHUB_STATUS_STALE_TIME_MS,
};
case "workspace-hover-card":
case "workspace-row":
return {
enabled: isEnabled,
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: PASSIVE_GITHUB_STATUS_STALE_TIME_MS,
};
}
return {
enabled: isEnabled,
refetchInterval:
isEnabled && !isHover ? GITHUB_STATUS_REFETCH_INTERVAL_MS : false,
refetchOnWindowFocus: isEnabled && !isHover,
staleTime: GITHUB_STATUS_STALE_TIME_MS,
};
}

export function getGitHubPRCommentsQueryPolicy({
hasWorkspaceId,
hasActivePullRequest,
isActive = true,
isReviewTabActive = false,
}: GitHubPRCommentsQueryPolicyOptions): GitHubQueryPolicy {
const isEnabled = hasWorkspaceId && isActive && hasActivePullRequest;

return {
enabled: isEnabled,
refetchInterval:
isEnabled && isReviewTabActive
? GITHUB_PR_COMMENTS_REFETCH_INTERVAL_MS
: false,
refetchOnWindowFocus: isEnabled && isReviewTabActive,
refetchInterval: isEnabled ? GITHUB_PR_COMMENTS_REFETCH_INTERVAL_MS : false,
refetchOnWindowFocus: isEnabled,
staleTime: GITHUB_PR_COMMENTS_STALE_TIME_MS,
};
}
1 change: 1 addition & 0 deletions apps/desktop/src/renderer/lib/githubQueryPolicy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export {
getGitHubPRCommentsQueryPolicy,
getGitHubStatusQueryPolicy,
} from "./githubQueryPolicy";
export { useHoverGitHubStatus } from "./useHoverGitHubStatus";
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useEffect, useRef, useState } from "react";
import { electronTrpc } from "renderer/lib/electron-trpc";
import {
GITHUB_STATUS_STALE_TIME_MS,
type GitHubStatusQuerySurface,
getGitHubStatusQueryPolicy,
} from "./githubQueryPolicy";

interface UseHoverGitHubStatusOptions {
workspaceId: string | null | undefined;
surface: GitHubStatusQuerySurface;
isWorktree: boolean;
}

export function useHoverGitHubStatus({
workspaceId,
surface,
isWorktree,
}: UseHoverGitHubStatusOptions) {
const [hasHovered, setHasHovered] = useState(false);

const queryPolicy = getGitHubStatusQueryPolicy(surface, {
hasWorkspaceId: !!workspaceId,
isActive: hasHovered && isWorktree,
});

const {
data: githubStatus,
dataUpdatedAt,
isStale,
refetch,
} = electronTrpc.workspaces.getGitHubStatus.useQuery(
{ workspaceId: workspaceId ?? "" },
queryPolicy,
);

const pendingRefetchRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(
() => () => {
if (pendingRefetchRef.current) clearTimeout(pendingRefetchRef.current);
},
[],
);

const onMouseEnter = () => {
if (!hasHovered) {
setHasHovered(true);
} else if (isStale) {
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
if (pendingRefetchRef.current) {
clearTimeout(pendingRefetchRef.current);
pendingRefetchRef.current = null;
}
void refetch();
} else if (!pendingRefetchRef.current) {
const msUntilStale =
GITHUB_STATUS_STALE_TIME_MS - (Date.now() - dataUpdatedAt);
pendingRefetchRef.current = setTimeout(
() => {
pendingRefetchRef.current = null;
void refetch();
},
Math.max(0, msUntilStale),
);
}
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return { githubStatus, hasHovered, onMouseEnter };
}
Comment thread
Kitenite marked this conversation as resolved.
Loading
Loading