Versions

Captures versions (snapshots) of the active project, including a detailed log of the changes new in each version.

When active, the feature monitors the project for changes and appends them to the changelog. When a version is captured, the version will consist of a complete snapshot of the project data at the time of the capture, in addition to the list of changes in the changelog that have occurred since the last version was captured.

For information about the data structure representing a version and how to persist it, see VersionModel.

For information about the data structures representing the changelog and how to persist them, see ChangeLogTransactionModel.

const scheduler = new SchedulerPro({
    features : {
        versions : true
    }
});

To display versions and their changes, use a VersionGrid configured with a ProjectModel.

Versions
//<code-header>
fiddle.title = 'Versions';
//</code-header>
const scheduler = new SchedulerPro({
    enableUndoRedoKeys : true,
    flex               : 2,

    project : {

        resources : [
            { id : 1, name : 'Resource 1' },
            { id : 2, name : 'Resource 2' },
            { id : 3, name : 'Resource 3' }
        ],

        autoHeight : true,

        events : [
            {
                id         : 11,
                name       : 'Design website',
                startDate  : new Date(2022, 10, 7),
                duration   : 5,
                resourceId : 1
            },
            {
                id         : 12,
                name       : 'Lease office space',
                startDate  : new Date(2022, 10, 9),
                duration   : 4,
                resourceId : 1
            },
            {
                id         : 13,
                name       : 'Buy coffee machine',
                startDate  : new Date(2022, 10, 13),
                duration   : 3,
                resourceId : 3
            },
            {
                id         : 14,
                name       : 'Hire designer',
                startDate  : new Date(2022, 10, 17),
                duration   : 3,
                resourceId : 2
            },
            {
                id         : 15,
                name       : 'Write design handbook',
                startDate  : new Date(2022, 10, 27),
                duration   : 3,
                resourceId : 2
            }
        ],

        // dependencies : [
        //     {
        //         id       : 1,
        //         fromTask : 11,
        //         toTask   : 12
        //     },
        //     {
        //         id       : 2,
        //         fromTask : 13,
        //         toTask   : 14
        //     },
        //     {
        //         id       : 3,
        //         fromTask : 14,
        //         toTask   : 15
        //     }
        // ],
        stm : {
            autoRecord : true
        }
    },

    columns : [
        { field : 'name', text : 'Name', width : 250 },
        { field : 'startDate', text : 'Start date' },
        { field : 'duration', text : 'Duration' }
    ],

    subGridConfigs : {
        locked : {
            width : 300
        }
    },

    features : {
        versions       : true,
        dependencies   : true,
        dependencyEdit : true
    },

    listeners : {
        /**
         * Demonstrates overriding the default transaction description to provide more detail
         * about which user action initiated the transaction. In this case, we set a custom
         * description for transactions involving a task drag event.
         */
        taskDrop({ taskRecords }) {
            this.features.versions.transactionDescription = taskRecords.length === 1
                ? `Dragged task ${taskRecords[0].name}` : `Dragged ${taskRecords.length} tasks`;
        },

        taskResizeEnd({ taskRecord }) {
            this.features.versions.transactionDescription = `Resized task ${taskRecord.name}`;
        },

        afterDependencyCreateDrop() {
            this.features.versions.transactionDescription = `Drew a link`;
        }
    }
});

const app = new Container({
    appendTo : targetElement,

    layout : 'box',
    height : 600,

    items : {
        scheduler,
        splitter    : { type : 'splitter' },
        versionGrid : {
            type                       : 'versiongrid',
            flex                       : 1,
            emptyText                  : 'No versions to display',
            project                    : scheduler.project,
            showUnattachedTransactions : true,
            selectionMode              : {
                row  : true,
                cell : false
            },
            features : {
                cellMenu : {
                    /**
                     * Add a button to the version row context menu.
                     */
                    items : {
                        compareButton   : undefined,
                        duplicateButton : {
                            text   : 'Duplicate',
                            icon   : 'fa fa-copy',
                            onItem : async({ record, source : grid }) => {
                                const result = await MessageDialog.confirm({
                                    title   : 'Duplicate Version?',
                                    message : `This will create a new project from the content of the selected version.
                                        Do you want to continue?`
                                });
                                if (result === MessageDialog.yesButton) {
                                    // Sample code demonstrating cloning a saved version
                                    await scheduler.features.versions.getVersionContent(record.versionModel);
                                    const clonedProject = new ProjectModel(record.versionModel.content);
                                    scheduler.project = clonedProject;
                                }
                            }
                        }
                    }
                }
            },
            dateFormat : 'M/D/YY h:mm a',
            tbar       : {
                items : {
                    saveButton : {
                        text      : 'Save Version',
                        icon      : 'fa fa-plus',
                        listeners : {
                            click : () => {
                                scheduler.features.versions.saveVersion();
                            }
                        }
                    },
                    spacer : {
                        text : '->'
                    },
                    onlyNamedToggle : {
                        type      : 'slidetoggle',
                        text      : 'Show named versions only',
                        listeners : {
                            change : ({ checked }) => {
                                app.widgetMap.versionGrid.showNamedVersionsOnly = checked;
                            }
                        }
                    },
                    showVersionsToggle : {
                        type      : 'slidetoggle',
                        text      : 'Changes only',
                        checked   : false,
                        listeners : {
                            change : ({ checked }) => {
                                app.widgetMap.versionGrid.showVersions = !checked;
                            }
                        }
                    }
                }
            },

            listeners : {
                // Handle the user asking to restore a given version
                restore : async({ version }) => {
                    const result = await MessageDialog.confirm({
                        title   : 'Restore Version?',
                        message : `Are you sure you want to restore the selected version, replacing the
                            current project? You will lose any unsaved changes.`
                    });
                    if (result === MessageDialog.yesButton) {
                        await gantt.features.versions.restoreVersion(version);
                        gantt.features.baselines.disabled = true;
                        // FIXME known issue with Undo after restoring version
                        project.stm.resetQueue();
                    }
                }
            }
        }
    }
});

