Skip to content

feat(work-item): make the Gantt timeline interactive (zoom + drag-to-reschedule) - #310

Merged
martian56 merged 2 commits into
Devlaner:mainfrom
cavidelizade:feat/interactive-gantt
Jul 13, 2026
Merged

feat(work-item): make the Gantt timeline interactive (zoom + drag-to-reschedule)#310
martian56 merged 2 commits into
Devlaner:mainfrom
cavidelizade:feat/interactive-gantt

Conversation

@cavidelizade

@cavidelizade cavidelizade commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Feature summary

The Gantt/Timeline layout is now interactive: you can zoom the day scale and drag work-item bars to reschedule them (move or resize), instead of only reading a static timeline.

Linked issues / discussion

Closes #180

User-facing behavior

On a project's work items, switch to the Timeline (Gantt) layout:

  • Zoom — new toolbar controls step the day scale in/out (14–56 px/day).
  • Drag to reschedule — drag a bar to move its start + target together; drag the left edge to change just the start, or the right edge to change just the target. A live preview follows the cursor and commits on release. Resizing clamps so an edge can't cross the opposite one.
  • A drag doesn't navigate; a plain click still opens the work item. Bars are only draggable when editing is available.

Changes persist through the same PATCH the list/board/calendar layouts already use for inline date edits.

What changed

UI (apps/web/)

  • IssueLayoutGantt.tsx: zoom state + controls; pointer-based drag (move / resize-start / resize-end) tracked in a ref with a state-mirrored preview so the render never reads a ref; commits via onUpdateIssue with YYYY-MM-DD dates (matching the calendar's format).
  • IssueListPage.tsx: passes onUpdateIssue={handleInlineUpdate} to the Gantt.

API / Database

  • None (reuses the existing issue PATCH).

Why this design

Reused the shared onUpdateIssue inline-update path so Gantt edits go through the same optimistic-update + serialized-PATCH machinery as the other layouts (no new endpoint, consistent behavior). Drag state lives in a ref so the global pointer listeners read live values without re-subscribing each move, and it's mirrored into a small state object purely for the preview render (keeping the render ref-free, which the React Compiler lint requires). Kept the scope to drag + zoom; dependency lines between bars are a natural follow-up.

Test plan

  • npm run validate (typecheck + lint + prettier) green
  • Manual end-to-end (Playwright) on a project with dated issues:
    • Move-drag a bar +4 days → both start and target shifted (persisted)
    • Resize the right edge +3 days → target extended, start unchanged (persisted)
    • Zoom in → bars widen (192px → 276px)
  • Tested at narrow viewport

Out of scope (follow-ups)

  • Dependency lines / arrows between bars
  • Drag on touch devices (basic pointer events are used; fine-tuning deferred)
  • Creating dates by dragging an undated item onto the timeline

AI assistance

  • AI tools were used — tool(s): Claude Code (Claude Opus 4.8) — and AI-assisted commits include a Co-Authored-By: trailer

Checklist

  • PR title follows Conventional Commits and is ≤ 100 chars
  • Acceptance criteria from the linked issue are met (interactive drag + zoom; dependencies noted as follow-up)

Summary by CodeRabbit

  • New Features

    • Added zoomable timelines to the Gantt view.
    • Added panning controls for navigating the visible date range.
    • Added drag-and-drop rescheduling for dated work items, including resizing and date updates.
    • Added keyboard-accessible navigation for Gantt items.
  • Bug Fixes

    • Enabled Gantt updates to use the same inline editing behavior as other work item views.
    • Prevented accidental item navigation after dragging.

…reschedule)

The Gantt was a read-only timeline. It now supports:

- Zoom: step the day scale in/out with toolbar controls (14-56 px/day).
- Drag-to-reschedule: drag a bar to move start + target together, or drag
  either edge to change just the start or the target. Changes commit through
  the existing onUpdateIssue path (same PATCH the list/board/calendar use), with
  a live preview while dragging and clamping so a resized edge can't cross the
  other. A drag doesn't trigger navigation; a plain click still opens the issue.

Dependency lines between bars are a planned follow-up.

Closes Devlaner#180

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cavidelizade
cavidelizade requested a review from a team as a code owner July 13, 2026 14:09
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@cavidelizade, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 43 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f05b6d45-aeb5-4ecf-9125-6f838344e1e3

📥 Commits

Reviewing files that changed from the base of the PR and between 9f111b9 and d871b2f.

📒 Files selected for processing (1)
  • apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx
📝 Walkthrough

Walkthrough

IssueLayoutGantt now provides zoomable and pannable timeline views, interactive bar movement and resizing, preview rendering, and persisted date updates. IssueListPage supplies its inline update handler so Gantt edits use the existing issue update path.

Changes

Gantt interactivity

