Skip to content

feat(ui): gantt chart implementation, entities swimlanes 2 - #496

Merged
rapids-bot[bot] merged 4 commits into
rapidsai:mainfrom
johallar:joe/long-entities-gantt-2
Aug 4, 2026
Merged

feat(ui): gantt chart implementation, entities swimlanes 2#496
rapids-bot[bot] merged 4 commits into
rapidsai:mainfrom
johallar:joe/long-entities-gantt-2

Conversation

@johallar

@johallar johallar commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description

Captures common quent functionality (data zoom sync, xaxis pointer, etc) in a GanttChart component, much like Timeline. This implementation will be used to implement the operators gantt chart and the entities gantt chart. This PR only updates the OperatorGantt to the new base implementation.

Related Issues

relates to #215

Testing

Operators gantt chart functions as previously

Screenshots

@johallar
johallar force-pushed the joe/long-entities-gantt-2 branch 2 times, most recently from 8e67edc to 34107cb Compare August 3, 2026 16:20
@johallar
johallar marked this pull request as ready for review August 3, 2026 16:23
@johallar
johallar requested a review from cmatzenbach as a code owner August 3, 2026 16:23
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds a reusable generic Gantt chart with typed options, ECharts rendering, hover tracking, zoom navigation, scrolling, and empty-state handling. OperatorGanttChart now uses this component and shared interval utilities.

Changes

Gantt chart extraction