scheduler.project.stm.enable();

See also:

  • VersionModel A stored version of a ProjectModel, captured at a point in time, with change log
  • ChangeLogTransactionModel The set of add/remove/update actions that occurred in response to a user action
  • VersionGrid Widget for displaying a project's versions and changes

This feature is disabled by default. For info on enabling it, see GridFeatures.

Configs

13

Common

disabledInstancePlugin
listenersEvents

Other

autoSaveInterval: hourly | Number= hourly

The interval between autosaves, in minutes. To disable autosave, set the interval to zero. To save on the hour, use 'hourly'.

knownBaseTypes: Array= [AssignmentModel, DependencyModel, ResourceModel, CalendarModel]

The set of Model types whose subtypes should be recorded as the base type in the change log. For example, by default if a subclassed TaskModelEx exists and an instance of one is updated, it will be recorded in the changelog as a TaskModel.

Optional subclass of ChangeLogTransactionModel to use instead of ChangeLogTransactionModel. Use this to extend ChangeLogTransactionModel to add any additional fields your application needs.

Optional subclass of VersionModel to use instead of VersionModel. Use this to extend VersionModel to add any additional fields your application needs.

Misc

clientInstancePlugin
localeClassLocalizable
localizableLocalizable

Properties

18

Common

hasChanges: Boolean

Whether a pending transaction is open with changes not yet added to the changelog.

isComparing: Boolean

Whether a saved version is currently being compared.

Sets the description of the current transaction. This will override the default transaction description.

disabledInstancePlugin

Class hierarchy

isVersions: Boolean= truereadonly
Identifies an object as an instance of Versions class, or subclass thereof.
isVersions: Boolean= truereadonlystatic
Identifies an object as an instance of Versions class, or subclass thereof.
isEventsEvents
isInstancePluginInstancePlugin
isLocalizableLocalizable

Lifecycle

configBase

Misc

clientInstancePlugin
localeHelperLocalizable
localeManagerLocalizable

Other

Functions

35

Other

When autosave is 'hourly', we check the time every 30 seconds and autosave on the hour.

Loads the given version as a set of baselines into the current project.

ParameterTypeDescription
versionVersionModel

The version to compare against the current working copy

Called on-demand by the feature in order to populate the content field of a VersionModel when the content is required for an operation.

Version content is allowed to be null in order to permit large numbers of version records on the front end, only loading the actual snapshot data (content) as required.

ParameterTypeDescription
versionVersionModel

The version whose content is requested

Returns: Object -

The serializable project data constituting the version.

Retrieve a single version's content from the backend.

ParameterTypeDescription
versionVersionModel

Load content into the content field of a VersionModel

Restores the given version, replacing any ProjectModel currently present in the scheduler.

ParameterTypeDescription
versionVersionModel

The version to compare against the current working copy

Save a new version containing any unsaved audit log entries, with the given name (optional).

ParameterTypeDescription
versionNameString

The name for the version

Stops comparing a currently compared version.

LstaticLocalizable
onEvents
relayAllEvents
triggerEvents
unEvents

Configuration

applyDefaultsstaticBase

Events

Lifecycle

destroystaticBase

Misc

doDisableInstancePlugin
initClassstaticBase
isOfTypeNamestaticBase
mixinstaticBase
optionalLstaticLocalizable

Events

7

Fires before the Versions feature attempts to load the content for a specific version. To handle populating the content yourself instead, listen for this event, set the content field of the context object passed to the event listener, and return false from your event listener.

If you do not handle this event, the Versions feature will fall back to its default behavior, which is to send a websockets command named loadVersionContent (if the project uses websockets). See .

If your project does not use websockets, you will need to handle this event in order to allow lazy-loading version content.

// Adding a listener using the "on" method
versions.on('beforeLoadVersionContent', ({ context, context.version, context.content }) => {

});
ParameterTypeDescription
contextObject

The event context

context.versionBoolean

The VersionModel for which content is requested

context.contentObject

Context field to receive the version content. Populate this field and return false in order to implement content loading. Object structure should match toJSON.

Note that this event fires on the owning SchedulerPro.

Fires when the list of observed transactions changes.

// Adding a listener using the "on" method
versions.on('transactionChange', ({ hasChanges }) => {

});
ParameterTypeDescription
hasChangesBoolean

Whether any changes are recorded that are not yet attached to a version.

catchAllEvents
destroyEvents
disableInstancePlugin
enableInstancePlugin

Event handlers

7

Called before the Versions feature attempts to load the content for a specific version. To handle populating the content yourself instead, listen for this event, set the content field of the context object passed to the event listener, and return false from your event listener.

If you do not handle this event, the Versions feature will fall back to its default behavior, which is to send a websockets command named loadVersionContent (if the project uses websockets). See .

If your project does not use websockets, you will need to handle this event in order to allow lazy-loading version content.

new Versions({
    onBeforeLoadVersionContent({ context }) {

    }
});
ParameterTypeDescription
contextObject

The event context

context.versionBoolean

The VersionModel for which content is requested

context.contentObject

Context field to receive the version content. Populate this field and return false in order to implement content loading. Object structure should match toJSON.

Note that this event called on the owning SchedulerPro.

Called when the list of observed transactions changes.

new Versions({
    onTransactionChange({ hasChanges }) {

    }
});
ParameterTypeDescription
hasChangesBoolean

Whether any changes are recorded that are not yet attached to a version.

onDestroyEvents
onDisableInstancePlugin
onEnableInstancePlugin

Typedefs

1