Our state of the art Gantt chart


Post by rtbennett »

Dear Bryntum:
I had a question regarding how to get filtering to work on new custom columns we created in our Gantt project.

I'll give to you the code below to show how I'm currently configuring it. I've not been able to get the custom columns to filter correctly -- however, please note the other columns (Name, Start Date, End Date, Duration, Effort) are working fine. I currently have the filter set to true (in features in gantt config) -- as shown in the code below (Gantt.js).

features: {
      filter: true,
    },

Code below given for reference on how I'm using filtering within each of my custom columns.

Please note the custom columns are shown as "Status" (StatusColumn.js), "Assigned To" (AssignedToColumn.js), "Responsiblity" (TaskResponsibility.js), "Visibility" (ExternalVisibilityColumn.js). I have also included a screenshot below to show each of the different columns displayed (custom columns are highlighted in red).

Could you please share with me info on how to make the custom columns filtering to work correctly? What am I doing wrong on this? Thank you so much for all your help. I will look forward to your response.


Gantt.js

import { BryntumGantt } from '@bryntum/gantt-react'
import '@bryntum/gantt/gantt.stockholm.css'
import { useGetGantt } from '~/views/hooks/Gantt/useGetGantt'

import './StatusColumn'
import './AssignedToColumn'
import './TaskResponsibilityColumn'
import './PriorityColumn'
import './ExternalVisibilityColumn'
import Task from './Task'
import './GanttToolbar'

import { useRouter } from 'next/router'
import React, { useEffect, useRef, useState } from 'react'
import Loader from '~/views/components/ui/Loader'

export default function Gantt() {
  const [ganttData, setGanttData] = useState(null)
  const [delayed, setDelayed] = useState(true)
  const ganttRef = useRef()
  const router = useRouter()

  const projectId = router.query.projectId
  const { data } = useGetGantt({
    projectId,
  })

  useEffect(() => {
    if (data) {
      setDelayed(false)
      setGanttData((ganttConfig.project.tasksData = data.ganttChartTimelines))
    }
  }, [data])

  const ganttConfig = {
    project: {
      // Let the Project know we want to use our own Task model with custom fields / methods
      taskModelClass: Task,
      autoLoad: true,
      manuallyScheduled: true,
      hoursPerDay: 24,
      daysPerWeek: 5,
      daysPerMonth: 20,
      validateResponse: true,
      tasksData: ganttData,
    },
    taskMenu: {
      items: {
        indent: false,
        outdent: false,
        convertToMilestone: false,
      },
    },
    tbar: {
      type: 'gantttoolbar',
    },
    columns: [
      { type: 'name', field: 'name', width: 230 },
      { type: 'date', field: 'startDate', text: 'Start Date', width: 50 },
      { type: 'date', field: 'endDate', text: 'Due Date', width: 50 },
      { type: 'duration', width: 70 },
      { type: 'effort' },
      { type: 'statuscolumn' },
      { type: 'assignedcolumn' },
      { type: 'taskresponsibility' },
      { type: 'prioritycolumn' },
      { type: 'visibilitycolumn' },
    ],
    viewPreset: {
      base: 'weekAndDay',
      displayDateFormat: 'YYYY-MM-DD',
    },
    barMargin: 10,
    headerMenuFeature: true,
    minHeight: 1200,
    autoHeight: true,

excelExporterFeature: {
  // Choose the date format for date fields
  dateFormat: 'YYYY-MM-DD HH:mm',
},

pdfExportFeature: {
  exportServer: 'http://localhost:3000',
  // Development config
  translateURLsToAbsolute: 'http://localhost:3000',
  clientURL: 'http://localhost:3000',
  // For production replace with this one. See README.md for explanation
  // translateURLsToAbsolute : 'http://localhost:8080/resources/', // Trailing slash is important

  keepPathName: false,
  openInNewTab: true,
  openAfterExport: true,
},
features: {
  filter: true,
},
  }

  return !delayed ? (
    <>
      <BryntumGantt {...ganttConfig} ref={ganttRef} />
    </>
  ) : (
    <Loader />
  )
}

