Request new features or modifications


Post by tanayb »

Scenario: Consider a single scheduler instance using CRUD manager, where various functionalities are implemented like

  1. additional custom stores
  2. filters on resource and events
  3. undo/redo using state management
  4. conditional row reorder using gridRowDrag, gridRowBeforeDragStart, gridRowDrop
  5. conditional event feature (like - resize, drag and drop, different event styles, beforeeventdropfinalize)
  6. conditional context menu for events and processed context menu for different resource
  7. additional fields by extending Resource Model class
  8. run-time column creation and configuration based on data
  9. certain functionality which happens based on logic during - beforeSend, beforeResponseApply, sync, load, beforeLoadApply, requestFail
  10. trasport configuration
  11. viewpresets configuration
  12. dependenciesFeature, cellTooltipFeature, timeRange tooltip, special templates for column cells, nonWorkingTimeFeature, eventTooltipFeature, timeRangesFeature

Requirement

I would like to have a split schedule functionality, which I have elaborated below
Step 1: I have a basic schedule with 25 rows (more than 50 in real scenario)

Basic Schedule
Basic Schedule
Split screen 1.png (140.13 KiB) Viewed 2220 times

Basic Schedule

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

//region Data

const
    resources = [
  {
    "id": 1,
    "name": "Arcady",
    "role": "Core developer"
  },
  {
    "id": 2,
    "name": "Dave",
    "role": "Tech Sales"
  },
  {
    "id": 3,
    "name": "Henrik",
    "role": "Sales"
  },
  {
    "id": 4,
    "name": "Linda",
    "role": "Core developer"
  },
  {
    "id": 5,
    "name": "Maxim",
    "role": "Developer & UX"
  },
  {
    "id": 6,
    "name": "Mike",
    "role": "CEO"
  },
  {
    "id": 7,
    "name": "Lee",
    "role": "CTO"
  },
  {
    "id": 8,
    "name": "Amit",
    "role": "Core developer"
  },
  {
    "id": 9,
    "name": "Kate",
    "role": "Tech Sales"
  },
  {
    "id": 10,
    "name": "Jong",
    "role": "Sales"
  },
  {
    "id": 11,
    "name": "Lola",
    "role": "Core developer"
  },
  {
    "id": 12,
    "name": "Lisa",
    "role": "UX"
  },
  {
    "id": 13,
    "name": "Steve",
    "role": "COO"
  },
  {
    "id": 14,
    "name": "Malik",
    "role": "CFO"
  },
  {
    "id": 15,
    "name": "Maxim",
    "role": "Developer & UX"
  },
  {
    "id": 16,
    "name": "Mike",
    "role": "CEO"
  },
  {
    "id": 17,
    "name": "Lee",
    "role": "CTO"
  },
  {
    "id": 18,
    "name": "Amit",
    "role": "Core developer"
  },
  {
    "id": 19,
    "name": "Kate",
    "role": "Tech Sales"
  },
  {
    "id": 20,
    "name": "Jong",
    "role": "Sales"
  },
  {
    "id": 21,
    "name": "Lola",
    "role": "Core developer"
  },
  {
    "id": 22,
    "name": "Lisa",
    "role": "UX"
  },
  {
    "id": 23,
    "name": "Steve",
    "role": "COO"
  },
  {
    "id": 24,
    "name": "Malik",
    "role": "CFO"
  }
    ],
    events = [
  {
    "id": "r1",
    "resourceId": 1,
    "name": "Restart server (not draggable)",
    "iconCls": "b-fa b-fa-movie",
    "startDate": "2025-12-01T08:00:00",
    "duration": 3,
    "durationUnit": "h",
    "draggable": false,
    "resizable": true
  },
  {
    "id": "r2",
    "resourceId": 1,
    "name": "Upgrade memory",
    "iconCls": "b-fa b-fa-laptop",
    "startDate": "2025-12-01T15:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r3",
    "resourceId": 2,
    "name": "Visit customer",
    "iconCls": "b-fa b-fa-user",
    "startDate": "2025-12-01T09:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r4",
    "resourceId": 3,
    "name": "Arrange meetup",
    "iconCls": "b-fa b-fa-users",
    "startDate": "2025-12-01T09:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r5",
    "resourceId": 7,
    "name": "Make coffee",
    "startDate": "2025-12-01T12:00:00",
    "iconCls": "b-fa b-fa-coffee",
    "duration": 4,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r6",
    "resourceId": 9,
    "name": "Conference prep",
    "iconCls": "b-fa b-fa-building",
    "startDate": "2025-12-01T09:00:00",
    "cls": "Special",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r16",
    "resourceId": 11,
    "name": "Presentation",
    "iconCls": "b-fa b-fa-video",
    "startDate": "2025-12-01T13:00:00",
    "cls": "Special",
    "duration": 2,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  }
    ];

