From 794357965dae5ec174930f663cc1bf17fe5368f4 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 10:53:32 -0800 Subject: [PATCH 1/9] feat(desktop): add bulk git operations to changes sidebar Add VSCode-like operations: discard all changes (staged/unstaged), stash, stash including untracked, and pop stash. Includes confirmation dialogs for destructive discard operations. --- .../routers/changes/security/git-commands.ts | 68 +++++ .../trpc/routers/changes/security/index.ts | 5 + .../src/lib/trpc/routers/changes/staging.ts | 40 +++ .../Sidebar/ChangesView/ChangesView.tsx | 271 +++++++++++++++--- .../ChangesHeader/ChangesHeader.tsx | 56 +++- 5 files changed, 403 insertions(+), 37 deletions(-) diff --git a/apps/desktop/src/lib/trpc/routers/changes/security/git-commands.ts b/apps/desktop/src/lib/trpc/routers/changes/security/git-commands.ts index 2877176b818..567ab1a7aca 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/security/git-commands.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/security/git-commands.ts @@ -135,3 +135,71 @@ export async function gitUnstageAll(worktreePath: string): Promise { const git = simpleGit(worktreePath); await git.reset(["HEAD"]); } + +/** + * Discard all unstaged changes (modified and deleted files). + * + * Uses `git checkout -- .` to restore all tracked files to HEAD state. + * Does NOT affect untracked files. + */ +export async function gitDiscardAllUnstaged( + worktreePath: string, +): Promise { + assertRegisteredWorktree(worktreePath); + + const git = simpleGit(worktreePath); + await git.checkout(["--", "."]); +} + +/** + * Discard all staged changes by unstaging then discarding. + * + * Uses `git reset HEAD` followed by `git checkout -- .`. + * Does NOT affect untracked files. + */ +export async function gitDiscardAllStaged(worktreePath: string): Promise { + assertRegisteredWorktree(worktreePath); + + const git = simpleGit(worktreePath); + await git.reset(["HEAD"]); + await git.checkout(["--", "."]); +} + +/** + * Stash all tracked changes. + * + * Uses `git stash push` to save current work-in-progress. + */ +export async function gitStash(worktreePath: string): Promise { + assertRegisteredWorktree(worktreePath); + + const git = simpleGit(worktreePath); + await git.stash(["push"]); +} + +/** + * Stash all changes including untracked files. + * + * Uses `git stash push --include-untracked`. + */ +export async function gitStashIncludeUntracked( + worktreePath: string, +): Promise { + assertRegisteredWorktree(worktreePath); + + const git = simpleGit(worktreePath); + await git.stash(["push", "--include-untracked"]); +} + +/** + * Pop the most recent stash. + * + * Uses `git stash pop` to apply and remove the top stash entry. + * Throws if no stash exists or if there are conflicts. + */ +export async function gitStashPop(worktreePath: string): Promise { + assertRegisteredWorktree(worktreePath); + + const git = simpleGit(worktreePath); + await git.stash(["pop"]); +} diff --git a/apps/desktop/src/lib/trpc/routers/changes/security/index.ts b/apps/desktop/src/lib/trpc/routers/changes/security/index.ts index 8fdb09c9e7a..d147bcc7bcd 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/security/index.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/security/index.ts @@ -10,8 +10,13 @@ export { gitCheckoutFile, + gitDiscardAllStaged, + gitDiscardAllUnstaged, gitStageAll, gitStageFile, + gitStash, + gitStashIncludeUntracked, + gitStashPop, gitSwitchBranch, gitUnstageAll, gitUnstageFile, diff --git a/apps/desktop/src/lib/trpc/routers/changes/staging.ts b/apps/desktop/src/lib/trpc/routers/changes/staging.ts index 678e1304c88..3a86468b1e6 100644 --- a/apps/desktop/src/lib/trpc/routers/changes/staging.ts +++ b/apps/desktop/src/lib/trpc/routers/changes/staging.ts @@ -2,8 +2,13 @@ import { z } from "zod"; import { publicProcedure, router } from "../.."; import { gitCheckoutFile, + gitDiscardAllStaged, + gitDiscardAllUnstaged, gitStageAll, gitStageFile, + gitStash, + gitStashIncludeUntracked, + gitStashPop, gitUnstageAll, gitUnstageFile, secureFs, @@ -72,5 +77,40 @@ export const createStagingRouter = () => { await secureFs.delete(input.worktreePath, input.filePath); return { success: true }; }), + + discardAllUnstaged: publicProcedure + .input(z.object({ worktreePath: z.string() })) + .mutation(async ({ input }): Promise<{ success: boolean }> => { + await gitDiscardAllUnstaged(input.worktreePath); + return { success: true }; + }), + + discardAllStaged: publicProcedure + .input(z.object({ worktreePath: z.string() })) + .mutation(async ({ input }): Promise<{ success: boolean }> => { + await gitDiscardAllStaged(input.worktreePath); + return { success: true }; + }), + + stash: publicProcedure + .input(z.object({ worktreePath: z.string() })) + .mutation(async ({ input }): Promise<{ success: boolean }> => { + await gitStash(input.worktreePath); + return { success: true }; + }), + + stashIncludeUntracked: publicProcedure + .input(z.object({ worktreePath: z.string() })) + .mutation(async ({ input }): Promise<{ success: boolean }> => { + await gitStashIncludeUntracked(input.worktreePath); + return { success: true }; + }), + + stashPop: publicProcedure + .input(z.object({ worktreePath: z.string() })) + .mutation(async ({ input }): Promise<{ success: boolean }> => { + await gitStashPop(input.worktreePath); + return { success: true }; + }), }); }; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx index 9c598663b06..ba89e3c2f5c 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx @@ -1,9 +1,18 @@ +import { + AlertDialog, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@superset/ui/alert-dialog"; import { Button } from "@superset/ui/button"; import { toast } from "@superset/ui/sonner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { useParams } from "@tanstack/react-router"; import { useEffect, useState } from "react"; import { HiMiniMinus, HiMiniPlus } from "react-icons/hi2"; +import { LuUndo2 } from "react-icons/lu"; import { electronTrpc } from "renderer/lib/electron-trpc"; import { useChangesStore } from "renderer/stores/changes"; import type { ChangeCategory, ChangedFile } from "shared/changes-types"; @@ -128,6 +137,68 @@ export function ChangesView({ }, }); + const discardAllUnstagedMutation = + electronTrpc.changes.discardAllUnstaged.useMutation({ + onSuccess: () => { + toast.success("Discarded all unstaged changes"); + refetch(); + }, + onError: (error) => { + console.error("Failed to discard all unstaged:", error); + toast.error(`Failed to discard: ${error.message}`); + }, + }); + + const discardAllStagedMutation = + electronTrpc.changes.discardAllStaged.useMutation({ + onSuccess: () => { + toast.success("Discarded all staged changes"); + refetch(); + }, + onError: (error) => { + console.error("Failed to discard all staged:", error); + toast.error(`Failed to discard: ${error.message}`); + }, + }); + + const stashMutation = electronTrpc.changes.stash.useMutation({ + onSuccess: () => { + toast.success("Changes stashed"); + refetch(); + }, + onError: (error) => { + console.error("Failed to stash:", error); + toast.error(`Failed to stash: ${error.message}`); + }, + }); + + const stashIncludeUntrackedMutation = + electronTrpc.changes.stashIncludeUntracked.useMutation({ + onSuccess: () => { + toast.success("All changes stashed (including untracked)"); + refetch(); + }, + onError: (error) => { + console.error("Failed to stash:", error); + toast.error(`Failed to stash: ${error.message}`); + }, + }); + + const stashPopMutation = electronTrpc.changes.stashPop.useMutation({ + onSuccess: () => { + toast.success("Stash applied and removed"); + refetch(); + }, + onError: (error) => { + console.error("Failed to pop stash:", error); + toast.error(`Failed to pop stash: ${error.message}`); + }, + }); + + const [showDiscardUnstagedDialog, setShowDiscardUnstagedDialog] = + useState(false); + const [showDiscardStagedDialog, setShowDiscardStagedDialog] = useState(false); + const handleDiscard = (file: ChangedFile) => { if (!worktreePath) return; if (file.status === "untracked" || file.status === "added") { @@ -285,6 +356,16 @@ export function ChangesView({ onViewModeChange={setFileListViewMode} worktreePath={worktreePath} workspaceId={workspaceId} + onStash={() => stashMutation.mutate({ worktreePath })} + onStashIncludeUntracked={() => + stashIncludeUntrackedMutation.mutate({ worktreePath }) + } + onStashPop={() => stashPopMutation.mutate({ worktreePath })} + isStashPending={ + stashMutation.isPending || + stashIncludeUntrackedMutation.isPending || + stashPopMutation.isPending + } /> toggleSection("staged")} actions={ - - - - - Unstage all - +
+ + + + + + Discard all staged + + + + + + + Unstage all + +
} > toggleSection("unstaged")} actions={ - - - - - Stage all - +
+ + + + + + Discard all unstaged + + + + + + + Stage all + +
} > )} + + {/* Discard Unstaged Confirmation Dialog */} + + + + + Discard all unstaged changes? + + + This will revert all unstaged modifications. Untracked files will + not be affected. This action cannot be undone. + + + + + + + + + + {/* Discard Staged Confirmation Dialog */} + + + + + Discard all staged changes? + + + This will unstage and revert all staged changes. Untracked files + will not be affected. This action cannot be undone. + + + + + + + + ); } diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx index 172baed4071..c5d91e2828d 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx @@ -1,4 +1,11 @@ import { Button } from "@superset/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@superset/ui/dropdown-menu"; import { Select, SelectContent, @@ -9,7 +16,7 @@ import { import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { useEffect, useRef, useState } from "react"; import { HiArrowPath } from "react-icons/hi2"; -import { LuLoaderCircle } from "react-icons/lu"; +import { LuArchive, LuArchiveRestore, LuLoaderCircle } from "react-icons/lu"; import { electronTrpc } from "renderer/lib/electron-trpc"; import { PRIcon } from "renderer/screens/main/components/PRIcon"; import { usePRStatus } from "renderer/screens/main/hooks"; @@ -23,6 +30,10 @@ interface ChangesHeaderProps { onViewModeChange: (mode: ChangesViewMode) => void; worktreePath: string; workspaceId?: string; + onStash?: () => void; + onStashIncludeUntracked?: () => void; + onStashPop?: () => void; + isStashPending?: boolean; } export function ChangesHeader({ @@ -31,6 +42,10 @@ export function ChangesHeader({ onViewModeChange, worktreePath, workspaceId, + onStash, + onStashIncludeUntracked, + onStashPop, + isStashPending, }: ChangesHeaderProps) { const [isManualRefresh, setIsManualRefresh] = useState(false); const timeoutRef = useRef(null); @@ -134,6 +149,45 @@ export function ChangesHeader({ viewMode={viewMode} onViewModeChange={onViewModeChange} /> + {onStash && onStashIncludeUntracked && onStashPop && ( + + + + + + + + + Stash operations + + + + + + Stash Changes + + + + Stash (Include Untracked) + + + + + Pop Stash + + + + )} - - - - Stash operations - - - - - - Stash Changes - - - - Stash (Include Untracked) - - - - - Pop Stash - - - - )} + + + + + + + + + Stash operations + + + + + + Stash Changes + + + + Stash (Include Untracked) + + + + + Pop Stash + + + - + - Stash operations + Refresh changes - - - - Stash Changes - - - - Stash (Include Untracked) - - - - - Pop Stash - - - - - - - - - Refresh changes - - + + - {/* PR Status Icon */} - {isPRLoading ? ( - - ) : pr ? ( - - - +
+ + + + + + + + + Stash operations + + + + + + Stash Changes + + - - - #{pr.number} - - - - - View PR on GitHub - - - ) : null} + + Stash (Include Untracked) + + + + + Pop Stash + + + +
+ + {/* PR Status */} +
+ {isPRLoading ? ( + + ) : pr ? ( + + + + + + #{pr.number} + + + + + View PR on GitHub + + + ) : null} +
); From d3734437d46395c78108b2cbce29e42033215426 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 13:38:03 -0800 Subject: [PATCH 5/9] style(desktop): move all action buttons to second row --- .../ChangesHeader/ChangesHeader.tsx | 120 +++++++++--------- 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx index 38f8f6a383a..cef9d9d2329 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx @@ -105,75 +105,49 @@ export function ChangesHeader({ return (
- {/* Row 1: Base branch, view mode, refresh */} -
-
- - Base: + {/* Row 1: Base branch */} +
+ + Base: + + {isLoading || !branchData ? ( + + {effectiveBaseBranch} - {isLoading || !branchData ? ( - - {effectiveBaseBranch} - - ) : ( - - - - Change base branch - - - )} -
-
- + ) : ( - - - + - Refresh changes + Change base branch -
+ )}
- {/* Row 2: Stash operations, PR status */} + {/* Row 2: All action buttons */}
@@ -213,6 +187,28 @@ export function ChangesHeader({ + + + + + + + Refresh changes + +
{/* PR Status */} From 03f4e00283690099cc59c14082db381b97550d9d Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 13:38:51 -0800 Subject: [PATCH 6/9] style(desktop): align all action buttons to start --- .../ChangesHeader/ChangesHeader.tsx | 156 +++++++++--------- 1 file changed, 75 insertions(+), 81 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx index cef9d9d2329..4f3b16f7b61 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx @@ -148,94 +148,88 @@ export function ChangesHeader({
{/* Row 2: All action buttons */} -
-
- - - - - - - - - Stash operations - - - - - - Stash Changes - - - - Stash (Include Untracked) - - - - - Pop Stash - - - - +
+ + + + + + + + + Stash operations + + + + + + Stash Changes + + + + Stash (Include Untracked) + + + + + Pop Stash + + + + + + + + + + Refresh changes + + + {isPRLoading ? ( + + ) : pr ? ( - + + + #{pr.number} + + - Refresh changes + View PR on GitHub -
- - {/* PR Status */} -
- {isPRLoading ? ( - - ) : pr ? ( - - - - - - #{pr.number} - - - - - View PR on GitHub - - - ) : null} -
+ ) : null}
); From f769b097690d049a6e5a1d93fbfd9a0414825b7f Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 13:39:50 -0800 Subject: [PATCH 7/9] refactor(desktop): extract ChangesHeader into smaller components - BaseBranchSelector: handles branch selection logic and UI - StashDropdown: stash operations dropdown menu - RefreshButton: refresh with spin animation - PRStatusLink: PR status display with loading state --- .../ChangesHeader/ChangesHeader.tsx | 345 ++++++++++-------- 1 file changed, 186 insertions(+), 159 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx index 4f3b16f7b61..a67b468d403 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx @@ -37,199 +37,226 @@ interface ChangesHeaderProps { isStashPending: boolean; } -export function ChangesHeader({ - onRefresh, - viewMode, - onViewModeChange, - worktreePath, - workspaceId, +function BaseBranchSelector({ worktreePath }: { worktreePath: string }) { + const { baseBranch, setBaseBranch } = useChangesStore(); + const { data: branchData, isLoading } = + electronTrpc.changes.getBranches.useQuery( + { worktreePath }, + { enabled: !!worktreePath }, + ); + + const effectiveBaseBranch = baseBranch ?? branchData?.defaultBranch ?? "main"; + const sortedBranches = [...(branchData?.remote ?? [])].sort((a, b) => { + if (a === branchData?.defaultBranch) return -1; + if (b === branchData?.defaultBranch) return 1; + return a.localeCompare(b); + }); + + const handleChange = (value: string) => { + if (value === branchData?.defaultBranch && baseBranch === null) return; + setBaseBranch(value); + }; + + if (isLoading || !branchData) { + return ( + + {effectiveBaseBranch} + + ); + } + + return ( + + + + Change base branch + + + ); +} + +function StashDropdown({ onStash, onStashIncludeUntracked, onStashPop, - isStashPending, -}: ChangesHeaderProps) { - const [isManualRefresh, setIsManualRefresh] = useState(false); + isPending, +}: { + onStash: () => void; + onStashIncludeUntracked: () => void; + onStashPop: () => void; + isPending: boolean; +}) { + return ( + + + + + + + + + Stash operations + + + + + + Stash Changes + + + + Stash (Include Untracked) + + + + + Pop Stash + + + + ); +} + +function RefreshButton({ + onRefresh, +}: { + onRefresh: () => void; +}) { + const [isSpinning, setIsSpinning] = useState(false); const timeoutRef = useRef(null); - const handleRefresh = () => { - setIsManualRefresh(true); + const handleClick = () => { + setIsSpinning(true); onRefresh(); - // Clear any existing timeout - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - // Stop spinning after a short delay - timeoutRef.current = setTimeout(() => { - setIsManualRefresh(false); - }, 600); + if (timeoutRef.current) clearTimeout(timeoutRef.current); + timeoutRef.current = setTimeout(() => setIsSpinning(false), 600); }; - // Cleanup timeout on unmount useEffect(() => { return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - timeoutRef.current = null; - } + if (timeoutRef.current) clearTimeout(timeoutRef.current); }; }, []); - const { baseBranch, setBaseBranch } = useChangesStore(); - - const { data: branchData, isLoading } = - electronTrpc.changes.getBranches.useQuery( - { worktreePath }, - { enabled: !!worktreePath }, - ); + return ( + + + + + + Refresh changes + + + ); +} - const { pr, isLoading: isPRLoading } = usePRStatus({ +function PRStatusLink({ workspaceId }: { workspaceId?: string }) { + const { pr, isLoading } = usePRStatus({ workspaceId, refetchInterval: 10000, }); - const effectiveBaseBranch = baseBranch ?? branchData?.defaultBranch ?? "main"; - const availableBranches = branchData?.remote ?? []; + if (isLoading) { + return ( + + ); + } - const sortedBranches = [...availableBranches].sort((a, b) => { - if (a === branchData?.defaultBranch) return -1; - if (b === branchData?.defaultBranch) return 1; - return a.localeCompare(b); - }); + if (!pr) return null; - const handleChange = (value: string) => { - if (value === branchData?.defaultBranch && baseBranch === null) { - return; - } - setBaseBranch(value); - }; + return ( + + + + + + #{pr.number} + + + + + View PR on GitHub + + + ); +} +export function ChangesHeader({ + onRefresh, + viewMode, + onViewModeChange, + worktreePath, + workspaceId, + onStash, + onStashIncludeUntracked, + onStashPop, + isStashPending, +}: ChangesHeaderProps) { return (
- {/* Row 1: Base branch */}
Base: - {isLoading || !branchData ? ( - - {effectiveBaseBranch} - - ) : ( - - - - Change base branch - - - )} +
- {/* Row 2: All action buttons */}
- - - - - - - - - Stash operations - - - - - - Stash Changes - - - - Stash (Include Untracked) - - - - - Pop Stash - - - + - - - - - - Refresh changes - - - {isPRLoading ? ( - - ) : pr ? ( - - - - - - #{pr.number} - - - - - View PR on GitHub - - - ) : null} + +
); From c56c1c5e1a79bd731eadf1f8093e79eabcbbb989 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 13:45:41 -0800 Subject: [PATCH 8/9] chore: remove redundant JSX comments --- .../WorkspaceView/Sidebar/ChangesView/ChangesView.tsx | 6 ------ .../components/CategorySection/CategorySection.tsx | 2 -- 2 files changed, 8 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx index 10083f917b4..07870092da5 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx @@ -385,7 +385,6 @@ export function ChangesView({
) : (
- {/* Against base branch */} - {/* Commits */} - {/* Staged */} - {/* Unstaged */} )} - {/* Discard Unstaged Confirmation Dialog */} - {/* Discard Staged Confirmation Dialog */} - {/* Section header */}
{actions}
}
- {/* Section content */} {children} From 887ed088c4174fd9e862ff2c29939f128bba2074 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Sun, 18 Jan 2026 13:50:31 -0800 Subject: [PATCH 9/9] Lint fix --- .../ChangesView/components/ChangesHeader/ChangesHeader.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx index a67b468d403..8eca56bb855 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx @@ -145,11 +145,7 @@ function StashDropdown({ ); } -function RefreshButton({ - onRefresh, -}: { - onRefresh: () => void; -}) { +function RefreshButton({ onRefresh }: { onRefresh: () => void }) { const [isSpinning, setIsSpinning] = useState(false); const timeoutRef = useRef(null);