# Upgrade guide for Gantt v4.0.0

Be sure to also check out the news in [Grid](#Grid/guides/upgrades/4.0.0.md),
[Scheduler](#Scheduler/guides/upgrades/4.0.0.md) and [Scheduler Pro](#SchedulerPro/guides/upgrades/4.0.0.md).

## Version in line with other Bryntum products

The version of Gantt was bumped from 2.0 -> 4.0 to bring it in line with Grid, Scheduler, Scheduler Pro and Calendar.
This will make it easier to determine which versions are compatible with each other.

## Calendar changes

`hoursPerDay`, `daysPerWeek` and `daysPerMonth` fields has been moved from `CalendarModel` to the `ProjectModel` class.
Loading the fields from the project calendar is still supported for backward compatibility. That support will be kept
for few next releases and will be dropped for good after. Please take care of changing your application code
accordingly.

- Old CrudManager load response:

```json
{
  "success": true,
  "project": {
    "calendar": 123,
    "..." : "..."
  },
  "calendars": {
    "rows": [
      {
        "id": 123,
        "hoursPerDay": 24,
        "daysPerWeek": 5,
        "daysPerMonth": 20
      },
      {
        "..." : "..."
      }
    ]
  }
}
```

- New CrudManager load response

```json
{
  "success": true,
  "project": {
    "calendar": 123,
    "hoursPerDay": 24,
    "daysPerWeek": 5,
    "daysPerMonth": 20,
    "...": "..."
  },
  "calendars": {
    "rows": [
      {
        "id": 123,
        "...": "..."
      }
    ]
  }
}
```

And in case you need to retrieve corresponding values...

**Old code:** dealing with the fields:

```javascript
console.log(`1 day === ${project.calendar.hoursPerDay} hours`);
console.log(`1 week === ${project.calendar.daysPerWeek} days`);
console.log(`1 month === ${project.calendar.daysPerMonth} days`);
```

**New code:**

```javascript
console.log(`1 day === ${project.hoursPerDay} hours`);
console.log(`1 week === ${project.daysPerWeek} days`);
console.log(`1 month === ${project.daysPerMonth} days`);
```

## Task calendar field change

Since 4.0.0 release task `calendar` field always returns the task own calendar or `null` in case it's not provided. To
get the effective calendar used by the task please use `effectiveCalendar` field. It falls back to the project calendar
the same way `calendar` field used to work.

-**Old code:**

```javascript
console.log(`The task uses ${task.calendar.name} for scheduling`)
```

-**New code:**

```javascript
console.log(`The task uses ${task.effectiveCalendar.name} for scheduling`)
```

## Dropped support for Edge 18 and older

We are not actively removing the fixes we have in place yet, but moving forward we will no longer add new fixes for
versions of Edge <= 18. If you are using an old version of Edge, we strongly encourage you to update to a new blink
based version.

Existing fixes are planned to be removed in version 5.0.

### New gantt.lite.umd.js bundle to use with Angular

Bryntum Gantt is delivered with a new UMD package without polyfills. This was done to avoid conflicts with any external
Promise polyfills, such as `ZoneAwarePromise` from `zone.js` for Angular applications. It fixes this runtime error:

```shell
Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten.
Most likely cause is that a Promise polyfill has been loaded after Zone.js 
(Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)
```

We recommend that all your Angular applications should be upgraded to use the new `gantt.lite.umd.js` bundle. Also,
there should be no polyfills imported in `app/src/polyfills.ts` after `import 'zone.js/dist/zone';`. We have updated all
our Angular examples to use this new bundle. Make sure to update all usages of `gantt.umd.js` to `gantt.lite.umd.js`
within your application to avoid `Bundle included twice` runtime error.

**Old code:**

```javascript
import { Button, Fullscreen, WidgetHelper } from 'bryntum-gantt/gantt.umd.js';
```

**New code:**

```javascript
import { Button, Fullscreen, WidgetHelper } from 'bryntum-gantt/gantt.lite.umd.js';
```

## WidgetHelper and BryntumWidgetAdapter

Registration of Widget classes for subsequent resolution through the `type` property of config objects has been
simplified. The "Adapter" concept has been removed. Widget classes now register themselves with the `Widget` base class
which is where they can also be looked up. When creating a custom widget, implement the `static get type` property to
return the type name. And at the end simply call `MyWidgetClass.initClass()` to have the new Widget class register
itself.

**Old code:**

```javascript
class MyWidget extends Widget {

}

BryntumWidgetAdapterRegister.register('mywidget', MyWidget);
```

**New code:**

```javascript
class MyWidget extends Widget {
    static get type() {
        return 'mywidget';
    }
}

MyWidget.initClass();
```

Fewer widgets are auto imported with the removal of the Adapter which imported a base set of Widgets. This means that
when not using a bundle, application code must import the widgets it uses. It also means that custom builds may be
smaller by including only what is used.

If your code previously had:

```javascript
import 'lib/Core/adapter/widget/BryntumWidgetAdapter.js';
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';

WidgetHelper.append([
    {
        type : 'button',
        text : 'Click'
    }
], /*...*/);
```

It should now instead not import the adapter, and instead directly import the button:

```javascript
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';
import 'lib/Core/widget/Button.js';

WidgetHelper.append([
    {
        type : 'button',
        text : 'Click'
    }
], /*...*/);
```

## Model Field Inheritance

Fields defined in a derived class Model that coincide by name with a field declared in a super class will now only
override those field config properties specified by the derived class. This allows derived classes to adjust a field
definition in one way, say to change the default value and still inherit other field properties, such as a convert
function.

For example:

```javascript
    class ModelOne extends Model {
    static get fields() {
        return [
            { name : 'barcode', convert : v => String(v) }
        ];
    }
}

class ModelTwo extends ModelOne {
    static get fields() {
        return [
            { name : 'barcode', defaultValue : 'ABC123' }
        ];
    }
}
```

In previous releases, `ModelTwo` would have had to redefine the `convert` config for the `barcode` field.

## Scheduling Engine changes

The Gantt Scheduling Engine has been seriously refactored which allowed to reduce memory usage and improve performance
when dealing with big datasets. The new Engine also provides more robust protection from cycles of the graph entries.

There are few noticeable API changes in that version:

1. `project.propagate` method has been renamed to `project.commitAsync` (there is also a synchronous version of it
   `project.commit`). Old name is still supported till the next major release so please change your code accordingly.
2. The Engine now commits changes automatically and asynchronously, so calling `project.commitAsync` is not really
   needed unless you need to get up-to-date consistent results:

```javascript
// move predecessor task
predecessor.startDate = new Date(2020, 8, 1)

// let's trigger propagation and wait till it's done
await project.commitAsync()

// now we know how that change affected the task successor
console.log("Successor moved to: " + successor.startDate)
```

## Changed event triggering timing

The stores that are part of the project (EventStore, ResourceStore, AssignmentStore and DependencyStore) has had the
timing of their event triggering for certain events modified. The change was made to assure async date calculations are
finished when the event is triggered. This affects the following events:

* `add`
* `remove`
* `removeAll`
* `change`
* `refresh`

This change should lead to better backward compatibility with the old Scheduler. Consider the following scenario:

```javascript
const scheduler = new Scheduler({
    events : [/*...*/],

    listeners : {
        add({ records }) {
            console.assert(records[0].endDate)
        }
    }
});

scheduler.eventStore.add({ startDate : '2020-09-09', duration : 1 });
```

Without the change, the `add` event would be triggered immediately on the call to `add()`. Since date calculations are
async, the `endDate` would not yet be available.

With the change, the event is triggered after calculations has finished, making `endDate` available in the listener.

It is still possible to catch the events at the earlier stage, in case you do not care about waiting for data to be in a
calculated state. To achieve that, listen for `addBeforeCommit`, `removeBeforeCommit` and so on instead.

## Renamed CSS themes

The `Default`, `Light` and `Dark` themes were renamed to `Classic`, `Classic-Light` and `Classic-Dark`. This change
highlights the fact that they are variations of the same theme, and that it is not the default theme (Stockholm is our
default theme since version 2.0).

If you are using one of these themes, you will have to adjust your css import to match the new name.

**Old code:**

```html
<link rel="stylesheet" href="build/grid.dark.css" id="bryntum-theme">
```

**New code:**

```html
<link rel="stylesheet" href="build/grid.classic-dark.css" id="bryntum-theme">
```

If you have theme specific selectors in your code/CSS you have to adjust those also:

**Old code:**

```css
.b-theme-dark {
. . .
}
```

**New code:**

```css
.b-theme-classic-dark {
. . .
}
```

## TaskEditor configs changes

`tabsConfig` and `extraItems` configs are deprecated and will be removed in version 5.0. TaskEditor tabs and widgets in
the tabs are configured in a single `items` config. Please check out our new Customization / TaskEdit guide for details.

**Old code:**

```javascript
const gantt = new Gantt({
    features : {
        taskEdit : {
            editorConfig : {
                extraItems : {
                    generaltab : [
                        { type : 'button', text : 'New Button' }
                    ]
                }
            },
            tabsConfig   : {
                generaltab : { title : 'Common' },
                notestab   : false,
                filestab   : { type : 'custom_filestab' }
            }
        }
    }
});
```

**New code:**

```javascript
const gantt = new Gantt({
    features : {
        taskEdit : {
            items : {
                generalTab : {
                    title : 'Common',
                    items : {
                        newButton : { type : 'button', text : 'New Button' }
                    }
                },
                notesTab   : false,
                filesTab   : { type : 'custom_filestab' }
            }
        }
    }
});
```

## Context menu

### Menu features renamed

All menu features have had the word "Context" removed from their names, to follow the same naming scheme in all
products.
`TaskContextMenu` is now called `TaskMenu` and so on.

### Task menu for cells

Task context menu is shown on cell click since cells are parts of a task in Gantt. Cell menu items are handled by the
TaskMenu feature. The CellMenu feature is no longer supported when the TaskMenu feature is enabled:

**Old code:**

```javascript
const gantt = new Gantt({
    features : {
        contextMenu : {
            cellItems : [
                { text : 'My cell item' }
            ]
        },

        taskContextMenu : {
            items : {
                myTaskItem : { text : 'My task item' }
            }
        }
    }
});
```

**New code:**

```javascript
const gantt = new Gantt({
    features : {
        taskMenu : {
            items : {
                myTaskItem : { text : 'My task item' },
                myCellItem : { text : 'My cell item' }
            },

            processItems({ items, column }) {
                if (!column || column.type === 'timeAxis') {
                    items.myCellItem = false;
                }
            }
        }
    }
});
```

But since task element and cells refer to the same TaskRecord, it makes sense to have similar items in both cases. If
you need a column specific item you can still use `cellMenuItems` column config:

```javascript
const gantt = new Gantt({
    columns : [
        {
            type          : 'name',
            field         : 'name',
            cellMenuItems : {
                columnSpecificItem : { text : 'Column specific cell item' }
            }
        }
    ],

    features : {
        taskMenu : {
            items : {
                myTaskItem : { text : 'My task item' }
            }
        }
    }
});
```

CellMenu feature can be used if TaskMenu feature is disabled:

```javascript
const gantt = new Gantt({
    features : {
        taskMenu : false,
        cellMenu : {
            items : {
                myCellItem : { text : 'My cell item' }
            }
        }
    },
});
```

### Context menu events

Some of the events triggered by TaskContextMenu was renamed to match the new name of the feature:

- `taskContextMenuBeforeShow` -> `taskMenuBeforeShow`;
- `taskContextMenuShow` -> `taskMenuShow`;
- `taskContextMenuItem` -> `taskMenuItem`;

For example:

**Old code:**

```javascript
const scheduler = new Scheduler({
    listeners : {
        taskContextMenuBeforeShow : () => {/*...*/},
        taskContextMenuShow : () => {/*...*/},
        taskContextMenuItem : () => {/*...*/}
    }
});
```

**New code:**

```javascript
const scheduler = new Scheduler({
    listeners : {
        taskMenuBeforeShow : () => {/*...*/},
        taskMenuShow : () => {/*...*/},
        taskMenuItem : () => {/*...*/}
    }
});
```


<p class="last-modified">Last modified on 2023-10-26 8:19:02</p>