Skip to content

Gantt Overview

RevoGrid Gantt is an Enterprise plugin layered on top of the base grid. RevoGrid owns rendering, virtualization, editing, and keyboard interactions. Gantt adds task timeline projection, dependency links, scheduling rules, resources/assignments, critical path, baselines, and timeline tools.

Source code
TypeScript ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();

import {
  defineGanttToolbar,
  GanttPlugin,
} from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import './gantt-task-editor-form.css';
import {
  SHOWCASE_ASSIGNMENTS,
  SHOWCASE_DEPENDENCIES,
  SHOWCASE_RESOURCES,
  SHOWCASE_TOOLBAR_COLUMNS,
  STANDARD_CALENDAR,
} from './gantt-project-data';
import {
  createInitialTaskSource,
  TASK_EDITOR_COLUMNS,
  TASK_EDITOR_DIALOG_CONFIG,
  TASK_EDITOR_GANTT_CONFIG,
} from './GanttTaskEditorFormShared';

const { isDark } = currentTheme();

type TaskEditorGridElement = HTMLRevoGridElement & Record<string, any>;

function createElement<K extends keyof HTMLElementTagNameMap>(
  tagName: K,
  className?: string,
): HTMLElementTagNameMap[K] {
  const element = document.createElement(tagName);
  if (className) {
    element.className = className;
  }
  return element;
}

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

  const taskSource = createInitialTaskSource();

  const root = createElement('section', 'gantt-task-editor-demo');
  const toolbar = createElement('div', 'gantt-task-editor-toolbar');
  const grid = document.createElement('revo-grid') as TaskEditorGridElement;

  grid.className = 'gantt-task-editor-grid';
  grid.theme = isDark() ? 'darkCompact' : 'compact';
  grid.hideAttribution = true;
  grid.plugins = [GanttPlugin as any];
  grid.columns = TASK_EDITOR_COLUMNS;
  grid.gantt = TASK_EDITOR_GANTT_CONFIG;
  grid.ganttCalendars = [STANDARD_CALENDAR];
  grid.ganttDependencies = SHOWCASE_DEPENDENCIES;
  grid.ganttResources = SHOWCASE_RESOURCES;
  grid.ganttAssignments = SHOWCASE_ASSIGNMENTS;
  grid.ganttTaskEditorDialog = TASK_EDITOR_DIALOG_CONFIG;

  root.appendChild(toolbar);
  root.appendChild(grid);
  parent.appendChild(root);
  defineGanttToolbar(toolbar, {
    grid,
    columns: SHOWCASE_TOOLBAR_COLUMNS,
    controls: {
      export: false,
      baseline: false,
    },
  });

  grid.source = taskSource;

  return () => {
    root.remove();
  };
}
React tsx
import React, { useEffect, useMemo, useRef } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { defineGanttToolbar, GanttPlugin } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import {
  SHOWCASE_ASSIGNMENTS,
  SHOWCASE_DEPENDENCIES,
  SHOWCASE_RESOURCES,
  SHOWCASE_TOOLBAR_COLUMNS,
  STANDARD_CALENDAR,
} from './gantt-project-data';
import {
  createInitialTaskSource,
  TASK_EDITOR_COLUMNS,
  TASK_EDITOR_DIALOG_CONFIG,
  TASK_EDITOR_GANTT_CONFIG,
} from './GanttTaskEditorFormShared';
import './gantt-task-editor-form.css';

const { isDark } = currentTheme();

export default function GanttTaskEditorForm() {
  const gridRef = useRef<HTMLRevoGridElement>(null);
  const toolbarRef = useRef<HTMLDivElement>(null);

  const source = useMemo(() => createInitialTaskSource(), []);
  const plugins = useMemo(() => [GanttPlugin], []);
  const columns = useMemo(() => TASK_EDITOR_COLUMNS, []);
  const gantt = useMemo(() => TASK_EDITOR_GANTT_CONFIG, []);
  const calendars = useMemo(() => [STANDARD_CALENDAR], []);
  const dependencies = useMemo(() => SHOWCASE_DEPENDENCIES, []);
  const resources = useMemo(() => SHOWCASE_RESOURCES, []);
  const assignments = useMemo(() => SHOWCASE_ASSIGNMENTS, []);
  const taskEditorDialog = useMemo(() => TASK_EDITOR_DIALOG_CONFIG, []);

  useEffect(() => {
    const toolbar = toolbarRef.current;
    const grid = gridRef.current;
    if (!toolbar || !grid) {
      return undefined;
    }

    defineGanttToolbar(toolbar, {
      grid,
      columns: SHOWCASE_TOOLBAR_COLUMNS,
      controls: {
        export: false,
        baseline: false,
      },
    });

    return () => {
      toolbar.textContent = '';
    };
  }, []);

  return (
    <section className="gantt-task-editor-demo">
      <div ref={toolbarRef} className="gantt-task-editor-toolbar" />
      <RevoGrid
        ref={gridRef}
        className="gantt-task-editor-grid"
        theme={isDark() ? 'darkCompact' : 'compact'}
        hideAttribution
        plugins={plugins}
        source={source}
        columns={columns}
        gantt={gantt}
        ganttCalendars={calendars}
        ganttDependencies={dependencies}
        ganttResources={resources}
        ganttAssignments={assignments}
        ganttTaskEditorDialog={taskEditorDialog}
      />
    </section>
  );
}
Vue vue
<template>
  <section class="gantt-task-editor-demo">
    <div ref="toolbarRef" class="gantt-task-editor-toolbar"></div>
    <RevoGrid
      ref="gridRef"
      class="gantt-task-editor-grid"
      hide-attribution
      :theme="isDark ? 'darkCompact' : 'compact'"
      :plugins="plugins"
      :source="tasks"
      :columns="columns"
      :gantt.prop="ganttConfig"
      :gantt-calendars.prop="calendars"
      :gantt-dependencies.prop="dependencies"
      :gantt-resources.prop="resources"
      :gantt-assignments.prop="assignments"
      :gantt-task-editor-dialog.prop="taskEditorDialog"
    />
  </section>
</template>

<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { defineGanttToolbar, GanttPlugin } from '@revolist/revogrid-enterprise';
import { currentThemeVue } from '../composables/useRandomData';
import {
  SHOWCASE_ASSIGNMENTS,
  SHOWCASE_DEPENDENCIES,
  SHOWCASE_RESOURCES,
  SHOWCASE_TOOLBAR_COLUMNS,
  STANDARD_CALENDAR,
} from './gantt-project-data';
import {
  createInitialTaskSource,
  TASK_EDITOR_COLUMNS,
  TASK_EDITOR_DIALOG_CONFIG,
  TASK_EDITOR_GANTT_CONFIG,
} from './GanttTaskEditorFormShared';
import './gantt-task-editor-form.css';

const { isDark } = currentThemeVue();

const plugins = ref([GanttPlugin]);
const columns = ref(TASK_EDITOR_COLUMNS);
const tasks = ref(createInitialTaskSource());
const ganttConfig = ref(TASK_EDITOR_GANTT_CONFIG);
const calendars = ref([STANDARD_CALENDAR]);
const dependencies = ref(SHOWCASE_DEPENDENCIES);
const resources = ref(SHOWCASE_RESOURCES);
const assignments = ref(SHOWCASE_ASSIGNMENTS);
const taskEditorDialog = ref(TASK_EDITOR_DIALOG_CONFIG);

