From a6b25b4507eae6a668658b129f7df9908276db05 Mon Sep 17 00:00:00 2001 From: enesteve0 Date: Mon, 23 Mar 2026 21:41:38 +0300 Subject: [PATCH 1/6] feat: implement source control components and functionality - Added ChangeSectionHeader component for displaying section headers in the source control panel. - Introduced CommitBox component for handling commit messages and actions. - Created FileChangeRow component to represent individual file changes with actions for staging, unstaging, and discarding. - Developed SourceControlView component to manage the overall source control interface, including file status and commit actions. - Implemented git source control logic with functions for staging, unstaging, committing, and discarding changes. - Integrated AI commit message generation functionality with API interaction for generating commit messages based on diffs. - Added CSS styles for the new components and overall layout of the source control panel. - Defined GitChangeStatus and related types for managing file change states. --- .../src/SourceControl/ChangeSectionHeader.tsx | 59 +++ .../src/SourceControl/CommitBox.tsx | 105 +++++ .../src/SourceControl/FileChangeRow.tsx | 131 ++++++ .../src/SourceControl/SourceControl.css | 359 +++++++++++++++ .../src/SourceControl/SourceControlView.tsx | 421 ++++++++++++++++++ .../components/src/SourceControl/index.ts | 1 + .../packages/shared/src/git-types.ts | 19 + .../packages/shared/src/window-api.d.ts | 23 + collab-electron/src/main/ai-commit.ts | 110 +++++ .../src/main/git-source-control.ts | 314 +++++++++++++ collab-electron/src/main/index.ts | 6 +- collab-electron/src/main/ipc-git.ts | 135 ++++++ collab-electron/src/main/ipc.ts | 2 + collab-electron/src/preload/universal.ts | 26 ++ collab-electron/src/windows/nav/src/App.tsx | 97 +++- .../src/windows/settings/src/App.tsx | 172 ++++++- 16 files changed, 1975 insertions(+), 5 deletions(-) create mode 100644 collab-electron/packages/components/src/SourceControl/ChangeSectionHeader.tsx create mode 100644 collab-electron/packages/components/src/SourceControl/CommitBox.tsx create mode 100644 collab-electron/packages/components/src/SourceControl/FileChangeRow.tsx create mode 100644 collab-electron/packages/components/src/SourceControl/SourceControl.css create mode 100644 collab-electron/packages/components/src/SourceControl/SourceControlView.tsx create mode 100644 collab-electron/packages/components/src/SourceControl/index.ts create mode 100644 collab-electron/packages/shared/src/git-types.ts create mode 100644 collab-electron/src/main/ai-commit.ts create mode 100644 collab-electron/src/main/git-source-control.ts create mode 100644 collab-electron/src/main/ipc-git.ts diff --git a/collab-electron/packages/components/src/SourceControl/ChangeSectionHeader.tsx b/collab-electron/packages/components/src/SourceControl/ChangeSectionHeader.tsx new file mode 100644 index 00000000..23930893 --- /dev/null +++ b/collab-electron/packages/components/src/SourceControl/ChangeSectionHeader.tsx @@ -0,0 +1,59 @@ +import React, { useState } from 'react'; +import { + CaretDown, + Plus, + Minus, +} from '@phosphor-icons/react'; + +interface ChangeSectionHeaderProps { + title: string; + count: number; + actionIcon: 'stage' | 'unstage'; + onAction: () => void; + children: React.ReactNode; +} + +export function ChangeSectionHeader({ + title, + count, + actionIcon, + onAction, + children, +}: ChangeSectionHeaderProps) { + const [collapsed, setCollapsed] = useState(false); + + if (count === 0) return null; + + const ActionIcon = actionIcon === 'stage' ? Plus : Minus; + const actionTitle = + actionIcon === 'stage' ? 'Stage All' : 'Unstage All'; + + return ( + <> +
setCollapsed((c) => !c)} + > + + + + {title} + {count} + +
+ {!collapsed && children} + + ); +} diff --git a/collab-electron/packages/components/src/SourceControl/CommitBox.tsx b/collab-electron/packages/components/src/SourceControl/CommitBox.tsx new file mode 100644 index 00000000..aeeb6f59 --- /dev/null +++ b/collab-electron/packages/components/src/SourceControl/CommitBox.tsx @@ -0,0 +1,105 @@ +import React, { useCallback, useState } from 'react'; +import { + Check, + Sparkle, + CircleNotch, +} from '@phosphor-icons/react'; + +interface CommitBoxProps { + message: string; + onMessageChange: (message: string) => void; + hasStagedChanges: boolean; + hasApiKey: boolean; + onCommit: () => void; + onGenerateMessage: () => void; + committing: boolean; + generating: boolean; +} + +export function CommitBox({ + message, + onMessageChange, + hasStagedChanges, + hasApiKey, + onCommit, + onGenerateMessage, + committing, + generating, +}: CommitBoxProps) { + const canCommit = + hasStagedChanges && message.trim().length > 0 && !committing; + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if ( + (e.metaKey || e.ctrlKey) && + e.key === 'Enter' && + canCommit + ) { + e.preventDefault(); + onCommit(); + } + }, + [canCommit, onCommit], + ); + + return ( +
+