Non-working time for nested events
We use nested events extensively in our project, where the child events have fixed durations and the parent event is calculated from the start/end of its child events. Drag-and-drop is broken for the nested events, as they do not calculate start times correctly with respect to non-working time.
I see that this feature request https://github.com/bryntum/support/issues/1959 got removed from the 4.X.X milestones. Can I request that it get added to the 5.X.X plans?
And in the meantime, do you have a suggested workaround?
We are currently calculating new start times for each child event in the scheduler.beforeEventDropFinalize
listener, using calendar.skipNonWorkingTime()
to compute the next available start date. However, this does not preserve gaps/overlaps between the child tasks.
beforeEventDropFinalize: async (event: any) => {
// Prevent the user's drag from going through
if (!event.context) return;
event.context.async = true;
const updateRequest: Partial<TaskFields>[] = [];
const delta = DateHelper.diff(
event.context.origStart,
event.context.startDate,
'hours'
);
const reassignedUnit: UnitModel | undefined =
event.context.resourceRecord?.id !== event.context.newResource?.id
? event.context.newResource
: undefined;
const calendar: CalendarModel | undefined =
getProject()?.calendarManagerStore.getById(
NON_WORKING_DAYS
) as CalendarModel;
const isForward = delta >= 0;
schedulerRef.current?.instance.eventStore.beginBatch();
for (const task of event.context.eventRecords || []) {
// The tasks in the context already have modified start dates
let newStart = task.startDate;
// If the task is a slug, loop through its sidecar tasks and modify their start dates
// with respect to the non-working time calendar
// This is a manual workaround until Bryntum adds support for nested events:
// https://github.com/bryntum/support/issues/1959
if (task.isParent && Array.isArray(task.children)) {
for (const sidecar of sortBy(task.children, 'startDate')) {
newStart =
calendar?.skipNonWorkingTime(newStart, isForward) || newStart;
const payload: Partial<TaskFields> = {
uuid: sidecar.getData('uuid'),
startDate: DateHelper.format(newStart, DATE_FORMAT),
sgStartTime: getStartTime(newStart),
};
// Round to quarter day
newStart =
getStartDateTime(
payload.startDate as Date,
payload.sgStartTime as number
) || newStart;
await sidecar.setAsync('startDate', newStart);
if (reassignedUnit) {
sidecar.reassign(sidecar.resource, reassignedUnit);
payload.sgUnit = (
reassignedUnit as UnitModel
).convertToNestedEntity();
}
updateRequest.push(payload);
newStart = sidecar.endDate;
}
if (reassignedUnit) {
task.reassign(task.resource, reassignedUnit);
}
} else {
// Nudge sidecar task directly
newStart =
calendar?.skipNonWorkingTime(newStart, isForward) || newStart;
const payload: Partial<TaskFields> = {
uuid: task.getData('uuid'),
startDate: DateHelper.format(newStart, DATE_FORMAT),
sgStartTime: getStartTime(newStart),
};
updateRequest.push(payload);
await task.setAsync('startDate', newStart);
}
}
schedulerRef.current?.instance.eventStore.endBatch();
// We manually update the tasks above, so cancel the default behavior of this drop op.
event.context.finalize(false);
// Send update mutation to backend
...
}
How do you recommend we calculate the nested event start dates with respect to non-working time?
The beforeEventDropFinalize
event context doesn't keep track of the events' previous start dates (to my knowledge at least), so we are unable to properly compute the nested events' position relative to each other to preserve gaps and overlaps.