Premium support for our pure JavaScript UI components


Post by jk@datapult.dk »

Howdy,

This is one does not reproduce on the examples side so I am attaching the full code below.

The issue: When copy and pasting an event with the CrudMananger, it emits an update to the backend rather than and added event. I know the the CrudManager generally speaking can handle CopyPasteEvents correctly, but not here. See this video:
https://www.dropbox.com/s/3maue33s36wwsxm/Screen%20Recording%202022-12-09%20at%2010.14.59.mov?dl=0

Here is the full code and I am running Bryntum 5.2.3.

<script lang="ts">
import type {Ref, UnwrapRef} from "vue";
import {ref} from "vue";
import EnLocale from '@bryntum/scheduler/locales/scheduler.locale.En';

import {LocaleManager, AjaxStore} from '@bryntum/scheduler';
import {BryntumScheduler} from '@bryntum/scheduler-vue-3';

import {storeToRefs} from "pinia";
import {commonStore} from "../../stores/common";

export default {
  components: {
    BryntumScheduler
  },

  setup() {
    const {teamFilter, isoLanguage} = storeToRefs(commonStore())

    LocaleManager.registerLocale('En', {
      ...EnLocale,
      desc: 'En',
      locale: {
        DateHelper: {
          locale: isoLanguage.value,
          weekStartDay: 1
        }
      }
    });
    LocaleManager.applyLocale('En');

    const wishTypes = new AjaxStore({ id: 'wishTypes', })

    const teamId = teamFilter.value

    const wishesConfig = {
      ref: "wishRef",
      insertFirst: "wishes-view",
      viewPreset: 'dayAndWeek',
      eventStyle: 'border',
      flex: 1,

      syncMask: null,
      loadMask: null,

      rowHeight: 35,
      weekStartDay: 1,
      zoomOnMouseWheel: true,
      zoomOnTimeAxisDoubleClick: false,
      infiniteScroll: true,
      useInitialAnimation: 'slide-from-left',
      createEventOnDblClick: true,

      features: {
        stripe: true,
        sort: 'list_order',
        eventCopyPaste: {
          generateNewName: (event) => event.name
        },
        eventDragSelect: true,
        eventDragCreate: false,
        eventResize: {
          disabled: true,
        },
        timeRanges: false,
      },

      columns: [
        {
          type: "resourceInfo",
          text: "Name",
          field: "name",
          showImage: false,
          showEventCount: false,
          width: 250,
          locked: true,
        },
      ],

      crudManager: {
        resourceStore: {
          fields: ['id', 'name', 'list_order', 'color']
        },
        eventStore: {
          fields: [
            {name: "id", dataSource: "frontendId",},
            {name: "backendId", type: "integer"},
            {name: "startDate", dataSource: "start",},
            {name: "endDate", dataSource: "end",},
            {name: "resourceId", dataSource: "userId",},
            {name: "wishTypeId", type: "integer"},
            {name: "historic", type: "boolean", defaultValue: true},
            {name: "note", type: "string"},
            {name: "name", type: "string"},
            {name: "schedule_id", type: "integer"},
            {name: "plan_detail_id", type: "integer"},
            {name: "color", type: "string"},
            {name: "roomId", type: "integer"},
            {name: "state", type: "string"},
            {name: "staffing_mode", type: "string"},
            {name: "preferred_user_ids", type: "array"},
            {name: "allowed_room_collisions", type: "array"},
            {name: "is_pinned", type: "boolean"},
            {name: "durationUnit", defaultValue: "day"},
            {name: "eventType", type: "string", defaultValue: "shift"},
          ]
        },
        stores: [wishTypes,],
        autoLoad: true,
        autoSync: true,
        writeAllFields: true,
        transport: {
          load: {
            url: `/api/scheduler/wishes/${teamId}`,
            method: 'GET',
          },
          sync: {
            url: `/api/scheduler/wishes/${teamId}`,
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-XSRF-TOKEN': decodeURIComponent(document.cookie.split(";").find(x => x.includes("XSRF")).trim().replace("XSRF-TOKEN=", ""))
            }
          }
        },
        validateResponse: true,
      },
    }
    const wishRef: Ref<UnwrapRef<BryntumScheduler>> = ref(null);

    return {
      teamFilter,
      wishesConfig,
      wishRef,
    }
  }
}

