mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 06:59:09 +00:00
feat: apply delays
This commit is contained in:
@@ -31,9 +31,14 @@ export const requestPatch = async (data) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const requestReorder = async (data) => {
|
export const requestReorder = async (data) => {
|
||||||
const reorder = 'reorder';
|
const action = 'reorder';
|
||||||
console.log('debug got reorder with payload', data);
|
const res = await axios.patch(eventsURL + '/' + action, data);
|
||||||
const res = await axios.patch(eventsURL + '/' + reorder, data);
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const requestApplyDelay = async (eventId) => {
|
||||||
|
const action = 'applydelay';
|
||||||
|
const res = await axios.patch(eventsURL + '/' + action + '/' + eventId);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { IconButton } from '@chakra-ui/button';
|
||||||
|
import { FiChevronsDown } from 'react-icons/fi';
|
||||||
|
|
||||||
|
export default function ApplyIconBtn(props) {
|
||||||
|
const { clickhandler, ...rest } = props;
|
||||||
|
return (
|
||||||
|
<IconButton
|
||||||
|
size={props.size || 'xs'}
|
||||||
|
icon={<FiChevronsDown />}
|
||||||
|
colorScheme='orange'
|
||||||
|
onClick={clickhandler}
|
||||||
|
_focus={{ boxShadow: 'none' }}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import TimeInput from '../../../common/input/TimeInput';
|
|||||||
import style from './Block.module.css';
|
import style from './Block.module.css';
|
||||||
import ActionButtons from './ActionButtons';
|
import ActionButtons from './ActionButtons';
|
||||||
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
import DeleteIconBtn from '../../../common/components/buttons/DeleteIconBtn';
|
||||||
|
import ApplyIconBtn from '../../../common/components/buttons/ApplyIconBtn';
|
||||||
|
|
||||||
export default function DelayBlock(props) {
|
export default function DelayBlock(props) {
|
||||||
const { data, eventsHandler, index } = props;
|
const { data, eventsHandler, index } = props;
|
||||||
@@ -22,6 +23,10 @@ export default function DelayBlock(props) {
|
|||||||
eventsHandler('delete', data.id);
|
eventsHandler('delete', data.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const applyDelayHandler = () => {
|
||||||
|
eventsHandler('applyDelay', { id: data.id, duration: data.duration });
|
||||||
|
};
|
||||||
|
|
||||||
let delayValue =
|
let delayValue =
|
||||||
data.duration != null ? millisToMinutes(data.duration) : undefined;
|
data.duration != null ? millisToMinutes(data.duration) : undefined;
|
||||||
return (
|
return (
|
||||||
@@ -37,6 +42,7 @@ export default function DelayBlock(props) {
|
|||||||
</span>
|
</span>
|
||||||
<TimeInput value={delayValue} submitHandler={submitHandler} />
|
<TimeInput value={delayValue} submitHandler={submitHandler} />
|
||||||
<div className={style.actionOverlay}>
|
<div className={style.actionOverlay}>
|
||||||
|
<ApplyIconBtn clickhandler={applyDelayHandler} />
|
||||||
<DeleteIconBtn clickhandler={deleteHandler} />
|
<DeleteIconBtn clickhandler={deleteHandler} />
|
||||||
<ActionButtons showAdd addHandler={addHandler} />
|
<ActionButtons showAdd addHandler={addHandler} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ export default function EventList(props) {
|
|||||||
// drop outside of area
|
// drop outside of area
|
||||||
if (!result.destination) return;
|
if (!result.destination) return;
|
||||||
|
|
||||||
|
// no change
|
||||||
|
if (result.destination === result.source.index) return;
|
||||||
|
|
||||||
// Call API
|
// Call API
|
||||||
eventsHandler('reorder', {
|
eventsHandler('reorder', {
|
||||||
index: result.draggableId,
|
index: result.draggableId,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
requestPut,
|
requestPut,
|
||||||
requestDelete,
|
requestDelete,
|
||||||
requestReorder,
|
requestReorder,
|
||||||
|
requestApplyDelay,
|
||||||
} from '../../../app/api/eventsApi.js';
|
} from '../../../app/api/eventsApi.js';
|
||||||
import EventList from './EventList';
|
import EventList from './EventList';
|
||||||
import EventListMenu from '../../menu/EventListMenu.jsx';
|
import EventListMenu from '../../menu/EventListMenu.jsx';
|
||||||
@@ -156,7 +157,14 @@ export default function EventListWrapper() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const reorderEvent = useMutation(requestReorder, {
|
const applyDelay = useMutation(requestApplyDelay, {
|
||||||
|
// Mutation finished, failed or successful
|
||||||
|
onSettled: () => {
|
||||||
|
queryClient.invalidateQueries(eventsNamespace);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const reorderEvent = useMutation(requestReorder, {
|
||||||
// we optimistically update here
|
// we optimistically update here
|
||||||
onMutate: async (data) => {
|
onMutate: async (data) => {
|
||||||
// cancel ongoing queries
|
// cancel ongoing queries
|
||||||
@@ -241,6 +249,41 @@ export default function EventListWrapper() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast('Error reordering event', error.message);
|
showErrorToast('Error reordering event', error.message);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'applyDelay':
|
||||||
|
let t = Date.now();
|
||||||
|
|
||||||
|
// if delay <= 0 delete delay and next block
|
||||||
|
if (payload.duration <= 0) {
|
||||||
|
try {
|
||||||
|
// look for block after
|
||||||
|
let afterId = false;
|
||||||
|
let blockAfter = null;
|
||||||
|
for (const d of data) {
|
||||||
|
if (d.id === payload.id) afterId = true;
|
||||||
|
if (afterId && d.type === 'block') {
|
||||||
|
blockAfter = d.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete delay
|
||||||
|
await deleteEvent.mutateAsync(payload.id);
|
||||||
|
// delete block after, if any
|
||||||
|
if (blockAfter) await deleteEvent.mutateAsync(blockAfter);
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast('Error applying delay', error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('debug applydelay', payload.id);
|
||||||
|
try {
|
||||||
|
await applyDelay.mutateAsync(payload.id);
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast('Error applying delay', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('debug m apply', Date.now() - t);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
showErrorToast('Unrecognised request', action);
|
showErrorToast('Unrecognised request', action);
|
||||||
|
|||||||
@@ -165,15 +165,11 @@ exports.eventsReorder = async (req, res) => {
|
|||||||
// TODO: Validate event
|
// TODO: Validate event
|
||||||
if (!req.body) {
|
if (!req.body) {
|
||||||
res.status(400).send(`No object found in request`);
|
res.status(400).send(`No object found in request`);
|
||||||
console.log(`No object found in request`);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { index, from, to } = req.body;
|
const { index, from, to } = req.body;
|
||||||
|
|
||||||
console.log(req.body);
|
|
||||||
|
|
||||||
// get events
|
// get events
|
||||||
let events = db.get('events').value();
|
let events = db.get('events').value();
|
||||||
let idx = events.findIndex((e) => e.id === index, from);
|
let idx = events.findIndex((e) => e.id === index, from);
|
||||||
@@ -181,7 +177,6 @@ exports.eventsReorder = async (req, res) => {
|
|||||||
// Check if item is at given index
|
// Check if item is at given index
|
||||||
if (idx !== from) {
|
if (idx !== from) {
|
||||||
res.status(400).send(`Id not found at index`);
|
res.status(400).send(`Id not found at index`);
|
||||||
console.log(`Id not found at index`, idx, from);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +201,71 @@ exports.eventsReorder = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create controller for PATCH request to '/events/applydelay/:eventId'
|
||||||
|
// Returns -
|
||||||
|
exports.eventsApplyDelay = async (req, res) => {
|
||||||
|
// no valid params
|
||||||
|
if (!req.params.eventId) {
|
||||||
|
res.status(400).send(`No id found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// get events
|
||||||
|
let events = db.get('events').value();
|
||||||
|
|
||||||
|
// AUX
|
||||||
|
let delayIndex = null;
|
||||||
|
let blockIndex = null;
|
||||||
|
let delayValue = 0;
|
||||||
|
|
||||||
|
for (const [index, e] of events.entries()) {
|
||||||
|
if (delayIndex == null) {
|
||||||
|
// look for delay
|
||||||
|
if (e.id === req.params.eventId && e.type === 'delay') {
|
||||||
|
delayValue = e.duration;
|
||||||
|
delayIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply delay value to all items until block or end
|
||||||
|
else {
|
||||||
|
if (e.type === 'event') {
|
||||||
|
// update times
|
||||||
|
e.timeStart += delayValue;
|
||||||
|
e.timeEnd += delayValue;
|
||||||
|
|
||||||
|
// increment revision
|
||||||
|
e.revision += 1;
|
||||||
|
} else if (e.type === 'block') {
|
||||||
|
// save id and stop
|
||||||
|
blockIndex = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete delay
|
||||||
|
events.splice(delayIndex, 1);
|
||||||
|
|
||||||
|
// delete block
|
||||||
|
// index would have moved down since we deleted delay
|
||||||
|
if (blockIndex) events.splice(blockIndex - 1, 1);
|
||||||
|
|
||||||
|
// update events
|
||||||
|
db.set('events', events).write();
|
||||||
|
|
||||||
|
// update timer
|
||||||
|
_updateTimers();
|
||||||
|
|
||||||
|
res.sendStatus(201);
|
||||||
|
} catch (error) {
|
||||||
|
console.log('debug:', error);
|
||||||
|
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Create controller for DELETE request to '/events/:eventId'
|
// Create controller for DELETE request to '/events/:eventId'
|
||||||
// Returns -
|
// Returns -
|
||||||
exports.eventsDelete = async (req, res) => {
|
exports.eventsDelete = async (req, res) => {
|
||||||
@@ -213,7 +273,6 @@ exports.eventsDelete = async (req, res) => {
|
|||||||
if (!req.params.eventId) {
|
if (!req.params.eventId) {
|
||||||
res.status(400).send(`No id found in request`);
|
res.status(400).send(`No id found in request`);
|
||||||
return;
|
return;
|
||||||
console.log('debug: No id found in request');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ router.patch('/', eventsController.eventsPatch);
|
|||||||
// create route between controller and '/events/reorder' endpoint
|
// create route between controller and '/events/reorder' endpoint
|
||||||
router.patch('/reorder/', eventsController.eventsReorder);
|
router.patch('/reorder/', eventsController.eventsReorder);
|
||||||
|
|
||||||
|
// create route between controller and '/events/applydelay/:eventId' endpoint
|
||||||
|
router.patch('/applydelay/:eventId', eventsController.eventsApplyDelay);
|
||||||
|
|
||||||
// create route between controller and '/events/:eventId' endpoint
|
// create route between controller and '/events/:eventId' endpoint
|
||||||
router.delete('/:eventId', eventsController.eventsDelete);
|
router.delete('/:eventId', eventsController.eventsDelete);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user