Skip to content
This repository has been archived by the owner on Jun 17, 2023. It is now read-only.

Commit

Permalink
v0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
yesBad committed Oct 3, 2021
1 parent 987409d commit ee05ba1
Show file tree
Hide file tree
Showing 10 changed files with 925 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useState } from 'react';
import deleteSchedule from '@/api/server/schedules/deleteSchedule';
import { ServerContext } from '@/state/server';
import { Actions, useStoreActions } from 'easy-peasy';
import { ApplicationStore } from '@/state';
import { httpErrorToHuman } from '@/api/http';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import ConfirmationModal from '@/components/elements/ConfirmationModal';
import lang from '../../../../../lang.json';

interface Props {
scheduleId: number;
onDeleted: () => void;
}

export default ({ scheduleId, onDeleted }: Props) => {
const [ visible, setVisible ] = useState(false);
const [ isLoading, setIsLoading ] = useState(false);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const { addError, clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);

const onDelete = () => {
setIsLoading(true);
clearFlashes('schedules');
deleteSchedule(uuid, scheduleId)
.then(() => {
setIsLoading(false);
onDeleted();
})
.catch(error => {
console.error(error);

addError({ key: 'schedules', message: httpErrorToHuman(error) });
setIsLoading(false);
setVisible(false);
});
};

return (
<>
<ConfirmationModal
visible={visible}
title={lang.schedule_delete}
buttonText={lang.schedule_yes_delete}
onConfirmed={onDelete}
showSpinnerOverlay={isLoading}
onModalDismissed={() => setVisible(false)}
>
{lang.schedule_are_you_sure_delete}
</ConfirmationModal>
<Button css={tw`flex-1 sm:flex-none mr-4 border-transparent`} color={'red'} isSecondary onClick={() => setVisible(true)}>
{lang.delete}
</Button>
</>
);
};
131 changes: 131 additions & 0 deletions resources/scripts/components/server/schedules/EditScheduleModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useContext, useEffect } from 'react';
import { Schedule } from '@/api/server/schedules/getServerSchedules';
import Field from '@/components/elements/Field';
import { Form, Formik, FormikHelpers } from 'formik';
import FormikSwitch from '@/components/elements/FormikSwitch';
import createOrUpdateSchedule from '@/api/server/schedules/createOrUpdateSchedule';
import { ServerContext } from '@/state/server';
import { httpErrorToHuman } from '@/api/http';
import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import ModalContext from '@/context/ModalContext';
import asModal from '@/hoc/asModal';
import lang from '../../../../../lang.json';

interface Props {
schedule?: Schedule;
}

interface Values {
name: string;
dayOfWeek: string;
month: string;
dayOfMonth: string;
hour: string;
minute: string;
enabled: boolean;
onlyWhenOnline: boolean;
}

const EditScheduleModal = ({ schedule }: Props) => {
const { addError, clearFlashes } = useFlash();
const { dismiss } = useContext(ModalContext);

const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);

useEffect(() => {
return () => {
clearFlashes('schedule:edit');
};
}, []);

const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
clearFlashes('schedule:edit');
createOrUpdateSchedule(uuid, {
id: schedule?.id,
name: values.name,
cron: {
minute: values.minute,
hour: values.hour,
dayOfWeek: values.dayOfWeek,
month: values.month,
dayOfMonth: values.dayOfMonth,
},
onlyWhenOnline: values.onlyWhenOnline,
isActive: values.enabled,
})
.then(schedule => {
setSubmitting(false);
appendSchedule(schedule);
dismiss();
})
.catch(error => {
console.error(error);

setSubmitting(false);
addError({ key: 'schedule:edit', message: httpErrorToHuman(error) });
});
};