//endregion

const scheduler = new Scheduler({
    appendTo         : 'container',
    resourceImagePath : '../_shared/images/users/',
    resources        : resources,
    events           : events,
    startDate        : new Date(2025, 11, 1, 7),
    endDate          : new Date(2025, 11, 1, 20),
    viewPreset       : 'hourAndDay',
    rowHeight        : 50,
    barMargin        : 5,
    multiEventSelect : true,
    columns          : [
{type:'rownumber'},
        { text : 'Name', type  : 'resourceInfo', field : 'name', width : 130 }
    ]
});

Step 2: Spliting Schedule to have row 1 to 12 in one top part, whereas 13 to 15 in bottom
[Note]: Here I have used Drag drop between multiple schedulers example that allows drag drop between two schedule for visual reference purpose only

Split Schedule with drag and drop across them
Split Schedule with drag and drop across them
Split screen 2.png (130.63 KiB) Viewed 2220 times

Split schedule visual

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

//region Data

const
    resources = [
  {
    "id": 1,
    "name": "Arcady",
    "role": "Core developer"
  },
  {
    "id": 2,
    "name": "Dave",
    "role": "Tech Sales"
  },
  {
    "id": 3,
    "name": "Henrik",
    "role": "Sales"
  },
  {
    "id": 4,
    "name": "Linda",
    "role": "Core developer"
  },
  {
    "id": 5,
    "name": "Maxim",
    "role": "Developer & UX"
  },
  {
    "id": 6,
    "name": "Mike",
    "role": "CEO"
  },
  {
    "id": 7,
    "name": "Lee",
    "role": "CTO"
  },
  {
    "id": 8,
    "name": "Amit",
    "role": "Core developer"
  },
  {
    "id": 9,
    "name": "Kate",
    "role": "Tech Sales"
  },
  {
    "id": 10,
    "name": "Jong",
    "role": "Sales"
  },
  {
    "id": 11,
    "name": "Lola",
    "role": "Core developer"
  },
  {
    "id": 12,
    "name": "Lisa",
    "role": "UX"
  },
  {
    "id": 13,
    "name": "Steve",
    "role": "COO"
  },
  {
    "id": 14,
    "name": "Malik",
    "role": "CFO"
  },
  {
    "id": 15,
    "name": "Maxim",
    "role": "Developer & UX"
  },
  {
    "id": 16,
    "name": "Mike",
    "role": "CEO"
  },
  {
    "id": 17,
    "name": "Lee",
    "role": "CTO"
  },
  {
    "id": 18,
    "name": "Amit",
    "role": "Core developer"
  },
  {
    "id": 19,
    "name": "Kate",
    "role": "Tech Sales"
  },
  {
    "id": 20,
    "name": "Jong",
    "role": "Sales"
  },
  {
    "id": 21,
    "name": "Lola",
    "role": "Core developer"
  },
  {
    "id": 22,
    "name": "Lisa",
    "role": "UX"
  },
  {
    "id": 23,
    "name": "Steve",
    "role": "COO"
  },
  {
    "id": 24,
    "name": "Malik",
    "role": "CFO"
  }
    ],
    events = [
  {
    "id": "r1",
    "resourceId": 1,
    "name": "Restart server (not draggable)",
    "iconCls": "b-fa b-fa-movie",
    "startDate": "2025-12-01T08:00:00",
    "duration": 3,
    "durationUnit": "h",
    "draggable": false,
    "resizable": true
  },
  {
    "id": "r2",
    "resourceId": 1,
    "name": "Upgrade memory",
    "iconCls": "b-fa b-fa-laptop",
    "startDate": "2025-12-01T15:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r3",
    "resourceId": 2,
    "name": "Visit customer",
    "iconCls": "b-fa b-fa-user",
    "startDate": "2025-12-01T09:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r4",
    "resourceId": 3,
    "name": "Arrange meetup",
    "iconCls": "b-fa b-fa-users",
    "startDate": "2025-12-01T09:00:00",
    "cls": "",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r5",
    "resourceId": 7,
    "name": "Make coffee",
    "startDate": "2025-12-01T12:00:00",
    "iconCls": "b-fa b-fa-coffee",
    "duration": 4,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r6",
    "resourceId": 9,
    "name": "Conference prep",
    "iconCls": "b-fa b-fa-building",
    "startDate": "2025-12-01T09:00:00",
    "cls": "Special",
    "duration": 3,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  },
  {
    "id": "r16",
    "resourceId": 11,
    "name": "Presentation",
    "iconCls": "b-fa b-fa-video",
    "startDate": "2025-12-01T13:00:00",
    "cls": "Special",
    "duration": 2,
    "durationUnit": "h",
    "draggable": true,
    "resizable": true
  }
    ];

