Our state of the art Gantt chart


Post by vitor.np »

Hello Bryntum Team,

I am using the Gantt component in a Next.js application, and I need to save the column state to the backend so that I can retrieve it on a subsequent access. Could you advise on how to achieve this?

What are the TypeScript types for this functionality?

Here is how we are currently initializing the Gantt configurations.

  
  
const handleStmUpdate = useCallback(() => { const stm = ganttRef.current?.instance.project.stm; if (!stm) return; setStmInfo({ queueLength: stm.queue.length, position: stm.position, }); }, []); const handleInitialize = useCallback(() => { if (!ganttRef.current) return; const instance = ganttRef.current.instance; const stm = instance.project.stm; stm.un("recordingstop", handleStmUpdate); stm.un("restoringstop", handleStmUpdate); stm.autoRecord = false; stm.resetQueue(); stm.disable(); setStmInfo(null); instance.features.criticalPaths.disabled = true; instance.features.baselines.disabled = true; instance.features.rollups.disabled = true; instance.features.progressLine.disabled = true; instance.features.dependencies.disabled = false; instance.features.nonWorkingTime.disabled = false; instance.features.labels.disabled = false; setGanttSettings({ showDependencyArrows: true, highlightNonWorkingTime: true, }); // Initialize stm.autoRecord = true; stm.enable(); stm.on("recordingstop", handleStmUpdate); stm.on("restoringstop", handleStmUpdate); instance.zoomToFit({ leftMargin: 48, rightMargin: 48, }); setGanttInitialized(true); }, [handleStmUpdate]);

Post by marcio »

Hey vitor.np,

Thanks for reaching out and welcome to our forums! :)

We have a demo that you can take a look at which does exactly what you're asking, please take a look here https://bryntum.com/products/gantt/examples/state/.

Please also check this documentation that explains how you can set things with State and StateProvider classes.
https://bryntum.com/products/gantt/docs/api/Core/state/StateProvider
https://bryntum.com/products/gantt/docs/api/Core/mixin/State

If you need more clarification, please don't hesitate to contact us here.

Best regards,
Márcio


Post by vitor.np »

Hey Marcio,

Thank you so much for the reply! I'm now saving the state on the backend server, but I encountered another issue.

When I change the columns and refresh the page, retrieving the changed columns doesn't display them in the GANTT. However, if I modify the width of an existing column, it does show the updates. Could you help me with this?

This is the object I'm receiving from the backend:

  {
    "id": "9c5fa84d-f1f7-4aca-ac3a-ab7baa4ac19b",
    "urn": "gantt-state-a559b15c-c122-4553-9ed2-01a22c220e33",
    "shared": false,
    "configs": {
        "ganttPageState": {
            "store": {
                "sorters": [
                    {
                        "field": "percentDone",
                        "ascending": false,
                        "columnOwned": true
                    }
                ]
            },
            "style": "min-height: 10em;",
            "scroll": {
                "scrollTop": 0,
                "scrollLeft": {
                    "locked": 0,
                    "normal": 0
                }
            },
            "columns": [
                {
                    "id": "ganttPageState-sequenceNumber-2",
                    "text": null,
                    "field": "sequenceNumber",
                    "width": 70,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "ganttPageState-name-1",
                    "text": "Nome",
                    "field": "name",
                    "width": 200,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "durationCol",
                    "text": "Duração",
                    "field": "fullDuration",
                    "width": 100,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "startDateCol",
                    "text": "Início",
                    "field": "startDate",
                    "width": 130,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "endDateCol",
                    "text": "Fim",
                    "field": "endDate",
                    "width": 130,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "percentDoneCol",
                    "text": "% concluído",
                    "field": "percentDone",
                    "width": 168,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "ganttPageState-manuallyScheduled-3",
                    "text": "Agendado manualmente",
                    "field": "manuallyScheduled",
                    "width": 100,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "ganttPageState-calendar-4",
                    "text": "Calendário",
                    "field": "calendar",
                    "width": 100,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "addnewCol",
                    "text": "Nova coluna",
                    "field": null,
                    "width": 173,
                    "hidden": false,
                    "locked": true,
                    "region": "locked"
                },
                {
                    "id": "timeaxiscolumn",
                    "hidden": false,
                    "locked": false,
                    "region": "normal"
                }
            ],
            "subGrids": {
                "locked": {
                    "width": 1265,
                    "collapsed": false
                },
                "normal": {
                    "collapsed": false
                }
            },
            "barMargin": 10,
            "rowHeight": 40,
            "zoomLevel": 9,
            "zoomLevelOptions": {
                "width": 35.57142857142857,
                "endDate": "2024-12-09T03:00:00.000Z",
                "startDate": "2024-09-23T03:00:00.000Z",
                "centerDate": "2024-10-01T08:00:43.373Z"
            }
        }
    },
    "user_id": "85f5e662-3d0f-4631-9ce3-6359d83cec1c"
}	

And this is how I'm applying it in the GANTT:

  useEffect(() => {
    const provider = StateProvider.setup("memory");
    setStateProvider(provider);

let isStateLoaded = false;

const loadState = async () => {
  if (!selectedProject) return;

  const stateData = await ScreenLayoutService.ganttState.getSelf(
    cApi,
    user?.id || "",
    selectedProject.id,
  );

  console.log("State data", stateData);

  if (!invalid(stateData) && stateData && stateData.configs) {
    provider.data = stateData.configs;
    ganttRef?.current?.instance.applyState(stateData.configs);
  }

  setGanttReady(true);
  isStateLoaded = true;
  setIsStateLoading(false);
};

loadState();

const onSave = () => {
  const data = provider.data;

  if (!selectedProject || !isStateLoaded) return;

  ScreenLayoutService.ganttState.update(
    cApi,
    { shared: false, configs: data },
    user?.id || "",
    selectedProject.id,
  );
};
provider.on("save", onSave);

return () => {
  provider.un("save", onSave);
};
  }, [cApi, selectedProject, user?.id]);

Post by marcio »

Hey vitor.np,

Are you able to share a runnable test case? You can have more info on that by checking our guidelines here https://www.bryntum.com/forum/viewtopic.php?f=1&t=772.

On our demo (the one that I shared earlier), the order of the columns are preserved after you changing them and reload the page. So we'll need a complete test case for us to debug and assist you.

Best regards,
Márcio


Post by vitor.np »

Hey Marcio,

The columns' order and width are being saved and retrieved perfectly from the back-end server.

The real problem is when I add a new column using the "addnew" column in the Gantt chart. When I do this the column is saved in the back-end, but if I reload the page, the columns are not added in the Gantt chart, even though they are present in the object returned by the back-end State, like this:

These are the default columns defined in the config object:

const ganttProps: BryntumGanttProps = {
  taskMenuFeature: {
    items: {
      splitTask: false,
    },
  },
  columns: [
    { id: "duration", type: "duration" },
    { id: "startdate", type: "startdate" },
    { id: "enddate", type: "enddate" },
    { id: "percentdone", type: "percentdone" },
    { id: "addnew", type: "addnew" },
  ],
  selectionMode: {
    cell: true,
    rowNumber: true,
    multiSelect: true,
    selectRecordOnCell: true,
  },
  dependenciesFeature: {
    radius: 5,
    clickWidth: 5,
  },
  rollupsFeature: {
    disabled: true,
  },
  baselinesFeature: {
    disabled: true,
  },
  progressLineFeature: {
    disabled: true,
  },
  cellEditFeature: {
    addNewAtEnd: true,
  },
  rowHeight: 40,
  fixedRowHeight: true,
  enableDeleteKey: true,
  fillHandleFeature: true,
  enableUndoRedoKeys: true,
  taskCopyPasteFeature: true,
  cellCopyPasteFeature: true,
  scrollTaskIntoViewOnCellClick: true,
};

This one is the columns received from the server:

{
    "rowHeight": 40,
    "style": "min-height: 10em;",
    "selectedRecords": [
        "4b4f3cda-b686-4d11-8ced-63b1565f0b55"
    ],
    "columns": [
        {
            "id": "ganttPageState-sequenceNumber-2",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": null,
            "field": "sequenceNumber",
            "width": 70
        },
        {
            "id": "ganttPageState-name-1",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Nome",
            "field": "name",
            "width": 150
        },
        {
            "id": "duration",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Duração",
            "field": "fullDuration",
            "width": 244
        },
        {
            "id": "percentdone",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "% concluído",
            "field": "percentDone",
            "width": 84
        },
        {
            "id": "startdate",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Início",
            "field": "startDate",
            "width": 170
        },
        {
            "id": "enddate",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Fim",
            "field": "endDate",
            "width": 135
        },
        {
            "id": "ganttPageState-manuallyScheduled-3",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Agendado manualmente",
            "field": "manuallyScheduled",
            "width": 100
        },
        {
            "id": "addnew",
            "hidden": false,
            "region": "locked",
            "locked": true,
            "text": "Nova coluna",
            "field": null,
            "width": 1028
        },
        {
            "id": "timeaxiscolumn",
            "hidden": false,
            "region": "normal",
            "locked": false
        }
    ],
    "store": {
        "sorters": [
            {
                "ascending": true,
                "field": "predecessors",
                "columnOwned": true
            },
            {
                "ascending": false,
                "field": "endDate",
                "columnOwned": true
            },
            {
                "ascending": true,
                "field": "fullDuration",
                "columnOwned": true
            }
        ]
    },
    "scroll": {
        "scrollTop": 0,
        "scrollLeft": {
            "locked": 0,
            "normal": 0
        }
    },
    "subGrids": {
        "locked": {
            "width": 1041,
            "collapsed": false
        },
        "normal": {
            "collapsed": false
        }
    },
    "barMargin": 10,
    "zoomLevel": 10,
    "zoomLevelOptions": {
        "startDate": "2024-09-23T03:00:00.000Z",
        "endDate": "2024-10-07T03:00:00.000Z",
        "centerDate": "2024-09-29T15:23:13.548Z",
        "width": 62
    }
}

This functionality of adding columns and having them saved and retrieved in another access in the state is not available in that demo, which only supports saving the columns size and their order. Is that even possible?


Post by marcio »

Hey,

Thanks for clarifying that. I was able to reproduce that behavior and looks like a bug.

I created a ticket to confirm that and provide a fix if it's confirmed that's not the expected behavior.

Please follow for updates here https://github.com/bryntum/support/issues/10154.

Best regards,
Márcio


Post Reply