Premium support for our pure JavaScript UI components


Post by jk@datapult.dk »

Hi,

On 5.3.1, I am experiencing this issue where a CrudManager triggers an updated event after receiving the backend response from an added event: https://www.dropbox.com/s/qu4ombiqje8kwj7/rounding-error.mov?dl=0

Replicating this issue is doable using the guide below but please keep in mind:
You must create the event starting March 23 00:00 through March 24 23:59 for the simple backend to create this.

I believe it is due to the rounding error because if I set the CrudManager writeAllFields: false it only sends the duration to the backend.

Also, attached are the payloads sent between CM and backend along some visual diffs for your convenience:

https://www.dropbox.com/s/k6t6buol3930dso/first-request.json?dl=0

https://www.dropbox.com/s/7bidtq5bujsfbms/first-response.json?dl=0

https://www.dropbox.com/s/sylo44t6z9wzz6r/second-request.json?dl=0

REPLICATING THE ISSUE
Download the zip file.

Since we do need a backend to server a few things, it is a multi-step setup.

In the project root:

python3 server.py

In another terminal window, do this to get an interactive session with npm 16:

docker run -it --rm -p 3000:3000 -v $PWD:/home/node/app node:16-buster /bin/bash

Inside the container do:

cd /home/node/app/ && npm install && npm run dev

Once done, you can now open this in your browser: http://localhost:3030/public/index.html

Attachments
Screenshot 2023-03-17 at 22.31.19.png
Screenshot 2023-03-17 at 22.31.19.png (532.03 KiB) Viewed 253 times
Screenshot 2023-03-17 at 22.32.45.png
Screenshot 2023-03-17 at 22.32.45.png (520 KiB) Viewed 253 times
bryntum-demo-main.zip
(3.18 MiB) Downloaded 17 times

Post by alex.l »

Thanks for the report, I've opened a ticket to investigate this https://github.com/bryntum/support/issues/6402

All the best,
Alex


Post by jk@datapult.dk »

Hi. I hope that you are well. This is currently blocking us. Is there any news? I would be happy to pay for making progress on this one out of respect for your time. Thanks.


Post by jk@datapult.dk »

Here is a replicable script based on your on example.

Copy/paste below in here: https://bryntum.com/products/scheduler/examples/shared-crudmanager/

I am always happy to file bugs but I a solution to this also urgent for me. What should I do to have something working for me?

import {Scheduler, CrudManager, EventModel, PresetManager, ViewPreset} from '../../build/scheduler.module.js?466403';
import shared from '../_shared/shared.module.js?466403';

const myViewPreset = new ViewPreset({
    id: 'myPreset',
    name: 'myPreset',
    defaultSpan: 7 * 4,
    shiftIncrement: 1,
    timeResolution: {
        unit: 'day',
        increment: 1
    },
    headers: [
        {unit: "week", dateFormat: "W",},
        {unit: "month", dateFormat: "MMMM",},
        {unit: "day", dateFormat: "D",},
        {unit: "day", dateFormat: "ddd",},
    ],
});

PresetManager.add(myViewPreset)


class MyModel extends EventModel {
    static get fields() {
        return [
            'description',
            {name: "durationUnit", defaultValue: "day"},
            {name: 'percentDone', type: 'number', defaultValue: 0}
        ]
    }
}

// CrudManager instance, both Schedulers chains their stores from it
const crudManager = new CrudManager({
    autoLoad: true,
    autoSync: true,
    writeAllFields: true,
    eventModel: MyModel,
    loadUrl: 'data/data.json',
    syncUrl: 'data/data.json',
});


// Top scheduler, showing "unassigned events" aka assigned to the "backlog" resource
const backlog = new Scheduler({
    snapRelativeToEventStartDate: true, fillTicks: true, viewPreset: 'myPreset', snap: true,
    appendTo: 'container',
    startDate: new Date(2023, 0, 29),
    endDate: new Date(2023, 1, 12),
    cls: 'backlog',
    height: 168,
    minHeight: 168,
    rowHeight: 100,
    eventLayout: 'pack',

    // Use the CrudManager's stores. Internally the eventStore will also be chained
    eventStore: crudManager.eventStore,
    resourceStore: crudManager.resourceStore.chain(r => r.id === 'backlog'),

    features: {
        columnLines: false,
        eventDrag: {
            constrainDragToTimeline: false
        },
        nonWorkingTime: true,
        stickyEvents: false
    },

    columns: [
        {field: 'name', text: 'Name', width: 150}
    ],

});

