mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-19 05:59:16 -04:00
[ENG-970] Job dropdown with actions (#1329)
* Job dropdown with actions * Update JobGroup.tsx * fix hover colors for theme support * Update Dropdown.tsx * Update JobGroup.tsx --------- Co-authored-by: Utku <74243531+utkubakir@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { Folder } from '@sd/assets/icons';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import clsx from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
import { DotsThreeVertical, Pause, Play, Stop } from '@phosphor-icons/react';
|
||||
import { DotsThreeVertical, Eye, Pause, Play, Stop, Trash } from '@phosphor-icons/react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import {
|
||||
getJobNiceActionName,
|
||||
@@ -12,8 +13,7 @@ import {
|
||||
useLibraryMutation,
|
||||
useTotalElapsedTimeText
|
||||
} from '@sd/client';
|
||||
import { Button, ProgressBar, Tooltip } from '@sd/ui';
|
||||
|
||||
import { Button, Dropdown, ProgressBar, Tooltip, toast } from '@sd/ui';
|
||||
import Job from './Job';
|
||||
import JobContainer from './JobContainer';
|
||||
|
||||
@@ -40,9 +40,14 @@ export default function ({ group, progress }: JobGroupProps) {
|
||||
if (jobs.length === 0) return <></>;
|
||||
|
||||
return (
|
||||
<ul className="relative overflow-hidden">
|
||||
<ul className="relative overflow-visible">
|
||||
<div className="row absolute right-3 top-3 z-50 flex space-x-1">
|
||||
<Options activeJob={runningJob} group={group} />
|
||||
<Options
|
||||
showChildJobs={showChildJobs}
|
||||
setShowChildJobs={() => setShowChildJobs((v) => !v)}
|
||||
activeJob={runningJob}
|
||||
group={group}
|
||||
/>
|
||||
</div>
|
||||
{jobs?.length > 1 ? (
|
||||
<>
|
||||
@@ -112,10 +117,70 @@ export default function ({ group, progress }: JobGroupProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function Options({ activeJob, group }: { activeJob?: JobReport; group: JobGroup }) {
|
||||
const resumeJob = useLibraryMutation(['jobs.resume'], { onError: alert });
|
||||
const pauseJob = useLibraryMutation(['jobs.pause'], { onError: alert });
|
||||
const cancelJob = useLibraryMutation(['jobs.cancel'], { onError: alert });
|
||||
function Options({
|
||||
activeJob,
|
||||
group,
|
||||
setShowChildJobs,
|
||||
showChildJobs
|
||||
}: {
|
||||
activeJob?: JobReport;
|
||||
group: JobGroup;
|
||||
setShowChildJobs: () => void;
|
||||
showChildJobs: boolean;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const toastErrorSuccess = (
|
||||
errorMessage?: string,
|
||||
successMessage?: string,
|
||||
successCallBack?: () => void
|
||||
) => {
|
||||
return {
|
||||
onError: () => {
|
||||
errorMessage &&
|
||||
toast.error({
|
||||
title: 'Error',
|
||||
body: errorMessage
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
successMessage &&
|
||||
toast.success({
|
||||
title: 'Success',
|
||||
body: successMessage
|
||||
}),
|
||||
successCallBack?.();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const resumeJob = useLibraryMutation(
|
||||
['jobs.resume'],
|
||||
toastErrorSuccess('Failed to resume job.', 'Job has been resumed.')
|
||||
);
|
||||
const pauseJob = useLibraryMutation(
|
||||
['jobs.pause'],
|
||||
toastErrorSuccess('Failed to pause job.', 'Job has been paused.')
|
||||
);
|
||||
const cancelJob = useLibraryMutation(
|
||||
['jobs.cancel'],
|
||||
toastErrorSuccess('Failed to cancel job.', 'Job has been canceled.')
|
||||
);
|
||||
const clearJob = useLibraryMutation(
|
||||
['jobs.clear'],
|
||||
toastErrorSuccess('Failed to remove job.', undefined, () => {
|
||||
queryClient.invalidateQueries(['jobs.reports']);
|
||||
})
|
||||
);
|
||||
|
||||
const clearJobHandler = () => {
|
||||
group.jobs.forEach((job) => {
|
||||
clearJob.mutate(job.id);
|
||||
//only one toast for all jobs
|
||||
if (job.id === group.id)
|
||||
toast.success({ title: 'Success', body: 'Job has been removed.' });
|
||||
});
|
||||
};
|
||||
|
||||
const isJobPaused = useMemo(
|
||||
() => group.jobs.some((job) => job.status === 'Paused'),
|
||||
@@ -137,18 +202,38 @@ function Options({ activeJob, group }: { activeJob?: JobReport; group: JobGroup
|
||||
</Tooltip>
|
||||
</Button>
|
||||
)}
|
||||
{/* TODO: Fix this */}
|
||||
{activeJob === undefined ? (
|
||||
<Button
|
||||
className="cursor-pointer"
|
||||
// onClick={() => clearJob?.(data.id as string)}
|
||||
size="icon"
|
||||
variant="outline"
|
||||
<Dropdown.Root
|
||||
align="right"
|
||||
itemsClassName="!bg-app-darkBox mt-1 border-app-line/90 !divide-none top-[-10px]"
|
||||
button={
|
||||
<Tooltip label="Actions">
|
||||
<Button className="!px-1" variant="outline">
|
||||
<DotsThreeVertical className="h-4 w-4 cursor-pointer" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Tooltip label="Remove">
|
||||
<DotsThreeVertical className="h-4 w-4 cursor-pointer" />
|
||||
</Tooltip>
|
||||
</Button>
|
||||
<Dropdown.Section>
|
||||
<Dropdown.Item
|
||||
active={showChildJobs}
|
||||
onClick={setShowChildJobs}
|
||||
icon={Eye}
|
||||
iconClassName="!w-3"
|
||||
className="!text-[11px] text-ink-dull"
|
||||
>
|
||||
Expand
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
onClick={() => clearJobHandler()}
|
||||
icon={Trash}
|
||||
iconClassName="!w-3"
|
||||
className="!text-[11px] text-ink-dull"
|
||||
>
|
||||
Remove
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Section>
|
||||
</Dropdown.Root>
|
||||
) : (
|
||||
<>
|
||||
{/* Pause / Stop */}
|
||||
|
||||
@@ -16,11 +16,11 @@ const itemStyles = cva(
|
||||
variants: {
|
||||
selected: {
|
||||
true: 'bg-accent text-white hover:!bg-accent',
|
||||
undefined: 'hover:bg-menu-hover',
|
||||
false: 'hover:bg-menu-hover'
|
||||
undefined: 'hover:bg-sidebar-selected/40',
|
||||
false: 'hover:bg-sidebar-selected/40'
|
||||
},
|
||||
active: {
|
||||
true: ''
|
||||
true: 'bg-sidebar-selected/40 text-sidebar-ink'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ type DropdownItemProps = PropsWithChildren<{
|
||||
to?: string;
|
||||
className?: string;
|
||||
icon?: any;
|
||||
iconClassName?: string;
|
||||
onClick?: () => void;
|
||||
}> &
|
||||
VariantProps<typeof itemStyles>;
|
||||
@@ -41,7 +42,9 @@ type DropdownItemProps = PropsWithChildren<{
|
||||
export const Item = ({ to, className, icon: Icon, children, ...props }: DropdownItemProps) => {
|
||||
const content = (
|
||||
<>
|
||||
{Icon && <Icon weight="bold" className={itemIconStyles(props)} />}
|
||||
{Icon && (
|
||||
<Icon weight="bold" className={clsx(itemIconStyles(props), props.iconClassName)} />
|
||||
)}
|
||||
<span className="text-left">{children}</span>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user