Update schedule view UI
This commit is contained in:
parent
33a43de723
commit
f33d0b1d72
12 changed files with 230 additions and 134 deletions
|
@ -1,12 +1,10 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Schedule } from '@/api/server/schedules/getServerSchedules';
|
||||
import getServerSchedule from '@/api/server/schedules/getServerSchedule';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
import ScheduleRow from '@/components/server/schedules/ScheduleRow';
|
||||
import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
|
||||
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
|
||||
import NewTaskButton from '@/components/server/schedules/NewTaskButton';
|
||||
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
|
||||
|
@ -16,7 +14,10 @@ import { ServerContext } from '@/state/server';
|
|||
import PageContentBlock from '@/components/elements/PageContentBlock';
|
||||
import tw from 'twin.macro';
|
||||
import Button from '@/components/elements/Button';
|
||||
import GreyRowBox from '@/components/elements/GreyRowBox';
|
||||
import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
|
||||
import isEqual from 'react-fast-compare';
|
||||
import { format } from 'date-fns';
|
||||
import ScheduleCronRow from '@/components/server/schedules/ScheduleCronRow';
|
||||
|
||||
interface Params {
|
||||
id: string;
|
||||
|
@ -26,6 +27,24 @@ interface State {
|
|||
schedule?: Schedule;
|
||||
}
|
||||
|
||||
const CronBox = ({ title, value }: { title: string; value: string }) => (
|
||||
<div css={tw`bg-neutral-700 rounded p-4`}>
|
||||
<p css={tw`text-neutral-300 text-sm`}>{title}</p>
|
||||
<p css={tw`text-2xl font-medium text-neutral-100`}>{value}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const ActivePill = ({ active }: { active: boolean }) => (
|
||||
<span
|
||||
css={[
|
||||
tw`rounded-full px-2 py-px text-xs ml-4 uppercase`,
|
||||
active ? tw`bg-green-600 text-green-100` : tw`bg-red-600 text-red-100`,
|
||||
]}
|
||||
>
|
||||
{active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
);
|
||||
|
||||
export default ({ match, history, location: { state } }: RouteComponentProps<Params, Record<string, unknown>, State>) => {
|
||||
const id = ServerContext.useStoreState(state => state.server.data!.id);
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||
|
@ -34,7 +53,8 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
|||
const [ isLoading, setIsLoading ] = useState(true);
|
||||
const [ showEditModal, setShowEditModal ] = useState(false);
|
||||
|
||||
const schedule = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), [ match ]);
|
||||
// @ts-ignore
|
||||
const schedule: Schedule | undefined = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), isEqual);
|
||||
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -53,6 +73,10 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
|||
.then(() => setIsLoading(false));
|
||||
}, [ match ]);
|
||||
|
||||
const toggleEditModal = useCallback(() => {
|
||||
setShowEditModal(s => !s);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContentBlock>
|
||||
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
|
||||
|
@ -60,52 +84,68 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
|
|||
<Spinner size={'large'} centered/>
|
||||
:
|
||||
<>
|
||||
<GreyRowBox css={tw`cursor-pointer mb-2 flex-wrap`}>
|
||||
<ScheduleRow schedule={schedule}/>
|
||||
</GreyRowBox>
|
||||
<EditScheduleModal
|
||||
visible={showEditModal}
|
||||
schedule={schedule}
|
||||
onDismissed={() => setShowEditModal(false)}
|
||||
/>
|
||||
<div css={tw`flex items-center mt-8 mb-4`}>
|
||||
<div css={tw`flex-1`}>
|
||||
<h2 css={tw`text-2xl`}>Configured Tasks</h2>
|
||||
<ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
|
||||
<div css={tw`hidden sm:grid grid-cols-5 md:grid-cols-7 gap-4 mb-6`}>
|
||||
<CronBox title={'Minute'} value={schedule.cron.minute}/>
|
||||
<CronBox title={'Hour'} value={schedule.cron.hour}/>
|
||||
<CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
|
||||
<CronBox title={'Month'} value={'*'}/>
|
||||
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
|
||||
</div>
|
||||
<div css={tw`rounded shadow`}>
|
||||
<div css={tw`sm:flex items-center bg-neutral-900 p-3 sm:p-6 border-b-4 border-neutral-600 rounded-t`}>
|
||||
<div css={tw`flex-1`}>
|
||||
<h3 css={tw`flex items-center text-neutral-100 text-2xl`}>
|
||||
{schedule.name}
|
||||
{schedule.isProcessing ?
|
||||
<span
|
||||
css={tw`flex items-center rounded-full px-2 py-px text-xs ml-4 uppercase bg-neutral-600 text-white`}
|
||||
>
|
||||
<Spinner css={tw`w-3! h-3! mr-2`}/>
|
||||
Processing
|
||||
</span>
|
||||
:
|
||||
<ActivePill active={schedule.isActive}/>
|
||||
}
|
||||
</h3>
|
||||
<p css={tw`mt-1 text-sm text-neutral-300`}>
|
||||
Last run at:
|
||||
{schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'}
|
||||
</p>
|
||||
</div>
|
||||
<div css={tw`flex sm:block mt-3 sm:mt-0`}>
|
||||
<Can action={'schedule.update'}>
|
||||
<Button
|
||||
isSecondary
|
||||
color={'grey'}
|
||||
size={'small'}
|
||||
css={tw`flex-1 mr-4 border-transparent`}
|
||||
onClick={toggleEditModal}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
<NewTaskButton schedule={schedule}/>
|
||||
</Can>
|
||||
</div>
|
||||
</div>
|
||||
<div css={tw`bg-neutral-700 rounded-b`}>
|
||||
{schedule.tasks.length > 0 ?
|
||||
schedule.tasks.map(task => (
|
||||
<ScheduleTaskRow key={`${schedule.id}_${task.id}`} task={task} schedule={schedule}/>
|
||||
))
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{schedule.tasks.length > 0 ?
|
||||
<>
|
||||
{
|
||||
schedule.tasks
|
||||
.sort((a, b) => a.sequenceId - b.sequenceId)
|
||||
.map(task => (
|
||||
<ScheduleTaskRow key={task.id} task={task} schedule={schedule}/>
|
||||
))
|
||||
}
|
||||
{schedule.tasks.length > 1 &&
|
||||
<p css={tw`text-xs text-neutral-400`}>
|
||||
Task delays are relative to the previous task in the listing.
|
||||
</p>
|
||||
}
|
||||
</>
|
||||
:
|
||||
<p css={tw`text-sm text-neutral-400`}>
|
||||
There are no tasks configured for this schedule.
|
||||
</p>
|
||||
}
|
||||
<div css={tw`mt-8 flex justify-end`}>
|
||||
<EditScheduleModal visible={showEditModal} schedule={schedule} onDismissed={toggleEditModal}/>
|
||||
<div css={tw`mt-6 flex sm:justify-end`}>
|
||||
<Can action={'schedule.delete'}>
|
||||
<DeleteScheduleButton
|
||||
scheduleId={schedule.id}
|
||||
onDeleted={() => history.push(`/server/${id}/schedules`)}
|
||||
/>
|
||||
</Can>
|
||||
<Can action={'schedule.update'}>
|
||||
<Button css={tw`mr-4`} onClick={() => setShowEditModal(true)}>
|
||||
Edit
|
||||
</Button>
|
||||
<NewTaskButton schedule={schedule}/>
|
||||
</Can>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
|
Reference in a new issue