diff --git a/src/components/GitPanel.jsx b/src/components/GitPanel.jsx
index 8dc9118..57b4fa2 100755
--- a/src/components/GitPanel.jsx
+++ b/src/components/GitPanel.jsx
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef } from 'react';
-import { GitBranch, GitCommit, Plus, Minus, RefreshCw, Check, X, ChevronDown, ChevronRight, Info, History, FileText, Mic, MicOff, Sparkles, Download, RotateCcw, Trash2, AlertTriangle } from 'lucide-react';
+import { GitBranch, GitCommit, Plus, Minus, RefreshCw, Check, X, ChevronDown, ChevronRight, Info, History, FileText, Mic, MicOff, Sparkles, Download, RotateCcw, Trash2, AlertTriangle, Upload } from 'lucide-react';
import { MicButton } from './MicButton.jsx';
import { authenticatedFetch } from '../utils/api';
@@ -27,8 +27,9 @@ function GitPanel({ selectedProject, isMobile }) {
const [remoteStatus, setRemoteStatus] = useState(null);
const [isFetching, setIsFetching] = useState(false);
const [isPulling, setIsPulling] = useState(false);
+ const [isPushing, setIsPushing] = useState(false);
const [isCommitAreaCollapsed, setIsCommitAreaCollapsed] = useState(isMobile); // Collapsed by default on mobile
- const [confirmAction, setConfirmAction] = useState(null); // { type: 'discard|commit|pull', file?: string, message?: string }
+ const [confirmAction, setConfirmAction] = useState(null); // { type: 'discard|commit|pull|push', file?: string, message?: string }
const textareaRef = useRef(null);
const dropdownRef = useRef(null);
@@ -238,6 +239,33 @@ function GitPanel({ selectedProject, isMobile }) {
}
};
+ const handlePush = async () => {
+ setIsPushing(true);
+ try {
+ const response = await authenticatedFetch('/api/git/push', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ project: selectedProject.name
+ })
+ });
+
+ const data = await response.json();
+ if (data.success) {
+ // Refresh status after successful push
+ fetchGitStatus();
+ fetchRemoteStatus();
+ } else {
+ console.error('Push failed:', data.error);
+ // TODO: Show user-friendly error message
+ }
+ } catch (error) {
+ console.error('Error pushing to remote:', error);
+ } finally {
+ setIsPushing(false);
+ }
+ };
+
const discardChanges = async (filePath) => {
try {
const response = await authenticatedFetch('/api/git/discard', {
@@ -283,6 +311,9 @@ function GitPanel({ selectedProject, isMobile }) {
case 'pull':
await handlePull();
break;
+ case 'push':
+ await handlePush();
+ break;
}
} catch (error) {
console.error(`Error executing ${type}:`, error);
@@ -702,6 +733,22 @@ function GitPanel({ selectedProject, isMobile }) {
)}
+ {/* Push button - show when ahead (primary action when ahead only) */}
+ {remoteStatus.ahead > 0 && (
+
+ )}
+
{/* Fetch button - show when ahead only or when diverged (secondary action) */}
{(remoteStatus.ahead > 0 || (remoteStatus.behind > 0 && remoteStatus.ahead > 0)) && (