Our state of the art Gantt chart


Post by gokulnaths »

Hi Bryntum team,

I’m using STM (StateTrackingManager) in Gantt with autoRecord: true to validate edits against custom authorization logic. My goal is:

When a user edits a task or dependency, I check if they have permission.

If unauthorized, I want to cancel/undo the entire transaction and show an error popup.

Here’s a simplified snippet of my STM config:

stm: {
  autoRecord: true,
  listeners: {
    recordingStop: ({ stm, transaction }) => {
      this.unauthorizedTasks = [];

  if (this.readOnlyTagVisible == false && !this.isCurrentUserAdmin) {
    let invalid = false;

    transaction.queue.forEach((queueItem: any) => {
      // Case 1: Task updates
      if (queueItem.$$name === "EventUpdateAction" && queueItem.model) {
        const editorIds = [
          ...(queueItem.model?.editor || []),
          ...(queueItem.model?.inheritedEditor || [])
        ];
        if (!this.isUserAuthorized(editorIds)) {
          invalid = true;
          this.unauthorizedTasks.push({
            name: queueItem.model?.name,
            wbs: queueItem.model?.wbsValue?._value,
            sequenceNumber: queueItem.model?.sequenceNumber
          });
        }
      }

      // Case 2: Dependency changes
      else if (
        queueItem.store._id === "dependencies" &&
        (queueItem.$$name === "AddAction" || queueItem.$$name === "RemoveAction") &&
        queueItem.modelList
      ) {
        const fromEvent = queueItem.modelList[0]?.fromEvent;
        const toEvent = queueItem.modelList[0]?.toEvent;

        const fromEditorIds = [
          ...(fromEvent?.editor || []),
          ...(fromEvent?.inheritedEditor || [])
        ];
        const toEditorIds = [
          ...(toEvent?.editor || []),
          ...(toEvent?.inheritedEditor || [])
        ];

        if (fromEvent && !this.isUserAuthorized(fromEditorIds)) {
          invalid = true;
          this.unauthorizedTasks.push({
            name: fromEvent.name,
            wbs: fromEvent.wbsValue?._value,
            sequenceNumber: fromEvent.sequenceNumber
          });
        }
        if (toEvent && !this.isUserAuthorized(toEditorIds)) {
          invalid = true;
          this.unauthorizedTasks.push({
            name: toEvent.name,
            wbs: toEvent.wbsValue?._value,
            sequenceNumber: toEvent.sequenceNumber
          });
        }
      }
    });

    if (invalid) {
      stm.undo(); // rollback
      this.isUnauthorizedEditVisible = true; // show popup
      console.warn("Invalid transaction, undoing...");
    }
  }
}
  }
}

Problem I’m facing:

The first time unauthorized changes are made, stm.undo() works correctly.

But on the second attempt, the changes are still applied in the Gantt and stm.undo() does not revert them.

It seems like after the first undo, STM does not always record the next invalid transaction, so there’s nothing to undo.

Question:

Is there a recommended way to cancel/rollback an STM transaction before it’s committed (so changes are never reflected in the Gantt)?

If not, how should I correctly use STM to ensure multiple consecutive unauthorized edits are always undone?

Thanks in advance!


Post by alex.l »

Hi,

Is there a recommended way to cancel/rollback an STM transaction before it’s committed (so changes are never reflected in the Gantt)?

It feels like validate rights using this https://bryntum.com/products/gantt/docs/api/Gantt/model/ProjectModel#event-beforeSync async and preventable event might be easier. Just check it here and if not valid, return false and undo changes.

What do you think, will that work for you?

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 Reply