From ad7503e34a5d42094291e7f7e399810995eaff3e Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Mon, 19 Jan 2026 13:10:44 -0800 Subject: [PATCH 1/2] Add side by side view and update UI --- .../components/DiffViewer/DiffViewer.tsx | 2 + .../TabView/FileViewerPane/FileViewerPane.tsx | 10 +-- .../FileViewerContent/FileViewerContent.tsx | 5 +- .../FileViewerToolbar/FileViewerToolbar.tsx | 65 +++++++++++++++---- .../ChangesHeader/ChangesHeader.tsx | 31 ++++++++- 5 files changed, 94 insertions(+), 19 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/ChangesContent/components/DiffViewer/DiffViewer.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/ChangesContent/components/DiffViewer/DiffViewer.tsx index 2453df26867..77175a3dfb2 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/ChangesContent/components/DiffViewer/DiffViewer.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/ChangesContent/components/DiffViewer/DiffViewer.tsx @@ -187,6 +187,7 @@ export function DiffViewer({ const diffEditor = ( s.panes[paneId]?.fileViewer); + const { viewMode: diffViewMode, setViewMode: setDiffViewMode } = + useChangesStore(); const editorRef = useRef(null); const [isDirty, setIsDirty] = useState(false); @@ -249,8 +252,6 @@ export function FileViewerPane({ const hasDraft = draftContentRef.current !== null; const isDiffEditable = (diffCategory === "staged" || diffCategory === "unstaged") && !hasDraft; - const showEditableBadge = - viewMode === "raw" || (viewMode === "diff" && isDiffEditable); return ( <> @@ -268,14 +269,14 @@ export function FileViewerPane({ ; initialLine?: number; initialColumn?: number; + diffViewMode: DiffViewMode; onSaveRaw: () => Promise; onSaveDiff?: (content: string) => Promise; onEditorChange: (value: string | undefined) => void; @@ -80,6 +82,7 @@ export function FileViewerContent({ draftContentRef, initialLine, initialColumn, + diffViewMode, onSaveRaw, onSaveDiff, onEditorChange, @@ -186,7 +189,7 @@ export function FileViewerContent({ modified: diffData.modified, language: diffData.language, }} - viewMode="inline" + viewMode={diffViewMode} filePath={filePath} editable={isDiffEditable} onSave={isDiffEditable ? onSaveDiff : undefined} diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx index e278ebb3d07..d437850f646 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx @@ -1,9 +1,12 @@ -import { Badge } from "@superset/ui/badge"; import { ToggleGroup, ToggleGroupItem } from "@superset/ui/toggle-group"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { cn } from "@superset/ui/utils"; -import { HiMiniPencil } from "react-icons/hi2"; -import { TbPinFilled } from "react-icons/tb"; +import { + TbLayoutSidebarRightFilled, + TbListDetails, + TbPinFilled, +} from "react-icons/tb"; +import type { DiffViewMode } from "shared/changes-types"; import type { FileViewerMode } from "shared/tabs-types"; import { PaneToolbarActions } from "../../../components"; import type { SplitOrientation } from "../../../hooks"; @@ -11,15 +14,15 @@ import type { SplitOrientation } from "../../../hooks"; interface FileViewerToolbarProps { fileName: string; isDirty: boolean; - isSaving: boolean; viewMode: FileViewerMode; /** If false, this is a preview pane (italic name, can be replaced) */ isPinned: boolean; isMarkdown: boolean; hasDiff: boolean; - showEditableBadge: boolean; splitOrientation: SplitOrientation; + diffViewMode: DiffViewMode; onViewModeChange: (value: string) => void; + onDiffViewModeChange: (mode: DiffViewMode) => void; onSplitPane: (e: React.MouseEvent) => void; /** Pin this pane (convert from preview to permanent) */ onPin: () => void; @@ -29,14 +32,14 @@ interface FileViewerToolbarProps { export function FileViewerToolbar({ fileName, isDirty, - isSaving, viewMode, isPinned, isMarkdown, hasDiff, - showEditableBadge, splitOrientation, + diffViewMode, onViewModeChange, + onDiffViewModeChange, onSplitPane, onPin, onClosePane, @@ -65,12 +68,6 @@ export function FileViewerToolbar({ )} - {showEditableBadge && ( - - - {isSaving ? "Saving..." : "⌘S"} - - )}
)} + {viewMode === "diff" && ( +
+ + + + + + Inline diff + + + + + + + + Side by side + + +
+ )}
@@ -238,6 +241,32 @@ export function ChangesHeader({ Base: +
+ + + + + + Expand sidebar + + + + + + + + Close sidebar + +
From 986b5e95227fc6d6daab77e389575e85b302bac2 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Mon, 19 Jan 2026 13:34:16 -0800 Subject: [PATCH 2/2] Merge --- .../MergedPortBadge/MergedPortBadge.tsx | 2 +- .../WorkspacePortGroup/WorkspacePortGroup.tsx | 2 +- .../TabView/FileViewerPane/FileViewerPane.tsx | 2 + .../FileViewerToolbar/FileViewerToolbar.tsx | 62 +++++++------------ .../hooks/useFileContent/useFileContent.ts | 2 +- 5 files changed, 28 insertions(+), 42 deletions(-) diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/MergedPortBadge/MergedPortBadge.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/MergedPortBadge/MergedPortBadge.tsx index ca14cda322b..6162cd84ce6 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/MergedPortBadge/MergedPortBadge.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/MergedPortBadge/MergedPortBadge.tsx @@ -81,7 +81,7 @@ export function MergedPortBadge({ port }: MergedPortBadgeProps) { type="button" onClick={handleClose} aria-label={`Close ${port.label || `port ${port.port}`}`} - className="opacity-0 group-hover:opacity-100 pr-1 transition-opacity text-muted-foreground hover:text-destructive focus-visible:opacity-100 focus-visible:outline-none" + className="opacity-0 group-hover:opacity-100 pr-1 transition-opacity text-muted-foreground hover:text-primary focus-visible:opacity-100 focus-visible:outline-none" > diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/WorkspacePortGroup/WorkspacePortGroup.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/WorkspacePortGroup/WorkspacePortGroup.tsx index 2079ff93e2b..e0ae493fc74 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/WorkspacePortGroup/WorkspacePortGroup.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/components/WorkspacePortGroup/WorkspacePortGroup.tsx @@ -41,7 +41,7 @@ export function WorkspacePortGroup({ group }: WorkspacePortGroupProps) { diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/FileViewerPane.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/FileViewerPane.tsx index 1b387fe1298..1939454f967 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/FileViewerPane.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/FileViewerPane.tsx @@ -120,6 +120,8 @@ export function FileViewerPane({ useEffect(() => { setIsDirty(false); originalContentRef.current = ""; + originalDiffContentRef.current = ""; + currentDiffContentRef.current = ""; draftContentRef.current = null; }, [filePath]); diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx index d437850f646..e6868ec6239 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerToolbar/FileViewerToolbar.tsx @@ -95,46 +95,30 @@ export function FileViewerToolbar({ )} {viewMode === "diff" && ( -
- - - - - - Inline diff - - - - - - - - Side by side - - -
+ ) : ( + + )} + + + + {diffViewMode === "side-by-side" + ? "Switch to inline diff" + : "Switch to side by side diff"} + + )} { - if (diffData?.modified && !isDirty) { + if (diffData && !isDirty) { originalDiffContentRef.current = diffData.modified; } }, [diffData]);