Skip to content
Draft
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
17 changes: 14 additions & 3 deletions apps/code/src/renderer/components/GlobalEventHandlers.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useReviewNavigationStore } from "@features/code-review/stores/reviewNavigationStore";
import { useFolders } from "@features/folders/hooks/useFolders";
import { usePanelLayoutStore } from "@features/panels/store/panelLayoutStore";
import { useRightSidebarStore } from "@features/right-sidebar";
import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore";
import { useSidebarData } from "@features/sidebar/hooks/useSidebarData";
import { useVisualTaskOrder } from "@features/sidebar/hooks/useVisualTaskOrder";
Expand Down Expand Up @@ -46,7 +46,12 @@ export function GlobalEventHandlers({
const { data: workspaces = {} } = useWorkspaces();
const clearAllLayouts = usePanelLayoutStore((state) => state.clearAllLayouts);
const toggleLeftSidebar = useSidebarStore((state) => state.toggle);
const toggleRightSidebar = useRightSidebarStore((state) => state.toggle);
const setReviewMode = useReviewNavigationStore(
(state) => state.setReviewMode,
);
const getReviewMode = useReviewNavigationStore(
(state) => state.getReviewMode,
);

const currentTaskId = view.type === "task-detail" ? view.data?.id : undefined;
const { workspace: currentWorkspace, handleToggleFocus } = useFocusWorkspace(
Expand Down Expand Up @@ -163,8 +168,14 @@ export function GlobalEventHandlers({
useHotkeys(SHORTCUTS.SETTINGS, handleOpenSettings, globalOptions);
useHotkeys(SHORTCUTS.GO_BACK, goBack, globalOptions);
useHotkeys(SHORTCUTS.GO_FORWARD, goForward, globalOptions);
const handleToggleReview = useCallback(() => {
if (!currentTaskId) return;
const mode = getReviewMode(currentTaskId);
setReviewMode(currentTaskId, mode === "closed" ? "split" : "closed");
}, [currentTaskId, getReviewMode, setReviewMode]);

useHotkeys(SHORTCUTS.TOGGLE_LEFT_SIDEBAR, toggleLeftSidebar, globalOptions);
useHotkeys(SHORTCUTS.TOGGLE_RIGHT_SIDEBAR, toggleRightSidebar, globalOptions);
useHotkeys(SHORTCUTS.TOGGLE_REVIEW_PANEL, handleToggleReview, globalOptions);
useHotkeys(SHORTCUTS.SHORTCUTS_SHEET, onToggleShortcutsSheet, globalOptions);
useHotkeys(SHORTCUTS.INBOX, navigateToInbox, globalOptions);
useHotkeys(SHORTCUTS.PREV_TASK, handlePrevTask, globalOptions, [
Expand Down
59 changes: 10 additions & 49 deletions apps/code/src/renderer/components/HeaderRow.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { DiffStatsBadge } from "@features/code-review/components/DiffStatsBadge";
import { CloudGitInteractionHeader } from "@features/git-interaction/components/CloudGitInteractionHeader";
import { GitInteractionHeader } from "@features/git-interaction/components/GitInteractionHeader";
import { RightSidebarTrigger } from "@features/right-sidebar/components/RightSidebarTrigger";
import { useRightSidebarStore } from "@features/right-sidebar/stores/rightSidebarStore";
import { SidebarTrigger } from "@features/sidebar/components/SidebarTrigger";
import { useSidebarStore } from "@features/sidebar/stores/sidebarStore";
import { useWorkspace } from "@features/workspace/hooks/useWorkspace";
Expand All @@ -24,19 +23,9 @@ export function HeaderRow() {
const isResizing = useSidebarStore((state) => state.isResizing);
const setIsResizing = useSidebarStore((state) => state.setIsResizing);

const rightSidebarOpen = useRightSidebarStore((state) => state.open);
const rightSidebarWidth = useRightSidebarStore((state) => state.width);
const rightSidebarIsResizing = useRightSidebarStore(
(state) => state.isResizing,
);
const setRightSidebarIsResizing = useRightSidebarStore(
(state) => state.setIsResizing,
);

const activeTaskId = view.type === "task-detail" ? view.data?.id : undefined;
const activeWorkspace = useWorkspace(activeTaskId);
const isCloudTask = activeWorkspace?.mode === "cloud";
const showRightSidebarSection = view.type === "task-detail";

const handleLeftSidebarMouseDown = (e: React.MouseEvent) => {
e.preventDefault();
Expand All @@ -45,13 +34,6 @@ export function HeaderRow() {
document.body.style.userSelect = "none";
};

const handleRightSidebarMouseDown = (e: React.MouseEvent) => {
e.preventDefault();
setRightSidebarIsResizing(true);
document.body.style.cursor = "col-resize";
document.body.style.userSelect = "none";
};

return (
<Flex
align="center"
Expand Down Expand Up @@ -108,45 +90,24 @@ export function HeaderRow() {
</Flex>
)}

{showRightSidebarSection && view.type === "task-detail" && view.data && (
{view.type === "task-detail" && view.data && (
<Flex
align="center"
justify={rightSidebarOpen ? "between" : "end"}
px="3"
gap="3"
pr="3"
style={{
width: rightSidebarOpen ? `${rightSidebarWidth}px` : undefined,
minWidth: rightSidebarOpen ? `${COLLAPSED_WIDTH}px` : undefined,
height: "100%",
borderLeft: "1px solid var(--gray-6)",
transition: rightSidebarIsResizing
? "none"
: "width 0.2s ease-in-out",
position: "relative",
flexShrink: 0,
}}
>
<RightSidebarTrigger />
{rightSidebarOpen &&
(isCloudTask ? (
<div className="no-drag">
{isCloudTask ? (
<CloudGitInteractionHeader taskId={view.data.id} />
) : (
<GitInteractionHeader taskId={view.data.id} />
))}
{rightSidebarOpen && (
<Box
onMouseDown={handleRightSidebarMouseDown}
className="no-drag"
style={{
position: "absolute",
left: 0,
top: 0,
bottom: 0,
width: "4px",
cursor: "col-resize",
backgroundColor: "transparent",
zIndex: 100,
}}
/>
)}
)}
</div>
<DiffStatsBadge task={view.data} />
</Flex>
)}
</Flex>
Expand Down
7 changes: 0 additions & 7 deletions apps/code/src/renderer/components/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ArchivedTasksView } from "@features/archive/components/ArchivedTasksVie
import { CommandMenu } from "@features/command/components/CommandMenu";
import { CommandCenterView } from "@features/command-center/components/CommandCenterView";
import { InboxView } from "@features/inbox/components/InboxView";
import { RightSidebar, RightSidebarContent } from "@features/right-sidebar";
import { FolderSettingsView } from "@features/settings/components/FolderSettingsView";
import { SettingsDialog } from "@features/settings/components/SettingsDialog";
import { MainSidebar } from "@features/sidebar/components/MainSidebar";
Expand Down Expand Up @@ -82,12 +81,6 @@ export function MainLayout() {

{view.type === "skills" && <SkillsView />}
</Box>

{view.type === "task-detail" && view.data && (
<RightSidebar>
<RightSidebarContent taskId={view.data.id} task={view.data} />
</RightSidebar>
)}
</Flex>

<CommandMenu open={commandMenuOpen} onOpenChange={setCommandMenuOpen} />
Expand Down
8 changes: 4 additions & 4 deletions apps/code/src/renderer/constants/keyboard-shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const SHORTCUTS = {
GO_BACK: "mod+[",
GO_FORWARD: "mod+]",
TOGGLE_LEFT_SIDEBAR: "mod+b",
TOGGLE_RIGHT_SIDEBAR: "mod+shift+b",
TOGGLE_REVIEW_PANEL: "mod+shift+b",
PREV_TASK: "mod+shift+[,ctrl+shift+tab",
NEXT_TASK: "mod+shift+],ctrl+tab",
CLOSE_TAB: "mod+w",
Expand Down Expand Up @@ -112,9 +112,9 @@ export const KEYBOARD_SHORTCUTS: KeyboardShortcut[] = [
category: "navigation",
},
{
id: "toggle-right-sidebar",
keys: SHORTCUTS.TOGGLE_RIGHT_SIDEBAR,
description: "Toggle right sidebar",
id: "toggle-review-panel",
keys: SHORTCUTS.TOGGLE_REVIEW_PANEL,
description: "Toggle review panel",
category: "navigation",
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import {
} from "./ReviewShell";

interface CloudReviewPageProps {
taskId: string;
task: Task;
}

export function CloudReviewPage({ taskId, task }: CloudReviewPageProps) {
export function CloudReviewPage({ task }: CloudReviewPageProps) {
const taskId = task.id;
const { effectiveBranch, prUrl, isRunActive, remoteFiles, isLoading } =
useCloudChangedFiles(taskId, task);
const onComment = useReviewComment(taskId);
Expand Down Expand Up @@ -64,6 +64,7 @@ export function CloudReviewPage({ taskId, task }: CloudReviewPageProps) {
return (
<ReviewShell
taskId={taskId}
task={task}
fileCount={remoteFiles.length}
linesAdded={linesAdded}
linesRemoved={linesRemoved}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { Tooltip } from "@components/ui/Tooltip";
import { useGitQueries } from "@features/git-interaction/hooks/useGitQueries";
import { computeDiffStats } from "@features/git-interaction/utils/diffStats";
import { useCwd } from "@features/sidebar/hooks/useCwd";
import { useCloudChangedFiles } from "@features/task-detail/hooks/useCloudChangedFiles";
import { useWorkspace } from "@features/workspace/hooks/useWorkspace";
import { GitDiff } from "@phosphor-icons/react";
import { Flex, Text } from "@radix-ui/themes";
import {
formatHotkey,
SHORTCUTS,
} from "@renderer/constants/keyboard-shortcuts";
import { useReviewNavigationStore } from "@renderer/features/code-review/stores/reviewNavigationStore";
import type { Task } from "@shared/types";
import { useMemo } from "react";

interface DiffStatsBadgeProps {
task: Task;
}

function useChangedFileStats(task: Task) {
const taskId = task.id;
const workspace = useWorkspace(taskId);
const isCloud =
workspace?.mode === "cloud" || task.latest_run?.environment === "cloud";
const repoPath = useCwd(taskId);

const { diffStats: localDiffStats } = useGitQueries(
isCloud ? undefined : repoPath,
);

const { changedFiles: cloudFiles } = useCloudChangedFiles(taskId, task);

return useMemo(() => {
if (isCloud) {
const stats = computeDiffStats(cloudFiles);
return {
filesChanged: stats.filesChanged,
linesAdded: stats.linesAdded,
linesRemoved: stats.linesRemoved,
};
}
return {
filesChanged: localDiffStats.filesChanged,
linesAdded: localDiffStats.linesAdded,
linesRemoved: localDiffStats.linesRemoved,
};
}, [isCloud, cloudFiles, localDiffStats]);
}

export function DiffStatsBadge({ task }: DiffStatsBadgeProps) {
const taskId = task.id;
const { filesChanged, linesAdded, linesRemoved } = useChangedFileStats(task);
const reviewMode = useReviewNavigationStore(
(s) => s.reviewModes[taskId] ?? "closed",
);
const setReviewMode = useReviewNavigationStore((s) => s.setReviewMode);

const hasChanges = filesChanged > 0;

const isOpen = reviewMode !== "closed";

const handleClick = () => {
setReviewMode(taskId, isOpen ? "closed" : "split");
};

return (
<Tooltip
content={isOpen ? "Close review panel" : "Open review panel"}
shortcut={formatHotkey(SHORTCUTS.TOGGLE_REVIEW_PANEL)}
side="bottom"
>
<button
type="button"
onClick={handleClick}
className="no-drag hover:bg-[var(--gray-a3)]"
style={{
display: "inline-flex",
alignItems: "center",
gap: "4px",
padding: "0 6px",
height: "24px",
borderRadius: "var(--radius-1)",
border: "none",
cursor: "pointer",
fontSize: "11px",
fontFamily: "var(--code-font-family)",
background: isOpen ? "var(--gray-a3)" : "transparent",
color: "var(--gray-11)",
transition: "background 0.1s",
}}
>
<GitDiff size={14} style={{ flexShrink: 0 }} />
{hasChanges ? (
<Flex align="center" gap="1">
{linesAdded > 0 && (
<Text style={{ color: "var(--green-9)", fontSize: "11px" }}>
+{linesAdded}
</Text>
)}
{linesRemoved > 0 && (
<Text style={{ color: "var(--red-9)", fontSize: "11px" }}>
-{linesRemoved}
</Text>
)}
</Flex>
) : (
<Text style={{ color: "var(--gray-9)", fontSize: "11px" }}>0</Text>
)}
</button>
</Tooltip>
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { makeFileKey } from "@features/git-interaction/utils/fileKey";
import { usePanelLayoutStore } from "@features/panels/store/panelLayoutStore";
import { isTabActiveInTree } from "@features/panels/store/panelStoreHelpers";
import { useCwd } from "@features/sidebar/hooks/useCwd";
import type { parsePatchFiles } from "@pierre/diffs";
import { Flex, Text } from "@radix-ui/themes";
import { useReviewNavigationStore } from "@renderer/features/code-review/stores/reviewNavigationStore";
import { useTRPC } from "@renderer/trpc/client";
import type { ChangedFile } from "@shared/types";
import type { ChangedFile, Task } from "@shared/types";
import { useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { useReviewComment } from "../hooks/useReviewComment";
Expand All @@ -22,17 +22,16 @@ import {
} from "./ReviewShell";

interface ReviewPageProps {
taskId: string;
task: Task;
}

export function ReviewPage({ taskId }: ReviewPageProps) {
export function ReviewPage({ task }: ReviewPageProps) {
const taskId = task.id;
const repoPath = useCwd(taskId);
const openFile = usePanelLayoutStore((s) => s.openFile);
const isReviewTabActive = usePanelLayoutStore((s) => {
const layout = s.getLayout(taskId);
if (!layout) return false;
return isTabActiveInTree(layout.panelTree, "review");
});
const isReviewOpen = useReviewNavigationStore(
(s) => (s.reviewModes[taskId] ?? "closed") !== "closed",
);
const onComment = useReviewComment(taskId);

const {
Expand All @@ -46,7 +45,7 @@ export function ReviewPage({ taskId }: ReviewPageProps) {
allPaths,
diffLoading,
refetch,
} = useReviewDiffs(repoPath, isReviewTabActive);
} = useReviewDiffs(repoPath, isReviewOpen);

const {
diffOptions,
Expand Down Expand Up @@ -86,6 +85,7 @@ export function ReviewPage({ taskId }: ReviewPageProps) {
return (
<ReviewShell
taskId={taskId}
task={task}
fileCount={totalFileCount}
linesAdded={linesAdded}
linesRemoved={linesRemoved}
Expand Down
Loading
Loading