StatusColumn.js

import { Column, ColumnStore } from '@bryntum/gantt'

class StatusColumn extends Column {
  static get $name() {
    return 'StatusColumn'
  }

  static get type() {
    return 'statuscolumn'
  }

  static get isGanttColumn() {
    return true
  }

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'status',
      text: 'Status',
      editor: false,
      cellCls: 'b-status-column-cell',
      htmlEncode: false,
      filterable: {
        filterField: {
          type: 'combo',
          items: [
            'Not Started',
            'Working on it',
            'Stuck',
            'Done',
            'Not Applicable',
          ],
        },
      },
    }
  }

  renderer({ record }) {
    const { originalData, statusStyle } = record
    return originalData.status
      ? [
          // {
          //   tag: 'i',
          //   className: `b-fa b-fa-circle ${statusStyle} `,
          // },
          capitalizeFirstLetter(
            originalData.status.replace('_', ' ').toLowerCase(),
          ),
        ]
      : ''
  }
}

function capitalizeFirstLetter(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

ColumnStore.registerColumnType(StatusColumn)

Task.js

import { TaskModel } from '@bryntum/gantt'
export default class Task extends TaskModel {
  static get fields() {
    return [{ name: 'deadline', type: 'date' }]
  }

  static get $name() {
    return 'StatusColumn'
  }

  get isLate() {
    return this.deadline && Date.now() > this.deadline
  }

  get status() {
    let status = 'Not started'

if (this.isCompleted) {
  status = 'Completed'
} else if (this.endDate < Date.now()) {
  status = 'Late'
} else if (this.isStarted) {
  status = 'Started'
}

return status
  }

  get statusStyle() {
    return `b-status-${this.status.toLowerCase().replace(' ', '')}`
  }
}

AssignedToColumn.js

import { Column, ColumnStore } from '@bryntum/gantt'

class AssignedToColumn extends Column {
  static get $name() {
    return 'AssignedToColumn'
  }

  static get type() {
    return 'assignedcolumn'
  }

  static get isGanttColumn() {
    return true
  }

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'assignee',
      text: 'Assigned To',
      editor: false,
      htmlEncode: false,
      width: 100,
      showAvatars: true,
      itemTpl: (assignment) => assignment.resourceName,
      editor: {
        chipView: {
          itemTpl: (assignment) => assignment.resourceName,
        },
      },
    }
  }

  renderer({ record }) {
    const { originalData, statusStyle } = record
    return originalData.assignee
      ? [`${originalData.assignee.firstName} ${originalData.assignee.lastName}`]
      : ''
  }
}

ColumnStore.registerColumnType(AssignedToColumn)

PriorityColumn.js

import { Column, ColumnStore } from '@bryntum/gantt'

class PriorityColumn extends Column {
  static get $name() {
    return 'PriorityColumn'
  }

  static get type() {
    return 'prioritycolumn'
  }

  static get isGanttColumn() {
    return true
  }

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'priority',
      text: 'Priority',
      flex: 1,
      filterable: {
        filterField: {
          type: 'combo',
          multiSelect: true,
          valueField: 'priority',
          displayField: 'priority',
          items: ['Low', 'Medium', 'High'],
        },
        filterFn: ({ record, value }) =>
          !value.length || value.includes(record),
      },
    }
  }

  renderer({ record }) {
    const { originalData, statusStyle } = record
    return originalData.priority
      ? [capitalizeFirstLetter(originalData.priority.toLowerCase())]
      : ''
  }
}

function capitalizeFirstLetter(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

ColumnStore.registerColumnType(PriorityColumn)

TaskResponsiblityColumn.js

import { Column, ColumnStore } from '@bryntum/gantt'

class TaskResponsibilityColumn extends Column {
  static get $name() {
    return 'TaskResponsibility'
  }

  static get type() {
    return 'taskresponsibility'
  }

  static get isGanttColumn() {
    return true
  }

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'taskresponsibility',
      text: 'Responsibility',
      editor: false,
      htmlEncode: false,
      flex: 1,
      filterable: {
        filterField: {
          type: 'combo',
          multiSelect: true,
          editable: false,
          items: ['Internal', 'Customer', 'Third Party'],
        },
        filterFn: ({ record, value }) =>
          !value.length || value.includes(record.city),
      },
    }
  }

  renderer({ record }) {
    const { originalData, statusStyle } = record
    return originalData.responsibility
      ? [capitalizeFirstLetter(originalData.responsibility.toLowerCase())]
      : ''
  }
}

