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

[Ext Gantt] Inherited parent dependencies are not collected into critical paths #9391

Open arcady-zherdev opened 1 month ago

arcady-zherdev commented 1 month ago

Reported here: https://forum.bryntum.com/viewtopic.php?p=148496#p148496

Ext Gantt does not include inherited parent dependencies into critical paths. Sample dataset:

{
    "success"      : true,
    "dependencies" : {
        "rows" : [
            { "From" : 11, "To" : 12, "Type" : 0 },
            { "From" : 12, "To" : 34 },
            { "From" : 12, "To" : 4 },
            { "From" : 45, "To" : 34 },
            { "From" : 33, "To" : 12 }
        ]
    },
    "tasks"        : {
        "metaData" : {
            "projectStartDate" : "2024-06-14"
        },
        "rows"     : [
            {
                "Id"                : 1,
                "Name"              : "Planning",
                "PercentDone"       : 50,
                "StartDate"         : "2024-06-14",
                "Duration"          : 2,
                "expanded"          : true,
                "children"          : [
                    {
                        "Id"                : 11,
                        "leaf"              : true,
                        "Name"              : "Investigate",
                        "PercentDone"       : 50,
                        "StartDate"         : "2024-06-14",
                        "Duration"          : 1
                    },
                    {
                        "Id"                : 12,
                        "leaf"              : true,
                        "Name"              : "Assign resources",
                        "PercentDone"       : 50,
                        "StartDate"         : "2024-06-17",
                        "Duration"          : 1
                    }
                ]
            },
            {
                "Id"                : 31,
                "Name"              : "Planning 2",
                "PercentDone"       : 50,
                "StartDate"         : "2024-06-14",
                "Duration"          : 5,
                "expanded"          : true,
                "children"          : [
                    {
                        "Id"                : 32,
                        "leaf"              : true,
                        "Name"              : "Investigate",
                        "PercentDone"       : 50,
                        "StartDate"         : "2024-06-14",
                        "Duration"          : 1
                    },
                    {
                        "Id"                : 33,
                        "leaf"              : true,
                        "Name"              : "Assign resources",
                        "PercentDone"       : 50,
                        "StartDate"         : "2024-06-14",
                        "Duration"          : 1
                    },
                    {
                        "Id"                : 34,
                        "leaf"              : true,
                        "Name"              : "Assign resources",
                        "PercentDone"       : 50,
                        "StartDate"         : "2024-06-19",
                        "Duration"          : 2
                    }
                ]
            },
            {
                "Id"                : 4,
                "Name"              : "Implementation Phase",
                "PercentDone"       : 46.95652173913044,
                "StartDate"         : "2024-06-18",
                "Duration"          : 1,
                "expanded"          : true,
                "children"          : [
                    {
                        "Id"                : 44,
                        "leaf"              : true,
                        "Name"              : "Report to Bla Bla",
                        "PercentDone"       : 0,
                        "StartDate"         : "2024-06-18",
                        "Duration"          : 1
                    },
                    {
                        "Id"                : 45,
                        "leaf"              : true,
                        "Name"              : "Report to Bla Bla 22",
                        "PercentDone"       : 0,
                        "StartDate"         : "2024-06-18",
                        "Duration"          : 1
                    }
                ]
            }
        ]
    }
}
arcady-zherdev commented 1 month ago

A quick workaround is:

// support inherited dependencies on the data level
Ext.define('MyApp.TaskModel', {
    extend  : 'Gnt.model.Task',

    getCriticalPaths: function () {
        var toProcess    = [this],
            cPath        = [[this]],
            task;

        while (task = toProcess.shift()) {
            var dependencies         = task.getIncomingDependencies(true).concat(task.getParentsIncomingDependencies()),
                criticalPredecessors = [];

            for (var i = 0; i < dependencies.length; i++) {
                var dependency  = dependencies[i],
                    predecessor = dependency.getSourceTask();

                if (predecessor.isCritical() && dependency.isCritical(dependency)) {
                    criticalPredecessors.push(predecessor);
                }
            }

            if (criticalPredecessors.length) {
                toProcess = toProcess.concat(criticalPredecessors);
                cPath.push(criticalPredecessors);
            }
        }

        return cPath;
    }
});

// support inherited dependencies on the UI level
Ext.define('MyApp.GanttViewOverride', {

    override : 'Gnt.view.Gantt',

    highlightCriticalPaths : function () {
        var me = this;

        this.callParent(arguments);

        var paths           = me.getCriticalPaths(),
            dependencyStore = me.getDependencyStore(),
            dependencyView  = me.ownerGrid.getDependencyView();

        // we might have multiple projects
        Ext.Array.each(paths, function (path) {
            var prevLevelTasks = [];

            // walk through the path
            Ext.Array.each(path, function (levelTasks) {
                // every element is an array of critical predecessors
                for (var i = 0, l = levelTasks.length; i < l; i++) {
                    var task = levelTasks[i];

                    // If we have the previous path chain
                    // let's loop over its tasks and highlight stressed dependencies
                    Ext.each(prevLevelTasks, function (prevTask) {
                        prevTask.bubble(function (parent) {
                            if (!parent.isRoot() && !parent.isProject) {
                                var dependency = dependencyStore.getTasksLinkingDependency(task, parent);
                                dependency && dependencyView.highlightDependency(dependency);
                            }
                        });
                    });
                }

                prevLevelTasks = levelTasks;
            });
        });
    }
});