Skip to content

Troubleshooting

Source code
TypeScript ts
// src/components/gantt/GanttBasic.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();

import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, tasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();
const columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));

export function load(parentSelector: string) {
  const parent = document.querySelector(parentSelector);
  if (!parent) {
    return () => {};
  }

  const root = document.createElement('section');
  const grid = document.createElement('revo-grid');

  root.className = 'gantt-basic-demo';
  grid.className = 'gantt-basic-grid';
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.hideAttribution = true;
  grid.canMoveColumns = true;
  grid.plugins = [GanttPlugin];
  grid.gantt = ganttConfig;
  grid.ganttCalendars = calendars;
  grid.ganttDependencies = dependencies;
  grid.columns = columns;

  root.appendChild(grid);
  parent.appendChild(root);

  grid.source = tasks.map((task) => ({ ...task }));

  return () => root.remove();
}
Data ts
import type {
  CalendarEntity,
  DependencyEntity,
  GanttToolbarColumnOption,
  GanttTaskSourceRow,
  TaskTableColumnProp,
} from '@revolist/revogrid-enterprise';

export const PROJECT_ID = 'project-web-redesign';
export const CALENDAR_ID = 'cal-standard';

export const ganttConfig = {
  id: PROJECT_ID,
  name: 'Website Redesign',
  version: '1',
  currency: 'USD',
  timeZone: 'UTC',
  primaryCalendarId: CALENDAR_ID,
  updatedAt: '2026-04-06T00:00:00Z',
  zoomPreset: 'week' as const,
  allowTaskCreate: true,
};

export const taskTableColumnProps: TaskTableColumnProp[] = [
  'wbs',
  'name',
  'status',
];

const initiallyVisibleColumnProps = new Set<TaskTableColumnProp>(taskTableColumnProps);

const allToolbarColumns = [
  { prop: 'status', label: 'Status' },
  { prop: 'name', label: 'Task' },
  { prop: 'wbs', label: 'WBS' },
] satisfies Array<Omit<GanttToolbarColumnOption, 'visible'>>;

export const toolbarColumns: GanttToolbarColumnOption[] = [...allToolbarColumns]
  .sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: 'base' }))
  .map((column) => ({
    ...column,
    visible: initiallyVisibleColumnProps.has(column.prop as TaskTableColumnProp),
  }));

export const calendars: CalendarEntity[] = [
  {
    id: CALENDAR_ID,
    name: 'Standard',
    timeZone: 'UTC',
    workingDays: [1, 2, 3, 4, 5],
    holidays: [],
    hoursPerDay: 8,
  },
];

