Skip to content

Commit 0ebf842

Browse files
committed
Clean up most of the schedules code to use server context
1 parent 07d19ad commit 0ebf842

File tree

9 files changed

+132
-92
lines changed

9 files changed

+132
-92
lines changed

resources/scripts/components/server/schedules/EditScheduleModal.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
66
import Switch from '@/components/elements/Switch';
77
import createOrUpdateSchedule from '@/api/server/schedules/createOrUpdateSchedule';
88
import { ServerContext } from '@/state/server';
9-
import { Actions, useStoreActions } from 'easy-peasy';
10-
import { ApplicationStore } from '@/state';
119
import { httpErrorToHuman } from '@/api/http';
1210
import FlashMessageRender from '@/components/FlashMessageRender';
11+
import useServer from '@/plugins/useServer';
12+
import useFlash from '@/plugins/useFlash';
1313

1414
type Props = {
1515
schedule?: Schedule;
16-
onScheduleUpdated: (schedule: Schedule) => void;
1716
} & RequiredModalProps;
1817

1918
interface Values {
@@ -73,15 +72,17 @@ const EditScheduleModal = ({ schedule, ...props }: Omit<Props, 'onScheduleUpdate
7372
);
7473
};
7574

76-
export default ({ schedule, onScheduleUpdated, visible, ...props }: Props) => {
77-
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
78-
const { addError, clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
75+
export default ({ schedule, visible, ...props }: Props) => {
76+
const { uuid } = useServer();
77+
const { addError, clearFlashes } = useFlash();
7978
const [ modalVisible, setModalVisible ] = useState(visible);
8079

80+
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
81+
8182
useEffect(() => {
8283
setModalVisible(visible);
8384
clearFlashes('schedule:edit');
84-
}, [visible]);
85+
}, [ visible ]);
8586

8687
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
8788
clearFlashes('schedule:edit');
@@ -98,7 +99,7 @@ export default ({ schedule, onScheduleUpdated, visible, ...props }: Props) => {
9899
})
99100
.then(schedule => {
100101
setSubmitting(false);
101-
onScheduleUpdated(schedule);
102+
appendSchedule(schedule);
102103
setModalVisible(false);
103104
})
104105
.catch(error => {

resources/scripts/components/server/schedules/NewTaskButton.tsx

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
import React, { useState } from 'react';
2-
import { Task } from '@/api/server/schedules/getServerSchedules';
2+
import { Schedule } from '@/api/server/schedules/getServerSchedules';
33
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
44

55
interface Props {
6-
scheduleId: number;
7-
onTaskAdded: (task: Task) => void;
6+
schedule: Schedule;
87
}
98

10-
export default ({ scheduleId, onTaskAdded }: Props) => {
11-
const [visible, setVisible] = useState(false);
9+
export default ({ schedule }: Props) => {
10+
const [ visible, setVisible ] = useState(false);
1211

1312
return (
1413
<>
1514
{visible &&
16-
<TaskDetailsModal
17-
scheduleId={scheduleId}
18-
onDismissed={task => {
19-
task && onTaskAdded(task);
20-
setVisible(false);
21-
}}
22-
/>
15+
<TaskDetailsModal
16+
schedule={schedule}
17+
onDismissed={() => setVisible(false)}
18+
/>
2319
}
2420
<button className={'btn btn-primary btn-sm'} onClick={() => setVisible(true)}>
2521
New Task

resources/scripts/components/server/schedules/ScheduleContainer.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { useEffect, useMemo, useState } from 'react';
22
import getServerSchedules, { Schedule } from '@/api/server/schedules/getServerSchedules';
33
import { ServerContext } from '@/state/server';
44
import Spinner from '@/components/elements/Spinner';
@@ -10,27 +10,35 @@ import { Actions, useStoreActions } from 'easy-peasy';
1010
import { ApplicationStore } from '@/state';
1111
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
1212
import Can from '@/components/elements/Can';
13+
import useServer from '@/plugins/useServer';
14+
import useFlash from '@/plugins/useFlash';
15+
import ListRefreshIndicator from '@/components/elements/ListRefreshIndicator';
1316

1417
export default ({ match, history }: RouteComponentProps) => {
15-
const { uuid } = ServerContext.useStoreState(state => state.server.data!);
16-
const [ schedules, setSchedules ] = useState<Schedule[] | null>(null);
18+
const { uuid } = useServer();
19+
const { clearFlashes, addError } = useFlash();
20+
const [ loading, setLoading ] = useState(true);
1721
const [ visible, setVisible ] = useState(false);
18-
const { clearFlashes, addError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
1922

20-
useMemo(() => {
23+
const schedules = ServerContext.useStoreState(state => state.schedules.data);
24+
const setSchedules = ServerContext.useStoreActions(actions => actions.schedules.setSchedules);
25+
26+
useEffect(() => {
2127
clearFlashes('schedules');
2228
getServerSchedules(uuid)
2329
.then(schedules => setSchedules(schedules))
2430
.catch(error => {
2531
addError({ message: httpErrorToHuman(error), key: 'schedules' });
2632
console.error(error);
27-
});
28-
}, [ setSchedules ]);
33+
})
34+
.then(() => setLoading(false));
35+
}, []);
2936

3037
return (
3138
<div className={'my-10 mb-6'}>
3239
<FlashMessageRender byKey={'schedules'} className={'mb-4'}/>
33-
{!schedules ?
40+
<ListRefreshIndicator visible={loading}/>
41+
{(!schedules.length && loading) ?
3442
<Spinner size={'large'} centered={true}/>
3543
:
3644
<>
@@ -59,7 +67,6 @@ export default ({ match, history }: RouteComponentProps) => {
5967
{visible && <EditScheduleModal
6068
appear={true}
6169
visible={true}
62-
onScheduleUpdated={schedule => setSchedules(s => [ ...(s || []), schedule ])}
6370
onDismissed={() => setVisible(false)}
6471
/>}
6572
<button

resources/scripts/components/server/schedules/ScheduleEditContainer.tsx

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ import React, { useEffect, useState } from 'react';
22
import { RouteComponentProps } from 'react-router-dom';
33
import { Schedule } from '@/api/server/schedules/getServerSchedules';
44
import getServerSchedule from '@/api/server/schedules/getServerSchedule';
5-
import { ServerContext } from '@/state/server';
65
import Spinner from '@/components/elements/Spinner';
76
import FlashMessageRender from '@/components/FlashMessageRender';
8-
import { Actions, useStoreActions } from 'easy-peasy';
9-
import { ApplicationStore } from '@/state';
107
import { httpErrorToHuman } from '@/api/http';
118
import ScheduleRow from '@/components/server/schedules/ScheduleRow';
129
import ScheduleTaskRow from '@/components/server/schedules/ScheduleTaskRow';
1310
import EditScheduleModal from '@/components/server/schedules/EditScheduleModal';
1411
import NewTaskButton from '@/components/server/schedules/NewTaskButton';
1512
import DeleteScheduleButton from '@/components/server/schedules/DeleteScheduleButton';
1613
import Can from '@/components/elements/Can';
14+
import useServer from '@/plugins/useServer';
15+
import useFlash from '@/plugins/useFlash';
16+
import { ServerContext } from '@/state/server';
1717

1818
interface Params {
1919
id: string;
@@ -24,11 +24,13 @@ interface State {
2424
}
2525

2626
export default ({ match, history, location: { state } }: RouteComponentProps<Params, {}, State>) => {
27-
const { id, uuid } = ServerContext.useStoreState(state => state.server.data!);
27+
const { id, uuid } = useServer();
28+
const { clearFlashes, addError } = useFlash();
2829
const [ isLoading, setIsLoading ] = useState(true);
2930
const [ showEditModal, setShowEditModal ] = useState(false);
30-
const [ schedule, setSchedule ] = useState<Schedule | undefined>(state?.schedule);
31-
const { clearFlashes, addError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
31+
32+
const schedule = ServerContext.useStoreState(st => st.schedules.data.find(s => s.id === state.schedule?.id), [ match ]);
33+
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
3234

3335
useEffect(() => {
3436
if (schedule?.id === Number(match.params.id)) {
@@ -38,13 +40,13 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
3840

3941
clearFlashes('schedules');
4042
getServerSchedule(uuid, Number(match.params.id))
41-
.then(schedule => setSchedule(schedule))
43+
.then(schedule => appendSchedule(schedule))
4244
.catch(error => {
4345
console.error(error);
4446
addError({ message: httpErrorToHuman(error), key: 'schedules' });
4547
})
4648
.then(() => setIsLoading(false));
47-
}, [ schedule, match ]);
49+
}, [ match ]);
4850

4951
return (
5052
<div className={'my-10 mb-6'}>
@@ -59,31 +61,20 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
5961
<EditScheduleModal
6062
visible={showEditModal}
6163
schedule={schedule}
62-
onScheduleUpdated={schedule => setSchedule(schedule)}
6364
onDismissed={() => setShowEditModal(false)}
6465
/>
6566
<div className={'flex items-center mt-8 mb-4'}>
6667
<div className={'flex-1'}>
6768
<h2>Configured Tasks</h2>
6869
</div>
6970
</div>
70-
{schedule?.tasks.length > 0 ?
71+
{schedule.tasks.length > 0 ?
7172
<>
7273
{
7374
schedule.tasks
7475
.sort((a, b) => a.sequenceId - b.sequenceId)
7576
.map(task => (
76-
<ScheduleTaskRow
77-
key={task.id}
78-
task={task}
79-
schedule={schedule.id}
80-
onTaskUpdated={task => setSchedule(s => ({
81-
...s!, tasks: s!.tasks.map(t => t.id === task.id ? task : t),
82-
}))}
83-
onTaskRemoved={() => setSchedule(s => ({
84-
...s!, tasks: s!.tasks.filter(t => t.id !== task.id),
85-
}))}
86-
/>
77+
<ScheduleTaskRow key={task.id} task={task} schedule={schedule}/>
8778
))
8879
}
8980
{schedule.tasks.length > 1 &&
@@ -108,12 +99,7 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
10899
<button className={'btn btn-primary btn-sm mr-4'} onClick={() => setShowEditModal(true)}>
109100
Edit
110101
</button>
111-
<NewTaskButton
112-
scheduleId={schedule.id}
113-
onTaskAdded={task => setSchedule(s => ({
114-
...s!, tasks: [ ...s!.tasks, task ],
115-
}))}
116-
/>
102+
<NewTaskButton schedule={schedule}/>
117103
</Can>
118104
</div>
119105
</>

resources/scripts/components/server/schedules/ScheduleTaskRow.tsx

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
11
import React, { useState } from 'react';
2-
import { Task } from '@/api/server/schedules/getServerSchedules';
2+
import { Schedule, Task } from '@/api/server/schedules/getServerSchedules';
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
44
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons/faTrashAlt';
55
import { faCode } from '@fortawesome/free-solid-svg-icons/faCode';
66
import { faToggleOn } from '@fortawesome/free-solid-svg-icons/faToggleOn';
77
import ConfirmTaskDeletionModal from '@/components/server/schedules/ConfirmTaskDeletionModal';
8-
import { ServerContext } from '@/state/server';
9-
import { Actions, useStoreActions } from 'easy-peasy';
10-
import { ApplicationStore } from '@/state';
118
import deleteScheduleTask from '@/api/server/schedules/deleteScheduleTask';
129
import { httpErrorToHuman } from '@/api/http';
1310
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
1411
import TaskDetailsModal from '@/components/server/schedules/TaskDetailsModal';
1512
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons/faPencilAlt';
1613
import Can from '@/components/elements/Can';
14+
import useServer from '@/plugins/useServer';
15+
import useFlash from '@/plugins/useFlash';
16+
import { ServerContext } from '@/state/server';
1717

1818
interface Props {
19-
schedule: number;
19+
schedule: Schedule;
2020
task: Task;
21-
onTaskUpdated: (task: Task) => void;
22-
onTaskRemoved: () => void;
2321
}
2422

25-
export default ({ schedule, task, onTaskUpdated, onTaskRemoved }: Props) => {
23+
export default ({ schedule, task }: Props) => {
24+
const { uuid } = useServer();
25+
const { clearFlashes, addError } = useFlash();
2626
const [ visible, setVisible ] = useState(false);
2727
const [ isLoading, setIsLoading ] = useState(false);
2828
const [ isEditing, setIsEditing ] = useState(false);
29-
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
30-
const { clearFlashes, addError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
29+
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
3130

3231
const onConfirmDeletion = () => {
3332
setIsLoading(true);
3433
clearFlashes('schedules');
35-
deleteScheduleTask(uuid, schedule, task.id)
36-
.then(() => onTaskRemoved())
34+
deleteScheduleTask(uuid, schedule.id, task.id)
35+
.then(() => appendSchedule({
36+
...schedule,
37+
tasks: schedule.tasks.filter(t => t.id !== task.id),
38+
}))
3739
.catch(error => {
3840
console.error(error);
3941
setIsLoading(false);
@@ -45,12 +47,9 @@ export default ({ schedule, task, onTaskUpdated, onTaskRemoved }: Props) => {
4547
<div className={'flex items-center bg-neutral-700 border border-neutral-600 mb-2 px-6 py-4 rounded'}>
4648
<SpinnerOverlay visible={isLoading} fixed={true} size={'large'}/>
4749
{isEditing && <TaskDetailsModal
48-
scheduleId={schedule}
50+
schedule={schedule}
4951
task={task}
50-
onDismissed={task => {
51-
task && onTaskUpdated(task);
52-
setIsEditing(false);
53-
}}
52+
onDismissed={() => setIsEditing(false)}
5453
/>}
5554
<ConfirmTaskDeletionModal
5655
visible={visible}

resources/scripts/components/server/schedules/TaskDetailsModal.tsx

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import React, { useEffect } from 'react';
22
import Modal from '@/components/elements/Modal';
3-
import { Task } from '@/api/server/schedules/getServerSchedules';
3+
import { Schedule, Task } from '@/api/server/schedules/getServerSchedules';
44
import { Field as FormikField, Form, Formik, FormikHelpers, useFormikContext } from 'formik';
55
import { ServerContext } from '@/state/server';
6-
import { Actions, useStoreActions } from 'easy-peasy';
7-
import { ApplicationStore } from '@/state';
86
import createOrUpdateScheduleTask from '@/api/server/schedules/createOrUpdateScheduleTask';
97
import { httpErrorToHuman } from '@/api/http';
108
import Field from '@/components/elements/Field';
119
import FlashMessageRender from '@/components/FlashMessageRender';
1210
import { number, object, string } from 'yup';
11+
import useFlash from '@/plugins/useFlash';
12+
import useServer from '@/plugins/useServer';
1313

1414
interface Props {
15-
scheduleId: number;
15+
schedule: Schedule;
1616
// If a task is provided we can assume we're editing it. If not provided,
1717
// we are creating a new one.
1818
task?: Task;
19-
onDismissed: (task: Task | undefined | void) => void;
19+
onDismissed: () => void;
2020
}
2121

2222
interface Values {
@@ -29,9 +29,11 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => {
2929
const { values: { action }, setFieldValue, setFieldTouched } = useFormikContext<Values>();
3030

3131
useEffect(() => {
32-
setFieldValue('payload', '');
33-
setFieldTouched('payload', false);
34-
}, [action]);
32+
return () => {
33+
setFieldValue('payload', '');
34+
setFieldTouched('payload', false);
35+
};
36+
}, [ action ]);
3537

3638
return (
3739
<Form className={'m-0'}>
@@ -80,18 +82,27 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => {
8082
);
8183
};
8284

83-
export default ({ task, scheduleId, onDismissed }: Props) => {
84-
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
85-
const { clearFlashes, addError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
85+
export default ({ task, schedule, onDismissed }: Props) => {
86+
const { uuid } = useServer();
87+
const { clearFlashes, addError } = useFlash();
88+
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
8689

8790
useEffect(() => {
8891
clearFlashes('schedule:task');
8992
}, []);
9093

9194
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
9295
clearFlashes('schedule:task');
93-
createOrUpdateScheduleTask(uuid, scheduleId, task?.id, values)
94-
.then(task => onDismissed(task))
96+
createOrUpdateScheduleTask(uuid, schedule.id, task?.id, values)
97+
.then(task => {
98+
let tasks = schedule.tasks.map(t => t.id === task.id ? task : t);
99+
if (!schedule.tasks.find(t => t.id === task.id)) {
100+
tasks = [ ...tasks, task ];
101+
}
102+
103+
appendSchedule({ ...schedule, tasks });
104+
onDismissed();
105+
})
95106
.catch(error => {
96107
console.error(error);
97108
setSubmitting(false);

0 commit comments

Comments
 (0)