mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-29 22:10:52 +01:00
feat: overhaul branch modal design
This commit is contained in:
@@ -13,7 +13,8 @@ import {
|
||||
GitBranchPlus,
|
||||
ArrowRightCircle,
|
||||
Loader,
|
||||
CloudUpload
|
||||
CloudUpload,
|
||||
Search
|
||||
} from 'lucide-react';
|
||||
import Tooltip from '../ui/Tooltip';
|
||||
import Alert from '../ui/Alert';
|
||||
@@ -27,6 +28,8 @@ const SettingsBranchModal = ({
|
||||
isDevMode
|
||||
}) => {
|
||||
const [branches, setBranches] = useState([]);
|
||||
const [filteredBranches, setFilteredBranches] = useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [branchOffMode, setBranchOffMode] = useState(null);
|
||||
const [newBranchName, setNewBranchName] = useState('');
|
||||
const [validBranchName, setValidBranchName] = useState(true);
|
||||
@@ -40,6 +43,14 @@ const SettingsBranchModal = ({
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
setFilteredBranches(
|
||||
branches.filter(branch =>
|
||||
branch.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
)
|
||||
);
|
||||
}, [branches, searchTerm]);
|
||||
|
||||
const fetchBranches = async () => {
|
||||
try {
|
||||
const response = await getBranches();
|
||||
@@ -59,6 +70,7 @@ const SettingsBranchModal = ({
|
||||
setValidBranchName(true);
|
||||
setBranchToDelete(null);
|
||||
setLoadingAction('');
|
||||
setSearchTerm('');
|
||||
};
|
||||
|
||||
const handleCheckout = async branchName => {
|
||||
@@ -200,171 +212,191 @@ const SettingsBranchModal = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} title='Manage Git Branches'>
|
||||
<div className='space-y-6 text-sm'>
|
||||
<div className='bg-gray-800 rounded-lg p-4 shadow-inner'>
|
||||
<h3 className='text-lg font-semibold mb-3 text-gray-100 border-b border-gray-700 pb-2'>
|
||||
Branches
|
||||
</h3>
|
||||
<ul className='space-y-3'>
|
||||
{branches.map((branch, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`flex items-center justify-between p-3 rounded-md transition-all duration-200 ${
|
||||
branch.name === currentBranch
|
||||
? 'bg-blue-900/30 border border-blue-500 shadow-md'
|
||||
: 'bg-gray-700 hover:bg-gray-650'
|
||||
}`}>
|
||||
<div className='flex items-center space-x-3'>
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
branch.name === currentBranch
|
||||
? 'bg-blue-400'
|
||||
: 'bg-gray-400'
|
||||
}`}></div>
|
||||
<span
|
||||
className={`font-medium ${
|
||||
branch.name === currentBranch
|
||||
? 'text-blue-200'
|
||||
: 'text-gray-200'
|
||||
}`}>
|
||||
{branch.name || 'Unknown Branch'}
|
||||
</span>
|
||||
<span className='text-xs text-gray-400'>
|
||||
{branch.isLocal && !branch.isRemote
|
||||
? '(Local)'
|
||||
: !branch.isLocal && branch.isRemote
|
||||
? '(Remote)'
|
||||
: '(Local & Remote)'}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex items-center space-x-2'>
|
||||
{branch.name !== currentBranch && (
|
||||
<Tooltip content='Checkout'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleCheckout(branch.name)
|
||||
}
|
||||
className='p-1.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 hover:scale-105 transition-all duration-200 shadow-sm'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`checkout-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`checkout-${branch.name}` ? (
|
||||
<Loader
|
||||
size={16}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<ArrowRightCircle
|
||||
size={16}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip content='Branch Off'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleBranchOffClick(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-1.5 bg-green-500 text-white rounded-md hover:bg-green-600 hover:scale-105 transition-all duration-200 shadow-sm'
|
||||
disabled={
|
||||
loadingAction === 'branchOff'
|
||||
}>
|
||||
{loadingAction === 'branchOff' ? (
|
||||
<Loader
|
||||
size={16}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<GitBranchPlus size={16} />
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
{branch.isLocal &&
|
||||
!branch.isRemote &&
|
||||
isDevMode && (
|
||||
<Tooltip content='Push to Remote'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handlePushToRemote(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-1.5 bg-purple-500 text-white rounded-md hover:bg-purple-600 hover:scale-105 transition-all duration-200 shadow-sm'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`push-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`push-${branch.name}` ? (
|
||||
<Loader
|
||||
size={16}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<CloudUpload
|
||||
size={16}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(branch.isLocal ||
|
||||
(branch.isRemote && isDevMode)) &&
|
||||
branch.name !== currentBranch &&
|
||||
branch.name.toLowerCase() !==
|
||||
'stable' && (
|
||||
<Tooltip content='Delete'>
|
||||
<button
|
||||
onClick={() =>
|
||||
confirmDeleteBranch(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-1.5 bg-red-500 text-white rounded-md hover:bg-red-600 hover:scale-105 transition-all duration-200 shadow-sm'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`delete-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`delete-${branch.name}` ? (
|
||||
<Loader
|
||||
size={16}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<Trash2 size={16} />
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
title='Manage Git Branches'
|
||||
size='4xl'>
|
||||
<div className='space-y-6'>
|
||||
<div className='bg-gray-100 dark:bg-gray-800 rounded-lg p-4'>
|
||||
<div className='relative mb-4'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='Search branches...'
|
||||
value={searchTerm}
|
||||
onChange={e => setSearchTerm(e.target.value)}
|
||||
className='w-full pl-10 pr-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400'
|
||||
/>
|
||||
<Search className='absolute left-3 top-2.5 h-5 w-5 text-gray-400 dark:text-gray-500' />
|
||||
</div>
|
||||
|
||||
{branch.isRemote && (
|
||||
<Tooltip content='View on GitHub'>
|
||||
<div className='overflow-visible'>
|
||||
<ul className='space-y-2'>
|
||||
{filteredBranches.map((branch, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`flex items-center justify-between p-4 rounded-lg transition-colors ${
|
||||
branch.name === currentBranch
|
||||
? 'bg-blue-100 dark:bg-blue-900/50'
|
||||
: 'hover:bg-gray-200 dark:hover:bg-gray-700'
|
||||
}`}>
|
||||
<div className='flex items-center space-x-3'>
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full ${
|
||||
branch.name === currentBranch
|
||||
? 'bg-blue-500'
|
||||
: 'bg-gray-400 dark:bg-gray-500'
|
||||
}`}></div>
|
||||
<span
|
||||
className={`font-medium ${
|
||||
branch.name === currentBranch
|
||||
? 'text-blue-700 dark:text-blue-300'
|
||||
: 'text-gray-700 dark:text-gray-200'
|
||||
}`}>
|
||||
{branch.name || 'Unknown Branch'}
|
||||
</span>
|
||||
<span className='text-xs text-gray-500 dark:text-gray-400'>
|
||||
{branch.isLocal && !branch.isRemote
|
||||
? '(Local)'
|
||||
: !branch.isLocal &&
|
||||
branch.isRemote
|
||||
? '(Remote)'
|
||||
: '(Local & Remote)'}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex items-center space-x-2'>
|
||||
{/* Keep existing buttons with updated styles */}
|
||||
{branch.name !== currentBranch && (
|
||||
<Tooltip content='Checkout'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleCheckout(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-3 text-blue-600 dark:text-blue-400 hover:bg-blue-200 dark:hover:bg-blue-800 rounded-full transition-colors'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`checkout-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`checkout-${branch.name}` ? (
|
||||
<Loader
|
||||
size={20}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<ArrowRightCircle
|
||||
size={20}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip content='Branch Off'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleOpenInGitHub(
|
||||
handleBranchOffClick(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-1.5 bg-gray-600 text-white rounded-md hover:bg-gray-500 hover:scale-105 transition-all duration-200 shadow-sm'>
|
||||
<ExternalLink size={16} />
|
||||
className='p-3 text-green-600 dark:text-green-400 hover:bg-green-200 dark:hover:bg-green-800 rounded-full transition-colors'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
'branchOff'
|
||||
}>
|
||||
{loadingAction ===
|
||||
'branchOff' ? (
|
||||
<Loader
|
||||
size={20}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<GitBranchPlus size={20} />
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{branch.isLocal &&
|
||||
!branch.isRemote &&
|
||||
isDevMode && (
|
||||
<Tooltip content='Push to Remote'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handlePushToRemote(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-3 text-purple-600 dark:text-purple-400 hover:bg-purple-200 dark:hover:bg-purple-800 rounded-full transition-colors'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`push-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`push-${branch.name}` ? (
|
||||
<Loader
|
||||
size={20}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<CloudUpload
|
||||
size={20}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(branch.isLocal ||
|
||||
(branch.isRemote && isDevMode)) &&
|
||||
branch.name !== currentBranch &&
|
||||
branch.name.toLowerCase() !==
|
||||
'stable' && (
|
||||
<Tooltip content='Delete'>
|
||||
<button
|
||||
onClick={() =>
|
||||
confirmDeleteBranch(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-3 text-red-600 dark:text-red-400 hover:bg-red-200 dark:hover:bg-red-800 rounded-full transition-colors'
|
||||
disabled={
|
||||
loadingAction ===
|
||||
`delete-${branch.name}`
|
||||
}>
|
||||
{loadingAction ===
|
||||
`delete-${branch.name}` ? (
|
||||
<Loader
|
||||
size={20}
|
||||
className='animate-spin'
|
||||
/>
|
||||
) : (
|
||||
<Trash2 size={20} />
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{branch.isRemote && (
|
||||
<Tooltip content='View on GitHub'>
|
||||
<button
|
||||
onClick={() =>
|
||||
handleOpenInGitHub(
|
||||
branch.name
|
||||
)
|
||||
}
|
||||
className='p-3 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full transition-colors'>
|
||||
<ExternalLink size={20} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{branchOffMode && (
|
||||
<div className='bg-gray-700 p-4 rounded-lg shadow-md'>
|
||||
<h4 className='text-sm font-semibold mb-2 text-gray-200'>
|
||||
<div className='bg-gray-100 dark:bg-gray-800 p-4 rounded-lg shadow-md'>
|
||||
<h4 className='text-lg font-semibold mb-2 text-gray-800 dark:text-gray-200'>
|
||||
Create New Branch
|
||||
</h4>
|
||||
<div className='flex items-center space-x-2'>
|
||||
@@ -375,11 +407,11 @@ const SettingsBranchModal = ({
|
||||
validateBranchName(e.target.value)
|
||||
}
|
||||
placeholder={`New branch from ${branchOffMode}`}
|
||||
className={`flex-grow p-2 border rounded bg-gray-800 text-gray-300 focus:ring-2 focus:ring-blue-500 transition-all ${
|
||||
className={`flex-grow p-2 rounded-lg border ${
|
||||
!validBranchName
|
||||
? 'border-red-500'
|
||||
: 'border-gray-600'
|
||||
}`}
|
||||
? 'border-red-500 dark:border-red-400'
|
||||
: 'border-gray-300 dark:border-gray-600'
|
||||
} bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400`}
|
||||
/>
|
||||
<button
|
||||
onClick={handleBranchOff}
|
||||
@@ -388,7 +420,7 @@ const SettingsBranchModal = ({
|
||||
!validBranchName ||
|
||||
loadingAction === 'branchOff'
|
||||
}
|
||||
className='px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors text-sm font-medium shadow-sm'>
|
||||
className='px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors text-sm font-medium shadow-sm disabled:opacity-50'>
|
||||
{loadingAction === 'branchOff'
|
||||
? 'Creating...'
|
||||
: 'Create'}
|
||||
@@ -396,14 +428,13 @@ const SettingsBranchModal = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{branchToDelete && (
|
||||
<div className='bg-red-900/30 border border-red-500 rounded-lg p-4 mt-4 text-sm text-gray-200'>
|
||||
<div className='bg-red-100 dark:bg-red-900/30 border border-red-300 dark:border-red-700 rounded-lg p-4 text-sm text-red-800 dark:text-red-200'>
|
||||
<p className='mb-3'>
|
||||
Are you sure you want to delete the branch{' '}
|
||||
<strong className='text-red-300'>
|
||||
{branchToDelete}
|
||||
</strong>
|
||||
? This action cannot be undone.
|
||||
<strong>{branchToDelete}</strong>? This action
|
||||
cannot be undone.
|
||||
</p>
|
||||
<div className='flex space-x-4'>
|
||||
<button
|
||||
@@ -411,14 +442,14 @@ const SettingsBranchModal = ({
|
||||
disabled={
|
||||
loadingAction === `delete-${branchToDelete}`
|
||||
}
|
||||
className='px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-sm font-medium shadow-sm'>
|
||||
className='px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors text-sm font-medium shadow-sm disabled:opacity-50'>
|
||||
{loadingAction === `delete-${branchToDelete}`
|
||||
? 'Deleting...'
|
||||
: 'Confirm Delete'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setBranchToDelete(null)}
|
||||
className='px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600 transition-colors text-sm font-medium shadow-sm'>
|
||||
className='px-4 py-2 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition-colors text-sm font-medium shadow-sm'>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -593,7 +593,11 @@ const SettingsPage = () => {
|
||||
<div className='max-w-4xl mx-auto mt-8 p-6 bg-gray-800 rounded-lg shadow-lg'>
|
||||
<h2 className='text-xl font-bold mb-4 text-gray-100'>
|
||||
Git Repository Settings
|
||||
<span className='ml-4 text-sm text-gray-300 mb-4'>
|
||||
{isDevMode ? 'Dev Mode: Enabled' : 'Dev Mode: Disabled'}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
{!settings && (
|
||||
<button
|
||||
onClick={() => setShowLinkModal(true)}
|
||||
@@ -862,6 +866,7 @@ const SettingsPage = () => {
|
||||
repoUrl={settings.gitRepo}
|
||||
currentBranch={status.branch}
|
||||
onBranchChange={fetchGitStatus}
|
||||
isDevMode={isDevMode}
|
||||
/>
|
||||
)}
|
||||
{showDiffModal && currentChange && (
|
||||
|
||||
Reference in New Issue
Block a user