Fix the entity lists loaded for another episode, and various improvements - #2195
Merged
Conversation
Spreading k sequence arrays as call arguments risks a RangeError past the engine argument limit, which varies with the remaining stack depth. flat() has the same complexity without going through the argument stack.
Four chained concat calls allocated four arrays per asset where one literal with spreads does the same job. Word order is unchanged, so the resulting index is identical.
Registering vue-date-picker globally pinned @vuepic/vue-datepicker and its CSS to the entry payload for every page, while DateField is the only component that renders one. Importing it locally drops the entry preload by 69.4 kB gzipped.
chartjs-adapter-date-fns pulled date-fns into the charts chunk, and the oxc lowering helpers that chunk shares with the entry pinned it to the initial payload: chart.js was downloaded on the login screen, before authentication. Isolating those helpers in their own group and registering the chartkick tags with defineAsyncComponent drops the entry preload by 88.0 kB gzipped, from 488.7 to 400.7 kB.
The guard forces an empty search field, so the nextTick onSearchChange falls into resetTasks(), which calls resetTaskIndex() on the same data one microtask after the explicit call did. Nothing reads taskIndex in between, so the first rebuild is dead work: 99 ms at 2000 entities, 277 ms at 5000. The handler also fired on tasks belonging to another task type, which getTasks filters out anyway, so the rebuild could not change anything on screen.
NEW_TASK_COMMENT_END only touches an entry of state.todos / state.personTasks. The done lists come from a separate fetch (is_done=True) and share no object with them, so rebuilding doneIndex and personDoneTasksIndex re-indexed untouched data on every posted comment.
The topbar commits the new current episode before the page instance exists (Main.vue renders it ahead of the router view, so its $route watcher is a pre-flush job of lower uid). Assets.vue's currentEpisode watcher, the only trigger reloading on a scope change, therefore cannot fire when the route lands from another page: coming back from a task type on another episode kept displaying the previous episode's assets until a manual reload. mounted() only tested the shape of the cache (map size, validation columns, validations of the first asset), never the scope it was loaded for. The store now records that scope, the way the shots store already does, and the page compares it. Assets cast in from other episodes are legitimate rows of an episode load, so the check cannot be based on the rows themselves. Two other paths to the same stale list: loadAssets() handed its in-flight promise to any caller regardless of the episode requested, and reset() bailed out on isAssetsLoading, dropping an episode switch made during a load.
Same staleness as the asset list: the topbar commits the new current episode before the page instance exists, so the currentEpisode watcher cannot fire when the route lands from another page, and mounted() only tested the shape of the cache, never the scope it was loaded for. The load already computed that scope to queue concurrent loads, but kept it in the non reactive module cache, where a getter would have been pinned to its first value. It moves to the state, records 'all' as itself so a page can compare it with the episode it displays, and the chained reload now waits for the loading flag to be down, which a response discarded on a production switch would otherwise leave up forever. The section watcher went through this.edits, which the page never mapped: it threw a TypeError on every section change instead of reloading.
Same staleness as the asset and edit lists: the topbar commits the new current episode before the page instance exists, so the currentEpisode watcher cannot fire when the route lands from another page. mounted() compared the production of the first cached sequence, which holds just as well for an episode of the same show, and the section watcher compared the episode of the first displayed row, which an empty search result or a production-wide dataset defeats. The load now records the scope it fetched, 'all' included, and the page compares it.
initTaskType resolved without loading as soon as the entity map held two rows, whatever episode had filled it. Reaching a task type page on another episode (a bookmark, a browser back, a topbar switch) therefore kept the map of the previous one, and the page, which filters on the current episode, showed an empty list. The asset, edit, sequence and shot stores now all record the scope they fetched, so the cache can be compared with the episode being displayed instead of being trusted on its size alone.
loadEditsData compared the production of the first cached edit, which holds just as well for another episode of the same show, while loadShotsData right above it already compared the episode. It now compares the scope the edits store records, which also tells the all pseudo-episode from a real one.
The validation headers of a list are rendered twice, once for the pinned columns and once for the scrolling ones, and the pinned block was a copy that kept the type of the list it was copied from: shots offered 'assets', sequences and episodes offered 'editor'. Nothing reads that segment of the task type URL except the topbar, which derives the current section from it. An unknown value resolves to no section at all, and switching episode from a task type reached through a pinned column lands on the production homepage instead of the list left behind. The added test compares both blocks of every list, since the defect comes from the duplication rather than from any one value.
Without `enabled`, Vitest disables optimizeDeps and the `include` list was dead config. sanitize-html stays out: pre-bundled for the client it pulls postcss and its fs/path/url access, which Vite externalizes with a warning per spec file.
- Add sequences/episodes/edits.fields.time_spent: the lists and the CSV exports already displayed them, so the raw key was showing up. - Point the task type modal at playlists.change_task_type_error, the key it asked for lived under a playlist namespace that does not exist. - Restore the leading space of notifications.and_change_status and drop the preposition that duplicated to_status in ten locales. - Leave people.role.undefined empty everywhere, as en.js does. - Add the final period on the sentences that lacked it and tighten the markdown lists of the quota explanations.
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
currentEpisodewatcher cannot fire, and the loaded rows say nothing about the scope they belong to.Solution
playlists.change_task_type_errorkey.DateField, and isolate the oxc runtime helpers in their own chunk so they stop pulling the charts chunk into the entry graph.Note
The
helperschunk group invite.config.jsmatches a rolldown-internal virtual module ID. If that format changes, the group silently stops matching, and the entry graph reverts to its previous shape, which is a size regression rather than a crash.