feat: Add button visibility depending on various factors - dev mode hide stage / commit - buttons show tooltips / are greyed out when they cant be clicked

This commit is contained in:
Sam Chau
2024-09-19 09:46:39 +09:30
parent 8df03175a2
commit daa3a70c2c
3 changed files with 164 additions and 142 deletions

View File

@@ -2,6 +2,37 @@ import React from 'react';
import {Loader, RotateCcw, Download, CheckCircle, Plus} from 'lucide-react';
import Tooltip from '../../ui/Tooltip';
const ActionButton = ({
onClick,
disabled,
loading,
icon,
text,
className,
disabledTooltip
}) => {
const baseClassName =
'flex items-center px-4 py-2 text-white rounded-md transition-all duration-200 ease-in-out text-xs';
const enabledClassName = `${baseClassName} ${className} hover:opacity-80`;
const disabledClassName = `${baseClassName} ${className} opacity-50 cursor-not-allowed`;
return (
<Tooltip content={disabled ? disabledTooltip : text}>
<button
onClick={onClick}
className={disabled ? disabledClassName : enabledClassName}
disabled={disabled || loading}>
{loading ? (
<Loader size={12} className='animate-spin mr-1' />
) : (
React.cloneElement(icon, {className: 'mr-1', size: 12})
)}
{text}
</button>
</Tooltip>
);
};
const ActionButtons = ({
isDevMode,
selectedOutgoingChanges,
@@ -12,106 +43,67 @@ const ActionButtons = ({
onStageSelected,
onCommitSelected,
onRevertSelected,
onPullSelected,
getStageButtonTooltip,
getCommitButtonTooltip,
getRevertButtonTooltip
onPullSelected
}) => {
const canStage =
isDevMode &&
selectedOutgoingChanges.length > 0 &&
selectionType !== 'staged';
const canCommit =
isDevMode &&
selectedOutgoingChanges.length > 0 &&
commitMessage.trim() &&
selectionType !== 'unstaged';
const canRevert = selectedOutgoingChanges.length > 0;
const canPull = selectedIncomingChanges.length > 0;
return (
<div className='mt-4 flex justify-end space-x-2'>
<div className='mt-4 flex justify-start space-x-2'>
{isDevMode && (
<>
{/* Stage */}
{selectedOutgoingChanges.length > 0 &&
selectionType !== 'staged' && (
<Tooltip content={getStageButtonTooltip()}>
<button
onClick={() =>
onStageSelected(selectedOutgoingChanges)
}
className='flex items-center px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors duration-200 ease-in-out text-xs'
disabled={
loadingAction === 'stage_selected'
}>
{loadingAction === 'stage_selected' ? (
<Loader
size={12}
className='animate-spin'
/>
) : (
<Plus className='mr-1' size={12} />
)}
Stage Selected
</button>
</Tooltip>
)}
{/* Commit */}
{selectedOutgoingChanges.length > 0 &&
commitMessage.trim() &&
selectionType !== 'unstaged' && (
<Tooltip content={getCommitButtonTooltip()}>
<button
onClick={() =>
onCommitSelected(
selectedOutgoingChanges,
commitMessage
)
}
className='flex items-center px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors duration-200 ease-in-out text-xs'
disabled={
loadingAction === 'commit_selected'
}>
{loadingAction === 'commit_selected' ? (
<Loader
size={12}
className='animate-spin'
/>
) : (
<CheckCircle
className='mr-1'
size={12}
/>
)}
Commit Selected
</button>
</Tooltip>
)}
<ActionButton
onClick={() => onStageSelected(selectedOutgoingChanges)}
disabled={!canStage}
loading={loadingAction === 'stage_selected'}
icon={<Plus />}
text='Stage'
className='bg-green-600'
disabledTooltip='Select unstaged files to enable staging'
/>
<ActionButton
onClick={() =>
onCommitSelected(
selectedOutgoingChanges,
commitMessage
)
}
disabled={!canCommit}
loading={loadingAction === 'commit_selected'}
icon={<CheckCircle />}
text='Commit'
className='bg-blue-600'
disabledTooltip='Select staged files and enter a commit message to enable committing'
/>
</>
)}
{/* Revert */}
{selectedOutgoingChanges.length > 0 && (
<Tooltip content={getRevertButtonTooltip()}>
<button
onClick={() =>
onRevertSelected(selectedOutgoingChanges)
}
className='flex items-center px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors duration-200 ease-in-out text-xs'
disabled={loadingAction === 'revert_selected'}>
{loadingAction === 'revert_selected' ? (
<Loader size={12} className='animate-spin' />
) : (
<RotateCcw className='mr-1' size={12} />
)}
Revert Selected
</button>
</Tooltip>
)}
{/* Pull */}
{selectedIncomingChanges.length > 0 && (
<Tooltip content='Pull selected changes'>
<button
onClick={() => onPullSelected(selectedIncomingChanges)}
className='flex items-center px-4 py-2 bg-yellow-600 text-white rounded-md hover:bg-yellow-700 transition-colors duration-200 ease-in-out text-xs'
disabled={loadingAction === 'pull_changes'}>
{loadingAction === 'pull_changes' ? (
<Loader size={12} className='animate-spin' />
) : (
<Download className='mr-1' size={12} />
)}
Pull Selected
</button>
</Tooltip>
)}
<ActionButton
onClick={() => onRevertSelected(selectedOutgoingChanges)}
disabled={!canRevert}
loading={loadingAction === 'revert_selected'}
icon={<RotateCcw />}
text='Revert'
className='bg-red-600'
disabledTooltip='Select files to revert'
/>
<ActionButton
onClick={() => onPullSelected(selectedIncomingChanges)}
disabled={!canPull}
loading={loadingAction === 'pull_changes'}
icon={<Download />}
text='Pull'
className='bg-yellow-600'
disabledTooltip='Select incoming changes to pull'
/>
</div>
);
};

View File

@@ -109,22 +109,46 @@ const StatusContainer = ({
}
}, [status]);
const hasChanges =
status.incoming_changes.length > 0 ||
status.outgoing_changes.length > 0;
return (
<div className='dark:bg-gray-800 border border-gray-200 dark:border-gray-700 p-4 rounded-md'>
<div className='flex items-center'>
<GitMerge className='mr-2 text-green-400' size={14} />
<h3 className='text-m font-semibold text-gray-100 mr-2'>
Sync Status:
</h3>
{status.incoming_changes.length === 0 &&
status.outgoing_changes.length === 0 ? (
<span className='text-m font-medium'>
{noChangesMessage}
</span>
) : (
<span className='text-gray-400 text-m flex items-center'>
Out of Date!
</span>
<div className='flex items-center justify-between'>
<div className='flex items-center'>
<GitMerge className='mr-2 text-green-400' size={14} />
<h3 className='text-m font-semibold text-gray-100 mr-2'>
Sync Status:
</h3>
{!hasChanges ? (
<span className='text-m font-medium'>
{noChangesMessage}
</span>
) : (
<span className='text-gray-400 text-m flex items-center'>
Out of Date!
</span>
)}
</div>
{!hasChanges && (
<div className='flex-shrink-0'>
<ActionButtons
isDevMode={isDevMode}
selectedOutgoingChanges={selectedOutgoingChanges}
selectedIncomingChanges={selectedIncomingChanges}
selectionType={selectionType}
commitMessage={commitMessage}
loadingAction={loadingAction}
onStageSelected={onStageSelected}
onCommitSelected={onCommitSelected}
onRevertSelected={onRevertSelected}
onPullSelected={onPullSelected}
getStageButtonTooltip={getStageButtonTooltip}
getCommitButtonTooltip={getCommitButtonTooltip}
getRevertButtonTooltip={getRevertButtonTooltip}
/>
</div>
)}
</div>
@@ -160,30 +184,36 @@ const StatusContainer = ({
/>
)}
<CommitSection
status={status}
commitMessage={commitMessage}
setCommitMessage={setCommitMessage}
loadingAction={loadingAction}
hasIncomingChanges={status.incoming_changes.length > 0}
isDevMode={isDevMode}
/>
{hasChanges && (
<>
<CommitSection
status={status}
commitMessage={commitMessage}
setCommitMessage={setCommitMessage}
loadingAction={loadingAction}
hasIncomingChanges={status.incoming_changes.length > 0}
isDevMode={isDevMode}
/>
<ActionButtons
isDevMode={isDevMode}
selectedOutgoingChanges={selectedOutgoingChanges}
selectedIncomingChanges={selectedIncomingChanges}
selectionType={selectionType}
commitMessage={commitMessage}
loadingAction={loadingAction}
onStageSelected={onStageSelected}
onCommitSelected={onCommitSelected}
onRevertSelected={onRevertSelected}
onPullSelected={onPullSelected}
getStageButtonTooltip={getStageButtonTooltip}
getCommitButtonTooltip={getCommitButtonTooltip}
getRevertButtonTooltip={getRevertButtonTooltip}
/>
<div className='mt-4 flex justify-end'>
<ActionButtons
isDevMode={isDevMode}
selectedOutgoingChanges={selectedOutgoingChanges}
selectedIncomingChanges={selectedIncomingChanges}
selectionType={selectionType}
commitMessage={commitMessage}
loadingAction={loadingAction}
onStageSelected={onStageSelected}
onCommitSelected={onCommitSelected}
onRevertSelected={onRevertSelected}
onPullSelected={onPullSelected}
getStageButtonTooltip={getStageButtonTooltip}
getCommitButtonTooltip={getCommitButtonTooltip}
getRevertButtonTooltip={getRevertButtonTooltip}
/>
</div>
</>
)}
</div>
);
};

View File

@@ -14,18 +14,18 @@ export const statusLoadingMessages = [
];
export const noChangesMessages = [
'No changes detected. Your regex is so precise, it could find a needle in a haystack... made of needles. 🧵🔍',
'All quiet on the commit front. Your custom formats are so perfect, even perfectionists are jealous. 🏆',
"No updates needed. Your media automation is running so smoothly, it's making butter jealous. 🧈",
'Zero modifications. Your torrent setup is seeding so efficiently, farmers are asking for advice. 🌾',
"No edits required. Your regex fu is so strong, it's bench-pressing parentheses for fun. 💪()",
'Unchanged status. Your Plex library is so well-organized, librarians are taking notes. 📚🤓',
"No alterations found. Your file naming scheme is so consistent, it's bringing tears to OCD eyes. 😢👀",
"All systems nominal. Your download queue is so orderly, it's making Marie Kondo question her career. 🧹✨",
"No revisions necessary. Your automation scripts are so smart, they're solving captchas for fun. 🤖🧩",
'Steady as she goes. Your media collection is so complete, Netflix is asking you for recommendations. 🎬👑'
'All synced up! Smooth sailing ahead.',
"No changes detected. We're all good here.",
"Everything's in order. Carry on!",
'Up to date and ready to go.',
'All quiet on the regex front!',
'Perfectly synced! Nice work.',
"No updates needed. You're all set.",
"Everything's hunky-dory in your repository.",
'All good in the code neighborhood.',
'Sync complete! Ship-Shape.'
];
export const getRandomMessage = (messages) => {
export const getRandomMessage = messages => {
return messages[Math.floor(Math.random() * messages.length)];
};