Layer / File(s) Summary
Zoomable timeline window
apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx
Adds zoom levels, zoom controls, view-window-aware date ranges, and zoom-dependent timeline sizing.
Drag rescheduling and persistence
apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx, apps/web/src/pages/IssueListPage.tsx
Adds move and edge-resize dragging with previews, clamped date calculations, keyboard-accessible navigation, click suppression, formatted date patches, and inline update-handler wiring.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant IssueLayoutGantt
  participant Window
  participant IssueListPage
  User->>IssueLayoutGantt: Drag a dated bar or resize handle
  IssueLayoutGantt->>Window: Track pointer movement and release
  Window->>IssueLayoutGantt: Send pointer events
  IssueLayoutGantt->>IssueLayoutGantt: Preview and calculate date changes
  IssueLayoutGantt->>IssueListPage: Submit formatted date patch
Loading

Possibly related PRs

Suggested labels: UI, enhancement

Suggested reviewers: martian56

Poem

I’m a rabbit with a timeline to hop,
Dragging each date to its proper stop.
Zoom in close, zoom out wide,
Bars now dance from side to side.
Updates thump where patches belong—
Gantt hops forward with a song!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is conventional, concise, and clearly summarizes the main change: making the Gantt timeline interactive with zoom and drag-to-reschedule.
Description check ✅ Passed The description covers the summary, linked issue, user-facing behavior, implementation notes, tests, and rationale; only optional template sections are omitted.
Linked Issues check ✅ Passed For [#180], the PR implements drag, edge-resize, and zoom, while leaving optional dependency lines as follow-up.
Out of Scope Changes check ✅ Passed The diff stays focused on Gantt interactivity and the page prop wiring, with no unrelated or extra scope changes evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx (1)

60-89: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use calendar-day arithmetic instead of fixed 24-hour milliseconds.

These local dates are added and divided using DAY_MS. Across daylight-saving transitions, headers can duplicate/skip dates and dragging by one day can serialize an unchanged or skipped date. Use calendar-day add/difference helpers throughout the window and drag calculations.

Also applies to: 380-412

🤖 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 `@apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx` around lines
60 - 89, Replace fixed DAY_MS arithmetic in the IssueLayoutGantt viewWindow,
days generation, todayOffset, and drag calculations with the existing
calendar-day add/difference helpers. Preserve the current padding, shifting, and
date-range behavior while ensuring one-day movement and serialization remain
correct across daylight-saving transitions.
🤖 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 `@apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx`:
- Around line 294-295: Update the bar positioning logic in IssueLayoutGantt
around offset and span to intersect each issue’s [start, end] range with
viewWindow, omit bars with no overlap, and calculate offset/span from the
clipped range rather than clamping the original offset to zero.
- Around line 102-153: Update the drag gesture state used by beginDrag, the
pointermove/pointerup handlers, and the related click suppression logic to track
pointerId and movement in pixels, suppressing navigation once the configured
pixel threshold is crossed rather than only after deltaDays changes. Handle
pointercancel by clearing the active drag and preview, and ensure suppression is
consumed only by the matching pointer’s click and expires when that gesture does
not produce one.

---

Outside diff comments:
In `@apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx`:
- Around line 60-89: Replace fixed DAY_MS arithmetic in the IssueLayoutGantt
viewWindow, days generation, todayOffset, and drag calculations with the
existing calendar-day add/difference helpers. Preserve the current padding,
shifting, and date-range behavior while ensuring one-day movement and
serialization remain correct across daylight-saving transitions.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9710867c-f6c9-4899-a156-6ec5c9b6a7ef

📥 Commits

Reviewing files that changed from the base of the PR and between dc28bb0 and 9f111b9.

📒 Files selected for processing (2)
  • apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx
  • apps/web/src/pages/IssueListPage.tsx

Comment thread apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx
Comment thread apps/web/src/components/work-item/layouts/IssueLayoutGantt.tsx Outdated
…he window

Address review findings on the interactive Gantt:

- Distinguish click from drag by a pixel threshold on the whole gesture, and
  resolve navigation in the pointer-up handler (a click, i.e. no meaningful
  move, opens the item) instead of a separate onClick guarded by a suppress
  flag. A sub-day drag no longer navigates, and a drag released off the bar no
  longer swallows a later click.
- Clip each bar to the visible window: a bar with no overlap renders as an empty
  row (preserving sidebar alignment) rather than being pinned to the first
  column after panning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cavidelizade

Copy link
Copy Markdown
Contributor Author

@martian56 addressed both CodeRabbit notes (pixel-threshold click/drag detection + clipping bars to the visible window). Green with no open comments — good to merge. Interactive drag-reschedule + zoom; dependency lines noted as a follow-up.

@martian56
martian56 merged commit d336163 into Devlaner:main Jul 13, 2026
2 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.

[IMPROVEMENT] Make the Gantt/Timeline layout interactive (drag, zoom, dependencies)

2 participants