return (
<Formik
onSubmit={submit}
initialValues={{
name: schedule?.name || '',
minute: schedule?.cron.minute || '*/5',
hour: schedule?.cron.hour || '*',
dayOfMonth: schedule?.cron.dayOfMonth || '*',
month: schedule?.cron.month || '*',
dayOfWeek: schedule?.cron.dayOfWeek || '*',
enabled: schedule?.isActive ?? true,
onlyWhenOnline: schedule?.onlyWhenOnline ?? true,
} as Values}
>
{({ isSubmitting }) => (
<Form>
<h3 css={tw`text-2xl mb-6`}>{schedule ? lang.schedule_edit : lang.schedule_create_new}</h3>
<FlashMessageRender byKey={'schedule:edit'} css={tw`mb-6`}/>
<Field
name={'name'}
label={lang.schedule_name}
description={lang.schedule_desc}
/>
<div css={tw`grid grid-cols-2 sm:grid-cols-5 gap-4 mt-6`}>
<Field name={'minute'} label={lang.minute}/>
<Field name={'hour'} label={lang.hour}/>
<Field name={'dayOfMonth'} label={lang.day_of_month}/>
<Field name={'month'} label={lang.month}/>
<Field name={'dayOfWeek'} label={lang.day_of_week}/>
</div>
<p css={tw`text-neutral-400 text-xs mt-2`}>
{lang.the_schedule_system_stuff_blabla_no_one_fucking_cares}
</p>
<div css={tw`mt-6 bg-neutral-700 border border-neutral-800 shadow-inner p-4 rounded`}>
<FormikSwitch
name={'onlyWhenOnline'}
description={lang.schedule_only_excec}
label={lang.only_when_server_is_online}
/>
</div>
<div css={tw`mt-6 bg-neutral-700 border border-neutral-800 shadow-inner p-4 rounded`}>
<FormikSwitch
name={'enabled'}
description={lang.schedule_will_be_exec_if_enabled}
label={lang.sceeeeeedule_enabled}
/>
</div>
<div css={tw`mt-6 text-right`}>
<Button css={tw`w-full sm:w-auto`} type={'submit'} disabled={isSubmitting}>
{schedule ? lang.save_changes : lang.create_schedule}
</Button>
</div>
</Form>
)}
</Formik>
);
};

export default asModal<Props>()(EditScheduleModal);
23 changes: 23 additions & 0 deletions resources/scripts/components/server/schedules/NewTaskButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { useState } from 'react';
import { Schedule } from '@/api/server/schedules/getServerSchedules';
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
import Button from '@/components/elements/Button';
import tw from 'twin.macro';
import lang from '../../../../../lang.json';

interface Props {
schedule: Schedule;
}

export default ({ schedule }: Props) => {
const [ visible, setVisible ] = useState(false);

return (
<>
<TaskDetailsModal schedule={schedule} visible={visible} onModalDismissed={() => setVisible(false)}/>
<Button onClick={() => setVisible(true)} css={tw`flex-1`}>
{lang.new_task}
</Button>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useCallback, useState } from 'react';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import tw from 'twin.macro';
import Button from '@/components/elements/Button';
import triggerScheduleExecution from '@/api/server/schedules/triggerScheduleExecution';
import { ServerContext } from '@/state/server';
import useFlash from '@/plugins/useFlash';
import { Schedule } from '@/api/server/schedules/getServerSchedules';
import lang from '../../../../../lang.json';

const RunScheduleButton = ({ schedule }: { schedule: Schedule }) => {
const [ loading, setLoading ] = useState(false);
const { clearFlashes, clearAndAddHttpError } = useFlash();

const id = ServerContext.useStoreState(state => state.server.data!.id);
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);

const onTriggerExecute = useCallback(() => {
clearFlashes('schedule');
setLoading(true);
triggerScheduleExecution(id, schedule.id)
.then(() => {
setLoading(false);
appendSchedule({ ...schedule, isProcessing: true });
})
.catch(error => {
console.error(error);
clearAndAddHttpError({ error, key: 'schedules' });
})
.then(() => setLoading(false));
}, []);

return (
<>
<SpinnerOverlay visible={loading} size={'large'}/>
<Button
isSecondary
color={'grey'}
css={tw`flex-1 sm:flex-none border-transparent`}
disabled={schedule.isProcessing}
onClick={onTriggerExecute}
>
{lang.run_now}
</Button>
</>
);
};

export default RunScheduleButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useEffect, useState } from 'react';
import getServerSchedules from '@/api/server/schedules/getServerSchedules';
import { ServerContext } from '@/state/server';
import Spinner from '@/components/elements/Spinner';
import { useHistory, useRouteMatch } from 'react-router-dom';
import FlashMessageRender from '@/components/FlashMessageRender';
import ScheduleRow from '@/components/server/schedules/ScheduleRow';
import { httpErrorToHuman } from '@/api/http';
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
import Can from '@/components/elements/Can';
import useFlash from '@/plugins/useFlash';
import tw from 'twin.macro';
import GreyRowBox from '@/components/elements/GreyRowBox';
import Button from '@/components/elements/Button';
import ServerContentBlock from '@/components/elements/ServerContentBlock';
import lang from '../../../../../lang.json';

export default () => {
const match = useRouteMatch();
const history = useHistory();

const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const { clearFlashes, addError } = useFlash();
const [ loading, setLoading ] = useState(true);
const [ visible, setVisible ] = useState(false);

const schedules = ServerContext.useStoreState(state => state.schedules.data);
const setSchedules = ServerContext.useStoreActions(actions => actions.schedules.setSchedules);

useEffect(() => {
clearFlashes('schedules');
getServerSchedules(uuid)
.then(schedules => setSchedules(schedules))
.catch(error => {
addError({ message: httpErrorToHuman(error), key: 'schedules' });
console.error(error);
})
.then(() => setLoading(false));
}, []);

return (
<ServerContentBlock title={'Schedules'}>
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
{(!schedules.length && loading) ?
<Spinner size={'large'} centered/>
:
<>
{
schedules.length === 0 ?
<p css={tw`text-sm text-center text-neutral-300`}>
{lang.there_isnt_arent_schedules_for_server_smile}
</p>
:
schedules.map(schedule => (
<GreyRowBox
as={'a'}
key={schedule.id}
href={`${match.url}/${schedule.id}`}
css={tw`cursor-pointer mb-2 flex-wrap`}
onClick={(e: any) => {
e.preventDefault();
history.push(`${match.url}/${schedule.id}`);
}}
>
<ScheduleRow schedule={schedule}/>
</GreyRowBox>
))
}
<Can action={'schedule.create'}>
<div css={tw`mt-8 flex justify-end`}>
<EditScheduleModal visible={visible} onModalDismissed={() => setVisible(false)}/>
<Button type={'button'} onClick={() => setVisible(true)}>
{lang.create_schedule}
</Button>
</div>
</Can>
</>
}
</ServerContentBlock>
);
};
36 changes: 36 additions & 0 deletions resources/scripts/components/server/schedules/ScheduleCronRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import tw from 'twin.macro';
import { Schedule } from '@/api/server/schedules/getServerSchedules';
import lang from '../../../../../lang.json';

interface Props {
cron: Schedule['cron'];
className?: string;
}

const ScheduleCronRow = ({ cron, className }: Props) => (
<div css={tw`flex`} className={className}>
<div css={tw`w-1/5 sm:w-auto text-center`}>
<p css={tw`font-medium`}>{cron.minute}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>{lang.minute}</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.hour}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>{lang.hour}</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.dayOfMonth}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>{lang.day_month}</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.month}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>{lang.month}</p>
</div>
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
<p css={tw`font-medium`}>{cron.dayOfWeek}</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>{lang.day_week}</p>
</div>
</div>
);

export default ScheduleCronRow;
Loading

0 comments on commit ee05ba1

Please sign in to comment.