// Bottom scheduler, showing "assigned events"
const planned = new Scheduler({
    snapRelativeToEventStartDate: true, fillTicks: true, viewPreset: 'myPreset', snap: true,
    appendTo: 'container',
    partner: backlog,
    hideHeaders: true,
    cls: 'planned',
    rowHeight: 110,
    tickSize: 75,

    eventStore: crudManager.eventStore,
    resourceStore: crudManager.resourceStore.chain(r => r.id !== 'backlog'),

    features: {
        columnLines: false,
        eventDrag: {
            constrainDragToTimeline: false
        },
        eventEdit: {
            items: {
                description: {
                    type: 'textareafield',
                    name: 'description',
                    label: 'Info',
                    weight: 150
                },
                percentDone: {
                    type: 'numberfield',
                    name: 'percentDone',
                    label: 'Progress',
                    max: 100,
                    min: 0
                }
            }
        },
        nonWorkingTime: true,
        stripe: true,
        stickyEvents: false
    },

    columns: [
        {field: 'name', text: 'Name', width: 150}
    ],

});
crudManager.on({
    load() {
        setTimeout(() => {
                crudManager.applyChangeset({
                    events: {
                        added: [
                            {
                                "id": 3000,
                                "startDate": "2023-02-03T00:00:00+02:00",
                                "endDate": "2023-02-04T00:00:00+02:00",
                                "cls": "",
                                "name": "Plan implementation",
                                "resourceId": "r1",
                                "allDay": false,
                                "eventColor": "pink",
                                "description": "Make a very detailed plan, to satisfy requirements",
                                "percentDone": 70
                            }
                        ]
                    }
                })
            },
            500)
    }
})

Post by jk@datapult.dk »

The heart of replication is wrapping is the setTimeout. This is meant to mimic how users does something after the Scheduler is loaded. Here is an even simpler example where the setTimeout is not nested inside an event and I removed other things not related to the bug. This example clearly shows that something "odd" is at play here :-)

import {Scheduler, CrudManager} from '../../build/scheduler.module.js?466403';
import shared from '../_shared/shared.module.js?466403';

// CrudManager instance, both Schedulers chains their stores from it
const crudManager = new CrudManager({
    autoLoad: true,
    autoSync: true,
    writeAllFields: true,
    eventFields: [
        'description',
        {name: 'percentDone', type: 'number', defaultValue: 0}
    ],
    loadUrl: 'data/data.json',
    syncUrl: 'data/data.json',
});


// Top scheduler, showing "unassigned events" aka assigned to the "backlog" resource
const backlog = new Scheduler({
    snapRelativeToEventStartDate: true, fillTicks: true, snap: true,
    appendTo: 'container',
    startDate: new Date(2023, 0, 29),
    endDate: new Date(2023, 1, 12),
    cls: 'backlog',
    height: 168,
    minHeight: 168,
    rowHeight: 100,
    eventLayout: 'pack',

    // Use the CrudManager's stores. Internally the eventStore will also be chained
    eventStore: crudManager.eventStore,
    resourceStore: crudManager.resourceStore.chain(r => r.id === 'backlog'),

    features: {
        columnLines: false,
        eventDrag: {
            constrainDragToTimeline: false
        },
        nonWorkingTime: true,
        stickyEvents: false
    },

    columns: [
        {field: 'name', text: 'Name', width: 150}
    ],

});

// Bottom scheduler, showing "assigned events"
const planned = new Scheduler({
    snapRelativeToEventStartDate: true, fillTicks: true, snap: true,
    appendTo: 'container',
    partner: backlog,
    hideHeaders: true,
    cls: 'planned',
    rowHeight: 110,
    tickSize: 75,

    eventStore: crudManager.eventStore,
    resourceStore: crudManager.resourceStore.chain(r => r.id !== 'backlog'),

    features: {
        columnLines: false,
        eventDrag: {
            constrainDragToTimeline: false
        },
        eventEdit: {
            items: {
                description: {
                    type: 'textareafield',
                    name: 'description',
                    label: 'Info',
                    weight: 150
                },
                percentDone: {
                    type: 'numberfield',
                    name: 'percentDone',
                    label: 'Progress',
                    max: 100,
                    min: 0
                }
            }
        },
        nonWorkingTime: true,
        stripe: true,
        stickyEvents: false
    },

    columns: [
        {field: 'name', text: 'Name', width: 150}
    ],

});

setTimeout(() => {
    crudManager.applyChangeset({
        events: {
            added: [
                {
                    "id": 3000,
                    "startDate": "2023-02-03T00:00:00+02:00",
                    "endDate": "2023-02-04T00:00:00+02:00",
                    "cls": "",
                    "name": "Plan implementation",
                    "resourceId": "r1",
                    "allDay": false,
                    "eventColor": "pink",
                    "description": "Make a very detailed plan, to satisfy requirements",
                    "percentDone": 70
                }
            ]
        }
    })
}, 500)

Post by johan.isaksson »

Hi,

I got your test case running and can confirm I see a duration change. Will investigate the reason and hopefully come up with a fix

Best regards,
Johan Isaksson

Post by johan.isaksson »

Hi again,

Having looked a bit more at it, it seems to be doing what it should. When given un-normalized data (duration is missing), it will fill in the missing parts, thus leaving the record modified.

If you do not want to store & pass the duration, I recommend you flag the duration field on your event model as persist: false. It should then not lead to another sync.

Hope that helps!

Best regards,
Johan Isaksson

Post by jk@datapult.dk »

Thanks!


Post Reply