Page 1 of 2

[REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri May 20, 2022 6:28 am
by andrew.perera

Hi Team,

Ever since we changed our version 4.0.8 to 5.0.1 eventDragAbort does not fire. However, in our two scheduler design when dragging the event from top-grid to bottom-grid we had event fire during eventDragAbort. We have this inside a useEffect without dependencies.

Currently we are using :
v5.0.1
scheduler.umd.min.js
cheduler.umd.min.js.map

 useEffect(() => {
    ref.current.schedulerEngine.on('eventDragAbort', (eventRecords) => {
      // console.log('targetResource', targetResource);
      let resourceBranch;
      const draggedEvent = eventRecords.draggedRecords[0].data;
      // console.log('draggedEvent', draggedEvent);
      const { duration: eventDuration, type: serviceType } = draggedEvent;
      const { typeCode, engineer, projectResource } = targetResource;

  if (!targetResource.projectBranches) {
    resourceBranch = draggedEvent.ownerCode;
  } else {
    resourceBranch = targetResource.projectBranches.find(
      (resBranch) => resBranch.code === draggedEvent.ownerCode
    );

Please do let me know if you need more info. This issue is a bit critical as none of the validations are firing. Cheers


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri May 20, 2022 6:50 am
by alex.l

Hi andrew.perera,

Hard to say with no context. Please post a runnable test case, not clear what's inside ref.current.schedulerEngine. Or check yourself if it's Scheduler instance. And please provide steps when do you expect to have this event fired.

https://bryntum.com/docs/scheduler/api/Scheduler/view/SchedulerBase#event-eventDragAbort


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri May 20, 2022 9:15 am
by andrew.perera

Hi Alex,
Thanks for getting back mate,

Yes, "ref.current.schedulerEngine" is the scheduler instance.

We fire this event,

  1. Event is dragged to the bottom grid
  2. Pre-validation is run via - using validatorFn
  3. Event will push back to where it was ( Return to the top grid)
  4. eventDragAbort runs to show users an error modal.

However, the eventDragAbort does not fire as expected. this did work 4.0.8 though.

Kind Regards

Andrew Perera.


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri May 20, 2022 12:21 pm
by andrew.perera

Hi Alex,
I tried changing the sample code in https://bryntum.com/examples/scheduler/validation/

  1. In this particular sample code validatorfn will fire after an eventDrag
  2. I have included eventDragAbort as a listener
  3. Now I tried to drag Scrum Task to a Sales or CEO/CTO guy
  4. I am expecting eventDragAbort to fire here.

Have I done anything wrong?

Please find the code here.

import { ResourceModel, EventModel, DateHelper, Scheduler, Toast, MessageDialog, StringHelper } from '../../build/scheduler.module.js?458964';
import shared from '../_shared/shared.module.js?458964';

class Employee extends ResourceModel {
    static get fields() {
        return [
            { name : 'available', type : 'boolean', defaultValue : true },
            { name : 'statusMessage', defaultValue : 'Gone fishing' }
        ];
    }

get cls() {
    return this.available ? '' : 'unavailable';
}
}

class Task extends EventModel {
    static get fields() {
        return ['type'];
    }

get dragValidationText() {
    const { resource, type } = this;

    let result = '';

    switch (type) {
        case 'Golf':
            result = 'Only C-suite people can play Golf';
            break;
        case 'Meeting':
            result = `Only ${resource.role} can participate in meetings`;
            break;
        case 'Coding':
            result = `Only ${resource.role} can do coding`;
            break;
        case 'Sales':
            result = `Only ${resource.role} can prepare marketing strategies`;
            break;
        case 'Fixed':
            result = 'Fixed time event - may be reassigned, but not rescheduled';
            break;
    }

    return result;
}

get resizeValidationText() {
    let result = '';

    switch (this.type) {
        case 'Golf':
            result = 'Golf game has always fixed duration';
            break;
        case 'Coding':
            result = 'Programming task duration cannot be shortened';
            break;
    }

    return result;
}
}

const scheduler = new Scheduler({
    appendTo          : 'container',
    // don't allow tasks to overlap
    allowOverlap      : false,
    resourceImagePath : '../_shared/images/users/',
    features          : {
        stripe       : true,
        timeRanges   : true,
        eventTooltip : {
            template : data => {
                const task = data.eventRecord;
                return `
                    ${task.name ? StringHelper.xss`<div class="b-sch-event-title">${task.name}</div>` : ''}
                    ${data.startClockHtml}
                    ${data.endClockHtml}
                    ${(task.dragValidationText || task.resizeValidationText) ? `<div class="restriction-title"><b>Restrictions:</b></div>
                    <ul class="restriction-list">
                        ${task.dragValidationText ? `<li>${task.dragValidationText}</li>` : ''}
                        ${task.resizeValidationText ? `<li>${task.resizeValidationText}</li>` : ''}
                    </ul>` : ''}
                `;
            }
        },
        eventDrag : {
            validatorFn({ eventRecords, newResource }) {
                console.log("eventDrag  validatorFn");
                const
                    task    = eventRecords[0],
                    isValid = task.type === 'Fixed' ||
                        // Only C-suite people can play Golf
                        (task.type === 'Golf' && ['CEO', 'CTO'].includes(newResource.role)) ||
                        // Tasks that have type defined cannot be assigned to another resource type
                        !(task.type && newResource.role !== task.resource.role);

            return {
                valid   : newResource.available && isValid,
                message : !newResource.available ? newResource.statusMessage : (!isValid ? task.dragValidationText : '')
            };
        }
    },
    eventResize : {
        validatorFn({ eventRecord : task, endDate, startDate }) {
            const
                originalDuration = task.endDate - task.startDate,
                isValid          = !(task.type === 'Golf' || (task.type === 'Coding' && originalDuration > endDate - startDate));
            return {
                valid   : isValid,
                message : isValid ? '' : task.resizeValidationText
            };
        }
    },
    eventDragCreate : {
        validatorFn({ resourceRecord : resource }) {
            return {
                valid   : resource.available,
                message : resource.available ? '' : resource.statusMessage
            };
        }
    }
},

subGridConfigs : {
    locked : { width : 350 }
},

columns : [
    {
        type : 'resourceInfo',
        text : 'Staff'
    },
    {
        text   : 'Role',
        field  : 'role',
        flex   : 1,
        editor : {
            type        : 'combo',
            items       : ['Sales', 'Developer', 'Marketing', 'Product manager'],
            editable    : false,
            pickerWidth : 140
        }
    },
    {
        text  : 'Available',
        type  : 'check',
        field : 'available'
    }
],

crudManager : {
    autoLoad   : true,
    eventStore : {
        modelClass : Task
    },
    resourceStore : {
        modelClass : Employee
    },
    transport : {
        load : {
            url : 'data/data.json'
        }
    },
    // This config enables CrudManager responses validation and dumping of found errors to the browser console.
    // It's meant to be used as a development stage helper only so please set it to false for production systems.
    validateResponse : true
},

barMargin  : 2,
rowHeight  : 50,
startDate  : new Date(2019, 1, 7, 8),
endDate    : new Date(2019, 1, 7, 22),
viewPreset : {
    base      : 'hourAndDay',
    tickWidth : 100
},
multiEventSelect : true,

// Specialized body template with header and footer
eventBodyTemplate : data => `${data.iconCls ? `<i class="${data.iconCls}"></i>` : ''}` +
    StringHelper.xss`<section>
        <div class="b-sch-event-header">${data.headerText}</div>
        <div class="b-sch-event-footer">${data.footerText}</div>
    </section>
`,

eventRenderer({ eventRecord, resourceRecord, renderData }) {
    return {
        headerText : DateHelper.format(eventRecord.startDate, 'LT'),
        footerText : eventRecord.name || '',
        iconCls    : eventRecord.iconCls
    };
},

listeners : {
    beforeEventAdd({ resourceRecords }) {
        const
            [resource] = resourceRecords,
            available  = resource.available;

        if (!available) {
            Toast.show(`Resource not available: ${resource.statusMessage}`);
        }

        return available;
    },

    beforeEventDrag({ eventRecord }) {
        // Only Henrik can be assigned Marketing tasks.
        // constrainDragToResource prevents dragging up or down.
        console.log("beforeEventDrag");
        scheduler.features.eventDrag.constrainDragToResource = eventRecord.type === 'Marketing' && eventRecord.resource.name === 'Henrik';

        // Events with type Fixed must not change time slot.
        scheduler.features.eventDrag.constrainDragToTimeSlot = eventRecord.type === 'Fixed';
    },
    eventDragAbort({ eventRecord }){ 
        console.log("eventDragAbort");
    },

    async beforeEventDropFinalize({ source : scheduler, context }) {
        if (scheduler.confirmationsEnabled) {
            context.async = true;

            const
                namesInQuotes = context.eventRecords.map(eventRecord => `"${StringHelper.encodeHtml(eventRecord.name)}"`),
                result        = await MessageDialog.confirm({
                    title   : 'Please confirm',
                    message : `${namesInQuotes.join(', ')} ${namesInQuotes.length > 1 ? 'were' : 'was'} moved. Allow this operation?`
                });

            // `true` to accept the changes or `false` to reject them
            context.finalize(result === MessageDialog.yesButton);
        }
    },

    async beforeEventResizeFinalize({ source : scheduler, context }) {
        if (scheduler.confirmationsEnabled) {
            context.async = true;

            const
                eventRecord = context.eventRecord,
                result      = await MessageDialog.confirm({
                    title   : 'Please confirm',
                    message : StringHelper.xss`"${eventRecord.name}" duration changed. Allow this operation?`
                });

            // `true` to accept the changes or `false` to reject them
            context.finalize(result === MessageDialog.yesButton);
        }
    }
},

tbar : [
    {
        type        : 'button',
        ref         : 'confirmationBtn',
        text        : 'Enable confirmations',
        toggleable  : true,
        icon        : 'b-fa-square',
        pressedIcon : 'b-fa-check-square',
        onAction    : ({ source : button }) => scheduler.confirmationsEnabled = button.pressed
    },
    {
        type        : 'button',
        ref         : 'lockBtn',
        text        : 'Read only',
        toggleable  : true,
        icon        : 'b-fa-square',
        pressedIcon : 'b-fa-check-square',
        onAction    : ({ source : button }) => scheduler.readOnly = button.pressed
    }
]
});

Cheers!!


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri May 20, 2022 2:05 pm
by mats

Reproduced, we will look into this! https://github.com/bryntum/support/issues/4658


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Mon May 23, 2022 2:27 am
by andrew.perera

@mats Thanks Mate,

Is there a rough time when we can expect the 5.0.5 release?

Cheers.


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Mon May 23, 2022 8:43 am
by alex.l

It should be released in next few weeks, cannot provide exact dates unfortunately.


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Tue May 31, 2022 3:40 pm
by mats

@andrew.perera Can you please try using afterEventDrop event and check the valid flag to detect invalid drops? Does that solve it for you?

We plan to refactor EventDrag later this year, so would be ideal if we can avoid turbulence until we start that task.


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri Jun 03, 2022 1:07 am
by andrew.perera

Hi Mats,
Thanks for the suggession,
We need to see the code and see how much work is involved in converting them to retain the business logic.


Re: [REACT] Scheduler : eventDragAbort does not trigger as expected in 5.0.1

Posted: Fri Jun 03, 2022 8:30 am
by alex.l

Here is an example

const scheduler = new Scheduler({
    appendTo          : 'container',
    
// ... listeners : { afterEventDrop({ eventRecords, valid }) { if (!valid) { // do action if drop is invalid } }, }