function capitalizeFirstLetter(string) {
  return string.charAt(0).toUpperCase() + string.slice(1)
}

ColumnStore.registerColumnType(TaskResponsibilityColumn)

ExternalVisiblityColumn.js

import { Column, ColumnStore } from '@bryntum/gantt'

class ExternalVisibilityColumn extends Column {
  static get $name() {
    return 'ExternalVisibilityColumn'
  }

  static get type() {
    return 'visibilitycolumn'
  }

  static get isGanttColumn() {
    return true
  }

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'visibility',
      text: 'Visibility',
      editor: false,
      htmlEncode: false,
      flex: 1,
      filterable: {
        filterField: {
          type: 'combo',
          multiSelect: true,
          editable: false,
          items: ['Visible', 'Name only', 'Hidden'],
        },
    }
  }

  renderer({ record }) {
    const { originalData, statusStyle } = record
    return originalData.visibility
      ? [
          capitalizeFirstLetter(
            originalData.visibility.replace('_', ' ').toLowerCase(),
          ),
        ]
      : ''
  }
}

function capitalizeFirstLetter(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

ColumnStore.registerColumnType(ExternalVisibilityColumn)

GanttToolbar.js

import { Toolbar, Toast, DateHelper, CSSHelper } from '@bryntum/gantt'

export default class GanttToolbar extends Toolbar {
  static get type() {
    return 'gantttoolbar'
  }

  static get $name() {
    return 'GanttToolbar'
  }

  // Called when toolbar is added to the Gantt panel
  set parent(parent) {
    super.parent = parent

const me = this

me.gantt = parent

parent.project.on({
  thisObj: me,
})

me.styleNode = document.createElement('style')
document.head.appendChild(me.styleNode)
  }

  get parent() {
    return super.parent
  }

  static get configurable() {
    return {
      items: [
        {
          type: 'buttonGroup',
          items: [
            {
              ref: 'expandAllButton',
              icon: 'b-fa b-fa-angle-double-down',
              tooltip: 'Expand all',
              onAction: 'up.onExpandAllClick',
            },
            {
              ref: 'collapseAllButton',
              icon: 'b-fa b-fa-angle-double-up',
              tooltip: 'Collapse all',
              onAction: 'up.onCollapseAllClick',
            },
          ],
        },
        {
          type: 'buttonGroup',
          items: [
            {
              ref: 'zoomInButton',
              icon: 'b-fa b-fa-search-plus',
              tooltip: 'Zoom in',
              onAction: 'up.onZoomInClick',
            },
            {
              ref: 'zoomOutButton',
              icon: 'b-fa b-fa-search-minus',
              tooltip: 'Zoom out',
              onAction: 'up.onZoomOutClick',
            },
            {
              ref: 'zoomToFitButton',
              icon: 'b-fa b-fa-compress-arrows-alt',
              tooltip: 'Zoom to fit',
              onAction: 'up.onZoomToFitClick',
            },
            {
              ref: 'previousButton',
              icon: 'b-fa b-fa-angle-left',
              tooltip: 'Previous time span',
              onAction: 'up.onShiftPreviousClick',
            },
            {
              ref: 'nextButton',
              icon: 'b-fa b-fa-angle-right',
              tooltip: 'Next time span',
              onAction: 'up.onShiftNextClick',
            },
          ],
        },
        {
          type: 'buttonGroup',
          items: [
            {
              type: 'button',
              ref: 'featuresButton',
              icon: 'b-fa b-fa-tasks',
              text: 'Features',
              tooltip: 'Toggle features',
              toggleable: true,
              menu: {
                onItem: 'up.onFeaturesClick',
                onBeforeShow: 'up.onFeaturesShow',
                items: [
                  {
                    text: 'Draw dependencies',
                    feature: 'dependencies',
                    checked: false,
                  },
                  {
                    text: 'Task labels',
                    feature: 'labels',
                    checked: true,
                  },
                  {
                    text: 'Project lines',
                    feature: 'projectLines',
                    checked: false,
                  },
                  {
                    text: 'Highlight non-working time',
                    feature: 'nonWorkingTime',
                    checked: false,
                  },
                  {
                    text: 'Enable cell editing',
                    feature: 'cellEdit',
                    checked: false,
                  },
                  {
                    text: 'Show baselines',
                    feature: 'baselines',
                    checked: false,
                  },
                  {
                    text: 'Show rollups',
                    feature: 'rollups',
                    checked: false,
                  },
                  {
                    text: 'Show progress line',
                    feature: 'progressLine',
                    checked: false,
                  },
                  {
                    text: 'Hide schedule',
                    cls: 'b-separator',
                    subGrid: 'normal',
                    checked: false,
                  },
                ],
              },
            },
            {
              type: 'button',
              ref: 'settingsButton',
              icon: 'b-fa b-fa-cogs',
              text: 'Settings',
              tooltip: 'Adjust settings',
              toggleable: true,
              menu: {
                type: 'popup',
                anchor: true,
                cls: 'settings-menu',
                layoutStyle: {
                  flexDirection: 'column',
                },
                onBeforeShow: 'up.onSettingsShow',

            items: [
              {
                type: 'slider',
                ref: 'rowHeight',
                text: 'Row height',
                width: '12em',
                showValue: true,
                min: 30,
                max: 70,
                onInput: 'up.onSettingsRowHeightChange',
              },
              {
                type: 'slider',
                ref: 'barMargin',
                text: 'Bar margin',
                width: '12em',
                showValue: true,
                min: 0,
                max: 10,
                onInput: 'up.onSettingsMarginChange',
              },
              {
                type: 'slider',
                ref: 'duration',
                text: 'Animation duration ',
                width: '12em',
                min: 0,
                max: 2000,
                step: 100,
                showValue: true,
                onInput: 'up.onSettingsDurationChange',
              },
            ],
          },
        },
      ],
    },
  ],
}
  }

  onPdfExportClick() {
    const { gantt } = this

gantt.features.pdfExport.showExportDialog()
  }

  setAnimationDuration(value) {
    const me = this,
      cssText = `.b-animating .b-gantt-task-wrap { transition-duration: ${
        value / 1000
      }s !important; }`

me.gantt.transitionDuration = value

if (me.transitionRule) {
  me.transitionRule.cssText = cssText
} else {
  me.transitionRule = CSSHelper.insertRule(cssText)
}
  }

  async onAddTaskClick() {
    const { gantt } = this,
      added = gantt.taskStore.rootNode.appendChild({
        name: 'New task',
        duration: 1,
      })

// wait for immediate commit to calculate new task fields
await gantt.project.commitAsync()

// scroll to the added task
await gantt.scrollRowIntoView(added)

gantt.features.cellEdit.startEditing({
  record: added,
  field: 'name',
})
  }

  onEditTaskClick() {
    const { gantt } = this

if (gantt.selectedRecord) {
  gantt.editTask(gantt.selectedRecord)
} else {
  Toast.show('First select the task you want to edit')
}
  }

  onExpandAllClick() {
    this.gantt.expandAll()
  }

  onCollapseAllClick() {
    this.gantt.collapseAll()
  }

  onZoomInClick() {
    this.gantt.zoomIn()
  }

  onZoomOutClick() {
    this.gantt.zoomOut()
  }

  onZoomToFitClick() {
    this.gantt.zoomToFit({
      leftMargin: 50,
      rightMargin: 50,
    })
  }

  onShiftPreviousClick() {
    this.gantt.shiftPrevious()
  }

  onShiftNextClick() {
    this.gantt.shiftNext()
  }

  onStartDateChange({ value, oldValue }) {
    if (!oldValue) {
      // ignore initial set
      return
    }

this.gantt.startDate = DateHelper.add(value, -1, 'week')

this.gantt.project.setStartDate(value)
  }

  onFilterChange({ value }) {
    if (value === '') {
      this.gantt.taskStore.clearFilters()
    } else {
      value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

  this.gantt.taskStore.filter({
    filters: (task) => task.name && task.name.match(new RegExp(value, 'i')),
    replace: true,
  })
}
  }

  onFeaturesClick({ source: item }) {
    const { gantt } = this

if (item.feature) {
  const feature = gantt.features[item.feature]
  feature.disabled = !feature.disabled
} else if (item.subGrid) {
  const subGrid = gantt.subGrids[item.subGrid]
  subGrid.collapsed = !subGrid.collapsed
}
  }

  onFeaturesShow({ source: menu }) {
    const { gantt } = this

menu.items.map((item) => {
  const { feature } = item

  if (feature) {
    // a feature might be not presented in the gantt
    // (the code is shared between "advanced" and "php" demos which use a bit different set of features)
    if (gantt.features[feature]) {
      item.checked = !gantt.features[feature].disabled
    }
    // hide not existing features
    else {
      item.hide()
    }
  } else {
    item.checked = gantt.subGrids[item.subGrid].collapsed
  }
  return item
})
  }

  onSettingsShow({ source: menu }) {
    const { gantt } = this,
      { rowHeight, barMargin, duration } = menu.widgetMap

rowHeight.value = gantt.rowHeight
barMargin.value = gantt.barMargin
barMargin.max = gantt.rowHeight / 2 - 5
duration.value = gantt.transitionDuration
  }

  onSettingsRowHeightChange({ value }) {
    this.gantt.rowHeight = value
    this.widgetMap.settingsButton.menu.widgetMap.barMargin.max = value / 2 - 5
  }

  onSettingsMarginChange({ value }) {
    this.gantt.barMargin = value
  }

  onSettingsDurationChange({ value }) {
    this.gantt.transitionDuration = value
    this.styleNode.innerHTML = `.b-animating .b-gantt-task-wrap { transition-duration: ${
      value / 1000
    }s !important; }`
  }

  onCriticalPathsClick({ source }) {
    this.gantt.features.criticalPaths.disabled = !source.pressed
  }
}

// Register this widget type with its Factory
GanttToolbar.initClass()
Attachments
Screen Shot 2023-01-09 at 5.26.37 PM.png
Screen Shot 2023-01-09 at 5.26.37 PM.png (697.94 KiB) Viewed 1507 times

Post by alex.l »

Hi rtbennett,

What is actual and expected result? It's not clear what exactly doesn't work in your code and what do you expect.

All the best,
Alex Lazarev

How to ask for help? Please read our Support Policy

We do not write the code in bounds of forum support. If you need help with development, contact us via bryntum.com/services


Post by rtbennett »

Sorry for not explaining better. The expected result is to be able to filter all the column headers. What is actually happening is I'm only able to filter on some of the columns: Name, Start Date, End Date, Duration, and Effort. I cannot filter on the "custom" column headers of Status, Assigned To, Responsiblity, and Visibility. And this is where I was hoping you would be able to help me to understand better how to implement the custom columns to correctly filter on these headers the same as it is working on the others?

So for example, if I were to take the "Visibility" column header (this is one of the custom columns). For visibility, there are 3 selections (or 3 values) the user can see (and filter) for this column. Those 3 selections are "Visible", "Name only", or "Hidden". You can reference the code in the ExternalVisibilityColumn.js above to see implementation (excerpt shown below). The screenshot example shown is for a status column, but would be a similar case for the selections in the dropdown. I'm able to get the selections to work, but when the user makes a selection, it does not filter properly.

  static get defaults() {
    return {
      // Set your default instance config properties here
      field: 'visibility',
      text: 'Visibility',
      editor: false,
      htmlEncode: false,
      flex: 1,
      filterable: {
        filterField: {
          type: 'combo',
          multiSelect: true,
          editable: false,
          items: ['Visible', 'Name only', 'Hidden'],
        },
    }
  }

When I do try to use the filter on this visibility column (as a user) for example -- I'm able to get these 3 selections on the dropdown. But if the user were to select one, it does not filter out that value, it always filters everything out as blank? I'm trying to understand Bryntum Gantt well enough to understand how the filtering is supposed to work -- or how to get this custom column to filter correctly? I'm using the "filterable" property and the "filterField" as shown.

What might I be doing wrong that I can get this to filter correctly (all the custom column code is given in my first post for reference)? I'm hoping that you can help me get the result of having these custom columns to be able to filter on the column headers like the others are doing. The expected result is when a user makes a selection -- it will filter that selection in the Gantt.

I hope this explains things a little better. Thanks so much for your help. I will look for your response.

Attachments
Screen Shot 2023-01-10 at 7.30.01 AM.png
Screen Shot 2023-01-10 at 7.30.01 AM.png (44.13 KiB) Viewed 1486 times

Post by marcio »

Hello rtbennett,

Do you have by any chance a sample of the data that you're using?? I copied/pasted your code regarding the Visibility column, and worked just fine (as you'll see in the attached video).

If you could set up a sample project with your full configuration and the not filtering behavior for us to check, would be a lot easier to assist you with this.

Attachments
Bryntum Grid - Columns demo - 10 January 2023.mp4
(356.8 KiB) Downloaded 36 times

Best regards,
Márcio

How to ask for help? Please read our Support Policy


Post by rtbennett »

I'm adding some of our sample data we're using (JSON format) -- per your request -- hoping this helps? We're structure the data to match what Bryntum expects (as you can see the "example" of the ganttData below) -- so we can just "plug" it into tasksData to display. I also show a screenshot of the console with how the data is structured for a reference to the data.

The top level are milestones. The "children" are tasks or task groups. Note if there are task groups -- it will be another level of "children" within in the task group (which would include tasks within the task group). I don't show it this way below for simplicity -- but just know there could be another level (nested).

I'm not able to give you a full project to check (our application is too large for that). But we are wondering looking at the video you supplied, that this could be a parent/child issue -- similar to this forum viewtopic.php?p=88817?

Wondering if this might solve our problem: https://bryntum.com/docs/taskboard/#Core/data/Store#function-filterBy? Just not sure? We were hoping you might be able to explain why the parent and child are not filtering correctly? Do we need to implement the filterBy method? And if so, would you have an example that might show how to use this in our case? We will be pursuing if this might be our issue?

I really hope the sample data helps. We fetch it and display from the tasksData array (within ganttConfig).
Notice the children (tasks) have the custom column data that we are looking to filter. So for example, the assignee, priority, status, and visibility fields are what were interested in.

Let me know if you need more info than this. Let me know if you might see what we might be doing wrong -- and help to guide us in the right direction to get this filtering working correctly. Thanks so much for all your help to this point! I feel like we are close to getting it to work -- just need to find out what I'm missing here. Thanks.

{
  "id": "72042aa7-1139-4805-9f0a-2b13d897abd4",
  "name": "Sue Ellen Mischke",
  "expanded": true,
  "startDate": "2022-12-21",
  "endDate": "2023-01-04",
  "percentDone": 0,
  "children": [
    {
      "assignee": null,
      "completed": false,
      "duration": 4,
      "endDate": "2022-12-27",
      "estimatedHours": 10,
      "id": "7a370e5d-1a64-4b12-8f1c-77e090f85fe8",
      "name": "Helm's Deep",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY"
    },
    {
      "assignee": {
        "avatar": {
          "originalUrl": "https://cdn.dev.guidecx.io/1gev3goud2ane83z3znpa2uaxayc"
        },
        "firstName": "Granville",
        "id": "8f0915f3-e86c-41f0-8d2d-ab2c5d1ca3ce",
        "lastName": "Kihn"
      },
      "completed": false,
      "duration": 10,
      "endDate": "2023-01-04",
      "estimatedHours": 10,
      "id": "c2536408-00c5-4058-a1c3-65f1d67b3d33",
      "name": "Black Gate",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY"
    },
    {
      "assignee": null,
      "completed": false,
      "duration": 5,
      "endDate": "2022-12-28",
      "estimatedHours": 10,
      "id": "7b96ab71-3ce3-4a64-8aaa-905b77d8bf49",
      "name": "Losgar",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY"
    }
  ]
},
{
  "id": "07405231-eb52-478d-ae4f-e8f1d1559f0f",
  "name": "Estelle Costanza",
  "expanded": true,
  "startDate": "2022-12-21",
  "endDate": "2022-12-27",
  "percentDone": 0,
  "children": [
    {
      "assignee": null,
      "completed": false,
      "duration": 4,
      "endDate": "2022-12-27",
      "estimatedHours": 10,
      "id": "2b8669db-3021-4b08-a919-64df32ffed54",
      "name": "Gladden Fields",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY"
    },
    {
      "assignee": null,
      "completed": false,
      "duration": 3,
      "endDate": "2022-12-26",
      "estimatedHours": 10,
      "id": "21c79df1-6294-4c4f-b970-1893b85e9c4f",
      "name": "Narchost",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY"
    }
  ]
},
{
  "id": "7cafb05b-8763-4f77-a008-5545bb27a2d2",
  "name": "Jerry Seinfeld",
  "expanded": true,
  "startDate": "2022-12-21",
  "endDate": "2023-01-10",
  "percentDone": 0,
  "children": [
    {
      "assignee": null,
      "completed": false,
      "duration": 4,
      "endDate": "2022-12-27",
      "estimatedHours": 10,
      "id": "c687d09f-d283-481d-a421-15b38cd9555d",
      "name": "Fens of Serech",
      "percentDone": null,
      "priority": "MEDIUM",
      "responsibility": "INTERNAL",
      "startDate": "2022-12-21",
      "status": "NOT_STARTED",
      "visibility": "NAME_ONLY",
      
}, { "assignee": null, "completed": false, "duration": 3, "endDate": "2022-12-26", "estimatedHours": 10, "id": "42ce8e6c-36f2-41b3-8b77-7f29bd5d8e16", "name": "Old Forest Road", "percentDone": null, "priority": "MEDIUM", "responsibility": "INTERNAL", "startDate": "2022-12-21", "status": "NOT_STARTED", "visibility": "NAME_ONLY", }, { "assignee": { "avatar": { "originalUrl": 'https://cdn.dev.guidecx.io/maa9wyi4n3glt1eamxuc0p30vmf4' } }, "firstName": "Ronald", "id": "9e0a7d7a-01a0-4755-90bb-5c27915c0e50", "lastName": "Kautzer", "completed": false, "duration": 7, "endDate": "2023-01-10", "estimatedHours": 10, "id": "be68a88d-8e4b-4819-83aa-fd757b5df6de", "name": "Argonath", "percentDone": null, "priority": "MEDIUM", "responsibility": "INTERNAL", "startDate": "2022-12-30", "status": "NOT_STARTED", "visibility": "NAME_ONLY" ] },
Attachments
Screen Shot 2023-01-10 at 5.05.07 PM.png
Screen Shot 2023-01-10 at 5.05.07 PM.png (473.21 KiB) Viewed 1465 times
Screen Shot 2023-01-10 at 5.44.49 PM.png
Screen Shot 2023-01-10 at 5.44.49 PM.png (385.78 KiB) Viewed 1465 times

Post by marcio »

Hey rtbennett,

Thanks again for the detailed report and data sample. Actually, that's a bug that I created a ticket to fix https://github.com/bryntum/support/issues/5919.

You can follow the ticket for updates and check when it's released in a patch version of Gantt.

Best regards,
Márcio

How to ask for help? Please read our Support Policy


Post by mats »

Your filter combo is a little misconfigured, I updated the ticket with instructions on how to get it working: https://github.com/bryntum/support/issues/5919

Please let us know if that helps!


Post by rtbennett »

Thanks for all your help! This helped a lot in my filtering issue. You can now close this post!
Thanks so much!


Post Reply