Previously viewStart defaulted to today-30 and the scroll container had
no left-edge expansion logic, so users hit a hard wall when scrolling
left. This change:
- Sets viewStart default to today so the viewport opens with today at
the left edge (URL ?startDate= override still respected).
- Adds left-edge auto-expansion in handleContainerScroll: when the user
scrolls within 40 cells of the left boundary, 120 days are prepended
and a useLayoutEffect applies the matching scrollLeft compensation in
the same paint frame to prevent a visual jump.
- Floors backward navigation at 5 years (minDate) to prevent unbounded
viewDays growth.
- Updates handleNavigateToday to match: resets to today rather than
today-30.
Both resource view and project view use the same TimelineContext /
TimelineView, so both are fixed by this change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract overlay/popover JSX from TimelineView (1268→1037 lines) into TimelineDragOverlays and
TimelinePopovers. Extract ResourceMonthConfigSection from ReportBuilder (1132→1018 lines).
Extract ResourceSkillsEditor and ResourceOrgClassification from ResourceModal (1035→714 lines).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- useInvalidateTimeline and useInvalidatePlanningViews now return
Promise.all instead of fire-and-forget void calls
- Timeline mutations now use useInvalidatePlanningViews to also
invalidate allocation list views, preventing stale data
- AllocationsClient sequential awaits replaced with single
invalidatePlanningViews() call (parallel invalidation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces unnecessary re-renders by separating the monolithic 20+ property
context into TimelineDataContext, TimelineViewContext, and
TimelineDisplayContext. Panel components now subscribe only to the
slices they need.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Install husky v9 + lint-staged: pre-commit runs eslint --fix and prettier on staged files
- Tighten ESLint base config: no-console→error, ban-ts-comment (ts-ignore banned, ts-expect-error with description allowed), reportUnusedDisableDirectives→error
- Migrate web app from deprecated `next lint` to `eslint src/` with flat config and react-hooks plugin
- Convert all 5 @ts-ignore to @ts-expect-error with descriptions, remove stale disable comments
- Add NEXT_PUBLIC_SENTRY_DSN to docker-compose.prod.yml and .env.example
- Add coverage artifact upload step to CI test job
- Pre-existing violations (102 warnings) downgraded to warn in web config for Phase 2 cleanup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents redundant re-renders when parent state changes by stabilising
event handler references and memoising expensive derived data in
TimelineView, TimelineResourcePanel, and TimelineProjectPanel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tracks scroll position via requestAnimationFrame to avoid re-renders
on every pixel. Allocation bars outside the visible horizontal window
(+ 10-column overscan) are skipped during render, reducing DOM nodes
significantly at day zoom (365 days × 40px = 14,600px canvas).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Double-clicking an allocation bar opens an inline editor overlay
with start date, end date, and hours/day fields. Saves via
trpc.allocation.update, closes on Escape or click outside.
Only visible to users with manage permissions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- #47: Remove misleading asterisk from Budget (EUR) label in project
wizard — budget is optional per canGoNext() logic
- #48: Parse Zod validation JSON in wizard submit error handler so users
see "Responsible person is required" instead of raw JSON array
- #45: Expose isEntriesError from timeline query context; TimelineView
now renders an explicit error message instead of a silent empty canvas
when the getEntriesView query fails
Co-Authored-By: claude-flow <ruv@ruv.net>
The scroll container's relative positioning created a stacking context
that rendered its children (z-30 sticky labels) above the toolbar's
dropdown (z-[60]). Adding z-0 to the scroll container explicitly places
it below the toolbar's z-20 stacking context, allowing dropdowns to
render on top.
Co-Authored-By: claude-flow <ruv@ruv.net>
- ResourceHoverCard: add isInitialLoading to useEffect deps so
mouseover/mouseout listeners attach after canvas mounts
- PreferencesModal: lift prefsOpen state to AppShell, render modal
outside sidebar's backdrop-blur stacking context
- Timeline page: constrain to max-h-[100dvh] overflow-hidden so
horizontal scrollbar is accessible without scrolling to bottom
- Multi-drag: pass selectedAllocationIds from ref at drag completion
to prevent stale closure in onMultiDragComplete callback
Co-Authored-By: claude-flow <ruv@ruv.net>
- Extract shared render helpers (vacation blocks, range overlay, overbooking blink) into renderHelpers.tsx
- Centralize status badge styles and vacation color maps into status-styles.ts
- Extract dragMath.ts utility from useTimelineDrag for reuse
- Split useInvalidatePlanningViews into useInvalidateTimeline (4 queries) + useInvalidatePlanningViews (8 queries)
- Adopt findUniqueOrThrow() and Prisma select constants across API routers
- Add shared fmtEur() helper for API-side money formatting
- Wrap TimelineResourcePanel and TimelineProjectPanel with React.memo
- Fix pre-existing TS2589 deep type errors in TeamCalendar and VacationModal
- 38 files changed, reducing ~400 lines of duplicated code
Co-Authored-By: claude-flow <ruv@ruv.net>
Redesigned timeline project and resource panels with expanded detail views,
added quick filter toolbar, improved drag handling, and enhanced vacation/entitlement
router logic. Includes e2e test updates and minor API fixes.
Co-Authored-By: claude-flow <ruv@ruv.net>