Our state of the art Gantt chart


Post by tasnim »

Hi,

The type of the pickergroup should be gridfieldfilterpickergroup and grid should have gantt instance not ganttConfig

I've updated our typescript react basic demo to implement functionality
Please check the attached test case below
You could run by running these commands

$ npm i
$ npm start

Hope this will help

Attachments
basic.zip
(2.02 MiB) Downloaded 18 times

Post by umesh »

Hi tasnim,

Here's the code of AppConfig.js. The question is how to access the gantt instance inside the change event.

AppConfig.js

import React from 'react';

const ganttConfig = {

    project: {

        autoLoad: true,

        transport: {

            load: {

                url: 'data/launch-saas.json'

            }

        },

        // 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,

    },

    columns: [

        { type: 'name', field: 'name', width: 250, renderer: ({record}) => {

            return record.isLeaf ? <span>{record.name}</span> : <b>{record.name}</b>

        } },

        {

            text: 'Start',

            type: 'startdate',

            width: 80,

          },

    ],

    viewPreset: 'weekAndDayLetter',

    barMargin: 10,

    tbar : [

        {

            type: 'button',

            ref: 'filterAllButton',

            icon: 'b-gantt-filter',

            tooltip: 'test',

            menu: {

              pickergroup: {

                type: 'fieldfilterpickergroup',

                fields: [{ name: 'name', type: 'string', text: 'Name' },{ name: 'status', type: 'string', text: 'Status' },],

                filters: [

                  {

                    property: 'name',

                    operator: 'notEmpty',

                    value: '',

                  },

                ],

                listeners: {

                  change: (props) => {

                    //how to access gantt instance here?

                  },            

                },

              },

            },

          },

    ],

};

export { ganttConfig };

Attached is the runnable code.

basic-filter.zip
(2.28 MiB) Downloaded 13 times

Thanks,
Umesh.


Post by marcio »

Hey Umesh,

You can access the instance if you configure your Gantt component like this

App.js

/**
 * Application
 */
import React, { Fragment, useRef } from 'react';
import { BryntumGantt } from '@bryntum/gantt-react';
import { ganttConfig } from './AppConfig';
import './App.scss';

const App = () => {
    const ganttRef = useRef();
    return (
        <Fragment>
            <BryntumGantt
                ref={ganttRef}
                {...ganttConfig}
                tbar={[
                    {
                        type: 'button',
                        ref: 'filterAllButton',
                        icon: 'b-gantt-filter',
                        tooltip: 'test',
                        menu: {
                          pickergroup: {
                            type: 'fieldfilterpickergroup',
                            fields: [{ name: 'name', type: 'string', text: 'Name' },{ name: 'status', type: 'string', text: 'Status' },],
                            filters: [
                              {
                                property: 'name',
                                operator: 'notEmpty',
                                value: '',
                              },
                            ],
                            listeners: {
                              change: (props) => {
                                console.log('gantt: ', ganttRef.current.instance)
                              },             
}, }, }, }, ]} /> </Fragment> ); }; export default App;

Best regards,
Márcio


Post by umesh »

Thank you for all your earlier responses.

Here is a new question regarding filtering.

I'm filtering the tasks based on the names. So for names property I need to show only 'contains' operator, but here by default bryntum showing all operators.

Operators.PNG
Operators.PNG (23.2 KiB) Viewed 156 times

And for other properties also I need only few operators to be displayed but not all. Can we make that operators dropdown customized? If yes, please suggest.

Regards,
Umesh.


Post by tasnim »

Hi,

You could try to filter out the store of that combo

ganttRef.current.instance.widgetMap.filterAllButton.menu.widgetMap.operatorPicker.store.filter(item => item.text === 'contains');

Docs https://bryntum.com/products/gantt/docs/api/Core/data/Store#function-filter

Attachments
Screenshot 2023-05-30 170027.png
Screenshot 2023-05-30 170027.png (13.1 KiB) Viewed 147 times

Post by umesh »

Hey tasnim,

Can I have a look at your entire code you wrote to achieve this please?

Thanks,
Umesh.


Post by marcio »

Hey Umesh,

You can put it inside an useEffect hook, for example

  useEffect(() => {
    ganttRef.current.instance.widgetMap.filterAllButton.menu.widgetMap.operatorPicker.store.filter(
      (item) => item.text === "contains"
    );
  }, [ganttRef]);

  return (
    <Fragment>
      <BryntumGantt
        ref={ganttRef}
        {...ganttConfig}
        tbar={[
          {
            type: "button",
            ref: "filterAllButton",
            icon: "b-gantt-filter",
            tooltip: "test",
            menu: {
              pickergroup: {
                type: "fieldfilterpickergroup",
                fields: [
                  { name: "name", type: "string", text: "Name" },
                  { name: "status", type: "string", text: "Status" },
                ],
                filters: [
                  {
                    property: "name",
                    operator: "notEmpty",
                    value: "",
                  },
                ],
                listeners: {
                  change: (props) => {
                    console.log("gantt: ", ganttRef.current.instance);
                  },
                },
              },
            },
          },
        ]}
      />
    </Fragment>

Best regards,
Márcio


Post by emil »

Hi Umesh,

One challenge with this is making sure to filter at the right times, for example in response to the change event from the filter picker group. You need to refresh the option list every time the property is selected, for example.

Another option would be to extend the filter picker class and override the operatorOptions getter, like this:

class MyFieldFilterPicker extends FieldFilterPicker {
    static type = 'myfieldfilterpicker';
    get operatorOptions() {
        let options = super.operatorOptions;
        // your logic here
        if (this.filter?.property === 'name') {
            options = options.filter(({ value }) => value === 'includes');
        }
        return options;
    }
}
MyFieldFilterPicker.initClass();

class MyGridFieldFilterPickerGroup extends GridFieldFilterPickerGroup {
    static type = 'mygridfieldfilterpickergroup';
    static childPickerType = MyFieldFilterPicker.type;
}
MyGridFieldFilterPickerGroup.initClass();

Then you would use the type name you defined in your UI, like this:

                filterPickers : {
                    type  : 'mygridfieldfilterpickergroup', 

Post by umesh »

Hi there,

this is my code

gantt.current.instance.tbar.add([
        {
          type: 'button',
          ref: 'filterAllButton',
          icon: 'b-gantt-filter',
          tooltip: 'Filter',
          menu: {
            pickergroup: {
              grid: gantt.current.instance,
              type: 'gridfieldfilterpickergroup',
              fields: [
                { name: 'owner', type: 'string', text: 'Owner' },
                { name: 'function', type: 'string', text: 'Function' },
                { name: 'status', type: 'string', text: 'Status' },
              ],
              filters: [
                {
                  // // property: 'name',
                  // // operator: 'includes',
                  // value: '',
                  // caseSensitive: false,
                },
              ],
            },
          },
        },
      ]);

So could you please provide me a runnable code such that Name property should have only 'contains' operator and status/owner properties should have 'is one of' operator.

Thanks,
Umesh.


Post by marcio »

If you follow Emil's custom picker approach, you would need to change the following

get operatorOptions() {
        let options = super.operatorOptions;
        // your logic here
        if (this.filter?.property === 'name') {
            options = options.filter(({ value }) => value === 'includes');
        } else if (this.filter?.property === 'status' || this.filter?.property === 'owner') {
            options = options.filter(({ value }) => value === 'is one of');
        }
        return options;
    }

Best regards,
Márcio


Post Reply