Skip to content

Commit ebf9bd5

Browse files
authored
Merge pull request #56 from beNative/codex/add-history-and-branches-tabs-for-svn
Enable SVN support for edit repository history and branches
2 parents eb1778b + e1c213e commit ebf9bd5

1 file changed

Lines changed: 75 additions & 40 deletions

File tree

components/modals/RepoFormModal.tsx

Lines changed: 75 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,9 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
17051705
const formLabelStyle = "block text-sm font-medium text-gray-700 dark:text-gray-300";
17061706

17071707
const isGitRepo = formData.vcs === VcsType.Git;
1708+
const isSvnRepo = formData.vcs === VcsType.Svn;
1709+
const supportsHistoryTab = isGitRepo || isSvnRepo;
1710+
const supportsBranchTab = isGitRepo || isSvnRepo;
17081711
const isGitHubRepo = useMemo(() => isGitRepo && formData.remoteUrl?.includes('github.com'), [isGitRepo, formData.remoteUrl]);
17091712

17101713
// Debounce history search
@@ -1789,7 +1792,7 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
17891792
}, [selectedBranches, branchInfo]);
17901793

17911794
const fetchHistory = useCallback(async (loadMore = false) => {
1792-
if (!repository) return;
1795+
if (!repository || !supportsHistoryTab) return;
17931796

17941797
if (loadMore) {
17951798
setIsMoreHistoryLoading(true);
@@ -1836,10 +1839,10 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
18361839
setHistoryLoading(false);
18371840
setIsMoreHistoryLoading(false);
18381841
}
1839-
}, [repository, setToast, commits.length, debouncedHistorySearch]);
1842+
}, [repository, setToast, commits.length, debouncedHistorySearch, supportsHistoryTab]);
18401843

18411844
const fetchBranches = useCallback(async () => {
1842-
if (!repository || !isGitRepo) return;
1845+
if (!repository || !supportsBranchTab) return;
18431846
setBranchesLoading(true);
18441847
try {
18451848
const branches = await window.electronAPI?.listBranches({ repoPath: repository.localPath, vcs: repository.vcs });
@@ -1868,7 +1871,7 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
18681871
} finally {
18691872
setBranchesLoading(false);
18701873
}
1871-
}, [repository, isGitRepo, setToast]);
1874+
}, [repository, supportsBranchTab, setToast]);
18721875

18731876
const fetchReleases = useCallback(async () => {
18741877
if (!repository || !isGitHubRepo) return;
@@ -1896,7 +1899,7 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
18961899

18971900
// Fetch branch info on mount for the dropdown if possible
18981901
useEffect(() => {
1899-
if (repository?.localPath && isGitRepo) {
1902+
if (repository?.localPath && supportsBranchTab) {
19001903
if (branchInfo) return; // Don't re-fetch if we already have the info.
19011904
const checkPathAndFetch = async () => {
19021905
const pathState = await window.electronAPI?.checkLocalPath(repository.localPath);
@@ -1906,13 +1909,13 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
19061909
};
19071910
checkPathAndFetch();
19081911
}
1909-
}, [repository, isGitRepo, fetchBranches, branchInfo]);
1912+
}, [repository, supportsBranchTab, fetchBranches, branchInfo]);
19101913

19111914
// Fetch data when a tab becomes active or search term changes
19121915
useEffect(() => {
1913-
if (activeTab === 'history') {
1916+
if (activeTab === 'history' && supportsHistoryTab) {
19141917
fetchHistory(false);
1915-
} else if (activeTab === 'branches') {
1918+
} else if (activeTab === 'branches' && supportsBranchTab) {
19161919
if (!branchInfo) {
19171920
fetchBranches();
19181921
}
@@ -2116,6 +2119,10 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
21162119

21172120
const handleCreateBranch = async () => {
21182121
if (!repository || !newBranchName.trim()) return;
2122+
if (!isGitRepo) {
2123+
setToast({ message: 'Branch creation is only supported for Git repositories.', type: 'info' });
2124+
return;
2125+
}
21192126
const result = await window.electronAPI?.createBranch(repository.localPath, newBranchName.trim());
21202127
if (result?.success) {
21212128
setToast({ message: `Branch '${newBranchName.trim()}' created`, type: 'success' });
@@ -2129,6 +2136,10 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
21292136

21302137
const handleDeleteBranch = async (branchIdentifier: string, scope: 'local' | 'remote') => {
21312138
if (!repository) return;
2139+
if (!isGitRepo) {
2140+
setToast({ message: 'Branch deletion is only supported for Git repositories.', type: 'info' });
2141+
return;
2142+
}
21322143
const isRemote = scope === 'remote';
21332144
const remoteDetails = isRemote ? parseRemoteBranchIdentifier(branchIdentifier) : null;
21342145
const branchLabel = formatBranchSelectionLabel(branchIdentifier, scope);
@@ -2173,6 +2184,11 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
21732184
return;
21742185
}
21752186

2187+
if (!isGitRepo) {
2188+
setToast({ message: 'Bulk branch deletion is only supported for Git repositories.', type: 'info' });
2189+
return;
2190+
}
2191+
21762192
const currentBranch = branchInfo?.current;
21772193
let skippedCurrentCount = 0;
21782194
let skippedProtectedCount = 0;
@@ -2290,10 +2306,14 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
22902306
}
22912307
}
22922308
});
2293-
}, [repository, selectedBranches, branchInfo?.current, confirmAction, setToast, fetchBranches, onRefreshState]);
2309+
}, [repository, selectedBranches, branchInfo?.current, confirmAction, setToast, fetchBranches, onRefreshState, isGitRepo]);
22942310

