What's new in Scheduler Pro v5.0.0+
Scheduler Pro v5.0.0
Events display faster
Scheduler Pro now uses a new "early render" mode by default. When data is loaded it renders events first and calculates everything afterwards, instead of as currently the other way around. This greatly decreases time taken until events are displayed for big data sets, but might display events at wrong positions or with wrong size if the loaded data is not correctly normalized. In such cases, the events will transition to their correct position / size when calculations are finalized.
During the calculation phase Scheduler Pro is made read-only, users are not allowed to manipulate the data until calculations are finished. Calculation progress is displayed in a small progress bar in the time axis header (configurable using the projectProgressReporting config).
If you want to disable the new mode, you can do so using the delayCalculation config on the project.
This mode might have consequences for your application if you have code manipulating tasks after the initial load. Please see the Upgrade guide.
New resource utilization view
A new view displaying resources allocation has been added to the Scheduler Pro. The component is similar to the resource histogram yet introduces rows as a tree of resources on the root level having assignments nested. That allows seeing individual assignments allocation thus gives a more detailed representation.
Please check the new demo demonstrating the view and the component docs.
New scheduling issues handling popup
With this release Scheduler Pro starts displaying a special popup informing user of the following scheduling issues:
- scheduling conflicts - when some constraints/dependencies contradict each other
- cycles - when dependencies structure builds a cycle
- calendar misconfigurations - when some calendar doesn't provide any working time intervals which makes its usage impossible
The popup allows user to pick a resolution for the case at hand.
Please check the new demo demonstrating the popup.
Also the project throws new events for the cases that can be listened to in order to provide a resolution programmatically:
new SchedulerPro({
// disable default resolution popup
displaySchedulingIssueResolutionPopup : false,
project : {
listeners : {
// handle scheduling conflicts case
schedulingConflict({ schedulingIssue, continueWithResolutionResult }) {
// apply the very first available resolution
schedulingError.getResolutions()[0].resolve();
// and continue calculation w/ the Engine
continueWithResolutionResult(EffectResolutionResult.Resume);
}
}
}
});
Useful links:
- displaySchedulingIssueResolutionPopup - config to disable the popup showing.
- cycle - event that indicates a cycle has been detected.
- schedulingConflict - event that indicates a scheduling conflict has been detected.
- emptyCalendar - event that indicates a calendar misconfiguration has been detected.
- SchedulingIssueResolutionPopup - class implementing the popup to handle scheduling conflicts and calendar misconfigurations
- CycleResolutionPopup - class implementing the popup to handle scheduling cycles.
Inactive dependencies support in UI
Dependency model has active field which allows deactivating it. Inactive dependencies do not take part in the scheduling process (don't push linked tasks).
The field was represented on the data level before and this version adds its support to user interface as well.
These changes include Scheduler Pro view where inactive dependencies are displayed dashed now. Also new Active field has been added to the dependency editor.
Dependency editor "Lag" field has been made visible by default
Lag field has been made visible in the dependency editor by default.
New JavaScript bundles for combining products
Each product now has a new ES module based JavaScript bundle that only contains the product specific code, called a thin bundle. They are intended to be used when combining multiple products on page, to avoid having shared code loaded multiple times. Previously if you combined for example Grid and TaskBoard on a single page you would import from these bundles (minified size):
grid.module.min.js(~993 kB)taskboard.module.min.js(~1100 kB)
Both products are built upon Bryntum's core library and hence both of them include the core JavaScript (buttons, toolbars, helpers etc.). With thin bundles you would instead import what you need from each product in the hierarchy separately:
core.module.thin.min.js(~643 kB)grid.module.thin.min.js(~268 kB)taskboard.module.thin.min.js(~88 kB)
This way the shared code (from core) is only included once. With the old approach, about 2 MB of JavaScript was loaded, with the new about 1 MB.
The gain (loss actually) will be greater if you combine products that share even more code, like Gantt and Calendar. Calendar builds upon Scheduler > Grid > Core, while Gantt builds upon Scheduler Pro > Scheduler > Grid > Core. When not using thin bundles:
gantt.module.min.js(~1978 kB)calendar.module.min.js(~1833 kB)
With thin bundles (many since these products build upon others):
core.module.thin.min.js(~643 kB)grid.module.thin.min.js(~268 kB)scheduler.module.thin.min.js(~466 kB)schedulerpro.module.thin.min.js(~119 kB)engine.module.thin.min.js(~266 kB)gantt.module.thin.min.js(~122 kB)calendar.module.thin.min.js(~164 kB)
Total ~ 3811 kB vs 2048 kB (1763 kB less).
You import from the thin bundles in the same way as with any other ES modules bundle. The difference compared to using the full bundles is that you have to import from the correct bundle. For example to use the StringHelper class from Core and GridRowModel from Grid, previously you would have something similar to this:
import { StringHelper, GridRowModel } from 'grid.module.js';
Now you have to import them separately (since they are from different bundles):
import { StringHelper } from 'core.module.thin.js';
import { GridRowModel } from 'grid.module.thin.js';
New CSS bundles for combining products
Each theme now has a new CSS bundle that only contains product specific styling, called a thin bundle. They are intended to be used when combining multiple products on page, to avoid having shared styling loaded multiple times. Previously if you combined for example Grid and TaskBoard on a single page, using the Stockholm theme, you would load:
grid.stockholm.css(~244 kB)taskboard.stockholm.css(~243 kB)
Both products are built upon Bryntum's core library and hence both of them include the core CSS (buttons, toolbars, icons etc.). With thin bundles you would instead load each product in the hierarchy separately:
core.stockholm.thin.css(~203 kB)grid.stockholm.thin.css(~40 kB)taskboard.stockholm.thin.css(~40 kB)
This way the shared CSS (from core) is only included once. With the old approach, about 487 kB of CSS was loaded, with the new about 283 kB (204 kB less).
The gain (loss actually) will be greater if you combine products that share even more styling, like Gantt and Calendar. Calendar builds upon Scheduler > Grid > Core, while Gantt builds upon Scheduler Pro > Scheduler > Grid > Core. When not using thin bundles:
gantt.stockholm.css(~659 kB)calendar.stockholm.css(~655 kB)
With thin bundles (many since these products build upon others):
core.stockholm.thin.css(~203 kB)grid.stockholm.thin.css(~40 kB)scheduler.stockholm.thin.css(~363 kB)schedulerpro.stockholm.thin.css(~10 kB)gantt.stockholm.thin.css(~27 kB)calendar.stockholm.thin.css(~47 kB)
Total ~ 1314 kB vs 690 kB (624 kB less).
In your html file, you would for the Gantt + Calendar scenario have something similar to:
<link rel="stylesheet" href="core.stockholm.thin.css" data-bryntum-theme>
<link rel="stylesheet" href="grid.stockholm.thin.css" data-bryntum-theme>
<link rel="stylesheet" href="scheduler.stockholm.thin.css" data-bryntum-theme>
<link rel="stylesheet" href="schedulerpro.stockholm.thin.css" data-bryntum-theme>
<link rel="stylesheet" href="gantt.stockholm.thin.css" data-bryntum-theme>
<link rel="stylesheet" href="calendar.stockholm.thin.css" data-bryntum-theme>
data-bryntum-theme attribute above, it is required if the app will be switching theme at runtime using DomHelper.setTheme(). New feature - Event buffer
In this release we have added a new feature called EventBuffer, which is sometimes referred to as travel time. It allows to render a visual element before and after event element, representing time required to prepare for the event and to clean up after it. For example, before an employee can start working on the site, one has to arrive to the site first.
Please refer to the travel time demo.
new SchedulerPro({
features : {
eventBuffer : true
},
project : {
eventsData : [
{
id : 1,
startDate : '2010-01-01',
endDate : '2010-01-02',
preamble : '1 hour'
},
{
id : 2,
startDate : '2010-01-01',
endDate : '2010-01-02',
postamble : '15 minutes'
}
]
}
});
NonWorkingTime and ResourceNonWorkingTime elements can now be styled easily
In this release, you can now set a cls field on the calendar data (or on the data of its intervals). This adds a CSS class on the rendered non-working time interval which you can use for styling. You can additionally show an icon by setting iconCls. Please refer to ResourceNonWorkingTime docs for more information.
Sample code:
const schedulerPro = new SchedulerPro({
appendTo: document.body,
height: 500,
startDate: new Date(2022, 7, 2),
endDate : new Date(2022, 7, 14),
columns: [
{ field: 'name', text: 'Name' },
{ field: 'calendar', text: 'Working on', editor: false },
],
features: {
nonWorkingTime : true,
resourceNonWorkingTime: {
maxTimeAxisUnit: 'week'
}
},
project: {
resourcesData: [
{ id: 1, name: 'Bernard', calendar: 'weekends' },
{ id: 2, name: 'Bianca', calendar: 'weekdays' }
],
calendarsData: [
{
id : 'weekends',
name : 'Weekends',
unspecifiedTimeIsWorking: true,
cls : 'weekendCalendar',
intervals : [
{
recurrentStartDate: 'on Mon at 0:00',
recurrentEndDate : 'on Sat at 0:00',
isWorking : false,
cls : 'nonworking'
}
]
},
{
id : 'weekdays',
name : 'Weekdays',
unspecifiedTimeIsWorking: true,
intervals : [
{
recurrentStartDate: 'on Sat at 0:00',
recurrentEndDate : 'on Mon at 0:00',
isWorking : false,
cls : 'weekend'
}
]
}
]
}
});
Simplified test case creation
When reporting a hard to reproduce issue on Bryntum's support forum we often request a test case showing the issue. Getting a good test case greatly reduces the time it takes from reporting the bug until a fix can be released. Worst case we won't be able to find and fix the bug at all without one.
We understand that for complex apps it is not always trivial to produce a standalone test case. The app might be using a lot of different configs and the issue might only appear with a certain dataset etc. To simplify the process of creating a test case we have added a new function called downloadTestCase() to all Bryntum products. Running it collects the current value for the configs your app is using, inlines the current dataset and compiles configs and data into a JavaScript app that is then downloaded.
The app will most likely require manual tweaking before you can submit it to us, but we are hoping it will make creating a test case easier for you. Run schedulerPro.downloadTestCase() on the console in a demo to try it. Any feedback on how this could be improved further is welcome on the forums!
Scheduler Pro v5.0.3
ProjectModel wrapper for Angular, React & Vue
Scheduler Pro ships with a new ProjectModel wrapper that can be used to share data between multiple Bryntum components in the same app by pointing them all to the same project instance. Either you use it to load data from the backend using the built-in CrudManager or you bind your locally available data to it.
Integration details can be found in guides for Angular, React and Vue.
Long distance projects support
By default the Scheduler Pro supports projects of 5 years duration max roughly. That limit was hardcoded in some private code. And in this release ProjectModel has got new maxCalendarRange config allowing to adjust this limit.
The value should be provided in milliseconds and should be configured in case the project deals with long tasks:
new SchedulerPro({
project : {
// adjust calendar iteration limit to 10 years roughly:
// 10 years expressed in ms
maxCalendarRange : 10 * 365 * 24 * 3600000,
/* ... */
}
});
Scheduler Pro v5.1.0
Introducing Create React App templates
Create React App script templates are now available in the public npm repository.
If you are using javascript only, just type:
npx create-react-app my-app --template @bryntum/cra-template-javascript-schedulerpro
or if you prefer using typescript:
npx create-react-app my-app --template @bryntum/cra-template-typescript-schedulerpro
Note: Please feel free to change my-app to your preferred application name
Check the React integration guide for more information.
Nested events support
Scheduler Pro has since version 4.0.0 shipped with a popular demo called nested-events, showing how you in application code could implement support for parent events containing child events (nested events) with basic drag and drop support.
In this release this concept has been built into Scheduler Pro and is now available as the new NestedEvents feature, making it more powerful and also much easier to use. By enabling it and using a tree EventStore parent events will render their children nested inside themselves:
const schedulerPro = new SchedulerPro({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, features : { nestedEvents : true }, rowHeight : 160, startDate : new Date(2022, 2, 20), endDate : new Date(2022, 2, 27), columns : [ { field : 'name', text : 'Name', width : 100 } ], project : { resources : [ { id : 1, name : 'Bruce' }, { id : 2, name : 'Diana' } ], events : [ { id : 1, name : 'Art project', startDate : '2022-03-21', duration : 5, children : [ { id : 11, name : 'Get supplies', startDate : '2022-03-21', duration : 2 }, { id : 12, name : 'Sketch', startDate : '2022-03-22', duration : 1, eventColor : 'indigo' }, { id : 13, name : 'Outline', startDate : '2022-03-22', duration : 2, eventColor : 'blue' }, { id : 14, name : 'Ink', startDate : '2022-03-23', duration : 2, eventColor : 'violet' }, { id : 15, name : 'Share', startDate : '2022-03-24', duration : 2, eventColor : 'pink' } ] }, { id : 2, name : 'DIY project', startDate : '2022-03-24', duration : 5, children : [ { id : 21, name : 'Plan', startDate : '2022-03-21', duration : 1, eventColor : 'indigo' }, { id : 22, name : 'Get supplies', startDate : '2022-03-22', duration : 2 }, { id : 23, name : 'Prototype', startDate : '2022-03-22', duration : 3, eventColor : 'violet' }, { id : 24, name : 'Make', startDate : '2022-03-24', duration : 1, eventColor : 'blue' } ] } ], assignments : [ { id : 1, event : 1, resource : 1 }, { id : 2, event : 11, resource : 1 }, { id : 3, event : 12, resource : 1 }, { id : 4, event : 13, resource : 1 }, { id : 5, event : 14, resource : 1 }, { id : 6, event : 15, resource : 1 }, { id : 7, event : 2, resource : 2 }, { id : 8, event : 21, resource : 2 }, { id : 9, event : 22, resource : 2 }, { id : 10, event : 23, resource : 2 }, { id : 11, event : 24, resource : 2 } ] }, tbar : [ { type : 'buttongroup', toggleGroup : true, rendition : 'padded', items : { none : { text : 'Overlap' }, stack : { text : 'Stack' }, pack : { text : 'Pack', pressed : true } }, onToggle({ source, pressed }) { if (pressed) { schedulerPro.features.nestedEvents.eventLayout = source.ref; } } } ] }); Nested events can be dragged and resized, with configuration options for constraining to parent, allowing drop on other parents etc. The feature also allows setting resourceMargin, barMargin and eventLayout for nested events. Check it out in new nested-events-configuration and nested-events-drag-from-grid demos, or in the updated nested-events demo.
Simplified url configuration on the project
Configuring the crud manager functionality of the project was made a little easier by introducing shortcuts for setting load and sync urls using the new loadUrl and syncUrl configs. When your application does not need to supply any additional configs to the transport layer you can use them in favor of having to nest the urls. Old code like this:
const schedulerPro = new SchedulerPro({
project : {
transport : {
load : {
url : 'load.aspx'
}
}
}
})
Can now be written more conveniently like this:
const schedulerPro = new SchedulerPro({
project : {
loadUrl : 'load.aspx'
}
})
Flattening the structure out makes it easier for framework developers, who can now assign directly to the prop on the project component rather than having to supply a config object. Pseudo framework code to illustrate the old approach:
const projectConfig = {
transport : {
load : {
url : 'load.php'
}
}
}
<BryntumProjectModel {...projectConfig} />
Simplified approach:
<BryntumProjectModel loadUrl={"load.php"} />
New module bundle for Angular
Bryntum Scheduler Pro is now delivered with new ES Module bundle without WebComponents. This was done to avoid conflicts with Angular which also uses WebComponents for applications.
Angular wrappers use schedulerpro.module.js bundle in favor of removed schedulerpro.lite.umd.js one.
Check the upgrading guide for the details.
New module bundle with WebComponents
Bryntum Scheduler Pro is now delivered with new schedulerpro.wc.module.js ES Module bundle with WebComponents.
Check the upgrading guide for the details.
New keyboard shortcuts functionality
KeyMap is a mixin that allows for standardized and customizable keyboard shortcuts functionality. KeyMap is mixed in to Widget by default and therefore available to all Widget child classes. There is a new guide describing how to customize currently integrated keyboard shortcuts.
Scheduler Pro v5.2.0
Segmented events support
In this release Scheduler Pro adds support for segmented events. Each event can be split into segments which then can be adjusted separately, moved or merged back.
On the data level splitting an event can be done with event model splitToSegments method call:
// split event1 into segments at 2022-07-27 with split duration of 1 day
await event1.splitToSegments(new Date(2022, 6, 27), 1, "day")
/* here rescheduling is done */
Event model has got a new segments field (plus properties to access the first and last segment) which returns an array of EventSegmentModel class instances.
Each segment can be changed individually:
// change last segment end date
event1.lastSegment.endDate = new Date(2022, 7, 4)
// wait till rescheduling is done
await event1.commitAsync()
/* here rescheduling is done */
Or with setEndDate method call:
await event1.lastSegment.setEndDate(new Date(2022, 7, 4))
/* here rescheduling is done */
Bringing two segments close to each other causes them to merge.
On the UI level segments support is done with the following new features:
- EventSegments - implements rendering and adds new "Split event" entry to the event context menu.
- EventSegmentResize - implement individual segments resizing with drag'n'drop.
- EventSegmentDrag - implement individual segments moving with drag'n'drop.
const schedulerPro = new SchedulerPro({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2022, 2, 20), endDate : new Date(2022, 2, 27), columns : [ { field : 'name', text : 'Name', width : 100 } ], project : { resources : [ { id : 1, name : 'Bruce' }, { id : 2, name : 'Diana' } ], events : [ { id : 1, name : 'Art project', startDate : '2022-03-21', segments : [ { startDate : '2022-03-21', duration : 1 }, { startDate : '2022-03-23', duration : 1 }, { startDate : '2022-03-25', duration : 1 } ] }, { id : 2, name : 'DIY project', startDate : '2022-03-21', segments : [ // segments can have their own names & colors { name : 'Plan', startDate : '2022-03-21', duration : 1, eventColor : 'indigo' }, { name : 'Get supplies', startDate : '2022-03-23', duration : 2 } ] } ], assignments : [ { id : 1, event : 1, resource : 1 }, { id : 7, event : 2, resource : 2 } ] }, features : { eventSegments : { // split at the exact date user clicks in UI roundedSplit : false } } }); New widget for switching views
The ViewPresetCombo is an easy-to-setup preset picker which can be added to the SchedulerPro's toolbar and provides a simple UI for switching between different "views". It's based on ViewPreset which is built-in to the SchedulerPro.
Try it out in the live demo here:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> </body></html> EventNonWorkingTime feature
Prior to this release Scheduler Pro had two features to visualize non-working time:
NonWorkingTime- visualizes the project level calendar using time rangesResourceNonWorkingTime- visualizes the resource level calendar using resource time ranges
With this release a new EventNonWorkingTime feature was added, which visualizes the event level calendar (project or resource calendar combined with any event calendar) by shading parts of the event bars.
//<code-header> CSSHelper.insertRule('.weekend { background: transparent repeating-linear-gradient(-55deg, #dddddd99, #dddddd99 10px, #eeeeee99 5px, #eeeeee99 20px); }', targetElement.getRootNode()); //</code-header> const schedulerPro = new SchedulerPro({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2022, 8, 4), endDate : new Date(2022, 8, 11), columns : [ { field : 'name', text : 'Name' }, { field : 'calendar', text : 'Working on', editor : false } ], features : { nonWorkingTime : false, eventNonWorkingTime : true }, project : { resources : [ { id : 1, name : 'Hulk', calendar : 'weekends' }, { id : 2, name : 'She-Hulk', calendar : 'weekdays' } ], events : [ { id : 1, name : 'Smash', startDate : '2022-09-01', duration : 6 }, { id : 2, name : 'Crush', startDate : '2022-09-07', duration : 4 } ], assignments : [ { id : 1, eventId : 1, resourceId : 1 }, { id : 2, eventId : 2, resourceId : 2 } ], calendars : [ { id : 'weekends', name : 'Weekends', unspecifiedTimeIsWorking : true, intervals : [ { recurrentStartDate : 'on Mon', recurrentEndDate : 'on Sat', isWorking : false, cls : 'nonworking' } ] }, { id : 'weekdays', name : 'Weekdays', unspecifiedTimeIsWorking : true, intervals : [ { recurrentStartDate : 'on Sat', recurrentEndDate : 'on Mon', isWorking : false, cls : 'weekend' } ] } ] } }); Ignoring resource calendars
An event normally performs work when both its own calendar and some of the assigned resource calendars (if any resource is assigned to the event) allow that.
With this release event model has got a new ignoreResourceCalendar boolean field allowing to toggle that logic. When the field is set to true the event will not take its assigned resource calendars into account and will perform according to its own calendar only.
On the UI level the field is represented as "Ignore resource calendar" checkbox on the "Advanced" tab of the task editor.
Improved PDF Export feature
Pdf Export feature now renders exported content directly and does not scroll the view anymore. This significantly improves performance (by an order of magnitude) and robustness of the export process. You can enable old behavior by setting enableDirectRendering config on the export feature to false. Old behavior is deprecated and will be removed in the next major release. Please report issues that make you disable direct rendering.
Scheduler Pro v5.2.6
Support for React Components in tooltips and widgets
React components are now supported in tooltips and widgets. Tooltips have renderer or template function that can now return a valid JSX that represents a React component. Widgets can now have JSX value for html property. For example:
Cell tooltip:
cellTooltipFeature: {
tooltipRenderer: ({ record }) => (
<React.StrictMode>
<DemoTooltip record={record} />
</React.StrictMode>
)
},
Event tooltip:
eventTooltipFeature: {
template: data => (
<React.StrictMode>
<DemoEventTip data={data} />
</React.StrictMode>
)
},
React component in widget:
bbar : {
items:[{
type:'widget',
html:<DemoWidget />
}]
},
See the React guide for details.
Scheduler Pro v5.3.0
AjaxHelper.fetch now supports passing parameters in request body
Since this release AjaxHelper.fetch method can pass provided queryParams in the request body instead of query string. This happens for application/x-www-form-urlencoded and multipart/form-data content types when addQueryParamsToBody option is set to true:
AjaxHelper.fetch('url', {
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
addQueryParamsToBody : true
});
Please check addQueryParamsToBody in FetchOptions
Please note that this behavior is disabled by default so if you need to enable it globally please use AjaxHelper.DEFAULTFETCHOPTIONS:
// enable addQueryParamsToBody by default
AjaxHelper.DEFAULT_FETCH_OPTIONS = {
addQueryParamsToBody : true
}
Basic recurring events support
Scheduler Pro now supports recurring events in a way very similar to the basic Scheduler. This means that while the original event adheres to Pro specific logic such as calendars and dependencies, the occurrences of it do not. For example an event repeated every third day will eventually occur on a weekend. To enable recurring events, configure your scheduler with enableRecurringEvents : true.
new SchedulerPro({ appendTo : targetElement, // makes scheduler as high as it needs to be to fit rows autoHeight : true, startDate : new Date(2022, 9, 2), endDate : new Date(2022, 9, 16), // Turn recurring events on enableRecurringEvents : true, project : { resources : [ { id : 1, name : 'Resource 1' } ], events : [ { id : 1, resourceId : 1, name : 'Daily', startDate : '2022-10-03', duration : 1, recurrenceRule : 'FREQ=DAILY', eventColor : 'blue' }, { id : 2, resourceId : 1, name : 'Weekly', startDate : '2022-10-05', duration : 2, recurrenceRule : 'FREQ=WEEKLY', eventColor : 'purple' } ] } }); Time zone support
Support for Time zone conversion has been added to all Bryntum scheduling products. Simply set a IANA time zone identifier as value for the timeZone config and that's it.
But since time zones is not natively supported in JavaScript we strongly recommend to read our Time zone guide.
Also, please check out the new Time zone demo.
new SchedulerPro({
timeZone : 'America/Chicago'
});
Versions feature
You can now enable the Versions feature on Scheduler Pro to capture, restore, and compare snapshots of a project, plus detailed change logs. The Versions feature adds a VersionStore and a ChangeLogStore to the project, and captures change logs using the STM feature.
Versions can be captured at any time programmatically, or on a configured schedule. Versions contain both a full snapshot of the project and a set of change log transactions describing the changes since the previous version, in a format useful for display to the user.
See demo below under VersionGrid widget.
VersionGrid widget
The VersionGrid widget displays versions and their change logs in a TreeGrid. Versions can be expanded to show the change logs they contain, and the context menu for version rows supports renaming, restoring, and comparing saved versions. If desired, the version rows can be hidden, providing a continuous view of change log actions for the project.
const scheduler = new SchedulerPro({ enableUndoRedoKeys : true, flex : 2, project : { resources : [ { id : 1, name : 'Resource 1' }, { id : 2, name : 'Resource 2' }, { id : 3, name : 'Resource 3' } ], autoHeight : true, events : [ { id : 11, name : 'Design website', startDate : new Date(2022, 10, 7), duration : 5, resourceId : 1 }, { id : 12, name : 'Lease office space', startDate : new Date(2022, 10, 9), duration : 4, resourceId : 1 }, { id : 13, name : 'Buy coffee machine', startDate : new Date(2022, 10, 13), duration : 3, resourceId : 3 }, { id : 14, name : 'Hire designer', startDate : new Date(2022, 10, 17), duration : 3, resourceId : 2 }, { id : 15, name : 'Write design handbook', startDate : new Date(2022, 10, 27), duration : 3, resourceId : 2 } ], // dependencies : [ // { // id : 1, // fromTask : 11, // toTask : 12 // }, // { // id : 2, // fromTask : 13, // toTask : 14 // }, // { // id : 3, // fromTask : 14, // toTask : 15 // } // ], stm : { autoRecord : true } }, columns : [ { field : 'name', text : 'Name', width : 250 }, { field : 'startDate', text : 'Start date' }, { field : 'duration', text : 'Duration' } ], subGridConfigs : { locked : { width : 300 } }, features : { versions : true, dependencies : true, dependencyEdit : true }, listeners : { /** * Demonstrates overriding the default transaction description to provide more detail * about which user action initiated the transaction. In this case, we set a custom * description for transactions involving a task drag event. */ taskDrop({ taskRecords }) { this.features.versions.transactionDescription = taskRecords.length === 1 ? `Dragged task ${taskRecords[0].name}` : `Dragged ${taskRecords.length} tasks`; }, taskResizeEnd({ taskRecord }) { this.features.versions.transactionDescription = `Resized task ${taskRecord.name}`; }, afterDependencyCreateDrop() { this.features.versions.transactionDescription = `Drew a link`; } } }); const app = new Container({ appendTo : targetElement, layout : 'box', height : 600, items : { scheduler, splitter : { type : 'splitter' }, versionGrid : { type : 'versiongrid', flex : 1, emptyText : 'No versions to display', project : scheduler.project, showUnattachedTransactions : true, selectionMode : { row : true, cell : false }, features : { cellMenu : { /** * Add a button to the version row context menu. */ items : { compareButton : undefined, duplicateButton : { text : 'Duplicate', icon : 'fa fa-copy', onItem : async({ record, source : grid }) => { const result = await MessageDialog.confirm({ title : 'Duplicate Version?', message : `This will create a new project from the content of the selected version. Do you want to continue?` }); if (result === MessageDialog.yesButton) { // Sample code demonstrating cloning a saved version await scheduler.features.versions.getVersionContent(record.versionModel); const clonedProject = new ProjectModel(record.versionModel.content); scheduler.project = clonedProject; } } } } } }, dateFormat : 'M/D/YY h:mm a', tbar : { items : { saveButton : { text : 'Save Version', icon : 'fa fa-plus', listeners : { click : () => { scheduler.features.versions.saveVersion(); } } }, spacer : { text : '->' }, onlyNamedToggle : { type : 'slidetoggle', text : 'Show named versions only', listeners : { change : ({ checked }) => { app.widgetMap.versionGrid.showNamedVersionsOnly = checked; } } }, showVersionsToggle : { type : 'slidetoggle', text : 'Changes only', checked : false, listeners : { change : ({ checked }) => { app.widgetMap.versionGrid.showVersions = !checked; } } } } }, listeners : { // Handle the user asking to restore a given version restore : async({ version }) => { const result = await MessageDialog.confirm({ title : 'Restore Version?', message : `Are you sure you want to restore the selected version, replacing the current project? You will lose any unsaved changes.` }); if (result === MessageDialog.yesButton) { await gantt.features.versions.restoreVersion(version); gantt.features.baselines.disabled = true; // FIXME known issue with Undo after restoring version project.stm.resetQueue(); } } } } } }); scheduler.project.stm.enable(); New locales
New locales for 31 languages have been added. Currently available languages are listed in the localization guide.
New effort aware scheduling mode
In this release Scheduler Pro adds support for event effort calculations. And event effort represents total amount of time scheduled on the event for all its assigned resources.
EventModel class has got four new fields:
To switch to the new mode EventModel class has got a new schedulingMode field that supports two values, Normal (old backward compatible behavior) and FixedDuration (the new mode that enables effort related calculations).
The new mode means, that event has fixed (provided by the user) duration, start and end dates, but its effort is computed dynamically, based on the assigned resources information.
Typical example of such event is a meeting. Meetings typically have pre-defined start and end dates and the more people are participating in the meeting, the more effort is spent on the event.
In this mode when an event duration increases, its effort is increased too. Whereas changing of effort does not cause duration change but instead adjusts corresponding assignment units to distribute the effort value across the duration.
Please note the above logic can be slightly changed by enabling the new effortDriven flag on the event. Effort driven events tend to preserve user provided effort value. So when changing such events duration they adjust their assignment units.
Enabling of the mode can be done by providing the field value either dynamically:
// set event1 effort to 8 hours and toggle scheduling mode to distribute the effort
event1.effort = 8;
event1.schedulingMode = 'FixedDuration';
Or if you need to make this mode enabled by default just change the schedulingMode field default value:
class MyEventModel extends EventModel {
static fields = [
{ name : 'schedulingMode', defaultValue : 'FixedDuration' }
]
}
On the UI level new fields have been added to the task editor:
Efforton theGeneraltab.Scheduling modeandEffort drivenon theAdvanced.
The Effort driven field is hidden by default and can be shown like this:
const scheduler = new SchedulerPro({
features : {
taskEdit : {
items : {
advancedTab : {
type : 'schedulerAdvancedTab',
items : {
// show "Effort driven" checkbox
effortDrivenField : {
hidden : false
}
}
}
}
}
}
});
Scheduler Pro v5.3.3
Angular IVY and View Engine wrappers
Bryntum Scheduler Pro now ships with two npm Angular wrappers packages to support different versions of Angular framework.
@bryntum/schedulerpro-angular is designed to work with Angular 12 and newer versions, which use the IVY rendering engine.
@bryntum/schedulerpro-angular-view is designed to work with Angular 11 and older versions, which use the View Engine for rendering.
Please check Angular integration guide for the additional information.
New TimelineHistogram view
This release introduces a new TimelineHistogram class which implements a grid with histogram charts displayed for rows in the timeaxis section.
const histogram = new TimelineHistogram({ appendTo : targetElement, startDate : new Date(2023, 0, 1), endDate : new Date(2023, 0, 6), autoHeight : true, columns : [{ text : 'Name', field : 'name' }], // define histogram value series series : { work : { // display work values as bars type : 'bar' }, maxWork : { // display maxWork values as outline type : 'outline' } }, // grid data store : new Store({ data : [ { id : 1, name : 'Mats', // the record histogram data histogramData : [ { work : 8, maxWork : 16 }, { work : 18, maxWork : 12 }, { work : 12, maxWork : 10 }, { work : 13, maxWork : 16 }, { work : 15, maxWork : 16 }, { work : 1, maxWork : 6 } ] }, { id : 2, name : 'Johan', histogramData : [ { work : 15, maxWork : 16 }, { work : 8, maxWork : 26 }, { work : 12, maxWork : 6 }, { work : 13, maxWork : 16 }, { work : 18, maxWork : 16 }, { work : 8, maxWork : 16 } ] }, { id : 3, name : 'Arcady', histogramData : [ { work : 15, maxWork : 16 }, { work : 18, maxWork : 9 }, { work : 8, maxWork : 11 }, { work : 12, maxWork : 16 }, { work : 13, maxWork : 16 }, { work : 10, maxWork : 5 } ] } ] }) }); Please check the new Timeline histogram demo and the "Timeline histogram" guide for more details.
Grouping support for ResourceHistogram and ResourceUtilization views
This release adds better grouping support to the ResourceHistogram and ResourceUtilization views. The classes now automatically aggregate data on parent node levels based on corresponding child nodes.
For more details on the views please see new "Resource histogram" and "Resource utilization" guides
Scheduler Pro v5.6.0
New npm packages for combining products
This release introduces a new set of npm packages and framework components, that allows combining multiple Bryntum products in the same application.
These packages contain the product specific code only, as opposed to the current packages that has all code for the products each product builds upon (for example Scheduler contains all code from Grid & Core).
The new packages are called thin packages, and moving forward it will be the recommended way of using Bryntum products in npm based applications (for all supported frameworks). The packages are initially available for licensed users only, but will be made available for trial users in the near future.
The following packages are available:
| Package | Purpose |
|---|---|
| @bryntum/core-thin | Bryntum Core data and UI components package |
| @bryntum/grid-thin | Bryntum Grid component package |
| @bryntum/scheduler-thin | Bryntum Scheduler component package |
| @bryntum/schedulerpro-thin | Bryntum Scheduler Pro component package |
| @bryntum/gantt-thin | Bryntum Gantt component package |
| @bryntum/calendar-thin | Bryntum Calendar component package |
| @bryntum/taskboard-thin | Bryntum TaskBoard component package |
| @bryntum/engine-thin | Bryntum Scheduling engine component package |
Applications should install packages for the products they use, and the products those are built upon (see links to guides below for more information). For example an application using Scheduler Pro should also install Scheduler, Grid & Core:
npm install @bryntum/core-thin @bryntum/grid-thin @bryntum/scheduler-thin @bryntum/schedulerpro-thin
There are also new corresponding wrappers for the supported frameworks, which should be used instead of the current wrappers. For example for React:
| Package | Purpose |
|---|---|
| @bryntum/core-react-thin | Bryntum Core UI widgets React wrappers package |
| @bryntum/grid-react-thin | Bryntum Grid React wrapper package |
| @bryntum/scheduler-react-thin | Bryntum Scheduler React wrapper package |
| @bryntum/schedulerpro-react-thin | Bryntum Scheduler Pro React wrapper package |
| @bryntum/gantt-react-thin | Bryntum Gantt React wrapper package |
| @bryntum/calendar-react-thin | Bryntum Calendar React wrapper package |
| @bryntum/taskboard-react-thin | Bryntum TaskBoard React wrapper package |
Applications should install wrappers only for the products they use, there is no need to install them for the products those are built upon. For example an application using Scheduler Pro:
npm install @bryntum/schedulerpro-react-thin
More information:
Nested events scheduled relative to parent
Prior to this release, nested events were positioned relative to their parent event initially, but when the parent was moved in a way that made it intersect non-working time the relative position was lost.
For example if a parent event on a Monday with one nested event on Tuesday and one on Wednesday was moved to a Friday, the nested events was both pushed to directly after the weekend, to Monday. Thus loosing their relative position. From the scheduling engines point of view this was the right decision, it scheduled them as early as possible. But from the users point of view it was not, the relative position was expected to be kept.
With this release this behaviour has changed, nested events are now scheduled relative to their parent. This is implemented using a new delayFromParent field on the EventModel. The field is calculated based on the parents start date and the nested events start date when not supplied (making it optional to specify), subtracting non-working time.
Behind the scenes this is enforced similarly to using a startnoearlierthan constraint on the nested events.
We consider the old behaviour a "bug", but if you were relying on it please let us know.
Dependencies between nested events
This release also adds support for dependencies between nested events (nested -> nested, parent -> nested & nested -> parent). A dependency is allowed to schedule a nested event later than its delayFromParent, but not earlier.
Functions and events declarations for TypeScript have been improved
Declarations of class config/property functions and events (which are represented as onEventName functions) were improved to contain all available parameters and return type.
See examples below:
Old declarations:
/**
* User typed into the field. Please note that the value attached to this event is the raw input field value and
* not the combos value
*/
onInput: Function|string
/**
* Template function that can be used to customize the displayed value
*/
displayValueRenderer: Function
New declarations:
/**
* User typed into the field. Please note that the value attached to this event is the raw input field value and
* not the combos value
*/
onInput: ((event : { source: Combo, value: string, event: Event }) => void)|string
/**
* Template function that can be used to customize the displayed value
*/
displayValueRenderer: (record: Model, combo: Combo) => string|null
Client side print / PDF export
A new Print feature was added to allow printing Scheduler Pro content using the browser print dialog. It extends the PDFExport feature and uses same configs which manage HTML markup rendering (exporters, columns, paper size, etc.). The only difference is that instead of sending generated HTML to a backend, the feature creates an iframe element with generated content and opens the browser print dialog from it.