Our state of the art Gantt chart


Post by c-amitkumar.singh »

I am using Bryntum Gantt in react where i have attached one React state variable in parent component using useState for storing selectedTask. But below error is coming as soon as i select the task in gantt.

error.PNG
error.PNG (63.25 KiB) Viewed 469 times
const BryntumContainer =  props => {
    const {
        startDate = new Date(),
        viewPreset,
        ganttRef
    } = props;

const [selectedProject, setSelectedProject] = useState(null);
const onSelectProject = useCallback((data) => {
    	setSelectedProject(()=>data);
},[]);

return (<Fragment>  
        <HeaderToolbar 
            startDate={startDate}
            viewPreset = {viewPreset}
            onPresetChange = {onPresetChange}
        />  
        <GanttView
            ganttRef= {ganttRef}
            startDate={startDate}
            viewPreset = {viewPreset}                
            onSelectProject = {onSelectProject}
        />
     </<Fragment>);
}

My final target is to achieve resource filtration in schedulerPro based on selected task in Gantt in react where Gantt have partner with SchedulerPro [schedulerRef.current.instance.addPartner(ganttRef.current.instance)].

const BryntumContainer =  props => {
    const {        
startDate = new Date(), viewPreset, ganttRef, schedulerRef } = props; const [selectedProject, setSelectedProject] = useState(null); const onSelectProject = useCallback((data) => { setSelectedProject(()=>data); },[]); useEffect(()=>{ if(ganttRef?.current && schedulerRef?.current){ ganttRef.current.instance.addPartner(schedulerRef.current.instance); } },[]); return (<Fragment> <HeaderToolbar startDate={startDate} viewPreset = {viewPreset} onPresetChange = {onPresetChange} /> <GanttView ganttRef= {ganttRef} startDate={startDate} viewPreset = {viewPreset} onSelectProject = {onSelectProject} /> <BryntumSplitter/> <SchedulerProView schedulerRef={schedulerRef} startDate={startDate} viewPreset = {viewPreset} selectedProject={selectedProject} /> </<Fragment>); }

Post by marcio »

Hey c-amitkumar.singh,

Could you provide a full example of your configuration for us to check? You could get one of our demos and update the code to match your project.

You can see our guidelines here https://www.bryntum.com/forum/viewtopic.php?f=1&t=772

Best regards,
Márcio


Post by c-amitkumar.singh »

Hi Marcio,

Thanks for your response. Here is the configurations i am using

Our component version:

"@bryntum/demo-resources": "^1.1.0",
"@bryntum/gantt": "5.3.5",
"@bryntum/gantt-react": "^5.3.5",
"@bryntum/schedulerpro": "5.3.5",
"@bryntum/schedulerpro-react": "5.3.5",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^4.0.3"

Browser version, OS: Microsoft Edge Version 113.0.1774.42 (Official build) (64-bit)
Step by step description: below are the code file in sequence of flow
App.js

import React from 'react';
import './App.scss';
import BryntumContainer from './BryntumContainer';

