misc_pterodactyl-panel/resources/scripts/components/server/schedules/ScheduleEditContainer.tsx

175 lines
8.2 KiB
TypeScript
Raw Normal View History

2020-10-15 03:13:36 +00:00
import React, { useCallback, useEffect, useState } from 'react';
import { useHistory, useLocation, useParams } from 'react-router-dom';
2020-03-18 06:33:53 +00:00
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 EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
2020-03-19 05:36:19 +00:00
import NewTaskButton from '@/components/server/schedules/NewTaskButton';
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
import Can from '@/components/elements/Can';
import useFlash from '@/plugins/useFlash';
import { ServerContext } from '@/state/server';
import PageContentBlock from '@/components/elements/PageContentBlock';
2020-07-05 00:00:19 +00:00
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
2020-10-15 03:13:36 +00:00
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';
import RunScheduleButton from '@/components/server/schedules/RunScheduleButton';
2020-03-18 06:33:53 +00:00
interface Params {
id: string;
}
interface State {
schedule?: Schedule;
}
2020-10-15 03:13:36 +00:00
const CronBox = ({ title, value }: { title: string; value: string }) => (
<div css={tw`bg-neutral-700 rounded p-3`}>
2020-10-15 03:13:36 +00:00
<p css={tw`text-neutral-300 text-sm`}>{title}</p>
<p css={tw`text-xl font-medium text-neutral-100`}>{value}</p>
2020-10-15 03:13:36 +00:00
</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 () => {
const history = useHistory();
2021-04-04 16:45:20 +00:00
const { state } = useLocation<State>();
const { id: scheduleId } = useParams<Params>();
2020-08-26 05:09:54 +00:00
const id = ServerContext.useStoreState(state => state.server.data!.id);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const { clearFlashes, clearAndAddHttpError } = useFlash();
2020-03-18 06:33:53 +00:00
const [ isLoading, setIsLoading ] = useState(true);
const [ showEditModal, setShowEditModal ] = useState(false);
2020-12-27 19:18:33 +00:00
const schedule = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), isEqual);
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
2020-03-18 06:33:53 +00:00
useEffect(() => {
2021-04-04 16:45:20 +00:00
if (schedule?.id === Number(scheduleId)) {
2020-03-18 06:33:53 +00:00
setIsLoading(false);
return;
}
clearFlashes('schedules');
2021-04-04 16:45:20 +00:00
getServerSchedule(uuid, Number(scheduleId))
.then(schedule => appendSchedule(schedule))
2020-03-18 06:33:53 +00:00
.catch(error => {
console.error(error);
clearAndAddHttpError({ error, key: 'schedules' });
2020-03-18 06:33:53 +00:00
})
.then(() => setIsLoading(false));
2021-04-04 16:45:20 +00:00
}, [ scheduleId ]);
2020-03-18 06:33:53 +00:00
2020-10-15 03:13:36 +00:00
const toggleEditModal = useCallback(() => {
setShowEditModal(s => !s);
}, []);
2020-03-18 06:33:53 +00:00
return (
<PageContentBlock title={'Schedules'}>
2020-07-05 00:00:19 +00:00
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
2020-03-18 06:33:53 +00:00
{!schedule || isLoading ?
2020-07-05 00:00:19 +00:00
<Spinner size={'large'} centered/>
2020-03-18 06:33:53 +00:00
:
<>
2020-10-15 03:13:36 +00:00
<ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
<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>
2020-11-01 22:07:31 +00:00
<p css={tw`mt-1 text-sm text-neutral-200`}>
2020-10-15 03:13:36 +00:00
Last run at:&nbsp;
2020-11-01 22:07:31 +00:00
{schedule.lastRunAt ?
format(schedule.lastRunAt, 'MMM do \'at\' h:mma')
:
<span css={tw`text-neutral-300`}>n/a</span>
}
<span css={tw`ml-4 pl-4 border-l-4 border-neutral-600 py-px`}>
Next run at:&nbsp;
{schedule.nextRunAt ?
format(schedule.nextRunAt, 'MMM do \'at\' h:mma')
:
<span css={tw`text-neutral-300`}>n/a</span>
}
</span>
2020-10-15 03:13:36 +00:00
</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`hidden sm:grid grid-cols-5 md:grid-cols-5 gap-4 mb-4 mt-4`}>
<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={schedule.cron.month}/>
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
</div>
2020-10-15 03:13:36 +00:00
<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
2020-03-18 06:33:53 +00:00
}
2020-10-15 03:13:36 +00:00
</div>
</div>
<EditScheduleModal visible={showEditModal} schedule={schedule} onModalDismissed={toggleEditModal}/>
2020-10-15 03:13:36 +00:00
<div css={tw`mt-6 flex sm:justify-end`}>
<Can action={'schedule.delete'}>
<DeleteScheduleButton
scheduleId={schedule.id}
onDeleted={() => history.push(`/server/${id}/schedules`)}
/>
</Can>
2021-04-24 22:06:21 +00:00
{schedule.tasks.length > 0 &&
<Can action={'schedule.update'}>
<RunScheduleButton schedule={schedule}/>
</Can>
}
</div>
2020-03-18 06:33:53 +00:00
</>
}
</PageContentBlock>
2020-03-18 06:33:53 +00:00
);
};