Layer / File(s) Summary
Shared Gantt types, options, and utilities
ui/packages/@quent/components/src/gantt-chart/options.ts, ui/packages/@quent/components/src/gantt-chart/utils.ts, ui/packages/@quent/components/src/gantt-chart/*.test.ts
Adds typed Gantt data, ECharts option construction, rectangle clipping, interval row stacking, and Vitest coverage.
Generic chart rendering and interaction
ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx, ui/packages/@quent/components/src/gantt-chart/hover.ts
Adds chart sizing, rendering, pointer synchronization, wheel navigation, hover tracking, scrolling, cleanup, and empty-state rendering.
Operator timeline migration
ui/packages/@quent/components/src/operator-timeline/OperatorGanttChart.tsx, ui/packages/@quent/components/src/operator-timeline/utils.ts, ui/packages/@quent/components/src/operator-timeline/utils.test.ts, ui/packages/@quent/components/src/index.ts
Routes operator timeline rendering and interval stacking through shared Gantt modules and updates public exports.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • rapidsai/quent#497: Implements an entities Gantt chart with the shared Gantt component and utilities introduced here.
  • rapidsai/quent#446: Changes operator-timeline zoom behavior and minimum-span handling.
  • rapidsai/quent#447: Changes OperatorGanttChart axis and timeline behavior.

Suggested labels: non-breaking, ui

Suggested reviewers: cmatzenbach

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the Gantt chart implementation, which is the primary change, although the entities swimlanes reference is not implemented in this PR.
Description check ✅ Passed The description includes all required sections, related issue information, and testing notes; the optional screenshots section is empty.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx (1)

52-166: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add test coverage for the shared GanttChart component.

GanttChart centralizes zoom sync, wheel navigation, hover tracking, and empty-state handling for multiple consumers (operator Gantt now, entities Gantt planned). Unlike utils.ts and options.ts, this file has no colocated test. Add a GanttChart.test.tsx covering the empty-state render, the renderTooltip hover wiring, and the onChartReady/cleanup lifecycle with a mocked EChartsInstance.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx around lines 52
- 166, Add a colocated GanttChart.test.tsx covering empty-state rendering,
renderTooltip hover updates through observeGanttHover, and onChartReady cleanup
using a mocked EChartsInstance. Exercise the component with the required props
and verify axis-pointer synchronization, wheel-navigation attachment, hover
teardown, and unmount cleanup without changing GanttChart behavior.

Source: Path instructions

ui/packages/@quent/components/src/gantt-chart/options.test.ts (1)

7-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test coverage for the default gridSpacing fallback and the wheel/pan dataZoom entries.

The single test case always passes an explicit gridSpacing and only asserts dataZoom[0]. Add a case that omits gridSpacing to lock in the TIMELINE_SPACING default, and assert on dataZoom[1] and dataZoom[2] to guard the pan/zoom wheel behavior contract.

🧪 Suggested additional test cases
+  it('falls back to TIMELINE_SPACING when gridSpacing is omitted', () => {
+    const option = buildGanttOption({
+      data: [],
+      durationSeconds: 1,
+      yAxisCategories: [],
+      seriesName: 'test-series',
+      renderItem: vi.fn(() => null) as GanttRenderItem,
+      minZoomSpanPct: 2,
+    });
+    expect(option.grid).toMatchObject(TIMELINE_SPACING);
+  });
+
+  it('configures the pan and shift-zoom dataZoom entries', () => {
+    const option = buildGanttOption({
+      data: [],
+      durationSeconds: 1,
+      yAxisCategories: [],
+      seriesName: 'test-series',
+      renderItem: vi.fn(() => null) as GanttRenderItem,
+      minZoomSpanPct: 5,
+    });
+    expect((option.dataZoom as object[])[1]).toMatchObject({ type: 'inside', zoomOnMouseWheel: false });
+    expect((option.dataZoom as object[])[2]).toMatchObject({ type: 'inside', zoomOnMouseWheel: 'shift', minSpan: 5 });
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/packages/`@quent/components/src/gantt-chart/options.test.ts around lines 7
- 40, Extend the buildGanttOption tests with a case that omits gridSpacing and
verifies the grid uses the TIMELINE_SPACING defaults. In the existing or added
assertions, also validate dataZoom[1] and dataZoom[2] to cover the expected pan
and wheel-zoom configuration while preserving the current slider assertions.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx:
- Around line 74-81: Update the useMemo calculation in GanttChart to determine
maxRow without spreading data.map results into Math.max; use a loop or reduce
over data while preserving the empty-data result and existing yAxisCategories
and rowCount outputs.

---

Nitpick comments:
In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx:
- Around line 52-166: Add a colocated GanttChart.test.tsx covering empty-state
rendering, renderTooltip hover updates through observeGanttHover, and
onChartReady cleanup using a mocked EChartsInstance. Exercise the component with
the required props and verify axis-pointer synchronization, wheel-navigation
attachment, hover teardown, and unmount cleanup without changing GanttChart
behavior.

In `@ui/packages/`@quent/components/src/gantt-chart/options.test.ts:
- Around line 7-40: Extend the buildGanttOption tests with a case that omits
gridSpacing and verifies the grid uses the TIMELINE_SPACING defaults. In the
existing or added assertions, also validate dataZoom[1] and dataZoom[2] to cover
the expected pan and wheel-zoom configuration while preserving the current
slider assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 319a7a6f-bee3-4913-a901-277d75012ea8

📥 Commits

Reviewing files that changed from the base of the PR and between 4c5d674 and 34107cb.

📒 Files selected for processing (10)
  • ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx
  • ui/packages/@quent/components/src/gantt-chart/hover.ts
  • ui/packages/@quent/components/src/gantt-chart/options.test.ts
  • ui/packages/@quent/components/src/gantt-chart/options.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.test.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.ts
  • ui/packages/@quent/components/src/index.ts
  • ui/packages/@quent/components/src/operator-timeline/OperatorGanttChart.tsx
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts
  • ui/packages/@quent/components/src/operator-timeline/utils.ts
💤 Files with no reviewable changes (1)
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts

Comment thread ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx

@cmatzenbach cmatzenbach left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few general questions for you to consider, but other than that looks good!


useEffect(() => {
return () => {
chartCleanupRef.current?.();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In OperatorGantChart.tsx there was a comment ("empty data replaces the chart without unmounting"). Do we need to do something similar here or are we fine unmounting each time? i.e.

  return () => {
    if (data.length > 0) return;
    chartCleanupRef.current?.():
    ....

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That effect would run the cleanup function when there was 0 operators, but I think now we want to keep the xaxis pointer and mouse wheel effects even when there is no data so it's goneeee. This one will run the cleanup function when the component is unmounted so we don't leak mouse wheel listeners.

Comment thread ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx Outdated
Comment thread ui/packages/@quent/components/src/gantt-chart/options.ts Outdated
Centralize timeline chart behavior so the operator Gantt only owns its domain-specific rendering and interactions.
@johallar
johallar force-pushed the joe/long-entities-gantt-2 branch from bb8f59d to 60f1863 Compare August 4, 2026 19:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx-109-127 (1)

109-127: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Rebind hover listeners when renderTooltip changes.

observeGanttHover runs only from onChartReady. useChartConnect updates its callback ref but does not invoke it when renderTooltip changes. Toggle the observer in an effect keyed by the ready chart instance and renderTooltip != null; clear hover when disabled and clean up on chart replacement or unmount. Add a prop-toggle test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx around lines
109 - 127, The hover observer currently only binds during onChartReady, so
changing renderTooltip leaves stale listeners. Add an effect keyed by the ready
chart instance and renderTooltip state that attaches or removes
observeGanttHover, clears hover when disabled, and cleans up on chart
replacement or unmount; avoid duplicating hover cleanup in onChartReady, and add
a test covering the prop toggle.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/packages/`@quent/components/src/gantt-chart/options.test.ts:
- Around line 12-21: Add a test case for buildGanttOption that omits
gridSpacing, then assert the resulting option uses the TIMELINE_SPACING
defaults. Keep the existing explicit-gridSpacing case unchanged and ensure the
new test covers the fallback path.

---

Other comments:
In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx:
- Around line 109-127: The hover observer currently only binds during
onChartReady, so changing renderTooltip leaves stale listeners. Add an effect
keyed by the ready chart instance and renderTooltip state that attaches or
removes observeGanttHover, clears hover when disabled, and cleans up on chart
replacement or unmount; avoid duplicating hover cleanup in onChartReady, and add
a test covering the prop toggle.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: 67e7d127-a2fe-4ed7-97b7-f08845153668

📥 Commits

Reviewing files that changed from the base of the PR and between ea1e716 and bb8f59d.

📒 Files selected for processing (10)
  • ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx
  • ui/packages/@quent/components/src/gantt-chart/hover.ts
  • ui/packages/@quent/components/src/gantt-chart/options.test.ts
  • ui/packages/@quent/components/src/gantt-chart/options.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.test.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.ts
  • ui/packages/@quent/components/src/index.ts
  • ui/packages/@quent/components/src/operator-timeline/OperatorGanttChart.tsx
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts
  • ui/packages/@quent/components/src/operator-timeline/utils.ts
💤 Files with no reviewable changes (1)
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts

Comment thread ui/packages/@quent/components/src/gantt-chart/options.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/packages/@quent/components/src/index.ts (1)

242-260: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Export GanttChart from the package root.

The barrel exports the new utilities but not the reusable GanttChart component. External package consumers cannot use the shared component through @quent/components.

Export GanttChart, GanttChartProps, and the public Gantt contracts from this barrel.

As per path instructions, each package must expose its public API through src/index.ts.

Proposed fix
 // ─── Operator-timeline components ────────────────────────────────────────────
+export { GanttChart } from './gantt-chart/GanttChart';
+export type {
+  GanttChartProps,
+  GanttDatum,
+  GanttGridSpacing,
+  GanttRenderItem,
+} from './gantt-chart/GanttChart';
+export type { GanttHover } from './gantt-chart/hover';
 export { OperatorGanttChart } from './operator-timeline/OperatorGanttChart';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/packages/`@quent/components/src/index.ts around lines 242 - 260, Update
the package-root barrel in src/index.ts to export the reusable GanttChart
component, its GanttChartProps type, and the public Gantt contracts from their
existing modules. Keep the current operator-timeline and utility exports
unchanged, and ensure these APIs are accessible to external consumers through
the package root.

Source: Path instructions

🟡 Other comments (1)
ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx-157-163 (1)

157-163: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear stale hover state when data disappears.

Line 163 hides the tooltip but retains hover. If data becomes empty and later returns, the previous tooltip can render before the next pointer event.

Reset hover when data.length becomes zero.

As per path instructions, clear synchronized visualization state when data disappears, even if the component remains mounted.

Proposed fix
+  useEffect(() => {
+    if (data.length === 0) {
+      setHover(null);
+    }
+  }, [data.length]);
+
   return (
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx around lines
157 - 163, Reset the GanttChart hover state when data becomes empty, rather than
only hiding the tooltip. Add an effect tied to data length that clears hover
when data.length reaches zero, while preserving the existing renderTooltip
behavior for non-empty data.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx:
- Line 21: Update the CHART_GROUP import in GanttChart.tsx to use its exported
module, ../timeline/types, instead of ../timeline/Timeline; leave the remaining
chart logic unchanged so the TypeScript build passes.

---

Outside diff comments:
In `@ui/packages/`@quent/components/src/index.ts:
- Around line 242-260: Update the package-root barrel in src/index.ts to export
the reusable GanttChart component, its GanttChartProps type, and the public
Gantt contracts from their existing modules. Keep the current operator-timeline
and utility exports unchanged, and ensure these APIs are accessible to external
consumers through the package root.

---

Other comments:
In `@ui/packages/`@quent/components/src/gantt-chart/GanttChart.tsx:
- Around line 157-163: Reset the GanttChart hover state when data becomes empty,
rather than only hiding the tooltip. Add an effect tied to data length that
clears hover when data.length reaches zero, while preserving the existing
renderTooltip behavior for non-empty data.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: a5192793-871b-4d57-99db-e2053c3ea729

📥 Commits

Reviewing files that changed from the base of the PR and between bb8f59d and 60f1863.

📒 Files selected for processing (10)
  • ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx
  • ui/packages/@quent/components/src/gantt-chart/hover.ts
  • ui/packages/@quent/components/src/gantt-chart/options.test.ts
  • ui/packages/@quent/components/src/gantt-chart/options.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.test.ts
  • ui/packages/@quent/components/src/gantt-chart/utils.ts
  • ui/packages/@quent/components/src/index.ts
  • ui/packages/@quent/components/src/operator-timeline/OperatorGanttChart.tsx
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts
  • ui/packages/@quent/components/src/operator-timeline/utils.ts
💤 Files with no reviewable changes (1)
  • ui/packages/@quent/components/src/operator-timeline/utils.test.ts

Comment thread ui/packages/@quent/components/src/gantt-chart/GanttChart.tsx Outdated
@johallar

johallar commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit c48e7fc into rapidsai:main Aug 4, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants