import React, { useState, useEffect } from "react"; import { getSettings, saveSettings, getGitStatus, addFiles, pushFiles, revertFile, revertAll, deleteFile, pullBranch, getDiff, } from "../../api/api"; import SettingsModal from "./SettingsModal"; import SettingsBranchModal from "./SettingsBranchModal"; import { FileText, Code, AlertCircle, Plus, MinusCircle, Edit, GitBranch, Loader, Eye, RotateCcw, Download, ArrowDown, ArrowUp, } from "lucide-react"; import Alert from "../ui/Alert"; import CommitSection from "./CommitSection"; import Tooltip from "../ui/Tooltip"; import DiffModal from "./DiffModal"; const SettingsPage = () => { const [settings, setSettings] = useState(null); const [status, setStatus] = useState(null); const [showModal, setShowModal] = useState(false); const [showBranchModal, setShowBranchModal] = useState(false); const [loadingAction, setLoadingAction] = useState(""); const [loadingStatus, setLoadingStatus] = useState(true); const [commitMessage, setCommitMessage] = useState(""); const [selectedIncomingChanges, setSelectedIncomingChanges] = useState([]); const [showDiffModal, setShowDiffModal] = useState(false); const [diffContent, setDiffContent] = useState(""); const [currentChange, setCurrentChange] = useState(null); const [loadingDiff, setLoadingDiff] = useState(false); useEffect(() => { fetchSettings(); }, []); const fetchSettings = async () => { try { const fetchedSettings = await getSettings(); if (fetchedSettings) { setSettings(fetchedSettings); await fetchGitStatus(); } else { setShowModal(true); } } catch (error) { console.error("Error fetching settings:", error); } }; const handleSaveSettings = async (newSettings) => { try { setLoadingAction("save_settings"); // Set a loading state if needed const response = await saveSettings(newSettings); if (response) { setSettings(response); // Update the settings in the state Alert.success("Settings saved successfully!"); await fetchGitStatus(); // Optionally refresh the Git status after saving } else { Alert.error("Failed to save settings. Please try again."); } } catch (error) { Alert.error("An unexpected error occurred while saving the settings."); console.error("Error saving settings:", error); } finally { setLoadingAction(""); // Reset the loading state setShowModal(false); // Close the modal after saving } }; const fetchGitStatus = async () => { setLoadingStatus(true); try { const result = await getGitStatus(); console.log("================ Git Status Response ================"); console.log(JSON.stringify(result, null, 2)); console.log("======================================================"); if (result.success) { setStatus({ ...result.data, outgoing_changes: Array.isArray(result.data.outgoing_changes) ? result.data.outgoing_changes : [], incoming_changes: Array.isArray(result.data.incoming_changes) ? result.data.incoming_changes : [], }); } } catch (error) { console.error("Error fetching Git status:", error); Alert.error("Failed to fetch Git status"); } finally { setLoadingStatus(false); } }; const renderChangeTable = (changes, title, icon, isIncoming) => (

{icon} {title} ({changes.length})

{isIncoming && ( )} {isIncoming && ( )} {changes.map((change, index) => ( handleSelectChange(change.file_path)} > {isIncoming && ( )} {isIncoming && ( )} ))}
Status Type Name Actions Select
{getStatusIcon(change.status)} {change.staged ? `${change.status} (Staged)` : change.status}
{getTypeIcon(change.type)} {change.type}
{change.name || "Unnamed"} e.stopPropagation()} />
{isIncoming && changes.length > 0 && (
)}
); const handleViewDiff = async (change) => { setLoadingDiff(true); // Start loading try { const response = await getDiff(change.file_path); if (response.success) { setDiffContent(response.diff); // Store the diff content setCurrentChange(change); // Set the current change being viewed setShowDiffModal(true); // Open the modal } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while fetching the diff."); console.error("Error fetching diff:", error); } finally { setLoadingDiff(false); // Stop loading setLoadingAction(""); } }; const handleAddFile = async (filePath) => { setLoadingAction(`add-${filePath}`); try { const response = await addFiles([filePath]); if (response.success) { await fetchGitStatus(); // Refresh status Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while adding the file."); console.error("Error adding untracked file:", error); } finally { setLoadingAction(""); } }; const handleStageAll = async () => { const unstagedChanges = status.outgoing_changes.filter( (change) => !change.staged || (change.staged && change.modified) ); if (unstagedChanges.length === 0) { Alert.warning("There are no changes to stage."); return; } setLoadingAction("stage_all"); try { const response = await addFiles([]); if (response.success) { await fetchGitStatus(); Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while staging files."); console.error("Error staging files:", error); } finally { setLoadingAction(""); } }; const handleCommitAll = async () => { if ( !status.outgoing_changes || !status.outgoing_changes.some((change) => change.staged) ) { Alert.warning("There are no staged changes to commit."); return; } if (!commitMessage.trim()) { Alert.warning("Please enter a commit message."); return; } setLoadingAction("commit_all"); try { const stagedFiles = status.outgoing_changes .filter((change) => change.staged) .map((change) => change.file_path); const response = await pushFiles(stagedFiles, commitMessage); if (response.success) { await fetchGitStatus(); setCommitMessage(""); Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while committing files."); console.error("Error committing files:", error); } finally { setLoadingAction(""); } }; const handleRevertFile = async (filePath) => { const fileToRevert = status.changes.find( (change) => change.file_path === filePath ); const isDeletedFile = fileToRevert && fileToRevert.status.includes("Deleted"); if ( !fileToRevert || (!fileToRevert.staged && !fileToRevert.modified && !isDeletedFile) ) { Alert.warning("There is nothing to revert for this file."); return; } setLoadingAction(`revert-${filePath}`); try { const response = await revertFile(filePath); if (response.success) { await fetchGitStatus(); Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while reverting the file."); console.error("Error reverting file:", error); } finally { setLoadingAction(""); } }; const handleRevertAll = async () => { const hasChangesToRevert = status.changes.some( (change) => change.staged || change.modified ); if (!hasChangesToRevert) { Alert.warning("There are no changes to revert."); return; } setLoadingAction("revert_all"); try { const response = await revertAll(); if (response.success) { await fetchGitStatus(); Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while reverting all changes."); console.error("Error reverting all changes:", error); } finally { setLoadingAction(""); } }; const handleDeleteFile = async (filePath) => { setLoadingAction(`delete-${filePath}`); try { const response = await deleteFile(filePath); if (response.success) { await fetchGitStatus(); // Refresh the status after deletion Alert.success(`File ${filePath} has been deleted.`); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while deleting the file."); console.error("Error deleting file:", error); } finally { setLoadingAction(""); } }; const handlePullSelectedChanges = async () => { if (selectedIncomingChanges.length === 0) { Alert.warning("Please select at least one change to pull."); return; } setLoadingAction("pull_changes"); try { // You would need to update your backend to handle pulling specific files const response = await pullBranch(status.branch, selectedIncomingChanges); if (response.success) { await fetchGitStatus(); setSelectedIncomingChanges([]); // Clear the selected changes after pulling Alert.success(response.message); } else { Alert.error(response.error); } } catch (error) { Alert.error("An unexpected error occurred while pulling changes."); console.error("Error pulling changes:", error); } finally { setLoadingAction(""); } }; const handleSelectChange = (filePath) => { setSelectedIncomingChanges((prevSelected) => { if (prevSelected.includes(filePath)) { return prevSelected.filter((path) => path !== filePath); } else { return [...prevSelected, filePath]; } }); }; const getActionButton = (change) => { if (change.status === "Untracked") { return ( ); } else { return ( ); } }; const loadingMessages = [ "Checking for changes... don't blink!", "Syncing with the mothership...", "Peeking under the hood...", "Counting bits and bytes...", "Scanning for modifications...", "Looking for new stuff...", "Comparing local and remote...", "Checking your project's pulse...", "Analyzing your code's mood...", "Reading the project's diary...", ]; const getRandomLoadingMessage = () => { return loadingMessages[Math.floor(Math.random() * loadingMessages.length)]; }; const getStatusIcon = (status) => { switch (status) { case "Untracked": return ; case "Staged (New)": return ; case "Staged (Modified)": case "Modified": return ; case "Deleted": return ; case "Deleted (Staged)": return ; case "Renamed": return ; default: return ; } }; const getTypeIcon = (type) => { switch (type) { case "Regex Pattern": return ; case "Custom Format": return ; default: return ; } }; return (

Git Repository Settings

{settings && (

Connected Repository

{settings.gitRepo}

Git Status

{loadingStatus ? (
{getRandomLoadingMessage()}
) : ( status && ( <>
Current Branch: {status.branch}
{status.incoming_changes.length > 0 && renderChangeTable( status.incoming_changes, "Incoming Changes", , true )} {status.outgoing_changes.length > 0 && renderChangeTable( status.outgoing_changes, "Outgoing Changes", , false )} 0} /> ) )}
)} setShowModal(false)} onSave={(newSettings) => handleSaveSettings(newSettings)} /> {settings && status && ( setShowBranchModal(false)} repoUrl={settings.gitRepo} currentBranch={status.branch} onBranchChange={fetchGitStatus} /> )} {showDiffModal && currentChange && ( setShowDiffModal(false)} diffContent={diffContent} type={currentChange.type} name={currentChange.name} commitMessage={currentChange.commit_message} /> )}
); }; export default SettingsPage;