[schedule] Reduce render, drag and network overhead#2142
Open
frankrousseau wants to merge 24 commits into
Open
[schedule] Reduce render, drag and network overhead#2142frankrousseau wants to merge 24 commits into
frankrousseau wants to merge 24 commits into
Conversation
A forced daily quota of 0 (or a field emptied by keyboard, which yields an empty string that ?? does not catch) made taskEstimation infinite: addBusinessDays then looped forever and froze the tab on Apply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The editable flag of root task-type bars was only computed in loadData, with the default mode and version. Switching to the real mode or to a locked version (or arriving with ?mode=real in the URL) kept the bars draggable, and drags were persisted on a schedule that should be locked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A multi-assignee task renders one bar per assignee, but reassigning a bar always removed assignees[0], which could unassign the wrong person server-side. The drag now remembers the person row it started on. The drag handler also mutated the assignees list before emitting item-assign, whose handler pushes the new assignee again: the id ended up duplicated. The page handlers now own those updates, and the unassign handler skips the API call for the local 'unassigned' row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Task dates are not clamped to the production range, so a task starting before or ending after it had no entry in the displayed-days index: dragging its bar silently did nothing (NaN length) and dragging its left handle threw on every mousemove tick (newStartDate undefined). The index lookups now resolve out-of-range dates to the nearest boundary, changeStartDate guards against a missing day and the changeEndDate clamp compares against the arrays instead of a .length that never existed on the index objects. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
getDisplayedWeeksIndex called startOf('isoweek') on the moment it
received, mutating it in place. In week zoom, resizing a bar snapped
the item's real end date back to its week's Monday without validation,
and the change was then persisted. The week-mode drag also assigned
the weeksAvailable moments to items without cloning, aliasing the
header entries with the item dates.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Selecting or dragging an entity-type row replaced its children array with the filtered (unassigned only) list. The assigned entities were gone for good: toggling "show assigned" never brought them back. The dragged entry is now a copy carrying the filtered children. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
loadData had no catch: a failed load left an unhandled rejection, never raised errors.schedule and aborted the query-param restore. The version edit and delete flows closed their modal before awaiting the API call, and their error flags were never set, so failures were invisible. The modals now stay open until the call succeeds and show the error state. loading.delete, bound in the template, was also missing from data(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The zoom watcher called onTimelineScroll(null, ...), which returns immediately on a null event and ignores a second argument: the intended scroll reset never happened. Reset the wrapper and header scroll positions directly instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The task-type fills passed 6-digit hex values where ExcelJS expects 8-digit ARGB (as the header already does with FFDDDDDD): Excel read the first byte as alpha and rendered wrong colors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
expandAll was toggled without being declared in data(), the task end-date fallback was duplicated verbatim, getNbSubChildren was unused (and read a Map with Object.values, always yielding 0) and weeksAvailable stamped properties on Date objects that nothing reads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The document-level mousemove/touchmove listeners lived for the whole component lifetime and forced a layout (getBoundingClientRect) plus a style write on every mouse move anywhere on the page. They are now attached on interaction start and removed on release. The hover position bar is driven by a local listener on the timeline wrapper, throttled with requestAnimationFrame and reading a cached rect that is invalidated on resize and zoom. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Expanding a task type loaded the tasks and the entities, then called selectTaskTypeElement which fetched the exact same tasks and entities again: two full asset (or shot/sequence/episode/edit) fetches and two task fetches per expand. The expand now hands its unversioned task list to the side panel, which skips the redundant loads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each entity-type branch filtered every asset/shot/sequence/episode/edit with tasks.some(entity_id === id), an O(entities x tasks) scan on every side-panel refresh. A Set built once replaces the linear lookups. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
isSelected scanned the selection array for every bar on every render. A computed Set of selected ids turns it into an O(1) lookup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gaming mice fire mousemove far above the display refresh rate, and each event ran the full drag pipeline (date computations, item positions). The handler now processes only the latest event per animation frame. The pan-scroll switches from per-event movementX/Y to the cumulative client delta so skipped events lose no distance, and a pending frame is cancelled on release so it cannot move the item after the drop is saved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
saveAssignments fetched the schedule-version tasks inside the entity loop, one HTTP request per entity, although they all belong to the selected task type. They are now loaded once and indexed by task id. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
saveAssignments awaited one updateTask round-trip per entity in sequence, so applying assignments on a large selection took dozens of seconds. The updates are collected during the distribution loop and flushed in small parallel batches. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The distribution loop searched the full task list for every entity, an O(entities x tasks) scan per assignment run. A Map built once replaces the linear find. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every task-type expand refetched the production days off although they only depend on the production and the schedule range. The result is kept until the production or the range changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The line packing allocated one array cell per day of the range for every line (hundreds of cells per line on long schedules) and recursed per collision, and it runs on every drag tick. Per-line interval lists give the same first-free-line assignment without the allocations or the recursion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The template expanded every root's and person's daysOff array with getDayOffRange on each render, reallocating the ranges over and over. A WeakMap keyed on the source array caches the expansion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pages with timesheets filtered the root's full timesheet list for every child row on every render, an O(rows x timesheets) scan. The timesheets are grouped by task id once per source array and cached in a WeakMap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
daysAvailable ran an includes() over the expanded day-off list for every displayed day, O(days x days off) on each recompute. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The week list walked the whole range day by day, formatting and reparsing a moment for each day just to keep the Mondays. Jumping seven days at a time from the first Monday gives the same list with a seventh of the iterations and no reparse. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Solution
Note: stacked on #2141, only the 14
perfcommits are new here.