</script>
<template>

  <div id="wishes-view" v-if="teamFilter !== 0">

    <bryntum-scheduler
        ref="wishRef"
        v-bind="wishesConfig" />

  </div>

</template>
<style scoped>
#wishes-view {
  display: flex;
  flex-direction: row;
  flex: 1 1 100%;
  margin: 2px;
  padding: 2px;
  height: 100%;
}
</style>

Post by alex.l »

In your video it looks like cut/paste. The event was moved and not copied. I can't use your full code because it's not runnable and has dependencies from other packages, also it linked to API I don't have access to.
But I tried to apply your config to our examples and test it. It works correct to me.
I guess the problem might be in data mapping you used in your data model. Could you please provide us a JSON with test data so I will be able to apply your mapping config and test it again?

All the best,
Alex


Post by jk@datapult.dk »

I UPDATED THE CODE HERE A FEW TIMES, THE LATEST AT 14.50 TO MAKE IT EASIER TO TEST

alex.l wrote: Fri Dec 09, 2022 2:27 pm

In your video it looks like cut/paste. The event was moved and not copied.

I thought the video clearly showed I pressed "copy"? In any case, I pressed copy and can replicate the issue with Ctrl+C/Ctrl+V.

alex.l wrote: Fri Dec 09, 2022 2:27 pm

It's not runnable and has dependencies from other packages, also it linked to API I don't have access to.

Fair. I have watered it down even more below but given this weird behavior I believe Vue is important :-)

alex.l wrote: Fri Dec 09, 2022 2:27 pm

Could you please provide us a JSON with test data so I will be able to apply your mapping config and test it again?

Sure, see below.

CODE

<script lang="ts">
import type {Ref, UnwrapRef} from "vue";
import {ref, onMounted} from "vue";
import EnLocale from '@bryntum/scheduler/locales/scheduler.locale.En';

import {LocaleManager, AjaxStore} from '@bryntum/scheduler';
import {BryntumScheduler} from '@bryntum/scheduler-vue-3';


export default {
  components: {
    BryntumScheduler
  },

  setup() {

    LocaleManager.registerLocale('En', {
      ...EnLocale,
      desc: 'En',
      locale: {
        DateHelper: {
          locale: "da-DK",
          weekStartDay: 1
        }
      }
    });
    LocaleManager.applyLocale('En');

    const wishTypes = new AjaxStore({ id: 'wishTypes', })

    const teamId = 875;

    const wishesConfig = {
      ref: "wishRef",
      insertFirst: "wishes-view",
      viewPreset: 'dayAndWeek',
      eventStyle: 'border',
      flex: 1,
      startDate: new Date("2022-11-01T00:00:00Z"),
      endDate: new Date("2022-11-03T00:00:00Z"),

      syncMask: null,
      loadMask: null,

      rowHeight: 35,
      weekStartDay: 1,
      zoomOnMouseWheel: true,
      zoomOnTimeAxisDoubleClick: false,
      infiniteScroll: true,
      useInitialAnimation: 'slide-from-left',
      createEventOnDblClick: true,

      features: {
        stripe: true,
        sort: 'list_order',
        eventCopyPaste: {
          generateNewName: (event) => event.name
        },
        eventDragSelect: true,
        eventDragCreate: false,
        eventResize: {
          disabled: true,
        },
        timeRanges: false,
      },

      columns: [
        {
          type: "resourceInfo",
          text: "Name",
          field: "name",
          showImage: false,
          showEventCount: false,
          width: 250,
          locked: true,
        },
      ],

      crudManager: {
        autoLoad: false,
        autoSync: false,
        resourceStore: {
          fields: ['id', 'name', 'list_order', 'color']
        },
        eventStore: {
          fields: [
            {name: "name", type: "string"},
            {name: "id", dataSource: "frontendId",},
            {name: "backendId", type: "integer"},
            {name: "wishTypeId", type: "integer"},
            {name: "roomId", type: "integer"},
            {name: "resourceId", dataSource: "userId",},
            {name: "note", type: "string"},
            {name: "eventType", type: "string", defaultValue: "shift"},
            {name: "startDate", dataSource: "start",},
            {name: "endDate", dataSource: "end",},
            {name: "historic", type: "boolean", defaultValue: true},
            {name: "durationUnit", defaultValue: "day"},
          ]
        },
        stores: [wishTypes,],
        autoLoad: false,
        autoSync: false,
        writeAllFields: true,
        transport: {
          load: {
            url: `/api/scheduler/wishes/${teamId}`,
            method: 'GET',
          },
          sync: {
            url: `/api/scheduler/wishes/${teamId}`,
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-XSRF-TOKEN': decodeURIComponent(document.cookie.split(";").find(x => x.includes("XSRF")).trim().replace("XSRF-TOKEN=", ""))
            }
          }
        },
        validateResponse: true,
      },
    }
    const wishRef: Ref<UnwrapRef<BryntumScheduler>> = ref(null);

    onMounted(() => {
      const scheduler: Scheduler = wishRef.value.instance.value;
      scheduler.crudManager.inlineData = {
        eventsData: [],
        resourcesData: [
          {
            "id": 16582,
            "name": "User 16743",
            "list_order": 4,
            "initials": "16743",
            "email": "user16743@email.com",
            "private_phone": "",
            "public_phone": "",
            "is_on_shift": true,
            "contract_id": 288,
            "color": null,
            "created_at": "2022-06-17T07:11:30.000000Z",
            "updated_at": "2022-12-08T10:34:03.000000Z",
            "deleted_at": null,
            "created_by": 9213,
            "updated_by": 9213,
            "pivot": {
              "team_id": 5311,
              "user_id": 16743,
              "start": null,
              "end": null
            }
          },
        ],
        eventsData: [
          {
            "start": "2022-11-02T23:00:00Z",
            "end": "2022-11-03T22:59:00Z",
            "userId": 16582,
            "name": "Afspadsering",
            "style": null,
            "frontendId": "WISHID10377",
            "backendId": 10377,
            "wishTypeId": 359,
            "roomId": null,
            "note": "Hej ",
            "eventType": "wish",
            "historic": false,
            "cls": "",
            "eventStyle": "dashed"
          }
        ],
      }
    })

    return {
      wishesConfig,
      wishRef,
    }
  }
}

