bryntum / support

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
https://www.bryntum.com
53 stars 6 forks source link

Resource Utilization Events ends later than Scheduler when resourceUtilization panel available #9435

Open taauntik opened 3 months ago

taauntik commented 3 months ago

Forum post

Reproducible here https://bryntum.com/products/schedulerpro/examples/resourceutilization/

With this code

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 msedge_OVGoR2dyDT

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 msedge_jfGSNNWNLM

marciogurka commented 1 month ago

+1