Our state of the art Gantt chart


Post by muhabbil »

Hey Maxim,
As per my understanding, it seems that we can take following route if we want to go through node js solution instead of custom solution:-

We should build an api in node js which will receive project json(tasks, dependencies, resources, assignments, startdate) as parameter and the milestones array for which start, end date and duration fields have been changed. Based on the code which you shared, we will alter the date fields for milestones using following code.

myNodeProject.taskStore.getById(1).startDate = 10;

For example if we have 10 milestones for which dates have been changed and if we apply same code logic on the impacted milestones and execute following code as it should give me updated project schedule which i can send back to salesforce to update the project milestone schedule.

await myNodeProject.commitAsync();

const changes = myNodeProject.changes;

Design::
Salesforce(if any milestone date is changed from cron job) => call node api with full project json and updated milestones data => api will process the changes into bryntum project using your npm package library => return results back to salesforce with posted changes => apply changes to salesforce metadata

Kindly share your thoughts on it.


Post by Maxim Gorkovsky »

This is a reasonable solution. You surely can instantiate project every time with an entire set of data and calculate changes. However, reloading entire project every time could be an impact on performance. If you don't care about extra time (depends on a size of a project) per every request - go with this solution, it cannot be simpler than that.
If you want to squeeze every bit of performance out of this, you need to keep project up and running only applying small changes made by the cron job.

Based on the code which you shared, we will alter the date fields for milestones using following code.

I can suggest trying this API instead: https://bryntum.com/products/gantt/docs/api/Gantt/model/ProjectModel#function-applyProjectChanges That way you can declare set of changes you need to apply which would save you effort looking up records and fields. Your code snippet would like this:

// old
myNodeProject.taskStore.getById(1).startDate = new Date(2020, 0, 1);

await myNodeProject.commitAsync();

const changes = myNodeProject.changes;

// new
await myNodeProject.applyProjectChanges({
  tasks : {
    modified : [{ id : 1, startDate : '2020-01-01' }]
  }
})

const changes = myNodeProject.changes;

Post by muhabbil »

Hey Maxim,
Following code give null result after applying project changes using await myNodeProject.applyProjectChanges({}) but if you get project.tasks, i think it give updated changes there.

Can you suggest how i can get changes only using apply project changes?

const changes = myNodeProject.changes;

Post by muhabbil »

Hey Maxim,
Any update on it?


Post by muhabbil »

Hey Maxim,
I have one more question as i am trying to update the end date but it does not change any thing until unless i change the duration in projectChanges node(json).

Please find code and json(the following code api is going to receive as parameters):-

/*
const { ProjectModel } = require('@bryntum/gantt/gantt.node.cjs'); 
const data = require('./launch-saas');
const { json } = require('body-parser');


/****************************
* Example post method *
****************************/

app.post('/executeScheduling', async function(req, res) {
  //console.log(JSON.stringify(data));

  let {projectGanttData, projectStartDate, projectChanges} = req.body;

  let project = new ProjectModel({
    calendar: data.project.calendar,
    startDate: projectStartDate,
    tasksData: projectGanttData.tasks,
    dependenciesData: projectGanttData.dependencies,
    calendarsData: data.calendars.rows
  }); 

  // // new //
  await project.applyProjectChanges({
    tasks : {
      modified : [{...projectChanges}]
    }
  })


  let result = [];
  project.taskStore.forEach(record=>{
    result.push({
      id : record.id,
      name : record.name,
      startDate : record.startDate,
      endDate : record.endDate,
      duration : record.duration,
      percentDone : record.percentDone
    })
  })
  // Add your code here
  res.json({success: 'post1 call succeed1!', url: req.url, body: result});//req.body
});







{
	"projectStartDate": "2023-01-02",
	"projectGanttData": {
		"tasks": [{
			"id": "a8IDI0000008Puu2AE",
			"parentIndex": 0,
			"startDate": "2023-01-02T00:00:00-08:00",
			"endDate": "2023-01-28T00:00:00-08:00",
			"duration": 20,
			"name": "Milestone # 01",
			"percentDone": 0
		}, {
			"id": "a8IDI0000008Puz2AE",
			"parentIndex": 1,
			"startDate": "2023-01-30T00:00:00-08:00",
			"endDate": "2023-02-02T00:00:00-08:00",
			"duration": 3,
			"name": "Milestone # 02",
			"percentDone": 50
		}],
        "dependencies": [{
            "id": "a8LDI000000GmgQ2AS",
            "from": "a8IDI0000008Puu2AE",
            "to": "a8IDI0000008Puz2AE",
            "type": 2,
            "cls": "",
            "lag": 0,
            "lagUnit": "day",
            "fromEvent": "a8IDI0000008Puu2AE",
            "toEvent": "a8IDI0000008Puz2AE",
            "active": true
        }]
	},
	"projectChanges": {
		"id": "a8IDI0000008Puu2AE",
		"endDate": "2023-01-31T00:00:00-08:00",
        "percentDone": 40
	}
}

Post by Maxim Gorkovsky »

project.changes returns null

StartDate field on the task does not really set a start date, unless task is manually scheduled. By default, tasks are moved as close to the start of the project as possible, so I assume you don't see any changes because they didn't have effect on a schedule. If you want to move task, you should set constraint instead:

project.applyProjectChanges({
    tasks : {
         modified : [{ id : 1, constraintType : 'startnoearlierthan', constraintDate : startDate }]
    }
})

