An issues-only repository for the Bryntum project management component suite which includes powerful Grid, Scheduler, Calendar, Kanban Task Board and Gantt chart components all built in pure JS / CSS / TypeScript
import { Splitter, SchedulerPro, ProjectModel, ResourceUtilization, DateHelper, StringHelper, Store } from '../../build/schedulerpro.module.js?477293';
import shared from '../_shared/shared.module.js?477293';
// Variables used in this demo
// Set group by Resource to City as initial default
let isGroupByResourceToCity = true;
const project = new ProjectModel({
// This config enables response 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
});
project.loadInlineData({
"success": true,
"eventsData": [
{
"id": 19469,
"startDate": "2024-06-24T00:00:00-06:00",
"endDate": "2024-07-04T00:00:00-06:00",
"name": "New event",
"allDay": false,
"note": "",
"eventType": "Tentative"
},
{
"id": 19470,
"startDate": "2024-06-26T00:00:00-06:00",
"endDate": "2024-07-15T00:00:00-06:00",
"name": "New event",
"allDay": false,
"note": "",
"eventType": "Tentative"
},
{
"id": 19471,
"startDate": "2024-06-24T00:00:00-06:00",
"endDate": "2024-07-23T00:00:00-06:00",
"name": "New event",
"allDay": false,
"note": "",
"eventType": "Tentative"
}
]
,
"resourcesData": [
{
"id": 18947,
"name": "New Resource",
"role": "/Role"
},
{
"id": 18948,
"name": "Role",
"role": "/Z"
}
]
,
"assignmentsData": [
{
"id": 9424,
"resourceId": 18947,
"eventId": 19469,
"units": 100
},
{
"id": 9425,
"resourceId": 18947,
"eventId": 19470,
"units": 100
},
{
"id": 9426,
"resourceId": 18948,
"eventId": 19471,
"units": 100
}
],
"dependencies": {
"rows": []
}
})
const scheduler = new SchedulerPro({
appendTo : 'container',
minHeight : '10em',
flex : '1 1 50%',
project,
// startDate : new Date(2024, 3, 28),
// endDate : new Date(2024, 4, 30),
viewPreset : 'dayAndWeek',
eventStyle : 'plain',
tickSize : 50,
resourceImagePath : '../_shared/images/users/',
columns : [
{ type : 'resourceInfo', text : 'Name', field : 'name', width : 130 },
{ text : 'City', field : 'city', width : 90 }
],
tbar : [
{
type : 'button',
ref : 'zoomInButton',
icon : 'b-icon-search-plus',
text : 'Zoom in',
onAction : () => scheduler.zoomIn()
},
{
type : 'button',
ref : 'zoomOutButton',
icon : 'b-icon b-icon-search-minus',
text : 'Zoom out',
onAction : () => scheduler.zoomOut()
}
]
});
new Splitter({
appendTo : 'container'
});
// Prepare array of functions we are going to group the view store by
// (we make a constant since we are going to use it in few places)
const treeGroupLevels = [
// group by resource
({ origin }) => {
// If record is a resource means it has no assignments ..since this function is called for leaves only.
// So further grouping makes no sense - stop grouping.
if (origin.isResourceModel) {
return Store.StopBranch;
}
return origin.resource;
},
// group by resource city
({ origin }) => origin.isResourceModel ? origin.city : origin.resource.city
];
const resourceUtilization = new ResourceUtilization({
project,
hideHeaders : true,
partner : scheduler,
appendTo : 'container',
// set a bit larger row height since we use a custom renderer() below
rowHeight : 50,
minHeight : '10em',
flex : '1 1 50%',
showBarTip : true,
features : {
treeGroup : {
levels : treeGroupLevels
}
},
columns : [
{
// this `cellCls` config is only used to target the example hint
cellCls : 'tree-resource-event',
type : 'tree',
text : 'Resource/Event',
flex : 1,
renderer({ record, grid }) {
record = grid.resolveRecordToOrigin(record);
// lets show event start/end for assignment row
if (record.isAssignmentModel) {
// get the assigned event
const { event } = record;
// add few nested tags for event name and for start/end dates
return {
children : [
{
tag : 'dl',
class : 'b-assignment-info',
children : [
// value has event name
{
tag : 'dt',
text : event.name
},
{
tag : 'dd',
text : DateHelper.format(event.startDate, 'L') + ' - ' + DateHelper.format(event.endDate, 'L')
}
]
}
]
};
}
else if (record.isResourceModel) {
return record.name;
}
// record.key will have either resource or event so display its name
return record.key?.name || record.key;
}
}
],
tbar : [
{
type : 'checkbox',
ref : 'showBarTip',
text : 'Enable bar tooltip',
tooltip : 'Check to show tooltips when moving mouse over bars',
checked : true,
onAction({ source }) {
resourceUtilization.showBarTip = source.checked;
}
},
'->',
{
type : 'label',
text : 'Group by'
},
{
type : 'buttongroup',
toggleGroup : true,
cls : 'group-buttons',
items : [
{
ref : 'resourceToCityButton', // for testing purpose
text : 'Resource - City',
tooltip : 'Click to group by Resource → City',
pressed : true,
supportsPressedClick : true,
onAction() {
// toggle grouping fields order by resource to city
!isGroupByResourceToCity && treeGroupLevels.reverse();
isGroupByResourceToCity = true;
resourceUtilization.group(treeGroupLevels);
}
},
{
ref : 'cityToResourceButton', // for testing purpose
text : 'City - Resource',
tooltip : 'Click to group by City → Resource',
pressed : false,
supportsPressedClick : true,
onAction() {
// toggle grouping fields order by city to resource
isGroupByResourceToCity && treeGroupLevels.reverse();
isGroupByResourceToCity = false;
resourceUtilization.group(treeGroupLevels);
}
},
{
ref : 'defaultButton', // for testing purpose
text : 'Default',
tooltip : 'Disable tree group feature and back to default Resource → Assignment look',
onAction() {
if (!isGroupByResourceToCity) {
treeGroupLevels.reverse();
isGroupByResourceToCity = true;
}
resourceUtilization.clearGroups();
}
}
]
}
]
});
Now when you hover over the third event you'll see this date
And now trying removing the resource utilization code, this part
const resourceUtilization = new ResourceUtilization({
project,
hideHeaders : true,
partner : scheduler,
appendTo : 'container',
// set a bit larger row height since we use a custom renderer() below
rowHeight : 50,
minHeight : '10em',
flex : '1 1 50%',
showBarTip : true,
features : {
treeGroup : {
levels : treeGroupLevels
}
},
columns : [
{
// this `cellCls` config is only used to target the example hint
cellCls : 'tree-resource-event',
type : 'tree',
text : 'Resource/Event',
flex : 1,
renderer({ record, grid }) {
record = grid.resolveRecordToOrigin(record);
// lets show event start/end for assignment row
if (record.isAssignmentModel) {
// get the assigned event
const { event } = record;
// add few nested tags for event name and for start/end dates
return {
children : [
{
tag : 'dl',
class : 'b-assignment-info',
children : [
// value has event name
{
tag : 'dt',
text : event.name
},
{
tag : 'dd',
text : DateHelper.format(event.startDate, 'L') + ' - ' + DateHelper.format(event.endDate, 'L')
}
]
}
]
};
}
else if (record.isResourceModel) {
return record.name;
}
// record.key will have either resource or event so display its name
return record.key?.name || record.key;
}
}
],
tbar : [
{
type : 'checkbox',
ref : 'showBarTip',
text : 'Enable bar tooltip',
tooltip : 'Check to show tooltips when moving mouse over bars',
checked : true,
onAction({ source }) {
resourceUtilization.showBarTip = source.checked;
}
},
'->',
{
type : 'label',
text : 'Group by'
},
{
type : 'buttongroup',
toggleGroup : true,
cls : 'group-buttons',
items : [
{
ref : 'resourceToCityButton', // for testing purpose
text : 'Resource - City',
tooltip : 'Click to group by Resource → City',
pressed : true,
supportsPressedClick : true,
onAction() {
// toggle grouping fields order by resource to city
!isGroupByResourceToCity && treeGroupLevels.reverse();
isGroupByResourceToCity = true;
resourceUtilization.group(treeGroupLevels);
}
},
{
ref : 'cityToResourceButton', // for testing purpose
text : 'City - Resource',
tooltip : 'Click to group by City → Resource',
pressed : false,
supportsPressedClick : true,
onAction() {
// toggle grouping fields order by city to resource
isGroupByResourceToCity && treeGroupLevels.reverse();
isGroupByResourceToCity = false;
resourceUtilization.group(treeGroupLevels);
}
},
{
ref : 'defaultButton', // for testing purpose
text : 'Default',
tooltip : 'Disable tree group feature and back to default Resource → Assignment look',
onAction() {
if (!isGroupByResourceToCity) {
treeGroupLevels.reverse();
isGroupByResourceToCity = true;
}
resourceUtilization.clearGroups();
}
}
]
}
]
});
And now you'll see the correct dates of the third event
Forum post
Reproducible here https://bryntum.com/products/schedulerpro/examples/resourceutilization/
With this code
Now when you hover over the third event you'll see this date
And now trying removing the resource utilization code, this part
And now you'll see the correct dates of the third event