Add manual refresh button to git diff controls (#1216)

* feat(git): add manual refresh button to diff controls

Adds a checkout_refresh RPC that forces a hard re-read of the git and
GitHub snapshot plus the diff, bypassing polling. The diff controls now
show a refresh button (feature-gated) that triggers it and surfaces
errors via a toast — an escape hatch when the polled state goes stale.

* refactor(git): address review — dotted RPC name + withUnistyles

- Rename checkout_refresh RPC to the dotted convention
  (checkout.refresh.request/response) per docs/rpc-namespacing.md.
- Replace the banned useUnistyles() call in DiffRefreshButton with
  withUnistyles wrappers for the icon/spinner color, per docs/unistyles.md.

* refactor(git): move refresh into the checkout actions store

Per the feature audit: the manual refresh was the one checkout action
whose UI logic lived inline in the component instead of alongside its
siblings (commit/pull/push) in useCheckoutGitActionsStore. Move it into
the store so there's one home for "UI triggers a checkout RPC" — it now
reuses runCheckoutAction's pending/success status and query invalidation.
The component just reads status and shows an error toast.

* fix(git): size refresh loader to the icon to stop layout shift

ActivityIndicator size="small" renders ~20px regardless of platform,
wider than the 14px refresh icon, so swapping to it grew the button and
shifted the controls row. Use SyncedLoader at the same iconSize — it
renders into a size×size box, so both states share one footprint.

* fix(git): match file-explorer refresh control (RotateCw + LoadingSpinner)

Mirror the file-explorer pane's refresh button exactly: RotateCw icon,
LoadingSpinner while refreshing, both centered in a fixed icon-sized box
so the spinner can't grow the control or shift the row. Replaces the
ad-hoc RefreshCw + SyncedLoader pairing.
This commit is contained in:
Mohamed Boudra
2026-05-29 14:23:16 +08:00
committed by GitHub
parent 04fb0f9b82
commit 14d176a4e2
8 changed files with 284 additions and 1 deletions

View File

@@ -1382,6 +1382,12 @@ export const CheckoutPushRequestSchema = z.object({
requestId: z.string(),
});
export const CheckoutRefreshRequestSchema = z.object({
type: z.literal("checkout.refresh.request"),
cwd: z.string(),
requestId: z.string(),
});
export const CheckoutPrCreateRequestSchema = z.object({
type: z.literal("checkout_pr_create_request"),
cwd: z.string(),
@@ -1887,6 +1893,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
CheckoutMergeFromBaseRequestSchema,
CheckoutPullRequestSchema,
CheckoutPushRequestSchema,
CheckoutRefreshRequestSchema,
CheckoutPrCreateRequestSchema,
CheckoutPrMergeRequestSchema,
CheckoutGithubSetAutoMergeRequestSchema,
@@ -2121,6 +2128,8 @@ export const ServerInfoStatusPayloadSchema = z
"terminal-restore-modes": z.boolean().optional(),
// COMPAT(rewind): added in v0.1.X, drop the gate when floor >= v0.1.X.
rewind: z.boolean().optional(),
// COMPAT(checkoutRefresh): added in v0.1.86, remove gate after 2026-11-29.
checkoutRefresh: z.boolean().optional(),
})
.optional(),
})
@@ -3075,6 +3084,16 @@ export const CheckoutPushResponseSchema = z.object({
}),
});
export const CheckoutRefreshResponseSchema = z.object({
type: z.literal("checkout.refresh.response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPrCreateResponseSchema = z.object({
type: z.literal("checkout_pr_create_response"),
payload: z.object({
@@ -3687,6 +3706,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
CheckoutMergeFromBaseResponseSchema,
CheckoutPullResponseSchema,
CheckoutPushResponseSchema,
CheckoutRefreshResponseSchema,
CheckoutPrCreateResponseSchema,
CheckoutPrMergeResponseSchema,
CheckoutGithubSetAutoMergeResponseSchema,
@@ -3949,6 +3969,8 @@ export type CheckoutPullRequest = z.infer<typeof CheckoutPullRequestSchema>;
export type CheckoutPullResponse = z.infer<typeof CheckoutPullResponseSchema>;
export type CheckoutPushRequest = z.infer<typeof CheckoutPushRequestSchema>;
export type CheckoutPushResponse = z.infer<typeof CheckoutPushResponseSchema>;
export type CheckoutRefreshRequest = z.infer<typeof CheckoutRefreshRequestSchema>;
export type CheckoutRefreshResponse = z.infer<typeof CheckoutRefreshResponseSchema>;
export type CheckoutPrCreateRequest = z.infer<typeof CheckoutPrCreateRequestSchema>;
export type CheckoutPrCreateResponse = z.infer<typeof CheckoutPrCreateResponseSchema>;
export type CheckoutPrMergeRequest = z.infer<typeof CheckoutPrMergeRequestSchema>;