const gridRef = ref<InstanceType<typeof RevoGrid> | HTMLRevoGridElement | null>(null);
const toolbarRef = ref<HTMLElement | null>(null);
let toolbarMounted = false;
let toolbarFrame = 0;

function getGridEl(): HTMLRevoGridElement | null {
  const refValue = gridRef.value as (InstanceType<typeof RevoGrid> & { $el?: HTMLRevoGridElement }) | HTMLRevoGridElement | null;
  const candidate = (refValue && '$el' in refValue ? refValue.$el : refValue) ?? null;
  return candidate instanceof HTMLElement && candidate.tagName.toLowerCase() === 'revo-grid'
    ? candidate as HTMLRevoGridElement
    : null;
}

function mountToolbar() {
  if (toolbarMounted) {
    return;
  }

  const grid = getGridEl();
  if (!toolbarRef.value || !grid) {
    toolbarFrame = requestAnimationFrame(mountToolbar);
    return;
  }

  toolbarMounted = true;
  defineGanttToolbar(toolbarRef.value, {
    grid,
    columns: SHOWCASE_TOOLBAR_COLUMNS,
    controls: {
      export: false,
      baseline: false,
    },
  });
}

onMounted(async () => {
  await nextTick();
  mountToolbar();
});

onBeforeUnmount(() => {
  if (toolbarFrame) {
    cancelAnimationFrame(toolbarFrame);
  }
  if (toolbarRef.value) {
    toolbarRef.value.textContent = '';
  }
});
</script>
Angular ts
import { AfterViewInit, Component, ElementRef, NO_ERRORS_SCHEMA, ViewChild, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { defineGanttToolbar, GanttPlugin } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
import {
  SHOWCASE_ASSIGNMENTS,
  SHOWCASE_DEPENDENCIES,
  SHOWCASE_RESOURCES,
  SHOWCASE_TOOLBAR_COLUMNS,
  STANDARD_CALENDAR,
} from './gantt-project-data';
import {
  createInitialTaskSource,
  TASK_EDITOR_COLUMNS,
  TASK_EDITOR_DIALOG_CONFIG,
  TASK_EDITOR_GANTT_CONFIG,
} from './GanttTaskEditorFormShared';

@Component({
  selector: 'gantt-task-editor-form-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-task-editor-demo">
      <div #toolbar class="gantt-task-editor-toolbar"></div>
      <revo-grid
        #grid
        class="gantt-task-editor-grid"
        [theme]="theme"
        [hideAttribution]="true"
        [plugins]="plugins"
        [source]="tasks"
        [columns]="columns"
        [gantt]="ganttConfig"
        [ganttCalendars]="calendars"
        [ganttDependencies]="dependencies"
        [ganttResources]="resources"
        [ganttAssignments]="assignments"
        [ganttTaskEditorDialog]="taskEditorDialog"
      ></revo-grid>
    </section>
  `,
  styleUrls: ['./gantt-task-editor-form.css'],
  encapsulation: ViewEncapsulation.None,
})
export class GanttTaskEditorFormGridComponent implements AfterViewInit {
  @ViewChild('grid', { read: ElementRef }) gridRef!: ElementRef<HTMLRevoGridElement>;
  @ViewChild('toolbar', { read: ElementRef }) toolbarRef!: ElementRef<HTMLElement>;

  theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
  plugins = [GanttPlugin];
  columns = TASK_EDITOR_COLUMNS;
  tasks = createInitialTaskSource();
  ganttConfig = TASK_EDITOR_GANTT_CONFIG;
  calendars = [STANDARD_CALENDAR];
  dependencies = SHOWCASE_DEPENDENCIES;
  resources = SHOWCASE_RESOURCES;
  assignments = SHOWCASE_ASSIGNMENTS;
  taskEditorDialog = TASK_EDITOR_DIALOG_CONFIG;

  ngAfterViewInit(): void {
    defineGanttToolbar(this.toolbarRef.nativeElement, {
      grid: this.gridRef.nativeElement,
      columns: SHOWCASE_TOOLBAR_COLUMNS,
      controls: {
        export: false,
        baseline: false,
      },
    });
  }
}
Project Data ts
/**
 * Shared project data for all Gantt documentation examples.
 * Uses the "Website Redesign" project — simple enough to follow,
 * rich enough to show hierarchy, milestones, dependencies, and baselines.
 */
import type {
  ColumnRegular,
} from '@revolist/revogrid';
import type {
  TaskEntity,
  DependencyEntity,
  CalendarEntity,
  ResourceEntity,
  AssignmentEntity,
  BaselineSnapshot,
  GanttPluginConfig,
} from '@revolist/revogrid-enterprise';
import { createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';

// ─── IDs ─────────────────────────────────────────────────────────────────────
export const PROJECT_ID = 'project-web-redesign';
export const CALENDAR_ID = 'cal-standard';
export const CALENDAR_US_ID = 'cal-us';

// ─── Base config (override per example) ──────────────────────────────────────
export const GANTT_BASE_CONFIG = {
  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,
};

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

export const US_CALENDAR: CalendarEntity = {
  id: CALENDAR_US_ID,
  name: 'US Standard',
  timeZone: 'America/New_York',
  workingDays: [1, 2, 3, 4, 5],
  holidays: ['2026-05-25', '2026-07-04'],
  hoursPerDay: 8,
};

// ─── Tasks ────────────────────────────────────────────────────────────────────
export const TASKS: TaskEntity[] = [
  {
    id: 't1', projectId: PROJECT_ID, parentId: null,
    wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress',
    startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15,
    progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't2', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done',
    startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't3', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done',
    startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
  {
    id: 't4', projectId: PROJECT_ID, parentId: 't1',
    wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress',
    startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10,
    progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't5', projectId: PROJECT_ID, parentId: null,
    wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started',
    startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
  },
  {
    id: 't6', projectId: PROJECT_ID, parentId: 't5',
    wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started',
    startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't7', projectId: PROJECT_ID, parentId: 't5',
    wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started',
    startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
  },
  {
    id: 't8', projectId: PROJECT_ID, parentId: null,
    wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
    startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
  },
];

/** Tasks with Visual Design slipped +3 days — used in the baseline example. */
export const TASKS_SLIPPED: TaskEntity[] = TASKS.map((task) => {
  if (task.id === 't4') {
    return { ...task, endDate: '2026-04-27', durationDays: 13, progressPercent: 30 };
  }
  if (task.id === 't1') {
    return { ...task, endDate: '2026-04-27', durationDays: 18, progressPercent: 50 };
  }
  if (task.id === 't5') {
    return { ...task, startDate: '2026-04-28', endDate: '2026-05-21' };
  }
  if (task.id === 't6') {
    return { ...task, startDate: '2026-04-28', endDate: '2026-05-14' };
  }
  if (task.id === 't7') {
    return { ...task, startDate: '2026-04-28', endDate: '2026-05-21' };
  }
  if (task.id === 't8') {
    return { ...task, startDate: '2026-05-21', endDate: '2026-05-21' };
  }
  return task;
});

/** Tasks with scheduling constraints — used in the scheduling example. */
export const TASKS_SCHEDULED: TaskEntity[] = TASKS.map((task) => {
  if (task.id === 't6') {
    return {
      ...task, startDate: '2026-05-04', endDate: '2026-05-20',
      constraintType: 'start-no-earlier-than', constraintDate: '2026-05-04',
    };
  }
  if (task.id === 't7') {
    return { ...task, durationDays: 24, endDate: '2026-05-28', deadlineDate: '2026-05-22' };
  }
  if (task.id === 't8') {
    return { ...task, startDate: '2026-05-28', endDate: '2026-05-28' };
  }
  return task;
});

// ─── Dependencies ─────────────────────────────────────────────────────────────
export const DEPENDENCIES: DependencyEntity[] = [
  { id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0 },
  { id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1 },
  { id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1 },
  { id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1 },
  { id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
  { id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
];

// ─── Resources & Assignments ──────────────────────────────────────────────────
export const RESOURCES: ResourceEntity[] = [
  { id: 'r1', name: 'Alice Chen', role: 'Designer', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 95 },
  { id: 'r2', name: 'Bob Kim', role: 'Frontend Dev', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 110 },
  { id: 'r3', name: 'Carla Díaz', role: 'Backend Dev', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 105 },
];

export const ASSIGNMENTS: AssignmentEntity[] = [
  { id: 'a1', taskId: 't2', resourceId: 'r1', allocationUnits: 1, responsibility: 'assigned' },
  { id: 'a2', taskId: 't4', resourceId: 'r1', allocationUnits: 1, responsibility: 'assigned' },
  { id: 'a3', taskId: 't6', resourceId: 'r2', allocationUnits: 1, responsibility: 'assigned' },
  { id: 'a4', taskId: 't7', resourceId: 'r3', allocationUnits: 1, responsibility: 'assigned' },
];

// ─── Baseline ─────────────────────────────────────────────────────────────────
export const BASELINES: BaselineSnapshot[] = [
  {
    id: 'baseline-approved',
    name: 'Approved Plan',
    capturedAt: '2026-04-01T08:00:00Z',
    tasks: [
      { taskId: 't1', startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15, progressPercent: 0 },
      { taskId: 't2', startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,  progressPercent: 0 },
      { taskId: 't3', startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,  progressPercent: 0 },
      { taskId: 't4', startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10, progressPercent: 0 },
      { taskId: 't5', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't6', startDate: '2026-04-27', endDate: '2026-05-13', durationDays: 13, progressPercent: 0 },
      { taskId: 't7', startDate: '2026-04-27', endDate: '2026-05-20', durationDays: 18, progressPercent: 0 },
      { taskId: 't8', startDate: '2026-05-20', endDate: '2026-05-20', durationDays: 0,  progressPercent: 0 },
    ],
  },
];

// ─── Default columns (basic examples) ────────────────────────────────────────
export const DEFAULT_COLUMNS = [
  createDefaultTaskTableColumn('wbs'),
  createDefaultTaskTableColumn('name'),
  createDefaultTaskTableColumn('assignees'),
  createDefaultTaskTableColumn('cost' as any),
  createDefaultTaskTableColumn('startDate'),
  createDefaultTaskTableColumn('endDate'),
  createDefaultTaskTableColumn('duration'),
  createDefaultTaskTableColumn('percentDone'),
].filter(Boolean);

// ─── Showcase column options (all 10, with visibility flags) ─────────────────
export const SHOWCASE_COLUMN_OPTIONS = [
  { prop: 'wbs',          label: 'WBS',          defaultVisible: true  },
  { prop: 'name',         label: 'Name',         defaultVisible: true  },
  { prop: 'assignees',    label: 'Assignees',    defaultVisible: true  },
  { prop: 'cost',         label: 'Cost',         defaultVisible: true  },
  { prop: 'startDate',    label: 'Start Date',   defaultVisible: true  },
  { prop: 'endDate',      label: 'End Date',     defaultVisible: false },
  { prop: 'duration',     label: 'Duration',     defaultVisible: true  },
  { prop: 'percentDone',  label: '% Done',       defaultVisible: false },
  { prop: 'predecessors', label: 'Predecessors', defaultVisible: false },
  { prop: 'successors',   label: 'Successors',   defaultVisible: false },
  { prop: 'status',       label: 'Status',       defaultVisible: true  },
] as const;

export const SHOWCASE_TOOLBAR_COLUMNS = [
  { prop: 'name', label: 'Task', visible: true },
  { prop: 'assignees', label: 'Assignees', visible: true },
  { prop: 'cost', label: 'Cost', visible: true },
  { prop: 'startDate', label: 'Start', visible: true },
  { prop: 'duration', label: 'Dur', visible: true },
];

export type ShowcaseColumnProp = (typeof SHOWCASE_COLUMN_OPTIONS)[number]['prop'];

/** All 10 showcase columns as RevoGrid column definitions. */
export const SHOWCASE_COLUMNS = SHOWCASE_COLUMN_OPTIONS
  .map((c) => createDefaultTaskTableColumn(c.prop as any))
  .filter((c): c is NonNullable<typeof c> => Boolean(c));

/** Props that are hidden by default in the showcase. */
export const SHOWCASE_DEFAULT_HIDDEN: string[] = SHOWCASE_COLUMN_OPTIONS
  .filter((c) => !c.defaultVisible)
  .map((c) => c.prop as string);

type ShowcaseTaskEntity = TaskEntity & {
  estimatedCost?: number;
};

export const SHOWCASE_PROJECT_ID = 'project-launch-saas';

export const SHOWCASE_GANTT_CONFIG = {
  ...GANTT_BASE_CONFIG,
  id: SHOWCASE_PROJECT_ID,
  name: 'Launch SaaS Product',
  updatedAt: '2026-04-28T10:00:00Z',
  zoomPreset: 'day-week' as const,
  allowTaskCreate: true,
  visuals: {
    showBaseline: true,
    showCriticalPath: true,
    showTaskLabels: true,
    shadeNonWorkingTime: true,
    showTodayLine: true,
    milestoneLines: [
      { id: 'public-launch', date: '2026-05-23', label: 'Launch', color: '#facc15' },
    ],
  },
  scheduling: {
    excludeHolidaysFromDuration: true,
  },
} satisfies GanttPluginConfig;

export const SHOWCASE_TASKS: ShowcaseTaskEntity[] = [
  {
    id: 'launch', projectId: SHOWCASE_PROJECT_ID, parentId: null,
    wbsCode: '', name: 'Launch SaaS Product', type: 'summary', status: 'blocked',
    startDate: '2026-04-06', endDate: '2026-05-23', durationDays: 47,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
    estimatedCost: 248400,
  },
  {
    id: 'backend', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '1', name: 'Backend Setup', type: 'summary', status: 'blocked',
    startDate: '2026-04-06', endDate: '2026-04-18', durationDays: 12,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['Backend'],
    estimatedCost: 32400,
  },
  {
    id: 'design', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '2', name: 'Design', type: 'summary', status: 'blocked',
    startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 18,
    progressPercent: 97, calendarId: CALENDAR_ID, isCritical: true, tags: ['Design'],
    estimatedCost: 14800,
  },
  {
    id: 'frontend', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '3', name: 'Frontend Development', type: 'summary', status: 'blocked',
    startDate: '2026-04-14', endDate: '2026-05-10', durationDays: 24,
    progressPercent: 50, calendarId: CALENDAR_ID, isCritical: true, tags: ['Frontend'],
    estimatedCost: 38600,
  },
  {
    id: 'devops', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '4', name: 'DevOps', type: 'summary', status: 'blocked',
    startDate: '2026-04-10', endDate: '2026-05-12', durationDays: 32,
    progressPercent: 85, calendarId: CALENDAR_ID, isCritical: true, tags: ['DevOps'],
    estimatedCost: 21800,
  },
  {
    id: 'iac', projectId: SHOWCASE_PROJECT_ID, parentId: 'devops',
    wbsCode: '4.1', name: 'Infrastructure as Code', type: 'task', status: 'done',
    startDate: '2026-04-10', endDate: '2026-04-18', durationDays: 8,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: ['DevOps'],
    estimatedCost: 7800,
  },
  {
    id: 'ci-cd', projectId: SHOWCASE_PROJECT_ID, parentId: 'devops',
    wbsCode: '4.2', name: 'CI / CD Pipeline', type: 'task', status: 'done',
    startDate: '2026-04-16', endDate: '2026-04-24', durationDays: 8,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: ['DevOps'],
    estimatedCost: 5200,
  },
  {
    id: 'monitoring', projectId: SHOWCASE_PROJECT_ID, parentId: 'devops',
    wbsCode: '4.3', name: 'Monitoring & Logging', type: 'task', status: 'blocked',
    startDate: '2026-04-22', endDate: '2026-04-30', durationDays: 8,
    progressPercent: 55, calendarId: CALENDAR_ID, isCritical: false, tags: ['DevOps'],
    estimatedCost: 4400,
  },
  {
    id: 'prod-deploy', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '5', name: 'Production Deploy', type: 'milestone', status: 'not-started',
    startDate: '2026-05-12', endDate: '2026-05-12', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['Milestone'],
  },
  {
    id: 'qa', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '6', name: 'QA', type: 'summary', status: 'blocked',
    startDate: '2026-04-20', endDate: '2026-05-18', durationDays: 28,
    progressPercent: 32, calendarId: CALENDAR_ID, isCritical: true, tags: ['QA'],
    estimatedCost: 12200,
  },
  {
    id: 'test-plan', projectId: SHOWCASE_PROJECT_ID, parentId: 'qa',
    wbsCode: '6.1', name: 'Test Plan', type: 'task', status: 'done',
    startDate: '2026-04-20', endDate: '2026-04-24', durationDays: 4,
    progressPercent: 100, calendarId: CALENDAR_ID, isCritical: false, tags: ['QA'],
    estimatedCost: 2800,
  },
  {
    id: 'unit-tests', projectId: SHOWCASE_PROJECT_ID, parentId: 'qa',
    wbsCode: '6.2', name: 'Unit Tests', type: 'task', status: 'in-progress',
    startDate: '2026-04-24', endDate: '2026-05-04', durationDays: 10,
    progressPercent: 62, calendarId: CALENDAR_ID, isCritical: false, tags: ['QA'],
    estimatedCost: 4200,
  },
  {
    id: 'integration-tests', projectId: SHOWCASE_PROJECT_ID, parentId: 'qa',
    wbsCode: '6.3', name: 'Integration Tests', type: 'task', status: 'not-started',
    startDate: '2026-05-02', endDate: '2026-05-12', durationDays: 10,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: ['QA'],
    estimatedCost: 3400,
  },
  {
    id: 'uat', projectId: SHOWCASE_PROJECT_ID, parentId: 'qa',
    wbsCode: '6.4', name: 'User Acceptance Test', type: 'task', status: 'not-started',
    startDate: '2026-05-10', endDate: '2026-05-18', durationDays: 8,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: ['QA'],
    estimatedCost: 1800,
  },
  {
    id: 'security', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '7', name: 'Security', type: 'summary', status: 'not-started',
    startDate: '2026-05-06', endDate: '2026-05-21', durationDays: 15,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['Security'],
    estimatedCost: 7200,
  },
  {
    id: 'pentest', projectId: SHOWCASE_PROJECT_ID, parentId: 'security',
    wbsCode: '7.1', name: 'Penetration Testing', type: 'task', status: 'not-started',
    startDate: '2026-05-06', endDate: '2026-05-14', durationDays: 8,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: ['Security'],
    estimatedCost: 4800,
  },
  {
    id: 'audit', projectId: SHOWCASE_PROJECT_ID, parentId: 'security',
    wbsCode: '7.2', name: 'Audit & Compliance', type: 'task', status: 'not-started',
    startDate: '2026-05-12', endDate: '2026-05-21', durationDays: 9,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: ['Security'],
    estimatedCost: 2400,
  },
  {
    id: 'public-launch', projectId: SHOWCASE_PROJECT_ID, parentId: 'launch',
    wbsCode: '8', name: 'Public Launch', type: 'milestone', status: 'not-started',
    startDate: '2026-05-23', endDate: '2026-05-23', durationDays: 0,
    progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['Milestone'],
  },
];

export const SHOWCASE_DEPENDENCIES: DependencyEntity[] = [
  { id: 'sd-1', predecessorTaskId: 'iac', successorTaskId: 'ci-cd', type: 'finish-to-start', lagDays: 0 },
  { id: 'sd-2', predecessorTaskId: 'ci-cd', successorTaskId: 'monitoring', type: 'finish-to-start', lagDays: 0 },
  { id: 'sd-3', predecessorTaskId: 'test-plan', successorTaskId: 'unit-tests', type: 'finish-to-start', lagDays: 0 },
  { id: 'sd-4', predecessorTaskId: 'unit-tests', successorTaskId: 'integration-tests', type: 'finish-to-start', lagDays: 0 },
  { id: 'sd-5', predecessorTaskId: 'integration-tests', successorTaskId: 'uat', type: 'finish-to-start', lagDays: 0 },
  { id: 'sd-6', predecessorTaskId: 'audit', successorTaskId: 'public-launch', type: 'finish-to-start', lagDays: 0 },
];

export const SHOWCASE_RESOURCES: ResourceEntity[] = [
  { id: 'nk', name: 'Nina Kim', role: 'Platform Engineer', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 125 },
  { id: 'rp', name: 'Ravi Patel', role: 'QA Lead', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 100 },
  { id: 'jd', name: 'Jordan Diaz', role: 'Automation Engineer', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 95 },
  { id: 'sr', name: 'Sam Rivera', role: 'Product Owner', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 90 },
  { id: 'vk', name: 'Vera Khan', role: 'Security Engineer', calendarId: CALENDAR_ID, allocationCapacity: 1, hourlyCost: 115 },
];

export const SHOWCASE_ASSIGNMENTS: AssignmentEntity[] = [
  { id: 'sa-1', taskId: 'iac', resourceId: 'nk', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-2', taskId: 'ci-cd', resourceId: 'nk', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-3', taskId: 'monitoring', resourceId: 'nk', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-4', taskId: 'test-plan', resourceId: 'rp', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-5', taskId: 'unit-tests', resourceId: 'rp', allocationUnits: 1, responsibility: 'Lead' },
  { id: 'sa-6', taskId: 'unit-tests', resourceId: 'jd', allocationUnits: 1, responsibility: 'Automation' },
  { id: 'sa-7', taskId: 'integration-tests', resourceId: 'rp', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-8', taskId: 'uat', resourceId: 'rp', allocationUnits: 1, responsibility: 'Lead' },
  { id: 'sa-9', taskId: 'uat', resourceId: 'sr', allocationUnits: 1, responsibility: 'Signoff' },
  { id: 'sa-10', taskId: 'pentest', resourceId: 'vk', allocationUnits: 1, responsibility: 'Owner' },
  { id: 'sa-11', taskId: 'audit', resourceId: 'vk', allocationUnits: 1, responsibility: 'Lead' },
  { id: 'sa-12', taskId: 'audit', resourceId: 'jd', allocationUnits: 1, responsibility: 'Compliance' },
];

export const SHOWCASE_BASELINES: BaselineSnapshot[] = [
  {
    id: 'showcase-approved',
    name: 'Approved launch plan',
    capturedAt: '2026-04-01T08:00:00Z',
    tasks: SHOWCASE_TASKS.map((task) => ({
      taskId: task.id,
      startDate: task.startDate,
      endDate: task.endDate,
      durationDays: task.durationDays,
      progressPercent: 0,
    })),
  },
];

const SHOWCASE_STATUS_COLOR: Record<string, string> = {
  'not-started': '#525866',
  'in-progress': '#f59e0b',
  done: '#39d07d',
  blocked: '#ff4d4f',
};

const SHOWCASE_TAG_COLORS: Record<string, { color: string; bg: string; border: string }> = {
  Backend: { color: '#ff66b3', bg: 'rgba(255, 102, 179, 0.14)', border: 'rgba(255, 102, 179, 0.35)' },
  Design: { color: '#a78bfa', bg: 'rgba(167, 139, 250, 0.14)', border: 'rgba(167, 139, 250, 0.36)' },
  Frontend: { color: '#34d399', bg: 'rgba(52, 211, 153, 0.14)', border: 'rgba(52, 211, 153, 0.36)' },
  DevOps: { color: '#fb923c', bg: 'rgba(251, 146, 60, 0.14)', border: 'rgba(251, 146, 60, 0.36)' },
  QA: { color: '#60a5fa', bg: 'rgba(96, 165, 250, 0.14)', border: 'rgba(96, 165, 250, 0.36)' },
  Security: { color: '#facc15', bg: 'rgba(250, 204, 21, 0.13)', border: 'rgba(250, 204, 21, 0.36)' },
};

function renderShowcaseNameCell(h: Parameters<Required<ColumnRegular>['cellTemplate']>[0], model: any) {
  const tag = model.tags?.[0];
  const tagStyle = tag && SHOWCASE_TAG_COLORS[tag]
    ? {
        '--showcase-tag-color': SHOWCASE_TAG_COLORS[tag].color,
        '--showcase-tag-bg': SHOWCASE_TAG_COLORS[tag].bg,
        '--showcase-tag-border': SHOWCASE_TAG_COLORS[tag].border,
      }
    : {};

  return h('div', { class: { 'gantt-showcase-task-cell': true } }, [
    h('span', {
      class: {
        'gantt-showcase-status-dot': true,
        'gantt-showcase-status-dot--milestone': model.taskKind === 'milestone',
      },
      style: { '--showcase-status-color': SHOWCASE_STATUS_COLOR[model.statusKey ?? 'not-started'] ?? SHOWCASE_STATUS_COLOR['not-started'] },
    }),
    h('span', { class: { 'gantt-showcase-task-name': true }, title: model.name }, model.name),
    tag && SHOWCASE_TAG_COLORS[tag]
      ? h('span', { class: { 'gantt-showcase-tag': true }, style: tagStyle }, tag)
      : null,
  ]);
}

function showcaseCellProperties({ model }: any) {
  return {
    class: {
      'gantt-showcase-cell--root': model.id === 'launch',
      'gantt-showcase-cell--summary': model.taskKind === 'summary',
    },
  };
}

export const SHOWCASE_COLUMNS_POLISHED: ColumnRegular[] = [
  {
    ...createDefaultTaskTableColumn('name'),
    name: 'Task',
    size: 292,
    cellTemplate: (h, { model }) => renderShowcaseNameCell(h, model),
    cellProperties: showcaseCellProperties,
  },
  {
    ...createDefaultTaskTableColumn('assignees'),
    size: 102,
    cellProperties: showcaseCellProperties,
  },
  {
    ...createDefaultTaskTableColumn('cost' as any),
    size: 114,
    cellProperties: showcaseCellProperties,
  },
  {
    ...createDefaultTaskTableColumn('startDate'),
    name: 'Start',
    size: 116,
    cellProperties: showcaseCellProperties,
  },
  {
    ...createDefaultTaskTableColumn('duration'),
    name: 'Dur',
    size: 90,
    cellProperties: showcaseCellProperties,
  },
];

type ShowcaseTaskColor = { barColor: string; progressColor: string; textColor?: string };

export const GANTT_SHOWCASE_DEFAULT_TASK_COLOR: ShowcaseTaskColor = {
  barColor: '#64748b',
  progressColor: '#94a3b8',
  textColor: '#ffffff',
};

export const GANTT_SHOWCASE_TASK_COLORS: Record<string, ShowcaseTaskColor> = {
  launch: { barColor: '#a5a7b0', progressColor: '#8f929d', textColor: '#f8fafc' },
  backend: { barColor: '#ff77d2', progressColor: '#f43f9e' },
  design: { barColor: '#d9b4ff', progressColor: '#a78bfa', textColor: '#25143f' },
  frontend: { barColor: '#5eead4', progressColor: '#34d399', textColor: '#092f25' },
  devops: { barColor: '#ffd45a', progressColor: '#fb923c', textColor: '#2d1f02' },
  iac: { barColor: '#b66b2e', progressColor: '#f97316' },
  'ci-cd': { barColor: '#b66b2e', progressColor: '#f97316' },
  monitoring: { barColor: '#5a2c12', progressColor: '#f97316' },
  'prod-deploy': { barColor: '#facc15', progressColor: '#facc15', textColor: '#18181b' },
  qa: { barColor: '#60a5fa', progressColor: '#7dd3fc', textColor: '#061633' },
  'test-plan': { barColor: '#4d76b2', progressColor: '#7dd3fc' },
  'unit-tests': { barColor: '#1e3558', progressColor: '#4f7dbd' },
  'integration-tests': { barColor: '#102441', progressColor: '#60a5fa' },
  uat: { barColor: '#102441', progressColor: '#60a5fa' },
  security: { barColor: '#facc15', progressColor: '#eab308', textColor: '#18181b' },
  pentest: { barColor: '#2f2610', progressColor: '#facc15' },
  audit: { barColor: '#2f2610', progressColor: '#facc15' },
  'public-launch': { barColor: '#facc15', progressColor: '#facc15', textColor: '#18181b' },
};

export function getShowcaseTaskBarColor({ row }: any) {
  const assigneeCount = row.assigneeDetails?.length ?? 0;

  return {
    ...GANTT_SHOWCASE_DEFAULT_TASK_COLOR,
    ...GANTT_SHOWCASE_TASK_COLORS[row.id],
    ...(assigneeCount && row.taskKind !== 'summary' ? { className: 'gantt-bar--with-assignee' } : {}),
  };
}

export function renderShowcaseTaskBarContent({ h, row, defaultContent }: any) {
  if (!row.assigneeDetails?.length || row.taskKind === 'summary') {
    return defaultContent;
  }

  return [
    ...defaultContent,
    h('span', { class: { 'gantt-bar__assignee-badge': true } }, row.assigneeDetails[0].initials),
  ];
}

// ─── Typed config builders ────────────────────────────────────────────────────
export function makeGanttConfig(overrides: Partial<GanttPluginConfig> = {}): GanttPluginConfig {
  return { ...GANTT_BASE_CONFIG, ...overrides } as GanttPluginConfig;
}

This document crossmatches the desired Scheduler, Gantt, and shared planning-platform feature list against the current implementation in packages/enterprise/plugins/gantt.

Status:

  • Existing ✅ - implemented now.
  • Partial ☑️ - foundation exists, but product/API/UX work is still needed.
  • Planned 🚧 - roadmap item.

Gantt

Project planning with task hierarchy, dependencies, milestones, baselines, calendars, resources, and scheduling logic.

Feature groupFeatureStatusNotes
Task modelTask tree / work breakdown structureTasks use parentId and wbsCode.
Task modelSummary tasksSummary task type and parent rollups exist.
Task modelRegular tasksStandard task type exists.
Task modelMilestonesMilestone task type exists.
Task modelCollapsible task groupsTree plugin integration exists.
Task modelParent-child rollupsSchedule and cost rollups exist.
DependenciesFinish-to-StartSupported dependency type.
DependenciesStart-to-StartSupported dependency type.
DependenciesFinish-to-FinishSupported dependency type.
DependenciesStart-to-FinishSupported dependency type.
DependenciesLead and lag timePositive lag and negative lead are supported.
DependenciesDependency validationValidation and diagnostics exist.
DependenciesMove task dependenciesDependency drag/link editing exists.
DependenciesHide dependency arrowsgantt.visuals.showDependencies = false hides dependency overlays without mutating ganttDependencies.
SchedulingAuto-schedulingDependency-aware recalculation exists.
SchedulingManual schedulingManual tasks preserve authored dates and can warn.
SchedulingForward schedulingProject-start scheduling exists.
SchedulingBackward schedulingProject-finish scheduling exists.
SchedulingTask constraintsStart/finish no-earlier/no-later and must-start/must-finish constraints exist.
SchedulingDeadline markersDeadline fields and indicators exist.
SchedulingDuration calculationCalendar-aware duration logic exists.
SchedulingStart / finish date calculationEngine computes effective dates.
SchedulingTask splittingSplit ranges affect date math and rendering.
Critical pathCritical pathCritical path calculation and highlighting exist.
Critical pathTotal slacktotalSlackDays is projected.
Critical pathFree slack🚧Separate free-slack field is not implemented.
BaselinesBaselinesBaseline snapshots and baseline bars exist.
BaselinesBaseline varianceStart, finish, duration, and progress variance fields exist.
ProgressPercent completeProgress field and editing exist.
ProgressProgress trackingActual dates, remaining duration, and progress-aware scheduling exist.
CalendarsProject calendarPrimary project calendar exists.
CalendarsTask calendarTasks reference calendars.
CalendarsResource calendarResources reference calendars.
CalendarsWorking / non-working daysCalendar working weekdays exist.
CalendarsHolidaysCalendar holidays exist.
ResourcesResource assignmentAssignment model exists.
ResourcesResource workload viewResource planning mode exists.
ResourcesResource utilizationLoad summaries and capacity display exist.
ResourcesOver-allocation warningsResource allocation diagnostics exist.
CostCost fieldsExplicit and calculated costs exist.
CustomizationCustom task fields☑️Rows can carry custom data; formal custom field schema is planned.
CustomizationCustom columns☑️RevoGrid column foundation and packaged Gantt column presets exist; broader custom-column API is planned.
EditingInline grid editingGrid edits patch task fields.
EditingDrag task barsTask bar drag exists.
EditingResize task barsTask bar resize exists.
EditingProgress drag/editProgress interaction exists.
TimelineZoom levelsPreset and custom zoom exist.
TimelineTimeline markersTime ranges, project line, today line, milestone lines, and task markers exist.
TimelineToday lineToday line is supported.
SelectionMulti-selection☑️RevoGrid selection exists; multi-task Gantt operations are planned.
KeyboardKeyboard navigation☑️RevoGrid foundation exists; Gantt-specific shortcuts are planned.
HistoryUndo / redoGantt history snapshots exist.
Import/exportGrid import / exportCSV export is available in RevoGrid core; Excel import/export is available in RevoGrid Pro, with Gantt toolbar action helpers.
Import/exportGantt project import / exportTyped project snapshots include clone/export/parse JSON helpers, REST/GraphQL adapter examples, and a PostgreSQL persistence recipe; broader project-file adapters are planned.
Import/exportMS Project-style compatibility layer🚧🚧.
PerformanceLarge project virtualization☑️RevoGrid virtualization exists; Gantt-specific server/window model is planned.
PerformanceServer-side loading for enterprise datasets🚧Not implemented.

Scheduler

Resource planning for teams, equipment, rooms, vehicles, and operations.

Feature groupFeatureStatusNotes
Timeline viewsResource timeline viewResource planning mode renders resource rows with load bars.
Timeline viewsDay / week / month / custom range viewsDefault timeline zoom levels include day-week, week-month, month-quarter, quarter-year, year-quarter, and multi-year-quarter; intraday presets are opt-in for performance, and custom zoom levels are configurable.
Timeline viewsHorizontal scheduling modeCurrent resource planning and Gantt timeline are horizontal.
Timeline viewsVertical scheduling mode🚧Needs dedicated Scheduler layout.
Resource managementResource scheduling☑️Resources, assignments, capacity, and calendars exist; dedicated events/bookings/jobs model is planned.
Resource managementMulti-resource assignmentMultiple resources can be assigned to a task.
Resource managementResource grouping🚧Resource filtering exists, but grouping UI/API is planned.
Resource managementNested resource trees🚧Needs resource hierarchy model/projection.
Event editingDrag-and-drop event creation☑️Task drag-create exists; Scheduler event creation is planned.
Event editingDrag-and-drop event moving☑️Task bar moving exists; Scheduler event moving is planned.
Event editingEvent resizing☑️Task resizing exists; Scheduler event resizing is planned.
Event editingEvent splitting☑️Task split ranges exist; Scheduler event split UX is planned.
Event editingEvent merging🚧Not implemented.
Event layoutOverlapping event layout🚧Needs Scheduler event layout engine.
Event layoutStack / pack / overlap display modes🚧Needs configurable event display modes.
Editing modesRead-only modegantt.readOnly blocks packaged task, dependency, and assignment mutation services.
Editing modesEditable mode☑️Task editing exists; Scheduler event editing is planned.
CalendarsCustom working hours☑️Calendars support working days, holidays, and hours/day; intraday hours are planned.
CalendarsNon-working time highlightingTimeline can shade non-working time.
CalendarsTimezone supportProject and calendars carry IANA time zones.
RecurrenceRecurring events🚧Not implemented.
RecurrenceEvent exceptions🚧Not implemented.
ValidationEvent validation hooks☑️Cancelable before-change hooks exist for tasks, dependencies, and assignments. Event-specific hooks are planned.
ValidationConflict detection☑️Resource over-allocation and scheduling diagnostics exist; booking conflict rules are planned.
ValidationCapacity warningsResource planning supports capacity and over-allocation display.
ValidationAvailability rules☑️Resource calendars exist; richer availability rules are planned.
ValidationLocked events☑️Gantt tasks support locked; Scheduler event locks remain planned.
RenderingCustom event templates☑️Task renderer hooks exist; Scheduler event renderer API is planned.
RenderingCustom resource rows☑️Resource row projection exists; public custom resource row API is planned.
RenderingCustom timeline headersTimeline zoom/header configuration exists.
RenderingTooltips and popovers☑️Task tooltip hook and Gantt task detail popover model exist; richer Scheduler popovers are planned.
Grid UXInline editingGrid edits update task data.
Grid UXKeyboard navigation☑️RevoGrid foundation exists; Scheduler-specific keyboard workflows are planned.
Grid UXCopy / paste☑️RevoGrid foundation exists; Scheduler-specific behavior is planned.
Grid UXUndo / redoGantt integrates with history snapshots.
Grid UXFiltering and searchTree-aware Gantt search exists.
PerformanceVirtual scrolling for large datasets☑️RevoGrid virtualization exists; Scheduler-specific data windowing is planned.
PerformanceLazy loading by date range🚧Not implemented.
ExportExcel exportSupported through RevoGrid Pro ExportExcelPlugin for grid data. Timeline-image/workbook specialization can be added later.
ExportExcel importSupported through RevoGrid Pro ExportExcelPlugin; Gantt-specific project mapping can be added later.
ExportCSV exportSupported through RevoGrid core ExportFilePlugin when grid exporting is enabled.
ExportPDF export☑️Print-oriented reporting recipe exists; timeline/PDF layout export is not provided by the current grid export plugins. A combined PDF + Excel reporting recipe documents the recommended toolbar wiring.

Shared RevoGrid Planning Platform

Built on the same high-performance grid engine and scheduling foundation.

Feature groupFeatureStatusNotes
Data modelTasksTaskEntity.
Data modelEvents🚧Scheduler event entity is planned.
Data modelResourcesResourceEntity.
Data modelAssignmentsAssignmentEntity.
Data modelDependenciesDependencyEntity.
Data modelCalendarsCalendarEntity.
Data modelBaselinesBaselineSnapshot.
Data modelTime rangesTimeline visual ranges exist.
Data modelConstraintsTask constraints exist.
Data modelCustom metadata☑️Tags/notes and row extensibility exist; typed metadata schema is planned.
Data modelCustom field schemas🚧Not implemented.
Data modelTyped data modelsTyped config, entities, events, and projected rows exist.
Data modelFramework-agnostic coreEngine/projection/core are framework-independent TypeScript modules.
Scheduling engineCalendar-aware date calculationImplemented.
Scheduling engineDependency-aware recalculationImplemented.
Scheduling engineForward schedulingImplemented.
Scheduling engineBackward schedulingImplemented.
Scheduling engineManual vs automatic schedulingImplemented.
Scheduling engineConstraint handlingImplemented.
Scheduling engineCritical path calculationImplemented.
Scheduling engineResource conflict detectionImplemented as resource over-allocation diagnostics.
Scheduling engineConfigurable validation rules☑️Policy options and cancelable hooks exist; rule registry is planned.
Scheduling engineTransaction-based updates☑️Mutation services exist; public transaction API is planned.
Scheduling engineBatch recalculationEngine recalculates resolved project snapshots.
Scheduling engineDeterministic scheduling resultsImplemented.
Grid foundationRevoGrid-powered left-side gridGantt projects rows and columns into RevoGrid.
Grid foundationVirtualized rows and columnsRevoGrid foundation.
Grid foundationFrozen columnsRevoGrid/Pro foundation.
Grid foundationColumn groupingRevoGrid foundation.
Grid foundationColumn resizingRevoGrid foundation.
Grid foundationColumn reorderingRevoGrid foundation.
Grid foundationCustom cell renderersRevoGrid templates and Gantt bar hooks.
Grid foundationCustom editors☑️RevoGrid editor foundation exists; Gantt editor forms are planned.
Grid foundationTree dataTree plugin integration.
Grid foundationRow grouping☑️RevoGrid/Pro foundation exists; Gantt-specific row grouping is planned.
Grid foundationSorting☑️RevoGrid foundation exists; scheduler-safe sorting policy is planned.
Grid foundationFilteringGantt search and RevoGrid filtering foundation.
Grid foundationSelectionRevoGrid foundation.
Grid foundationClipboardRevoGrid/Pro foundation.
Grid foundationKeyboard navigationRevoGrid foundation.
Grid foundationThemingGantt SCSS and RevoGrid theming foundation.
Grid foundationPlugin architectureGantt composes feature tools and Pro plugins.
Enterprise performanceVirtual renderingRevoGrid foundation.
Enterprise performanceLarge dataset support☑️Rendering foundation exists; server/window data model is planned.
Enterprise performanceLazy loading🚧Not implemented.
Enterprise performanceDate-range loading🚧Not implemented.
Enterprise performanceViewport-aware loading🚧Not implemented.
Enterprise performanceServer-side data model🚧Not implemented.
Enterprise performanceIncremental updates☑️Local mutation services exist; remote incremental sync is planned.
Enterprise performanceReal-time updates🚧Not implemented.
Enterprise performanceOptimistic updates🚧Not implemented.
Enterprise performanceWebSocket-ready data flow🚧Not implemented.
Enterprise performanceBatched mutations☑️Controlled local mutations exist; explicit batch API is planned.
Enterprise performanceMinimal re-rendering☑️Grid sync update modes exist.
Framework supportReactGantt demos/components exist.
Framework supportVueGantt demos/components exist.
Framework supportAngularGantt demos/components exist.
Framework supportSvelte☑️Svelte usage example exists; packaged wrapper/API docs are planned.
ExtensibilityCustom task rendererTask bar color/content/tooltip hooks.
ExtensibilityCustom event renderer🚧Requires Scheduler event model.
ExtensibilityCustom dependency renderer☑️Dependency layer exists; public renderer hook is planned.
ExtensibilityCustom tooltip rendererTask tooltip hook and built-in tooltip field selection exist.
ExtensibilityCustom editor formsTask editor form schema, submit normalization helper, and packaged Preact row-context-menu dialog plugin exist; the packaged dialog edits task fields and resource assignments.
ExtensibilityCustom validation☑️Cancelable before-change events and validation recipe examples exist; validation registry is planned.
ExtensibilityCustom scheduling rules🚧🚧.
ExtensibilityCustom calendarsCalendar entities are configurable.
ExtensibilityCustom export pipeline☑️Gantt Excel row mapping, toolbar export actions, print recipe, and combined PDF + Excel reporting recipe exist; full pipeline hooks are planned.
ExtensibilityCustom context menuGantt enables row, column, and timeline context menus by default, prepends default actions through RevoGrid Pro ContextMenuPlugin, preserves custom menu items, and supports opt-out through gantt.contextMenu.
ExtensibilityPlugin APIGantt plugin and feature-tool architecture exist.
ExtensibilityEvent lifecycle hooksBefore-change and interaction events exist.
ExtensibilityTyped APITyped config/entities/events exist.
CollaborationOptimistic editing🚧🚧.
CollaborationConflict resolution hooks🚧🚧.
CollaborationChange historyHistory integration exists.
CollaborationAudit log support🚧🚧.
CollaborationUser presence markers🚧🚧.
CollaborationComments on tasks/events🚧🚧.
CollaborationLocking / checkout mode☑️Gantt task locked prevents packaged task mutation paths; broader checkout workflows are planned.
CollaborationRole-based editability☑️Role/permission helpers exist for before-change hooks; packaged policy wiring is planned.
CollaborationRead-only viewsgantt.readOnly blocks packaged task, dependency, and assignment mutations.
CollaborationApproval workflow hooks🚧🚧.
Export and integrationCSV exportRevoGrid core ExportFilePlugin exports visible grid data as CSV.
Export and integrationExcel exportRevoGrid Pro ExportExcelPlugin exports grid data to .xlsx.
Export and integrationExcel importRevoGrid Pro ExportExcelPlugin imports .xlsx/.xls into the grid.
Export and integrationPDF export☑️Print-oriented reporting recipe exists; native PDF export is not implemented by core/Pro/Gantt export plugins.
Export and integrationPNG export🚧Not implemented by core/Pro/Gantt export plugins.
Export and integrationJSON import/exportGantt core exports clone/export/parse helpers for typed project snapshots.
Export and integrationiCalendar support for Scheduler🚧🚧.
Export and integrationMS Project-style import/export layer🚧🚧.
Export and integrationREST API integration☑️Project snapshot REST adapter example exists; production backend templates are planned.
Export and integrationGraphQL integration☑️Project snapshot GraphQL adapter example exists; production backend templates are planned.
Export and integrationServer-side adapter examples☑️REST, GraphQL, and PostgreSQL/Supabase-style examples exist; Firebase and server-window examples are planned.
Export and integrationSupabase / Firebase / PostgreSQL examples☑️PostgreSQL SQL builders and Supabase-style adapter exist; Firebase example is planned.
Export and integrationHeadless scheduling engine mode☑️Engine is framework-independent; public headless API/package is planned.

Feature: Gantt Task Editor Dialog Plugin

Status: Existing ✅

The packaged task editor dialog provides an MS Project-style “Task Information” entry point without forcing application teams to build the popup UI from scratch. GanttPlugin installs GanttTaskEditorDialogPlugin by default for every Gantt instance; the plugin mounts a Preact <dialog> host beside the grid, prepends Edit task... to the row context menu, renders the task editor schema from TASK_EDITOR_FIELD_SCHEMA, and normalizes submissions with normalizeTaskEditorSubmit().

Design notes:

  • The plugin is still exported as a separate enterprise plugin for backwards compatibility, but GanttPlugin auto-installs it so teams do not need to register it manually for normal Gantt usage.
  • Row context menus get Edit task... from the task editor plugin and Add task from the Gantt context-menu tool by default; both compose with custom row context-menu configuration instead of replacing application items.
  • gantt.contextMenu = false opts out of generated Gantt menu items; ganttTaskEditorDialog.contextMenu can independently disable or re-enable the packaged edit-task menu entry.
  • Newly created tasks open in the editor by default after gantt-task-created; ganttTaskEditorDialog.openOnCreate = false keeps creation silent for applications that want a custom follow-up flow.
  • The dialog is closed by default. Its CSS explicitly hides dialog:not([open]) so the browser default dialog box never occupies layout before a user opens it.
  • Default submit behavior applies task field patches through the Gantt runtime/provider edit path, not by replacing grid.source directly. Applications can intercept through ganttTaskEditorDialog.onSubmit; returning false skips the default update.
  • History covers task editor task field patches, resource assignment changes, dependency tab changes, direct external grid.source edits observed by Gantt, and toolbar-driven task/dependency/baseline changes.
  • Task resolution prefers Gantt task-bar data-gantt-task-id, then focused row data, then row text fallback for framework/browser context-menu timing differences.
  • Read-only projects hide the context-menu item unless ganttTaskEditorDialog.readOnly overrides the behavior.

Current Extra Strengths Beyond The Initial List

AreaFeatureStatus
SchedulingBackward/project-finish scheduling
SchedulingResource leveling modes: off, warn, auto
SchedulingSlack-bound resource leveling
SchedulingProgress-aware remaining-duration scheduling
SchedulingFixed-duration, fixed-work, and fixed-units effort modes
DiagnosticsScheduler warnings projected into row data
DiagnosticsDependency validation summary helper
DiagnosticsResource over-allocation summary helper
DependenciesPredecessor/successor text parser and formatter
TimelineCustom milestone flag lines
TimelineCustom task marker hook
TimelineCustom task bar color/content/tooltip hooks
ToolbarBaseline capture, critical-path toggle, and timeline navigation actions
RenderingRead-only and locked-task indicator metadata
CostAssignment-derived cost and parent cost rollups
HistoryStructural undo/redo for task hierarchy and dependencies
SearchTree-aware search preserving ancestors and descendants

Roadmap Summary

Priority area🚧 work
Scheduler product layerEvent model, booking/job/shift terminology, dedicated views, recurrence, exceptions, vertical mode, event layout modes, Scheduler-specific renderers and validation.
Enterprise dataLazy loading, date-range loading, viewport-aware loading, server-side model, real-time adapters, optimistic updates, WebSocket-ready data flow.
CollaborationPresence, comments, audit logs, role-based editability, locking/check-out, conflict resolution, approval hooks.
Import/exportNative PDF/PNG export, iCalendar, MS Project-style compatibility layer. CSV export and Excel import/export already come from RevoGrid core/Pro; Gantt adds toolbar helpers, Excel row mapping, print recipe, and JSON project snapshot helpers.
ExtensibilityCustom dependency renderer, editor forms, scheduling-rule registry, export pipeline.
IntegrationsFirebase, production server-side templates, headless scheduling engine API/package, packaged Svelte docs/wrapper. REST, GraphQL, and PostgreSQL/Supabase-style examples now exist.