I have one more question as i am trying to update the end date but it does not change any thing until unless i change the duration in projectChanges node(json).

Duration field has priority over end date. If you want to set end date you can omit duration field from the change object, in this case it will be recalculated


Post by muhabbil »

Maxim, with following json and code amendments, it still gives null. Please note that projectChanges is a attribute which i receive from json and apply it in project.

 await project.applyProjectChanges({
    tasks : {
      modified : [{...projectChanges}]
    }
  })
  const changes = project.changes;
{
	"projectStartDate": "2023-01-02",
	"projectGanttData": {
		"tasks": [{
			"id": "a8IDI0000008Puu2AE",
			"parentIndex": 0,
			"startDate": "2023-01-02T00:00:00-08:00",
			"endDate": "2023-01-28T00:00:00-08:00",
			"duration": 20,
			"name": "Milestone # 01",
			"percentDone": 0
		}, {
			"id": "a8IDI0000008Puz2AE",
			"parentIndex": 1,
			"startDate": "2023-01-30T00:00:00-08:00",
			"endDate": "2023-02-02T00:00:00-08:00",
			"duration": 3,
			"name": "Milestone # 02",
			"percentDone": 50
		}],
        "dependencies": [{
            "id": "a8LDI000000GmgQ2AS",
            "from": "a8IDI0000008Puu2AE",
            "to": "a8IDI0000008Puz2AE",
            "type": 2,
            "cls": "",
            "lag": 0,
            "lagUnit": "day",
            "fromEvent": "a8IDI0000008Puu2AE",
            "toEvent": "a8IDI0000008Puz2AE",
            "active": true
        }]
	},
	"projectChanges": {
		"id": "a8IDI0000008Puu2AE",
		"duration": 25,
        "constraintType" : "startnoearlierthan",
        "constraintDate" : "2023-01-02"
    }
}

Secondly, even with following end date changes, it does not perform any calculations:-

"projectChanges": {
		"id": "a8IDI0000008Puu2AE",
		"endDate": "2023-01-31T00:00:00-08:00",
        "percentDone": 40
	}

if i add following changes with duration, it apply the changes but not with end date:-

"projectChanges": {
		"id": "a8IDI0000008Puu2AE",
		"duration": 25,
        "percentDone": 40
	}

Kindly let me know if i am missing anything here.


Post by Maxim Gorkovsky »

You're right, endDate passed to the applyProjectChanges does not change duration. I've opened a feature request for it: https://github.com/bryntum/support/issues/6553

Speaking of the first code snippet, with this data indeed it does not yield any changes. But that is because you set constraint to the task current start date. With a different date (next day) it does yield changes


Post by muhabbil »

Maxim,

  1. You're right, endDate passed to the applyProjectChanges does not change duration. I've opened a feature request for it: 
    

    For this one, even it do not change duration as well as dependent tasks recalculations.

  2. First code snippet, i have added constraint date and constraint type as per your suggestions and added start date of that updated task in constraintDate but it gives null. I even tried with following code, it gives null. For our use case, we will be changing the end date, percent done or duration field, can you let me know how i can get the changes only?

"projectChanges": {
		"id": "a8IDI0000008Puu2AE",
        "duration": 25
    }

Post by Maxim Gorkovsky »

Here is a Node code snippet to apply constraint change which moves task forward. Try to run it on your env and see if it logs changes:

import { ProjectModel } from './gantt.node.mjs';

async function run() {
	const project = new ProjectModel({
		startDate: "2023-01-02",
		tasksData: [{
			"id": "a8IDI0000008Puu2AE",
			"parentIndex": 0,
			"startDate": "2023-01-02",
			"endDate": "2023-01-28",
			"duration": 20,
			"name": "Milestone # 01",
			"percentDone": 0
		}, {
			"id": "a8IDI0000008Puz2AE",
			"parentIndex": 1,
			"startDate": "2023-01-30",
			"endDate": "2023-02-02",
			"duration": 3,
			"name": "Milestone # 02",
			"percentDone": 50
		}],
	    dependenciesData: [{
	        "id": "a8LDI000000GmgQ2AS",
	        "from": "a8IDI0000008Puu2AE",
	        "to": "a8IDI0000008Puz2AE",
	        "type": 2,
	        "cls": "",
	        "lag": 0,
	        "lagUnit": "day",
	        "fromEvent": "a8IDI0000008Puu2AE",
	        "toEvent": "a8IDI0000008Puz2AE",
	        "active": true
	    }]
	});

	await project.commitAsync();

	await project.applyProjectChanges({
		tasks : {
			modified : [{
				"id": "a8IDI0000008Puu2AE",
				"duration": 25,
		        "constraintType" : "startnoearlierthan",
		        "constraintDate" : "2023-01-05"
			}]
		}
	});

	console.log(JSON.stringify(project.changes));
}

run().then(() => console.log('done'));

It logs changes to the target task and its successor:

{"tasks":{"updated":[
{
  "endDate":"2023-01-30T00:00:00+04:00",
  "startDate":"2023-01-05T00:00:00+04:00",
  "duration":25,
  "constraintType":"startnoearlierthan",
  "constraintDate":"2023-01-05T00:00:00+04:00",
  "id":"a8IDI0000008Puu2AE"
},
{
  "endDate":"2023-02-02T00:00:00+04:00",
  "startDate":"2023-01-30T00:00:00+04:00",
  "id":"a8IDI0000008Puz2AE"
}]}}

Post Reply