export const tasks: GanttTaskSourceRow[] = [
  {
    id: 't1', parentId: null,
    name: 'Discovery', type: 'summary',
    status: 'done',
    startDate: '2026-04-06', endDate: '2026-04-17', duration: 10,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't2', parentId: 't1',
    name: 'Stakeholder Interviews', type: 'task',
    status: 'done',
    startDate: '2026-04-06', endDate: '2026-04-08', duration: 3,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't3', parentId: 't1',
    name: 'Analytics Review', type: 'task',
    status: 'done',
    startDate: '2026-04-07', endDate: '2026-04-10', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't4', parentId: 't1',
    name: 'Content Inventory', type: 'task',
    status: 'done',
    startDate: '2026-04-09', endDate: '2026-04-14', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't5', parentId: 't1',
    name: 'Requirements Workshop', type: 'task',
    status: 'done',
    startDate: '2026-04-13', endDate: '2026-04-16', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't6', parentId: 't1',
    name: 'Discovery Sign-off', type: 'milestone',
    status: 'done',
    startDate: '2026-04-17', endDate: '2026-04-17', duration: 0,
    percentDone: 100, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't7', parentId: null,
    name: 'Design', type: 'summary',
    status: 'in-progress',
    startDate: '2026-04-20', endDate: '2026-05-08', duration: 15,
    percentDone: 55, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't8', parentId: 't7',
    name: 'Information Architecture', type: 'task',
    status: 'done',
    startDate: '2026-04-20', endDate: '2026-04-23', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't9', parentId: 't7',
    name: 'Wireframes', type: 'task',
    status: 'done',
    startDate: '2026-04-24', endDate: '2026-04-29', duration: 4,
    percentDone: 100, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't10', parentId: 't7',
    name: 'Design System Updates', type: 'task',
    status: 'in-progress',
    startDate: '2026-04-27', endDate: '2026-05-01', duration: 5,
    percentDone: 70, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't11', parentId: 't7',
    name: 'Visual Design', type: 'task',
    status: 'in-progress',
    startDate: '2026-04-30', endDate: '2026-05-07', duration: 6,
    percentDone: 45, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't12', parentId: 't7',
    name: 'Prototype Review', type: 'task',
    status: 'not-started',
    startDate: '2026-05-05', endDate: '2026-05-07', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't13', parentId: 't7',
    name: 'Design Approval', type: 'milestone',
    status: 'not-started',
    startDate: '2026-05-08', endDate: '2026-05-08', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't14', parentId: null,
    name: 'Development', type: 'summary',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-06-05', duration: 20,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't15', parentId: 't14',
    name: 'Frontend Shell', type: 'task',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-15', duration: 5,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't16', parentId: 't14',
    name: 'CMS Integration', type: 'task',
    status: 'not-started',
    startDate: '2026-05-11', endDate: '2026-05-20', duration: 8,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't17', parentId: 't14',
    name: 'Reusable Page Sections', type: 'task',
    status: 'not-started',
    startDate: '2026-05-18', endDate: '2026-05-27', duration: 8,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't18', parentId: 't14',
    name: 'Search Experience', type: 'task',
    status: 'not-started',
    startDate: '2026-05-19', endDate: '2026-05-26', duration: 6,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't19', parentId: 't14',
    name: 'Analytics Events', type: 'task',
    status: 'not-started',
    startDate: '2026-05-25', endDate: '2026-05-29', duration: 5,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't20', parentId: 't14',
    name: 'Accessibility Pass', type: 'task',
    status: 'not-started',
    startDate: '2026-05-28', endDate: '2026-06-02', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't21', parentId: 't14',
    name: 'Performance Tuning', type: 'task',
    status: 'not-started',
    startDate: '2026-06-01', endDate: '2026-06-04', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't22', parentId: 't14',
    name: 'Feature Complete', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-05', endDate: '2026-06-05', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't23', parentId: null,
    name: 'QA and Release Prep', type: 'summary',
    status: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-18', duration: 9,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't24', parentId: 't23',
    name: 'Test Plan', type: 'task',
    status: 'not-started',
    startDate: '2026-06-08', endDate: '2026-06-10', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't25', parentId: 't23',
    name: 'Cross-browser QA', type: 'task',
    status: 'not-started',
    startDate: '2026-06-10', endDate: '2026-06-15', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't26', parentId: 't23',
    name: 'Content QA', type: 'task',
    status: 'not-started',
    startDate: '2026-06-11', endDate: '2026-06-16', duration: 4,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't27', parentId: 't23',
    name: 'Release Candidate', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-18', endDate: '2026-06-18', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
  {
    id: 't28', parentId: null,
    name: 'Launch', type: 'task',
    status: 'not-started',
    startDate: '2026-06-19', endDate: '2026-06-23', duration: 3,
    percentDone: 0, calendarId: CALENDAR_ID, tags: [],
  },
  {
    id: 't29', parentId: null,
    name: 'Post-launch Review', type: 'milestone',
    status: 'not-started',
    startDate: '2026-06-26', endDate: '2026-06-26', duration: 0,
    percentDone: 0, calendarId: CALENDAR_ID, tags: ['milestone'],
  },
];

export const dependencies: DependencyEntity[] = [
  { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't5', type: 'finish-to-start', lagDays: 0 },
  { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd4', predecessorTaskId: 't5', successorTaskId: 't6', type: 'finish-to-start', lagDays: 0 },
  { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 1 },
  { id: 'd6', predecessorTaskId: 't8', successorTaskId: 't9', type: 'finish-to-start', lagDays: 0 },
  { id: 'd7', predecessorTaskId: 't9', successorTaskId: 't11', type: 'finish-to-start', lagDays: 0 },
  { id: 'd8', predecessorTaskId: 't10', successorTaskId: 't12', type: 'finish-to-start', lagDays: 0 },
  { id: 'd9', predecessorTaskId: 't11', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd10', predecessorTaskId: 't12', successorTaskId: 't13', type: 'finish-to-start', lagDays: 0 },
  { id: 'd11', predecessorTaskId: 't13', successorTaskId: 't15', type: 'finish-to-start', lagDays: 1 },
  { id: 'd12', predecessorTaskId: 't15', successorTaskId: 't17', type: 'finish-to-start', lagDays: 0 },
  { id: 'd13', predecessorTaskId: 't16', successorTaskId: 't18', type: 'finish-to-start', lagDays: 0 },
  { id: 'd14', predecessorTaskId: 't17', successorTaskId: 't20', type: 'finish-to-start', lagDays: 0 },
  { id: 'd15', predecessorTaskId: 't18', successorTaskId: 't19', type: 'finish-to-start', lagDays: 0 },
  { id: 'd16', predecessorTaskId: 't19', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd17', predecessorTaskId: 't20', successorTaskId: 't21', type: 'finish-to-start', lagDays: 0 },
  { id: 'd18', predecessorTaskId: 't21', successorTaskId: 't22', type: 'finish-to-start', lagDays: 0 },
  { id: 'd19', predecessorTaskId: 't22', successorTaskId: 't24', type: 'finish-to-start', lagDays: 1 },
  { id: 'd20', predecessorTaskId: 't24', successorTaskId: 't25', type: 'finish-to-start', lagDays: 0 },
  { id: 'd21', predecessorTaskId: 't24', successorTaskId: 't26', type: 'finish-to-start', lagDays: 0 },
  { id: 'd22', predecessorTaskId: 't25', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd23', predecessorTaskId: 't26', successorTaskId: 't27', type: 'finish-to-start', lagDays: 0 },
  { id: 'd24', predecessorTaskId: 't27', successorTaskId: 't28', type: 'finish-to-start', lagDays: 0 },
  { id: 'd25', predecessorTaskId: 't28', successorTaskId: 't29', type: 'finish-to-start', lagDays: 2 },
];
Vue vue
<template>
  <section class="gantt-basic-demo">
    <RevoGrid
      class="gantt-basic-grid"
      hide-attribution
      :can-move-columns="true"
      :theme="isDark ? 'darkCompact' : 'compact'"
      :plugins="plugins"
      :source="tasks"
      :columns="columns"
      :gantt.prop="ganttConfig"
      :gantt-dependencies.prop="dependencies"
      :gantt-calendars.prop="calendars"
    />
  </section>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentThemeVue } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, tasks as basicTasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentThemeVue();

const plugins = ref([GanttPlugin]);
const ganttConfig = ref(basicGanttConfig);
const calendars = ref(basicCalendars);
const tasks = ref(basicTasks.map((task) => ({ ...task })));
const dependencies = ref(basicDependencies);

const columns = ref(taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)));
</script>
React tsx
// src/components/gantt/GanttBasic.tsx
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars, dependencies, ganttConfig, tasks, taskTableColumnProps } from './gantt-basic-data';
import './gantt-basic.css';

const { isDark } = currentTheme();

function GanttBasic() {
  const project = useMemo(() => ganttConfig, []);
  const source = useMemo(() => tasks.map((task) => ({ ...task })), []);

  const columns = useMemo(() => taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop)), []);

  return (
    <section className="gantt-basic-demo">
      <RevoGrid
        className="gantt-basic-grid"
        theme={isDark() ? 'darkCompact' : 'compact'}
        hideAttribution
        canMoveColumns
        plugins={[GanttPlugin]}
        source={source}
        columns={columns}
        gantt={project}
        ganttDependencies={dependencies}
        ganttCalendars={calendars}
      />
    </section>
  );
}