22952311
const handleMergeBranch = async () => {
22962312
if (!repository || !branchToMerge) return;
2313+
if (!isGitRepo) {
2314+
setToast({ message: 'Branch merging is only supported for Git repositories.', type: 'info' });
2315+
return;
2316+
}
22972317
const currentBranch = branchInfo?.current;
22982318
if (!currentBranch || branchToMerge === currentBranch) {
22992319
setToast({ message: 'Cannot merge a branch into itself.', type: 'info' });
@@ -2626,6 +2646,9 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
26262646
</div>
26272647
);
26282648
case 'history':
2649+
if (!supportsHistoryTab) {
2650+
return <div className="p-4 text-center text-gray-500">History is only available for Git or SVN repositories.</div>;
2651+
}
26292652
return (
26302653
<div className="p-4 space-y-3 flex flex-col overflow-hidden h-full">
26312654
<div className="relative flex-shrink-0">
@@ -2664,6 +2687,9 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
26642687
</div>
26652688
);
26662689
case 'branches': {
2690+
if (!supportsBranchTab) {
2691+
return <div className="p-4 text-center text-gray-500">Branch management is only available for Git or SVN repositories.</div>;
2692+
}
26672693
const selectedBranchCount = selectedBranches.length;
26682694
const selectedLocalCount = selectedBranches.filter(selection => selection.scope === 'local').length;
26692695
const selectedRemoteCount = selectedBranchCount - selectedLocalCount;
@@ -2777,7 +2803,7 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
27772803
{isCurrent && <span className="text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 dark:bg-blue-900/60 dark:text-blue-200">Current</span>}
27782804
{isProtectedLocal && <span className="text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-200">Protected</span>}
27792805
</div>
2780-
{!isCurrent && !isProtectedLocal && (
2806+
{!isCurrent && !isProtectedLocal && isGitRepo && (
27812807
<button
27822808
type="button"
27832809
onClick={(event) => {
@@ -2818,7 +2844,7 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
28182844
</span>
28192845
{isProtectedRemote && <span className="text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-200">Protected</span>}
28202846
</div>
2821-
{!isProtectedRemote && (
2847+
{!isProtectedRemote && isGitRepo && (
28222848
<button
28232849
type="button"
28242850
onClick={(event) => {
@@ -2841,15 +2867,17 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
28412867
<div className="flex flex-wrap items-center justify-between gap-3">
28422868
<p className="text-sm text-gray-600 dark:text-gray-300">{selectionDescription}</p>
28432869
<div className="flex flex-wrap items-center gap-2">
2844-
<button
2845-
type="button"
2846-
onClick={handleBulkDeleteSelectedBranches}
2847-
disabled={bulkDeleteDisabled}
2848-
title={bulkDeleteTitle}
2849-
className={`px-4 py-2 rounded-md text-sm font-medium text-white bg-red-600 hover:bg-red-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 disabled:bg-gray-400 disabled:cursor-not-allowed ${isDeletingBranches ? 'cursor-wait' : ''}`}
2850-
>
2851-
{isDeletingBranches ? 'Deleting…' : 'Delete Selected'}
2852-
</button>
2870+
{isGitRepo && (
2871+
<button
2872+
type="button"
2873+
onClick={handleBulkDeleteSelectedBranches}
2874+
disabled={bulkDeleteDisabled}
2875+
title={bulkDeleteTitle}
2876+
className={`px-4 py-2 rounded-md text-sm font-medium text-white bg-red-600 hover:bg-red-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 disabled:bg-gray-400 disabled:cursor-not-allowed ${isDeletingBranches ? 'cursor-wait' : ''}`}
2877+
>
2878+
{isDeletingBranches ? 'Deleting…' : 'Delete Selected'}
2879+
</button>
2880+
)}
28532881
<button
28542882
type="button"
28552883
onClick={handleCheckoutBranch}
@@ -2860,27 +2888,34 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
28602888
</button>
28612889
</div>
28622890
</div>
2863-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
2864-
<div>
2865-
<h4 className="font-semibold mb-2">Create New Branch</h4>
2866-
<div className="flex gap-2">
2867-
<input type="text" value={newBranchName} onChange={e => setNewBranchName(e.target.value)} placeholder="new-branch-name" className={formInputStyle}/>
2868-
<button type="button" onClick={handleCreateBranch} className="px-4 py-2 bg-green-600 text-white rounded-md text-sm font-medium hover:bg-green-700">Create</button>
2891+
{isSvnRepo && (
2892+
<p className="text-xs text-gray-500 dark:text-gray-400">
2893+
Branch creation, deletion, and merging are currently only available for Git repositories.
2894+
</p>
2895+
)}
2896+
{isGitRepo && (
2897+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
2898+
<div>
2899+
<h4 className="font-semibold mb-2">Create New Branch</h4>
2900+
<div className="flex gap-2">
2901+
<input type="text" value={newBranchName} onChange={e => setNewBranchName(e.target.value)} placeholder="new-branch-name" className={formInputStyle}/>
2902+
<button type="button" onClick={handleCreateBranch} className="px-4 py-2 bg-green-600 text-white rounded-md text-sm font-medium hover:bg-green-700">Create</button>
2903+
</div>
28692904
</div>
2870-
</div>
2871-
<div>
2872-
<h4 className="font-semibold mb-2">Merge Branch into Current</h4>
2873-
<div className="flex gap-2">
2874-
<select value={branchToMerge || ''} onChange={e => setBranchToMerge(e.target.value)} className={formInputStyle}>
2875-
<option value="" disabled>Select a branch</option>
2876-
{(branchInfo?.local || []).filter(b => b !== branchInfo?.current).map(b => (
2877-
<option key={b} value={b}>{b}</option>
2878-
))}
2879-
</select>
2880-
<button type="button" onClick={handleMergeBranch} className="px-4 py-2 bg-indigo-600 text-white rounded-md text-sm font-medium hover:bg-indigo-700">Merge</button>
2905+
<div>
2906+
<h4 className="font-semibold mb-2">Merge Branch into Current</h4>
2907+
<div className="flex gap-2">
2908+
<select value={branchToMerge || ''} onChange={e => setBranchToMerge(e.target.value)} className={formInputStyle}>
2909+
<option value="" disabled>Select a branch</option>
2910+
{(branchInfo?.local || []).filter(b => b !== branchInfo?.current).map(b => (
2911+
<option key={b} value={b}>{b}</option>
2912+
))}
2913+
</select>
2914+
<button type="button" onClick={handleMergeBranch} className="px-4 py-2 bg-indigo-600 text-white rounded-md text-sm font-medium hover:bg-indigo-700">Merge</button>
2915+
</div>
28812916
</div>
28822917
</div>
2883-
</div>
2918+
)}
28842919
</div>
28852920
</div>
28862921
)}
@@ -3214,8 +3249,8 @@ const RepoEditView: React.FC<RepoEditViewProps> = ({ onSave, onCancel, repositor
32143249
<div className="flex-shrink-0 border-b border-gray-200 dark:border-gray-700">
32153250
<nav className="-mb-px flex space-x-4 px-4">
32163251
<button onClick={() => setActiveTab('tasks')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'tasks' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>Tasks</button>
3217-
{isGitRepo && <button onClick={() => setActiveTab('history')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'history' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>History</button>}
3218-
{isGitRepo && <button onClick={() => setActiveTab('branches')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'branches' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>Branches</button>}
3252+
{supportsHistoryTab && <button onClick={() => setActiveTab('history')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'history' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>History</button>}
3253+
{supportsBranchTab && <button onClick={() => setActiveTab('branches')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'branches' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>Branches</button>}
32193254
{isGitRepo && <button onClick={() => setActiveTab('releases')} className={`whitespace-nowrap py-3 px-1 border-b-2 font-medium text-sm ${activeTab === 'releases' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'}`}>Releases</button>}
32203255
</nav>
32213256
</div>

0 commit comments

Comments
 (0)