//endregion

const scheduler = new Scheduler({
    ref              : 'top-schedule',
    appendTo         : 'container',
    flex             : '1 1 50%',
    resourceImagePath: '../_shared/images/users/',
    resources        : resources,
    events           : events,
    startDate        : new Date(2025, 11, 1, 7),
    endDate          : new Date(2025, 11, 1, 20),
    viewPreset       : 'hourAndDay',
    rowHeight        : 50,
    barMargin        : 5,
    multiEventSelect : true,
    columns          : [
        { type : 'rownumber'},
        { text : 'Name', type  : 'resourceInfo', field : 'name', width : 130 }
    ],
    eventDrag : {
            // Allow drag outside of this Scheduler
            constrainDragToTimeline : false
        },
});
new Splitter({
    appendTo : 'container'
});
const scheduler2 = new Scheduler({
    ref              : 'bottom-schedule',
    appendTo         : 'container',
    flex             : '1 1 50%',
    resourceImagePath: '../_shared/images/users/',
    hideHeaders      : 'true',
    resources        : resources,
    events           : events,
    startDate        : new Date(2025, 11, 1, 7),
    endDate          : new Date(2025, 11, 1, 20),
    viewPreset       : 'hourAndDay',
    rowHeight        : 50,
    barMargin        : 5,
    multiEventSelect : true,
    columns          : [
        { type : 'rownumber'},
        { text : 'Name', type  : 'resourceInfo', field : 'name', width : 130 }
    ],
    eventDrag : {
            // Allow drag outside of this Scheduler
            constrainDragToTimeline : false
        },
});

Challenges and Solutions

Drag drop between multiple schedulers is so far closet visual representation of the required functionality. Nevertheless, it has it's own challenge

  1. One cannot have two schedule instance with all those mentioned functionality in Scenario section, as it will be heavily taxing on the system resources and maintaining that code
  2. Having two instance means two different crud manager, that is to say that two data object or api mapped to schedules, which are identical
  3. Having same resources and events means same "ids" in both schedules, one cannot do drag and drop across these schedule with same ids - dropping event1 with id 1 from schedule 1 into schedule 2 already having an event with id 1 will cause problem.
  4. In order to solve the id collision issue we might need a mechanism to split resources and events across both the instances's stores, in a way that sch1 resourceStore has resource 1 to 12 and rest in sch 2's store, same for events.
  5. Moreover, this mechanism should somehow be internal to schedule, so we need not need to create 2 instances, and rest of the already implemented functionality just work around it.
    By this I mean that, splitting the view is just a visual representation of single instance of schedule; However, behind the scene same code and api are used. For instance, dragging a event from the top splitted section and dropping it into the bottom section will be similar to dragging and dropping in normal view. Overall, both the views will perform an API call in similar manner.
  6. A possible temporary work around is to filter out those rows which are required to be compared

Benefits

The primary business benefit are

  1. Comparing resources spread far across the schedule without scrolling much, which however is not currently possible when user wants to view row 1 to 5 with row 20 to 25.
  2. Dragging the event then scrolling on the way and dropping to another resource is inconvenient and inefficient
  3. Ease of operation along with faster and efficient way to re-schedule, this aids business to make quick decision and lead to optimize schedules which results in saving money

From my study it seems this feature is not available in the product. Furthermore, to incorporate this feature it will require major changes in the codebase and time so other functionality works seamlessly. Nevertheless, the process of developing such feature is going to be incremental. So I would insist to provide me a rough estimate of release time period.


Post by mats »

Great feature request, we will discuss this internally and see if we can come up with a nice solution! Here is the ticket to track: https://github.com/bryntum/support/issues/3917


Post by tanayb »

Thank you for fast response Mats.
You can also refer to Google spreedsheets implementation of freeze rows https://support.google.com/docs/answer/9060449?hl=en&ref_topic=9055295

Other than that, I am curious to know, generally how much time does feature request like these take?


Post by mats »

If you need this asap, we can offer you to sponsor it (see Sponsored Feature here: https://www.bryntum.com/services/).

Rough estimate would be 24-40 hours of work.


Post by tanayb »

If not required immediately, what would be the idle time period for addition of this feature.(eg: 3-6 months?)


Post by mats »

Very likely it will be ready within next 3-6 months yes!


Post Reply