</script>
<template>

  <div id="wishes-view">

    <bryntum-scheduler
        ref="wishRef"
        v-bind="wishesConfig" />

  </div>

</template>
<style scoped>
#wishes-view {
  display: flex;
  flex-direction: row;
  flex: 1 1 100%;
  margin: 2px;
  padding: 2px;
  height: 100%;
}
</style>

Post by jk@datapult.dk »

Just a small update: At 14:51 I updated the code in the previous so it is super-easy to replicate and run.


Post by alex.l »

Thanks for clarifications!
As I initially supposed, the problem with data mapping - it works incorrect with id field mapping.
That's a bug that we will fix. Here is the ticket to track the status https://github.com/bryntum/support/issues/5770

All the best,
Alex


Post by jk@datapult.dk »

Is there a workaround until then? On - forgive my bluntness - can I buy the hours needed from Professional Service to go ahead and fix this in a coming release?


Post by alex.l »

Yes, you can contact our sales to arrange that https://www.bryntum.com/services

As a workaround, try to not use mapping for id field and set idField in extended EventModel. I tried it with basic setup and it worked.
Docs:
https://bryntum.com/products/scheduler/docs/api/Scheduler/data/EventStore#config-modelClass
https://bryntum.com/products/scheduler/docs/api/Scheduler/model/EventModel#subclassing-the-event-model-class

Code:

class MyModel extends EventModel {
    // this is that you need!
    static idField = 'frontendId';
    
fields : [ {name: "name", type: "string"}, {name: "backendId", type: "integer"}, {name: "wishTypeId", type: "integer"}, {name: "roomId", type: "integer"}, {name: "resourceId", dataSource: "userId",}, {name: "note", type: "string"}, {name: "eventType", type: "string", defaultValue: "shift"}, {name: "startDate", dataSource: "start",}, {name: "endDate", dataSource: "end",}, {name: "historic", type: "boolean", defaultValue: true}, {name: "durationUnit", defaultValue: "day"} ] } // ... const scheduler = new Scheduler({ // ... crudManager: { eventStore: { modelClass : MyModel } },

All the best,
Alex


Post Reply