feat(sidebar): add PR status hint badge to workspace rows
This commit is contained in:
@@ -3,6 +3,7 @@ import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-
|
||||
import type { CheckoutPrStatusResponse } from "@server/shared/messages";
|
||||
|
||||
const CHECKOUT_PR_STATUS_STALE_TIME = 20_000;
|
||||
const WORKSPACE_PR_HINT_REFETCH_INTERVAL = 60_000;
|
||||
|
||||
function checkoutPrStatusQueryKey(serverId: string, cwd: string) {
|
||||
return ["checkoutPrStatus", serverId, cwd] as const;
|
||||
@@ -15,6 +16,48 @@ interface UseCheckoutPrStatusQueryOptions {
|
||||
}
|
||||
|
||||
export type CheckoutPrStatusPayload = CheckoutPrStatusResponse["payload"];
|
||||
export interface PrHint {
|
||||
url: string;
|
||||
number: number;
|
||||
state: "open" | "merged" | "closed";
|
||||
}
|
||||
|
||||
function parsePullRequestNumber(url: string): number | null {
|
||||
try {
|
||||
const pathname = new URL(url).pathname;
|
||||
const match = pathname.match(/\/pull\/(\d+)(?:\/|$)/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const number = Number.parseInt(match[1], 10);
|
||||
return Number.isFinite(number) ? number : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function selectWorkspacePrHint(payload: CheckoutPrStatusPayload): PrHint | null {
|
||||
const status = payload.status;
|
||||
if (!status?.url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const number = parsePullRequestNumber(status.url);
|
||||
if (number === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
url: status.url,
|
||||
number,
|
||||
state: status.isMerged || status.state === "MERGED"
|
||||
? "merged"
|
||||
: status.state === "OPEN"
|
||||
? "open"
|
||||
: "closed",
|
||||
};
|
||||
}
|
||||
|
||||
export function useCheckoutPrStatusQuery({
|
||||
serverId,
|
||||
@@ -48,3 +91,28 @@ export function useCheckoutPrStatusQuery({
|
||||
refresh: query.refetch,
|
||||
};
|
||||
}
|
||||
|
||||
export function useWorkspacePrHint({
|
||||
serverId,
|
||||
cwd,
|
||||
enabled = true,
|
||||
}: UseCheckoutPrStatusQueryOptions): PrHint | null {
|
||||
const client = useHostRuntimeClient(serverId);
|
||||
const isConnected = useHostRuntimeIsConnected(serverId);
|
||||
|
||||
const query = useQuery<CheckoutPrStatusPayload, Error, PrHint | null>({
|
||||
queryKey: checkoutPrStatusQueryKey(serverId, cwd),
|
||||
queryFn: async () => {
|
||||
if (!client) {
|
||||
throw new Error("Daemon client not available");
|
||||
}
|
||||
return await client.checkoutPrStatus(cwd);
|
||||
},
|
||||
enabled: !!client && isConnected && !!cwd && enabled,
|
||||
staleTime: CHECKOUT_PR_STATUS_STALE_TIME,
|
||||
refetchInterval: WORKSPACE_PR_HINT_REFETCH_INTERVAL,
|
||||
select: selectWorkspacePrHint,
|
||||
});
|
||||
|
||||
return query.data ?? null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user