function App() {
    // Creating a ref object using useRef hook
   const ganttRef = React.useRef();   
//render return ( <BryntumContainer ganttRef={ganttRef}/> ); } export default App;

BryntumContainer .jsx

import { Fragment, useCallback, useState } from 'react';
import GanttView from './GanttView';

const BryntumContainer =  props => {
    const {
        startDate = new Date(),
        viewPreset  = 'weekAndDayLetter',
        ganttRef
    } = props;

const [selectedProject, setSelectedProject] = useState(null);
const onSelectProject = useCallback((data) => {
    	setSelectedProject(()=>data);
},[]);

return (<Fragment>  
<GanttView ganttRef= {ganttRef} startDate={startDate} viewPreset = {viewPreset}
onSelectProject = {onSelectProject} /> </Fragment>); } export default BryntumContainer ;

GanttView.jsx

import React, { useCallback, useEffect } from 'react';
import { BryntumGantt } from '@bryntum/gantt-react';
import { AjaxStore, DateHelper, DomHelper, PresetManager, StringHelper, TaskTooltip, Toast} from '@bryntum/gantt';
import taskData from './taskData.json';

const GanttView =  props => {
    const {
        startDate = new Date(),
        viewPreset  = 'weekAndDayLetter',
        ganttRef,
        onSelectProject 
    } = props;

const requiredPresetIds = {
        secondAndMinute   : 1, //minutes and seconds
        minuteAndHour     : 1, //hours and minutes
        hourAndDay        : 1, //days and hours
        //dayAndWeek        : 1, //weeks and days 
        //dayAndMonth       : 1, //months and days
        dayNightShift     : 1, 
        weekAndDay        : 1, //just like dayAndWeek but with different formatting
        weekAndMonth      : 1, //months and weeks
        weekAndDayLetter  : 1, //weeks and day
        weekDateAndMonth  : 1, //months and weeks (weeks shown by first day only)
        weekNumberAndYear : 1,
        monthAndYear      : 1, //years and months
        year              : 1, //years and quarters
        manyYears         : 1  //5-years and years
    };
	// The set of available Presets is what provides the zoom levels.
    const presets = PresetManager.records.filter(p => requiredPresetIds[p.id])
	const ganttConfig = {
        startDate           : startDate,
        viewPreset          : viewPreset,
        presets             : presets,
        //visibleZoomFactor   : 10,
        barMargin           : 2,
        rowHeight           : 20,
        timeRangesFeature   : {
            showCurrentTimeLine : true
        },
        // The following features are enabled by default:
        features : {
            cellEdit      : true, //isGanttEditable
        },
        columns: [
            { 
                type: 'name', 
                text : 'Project',  
field: 'name', width: 250, renderer: ({record}) => { return record.isLeaf ? <span>{record.name}</span> : <b>{record.name}</b> } } ], // Custom task content, display task name on child tasks taskRenderer({ taskRecord }) { if (taskRecord.isLeaf && !taskRecord.isMilestone) { return StringHelper.encodeHtml(taskRecord.name); } }, listeners : { cellClick: ({record} ) =>onSelectProject(record) }, project:{ project:{ "calendar" : "general", "startDate" : startDate, "hoursPerDay" : 24, "daysPerWeek" : 5, "daysPerMonth" : 20 }, tasksData: taskData, timeRangesData: [ { "id" : 1, "name" : "Important date", "startDate": startDate, "duration" : 0, "durationUnit" : "d", "cls" : "b-fa b-fa-diamond" } ], autoLoad : true, // The State TrackingManager which the UndoRedo widget in the toolbar uses stm : { autoRecord : true } } }; return <BryntumGantt ref={ganttRef} {...ganttConfig} /> }; export default React.memo(GanttView);

Any debugging you've done so far: I have tried to use reacts hooks viz. useCallback, Memo etc but didn't solve the issue

Last edited by c-amitkumar.singh on Wed May 24, 2023 11:14 am, edited 1 time in total.

Post by alex.l »

Hi,

I was not able to apply these code snippets to our examples and make it runnable.
Could you please zip your full application with package.json included, remove node_modules folder and attach it here with instructions how to build and run it, and steps to reproduce the issue? We need a runnable test case for debugging.

Thank you!

All the best,
Alex


Post by c-amitkumar.singh »

Hi,

Here I have attached source code along with package.json and mock data. I am having licence version of Gantt and Scheduler-pro with another username and here only using Gantt so you may remove Scheduler-pro dependecy from package.json. After application lunch it will look alike as in attched image. Click on any task name in grid will through the error.

brytnum_demo.PNG
brytnum_demo.PNG (16.73 KiB) Viewed 385 times

Please let me know if anything else is required. Thanks for your support.

Cheers
Amit

Attachments
bryntum_demo.zip
(3.8 KiB) Downloaded 19 times

Post by alex.l »

Hi,

I am afraid the app you attached is not runnable. Please see the error I see when I do npm start.

Screenshot 2023-05-25 at 14.06.42.png
Screenshot 2023-05-25 at 14.06.42.png (12.69 KiB) Viewed 356 times

All the best,
Alex


Post by c-amitkumar.singh »

Hi Alex,

I have only shared the src folder along with package.json, to be replaced in any example of Gantt.

Anyway, here I am sharing complete project structure excluding (node_module, .git directories and package-lock.json). if you require that as well than please let me know.

Thanks
Amit

Attachments
bryntum_demo.zip
(10.69 KiB) Downloaded 22 times

Post by alex.l »

Hi Amit,

Thank you for clarifications. I was able to run your app and it helped a lot.
The problem was not so obvious because of exception in the console, but after I commented the code inside a listener that caused that error, I found a warning

Screenshot 2023-05-25 at 19.38.11.png
Screenshot 2023-05-25 at 19.38.11.png (129.93 KiB) Viewed 340 times

After I fixed this problem by wrapping ganttConfig object into useState, because it contains static configs that cannot be dynamically updated, such as listeners config, the problem was gone.

Screenshot 2023-05-25 at 19.50.30.png
Screenshot 2023-05-25 at 19.50.30.png (72.25 KiB) Viewed 340 times

Please try yourself and let us know if it helped.

All the best,
Alex


Post by c-amitkumar.singh »

Hi Alex,

Thanks for the solution. With your changes, It is not throwing any errors and able to set the selected task but I have tried to display the name of selected task into tbar, which is not happening.
I tried same by creating state for the label as well but didn't work.

const [filterResourcesLabel, setFilterResourcesLabel] = useState('Project : None Selected');
    useEffect(()=>{
        if(filterProject && selectedProject)
            setFilterResourcesLabel('Project : '+selectedProject?.name);
        else
            setFilterResourcesLabel('Project : None Selected');
        
},[selectedProject,filterProject]);
brytnum_demo.PNG
brytnum_demo.PNG (15.02 KiB) Viewed 324 times

There is one more problem I am facing on zoom, I thought to create a new topic but it might be smaller. While zooming In/Out, it only zooms once even i have added 12 default presets. Please suggest what i am missing here.

Here I am sharing updated project structure excluding (node_module, .git directories and package-lock.json). if you require that as well than please let me know.

Cheers
Amit

Attachments
bryntum_demo.zip
(11.28 KiB) Downloaded 20 times

Post by alex.l »

Hi,

Label has not being updated because checkbox in a toolbar is a vanilla JS component, not React. You need to use our API to manage our components. So, just set checkbox.text = 'new value'

        listeners : {
            cellClick: ({record, grid : gantt} ) => {
                gantt.widgetMap.checkboxProject.text = 'Project : ' + (record ? record.name : 'None Selected');
                
onSelectProject(record); // if still required } }, tbar : [ { type : 'checkbox', ref : 'checkboxProject', color : 'b-blue', text : 'Project : None Selected', style : 'margin-right: .5em', onChange : filterResources },

Regarding to zooming. You set toggleGroup : true for button group which means button will stay pressed after first click. If you clicked again, onAction won't be called, that's why usually toggleGroup used for - allow to call handler for button only once when it toggled. When you comment this line, all will be working great.

Another moment. Please always create a new thread for new questions. There 2 questions doesn't related to the name on the topic "callback is not a function while using useState at parent component" and the entire problem. Our forum rule is: one thread - one question.

I hope you're unblocked now.
Thank you!

All the best,
Alex


Post Reply