export default GanttBasic;
Angular ts
// src/components/gantt/GanttBasicAngular.ts
import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import { calendars as basicCalendars, dependencies as basicDependencies, ganttConfig as basicGanttConfig, tasks as basicTasks, taskTableColumnProps } from './gantt-basic-data';

@Component({
  selector: 'gantt-basic-grid',
  standalone: true,
  // Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
  schemas: [NO_ERRORS_SCHEMA],
  imports: [RevoGrid],
  template: `
    <section class="gantt-basic-demo">
      <revo-grid
        class="gantt-basic-grid"
        [theme]="theme"
        [hideAttribution]="true"
        [canMoveColumns]="true"
        [plugins]="plugins"
        [source]="tasks"
        [columns]="columns"
        [gantt]="ganttConfig"
        [ganttDependencies]="dependencies"
        [ganttCalendars]="calendars"
      ></revo-grid>
    </section>
  `,
  styleUrls: ['./gantt-basic.css'],
  encapsulation: ViewEncapsulation.None,
})
export class GanttBasicGridComponent {
  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  plugins = [GanttPlugin];

  ganttConfig = basicGanttConfig;
  calendars = basicCalendars;
  tasks = basicTasks.map((task) => ({ ...task }));
  dependencies = basicDependencies;

  columns = taskTableColumnProps.map((prop) => createDefaultTaskTableColumn(prop));
}

Common checks:

  • Missing ganttCalendars or mismatched calendarId.
  • Duplicate IDs in tasks/dependencies/resources/assignments.
  • Dependency points to missing task ID.
  • A circular dependency chain such as Setup load balancer -> Configure firewall -> Setup load balancer. The scheduler reports this as dependency-cycle; inspect the issue's taskIds and dependencyIds, then remove or change one of the links.
  • Invalid task date ranges or malformed constraints.
  • No visible timeline because viewport/zoom span does not include task dates.

If a task appears to jump during drag or resize, first check for dependency validation issues. Automatic tasks normally clamp to the earliest date allowed by their predecessors. A circular dependency cannot produce a valid predecessor order, so RevoGrid reports dependency-cycle and leaves dependency clamping disabled until the cycle is fixed.

Use the scheduling result passed to your diagnostics flow to locate the invalid links:

const cycleIssue = schedulerResult.issues.find((issue) => issue.code === 'dependency-cycle');
if (cycleIssue) {
console.table({
tasks: cycleIssue.taskIds.join(', '),
dependencies: cycleIssue.dependencyIds.join(', '),
});
}

Validation and diagnostics are produced by:

  • engine/scheduler-engine/validation.ts
  • engine/scheduler-types.ts