An entry revision advances on every change to that entry, which makes it a
cheap marker for what has moved on in a rundown. The client did not maintain
it: an optimistic entry carried the old revision, so the entry the server
returned always differed from ours by that one field.
That difference is enough to defeat structural sharing. A new entries object
recomputes the rundown metadata, which fires the effect behind the list, which
re-renders every visible row. Editing one title on a fourteen entry rundown
cost eight structural and sixty-one attribute mutations, twice over.
- optimistic patches apply the same revision bump the server does, so an
unchanged entry keeps its identity and a refetch costs nothing to render
- the rundown metadata memo keys on the fields the derivation reads, so a
change of rundown revision alone no longer churns the list
- editing an entry now reads the server response, which is the authority on
what was applied, and only writes when it differs from what we predicted
Measured on the same edit: eight to four structural, sixty-one to forty-one
attribute mutations. Both changes are needed, neither helps on its own.
Two bugs found on the way. A swap stored the pre increment revision, so
swapped entries were indistinguishable from untouched ones. The optimistic
batch edit spread the request envelope onto the entry rather than the patch,
so it never applied the edit it was predicting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011a5cbVjNC5XXF88b2PkUCa
Only the editor and the cuesheet can be pointed at a background rundown.
Everything else always works against the rundown being played, so it has
no business taking part in a rundown scope.
Split the readers by that assumption:
- useRundownById holds the query and the shared derivation
- useRundown reads from the enclosing scope, for the editor and cuesheet
- useLoadedRundown resolves the loaded rundown directly, for the viewers,
the operator, app settings and the overview
This drops the app wide scope provider, so views which read no rundown
(studio, project info) no longer subscribe to the rundown list, and a
scope becomes what it claims to be: a panel concern which throws when
used outside a panel.
It also fixes the overview, which reads runtime ids (the playing group,
the next flag). Those only exist in the loaded rundown, so resolving them
against a scope returned nothing while a background rundown was open in
the cuesheet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011a5cbVjNC5XXF88b2PkUCa
- extract getRundownCacheKey, the fallback to the bootstrap alias for an
unresolved rundown id was spelled out in two readers and missing in the
selection store, which could not resolve shift/ctrl ranges during startup
- an unresolved target is no longer reported as the loaded rundown, it was
briefly enabling run mode and playback following before a rundown existed
- only the reader which bootstrapped drops the /current alias, a reader on
another rundown was evicting a cache others still relied on
- the selection store returns a new Set on toggle and unselect, components
selecting the set by reference never saw the change
- useSelectAndRevealEntry takes its rundown from the scope, callers were
threading an id for no other reason
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011a5cbVjNC5XXF88b2PkUCa
The editor and cuesheet had three overlapping notions of which rundown
they were showing: loaded-only data hooks, a prop-drilled RundownSource,
and a selection store which read the loaded rundown out of the query
cache. Rendering two rundowns at once was not possible.
Introduce a rundown scope: a context carrying the rundown identity
(id, isLoaded and a selection store) which the utility hooks read from.
useRundown, useEntry and friends keep their signatures and call sites,
they simply resolve their rundown from the enclosing scope. The app
mounts a scope at the root which follows the loaded rundown, so runtime
views are unaffected; the editor and cuesheet mount an editable scope
which also binds entry actions to the same rundown.
- useEventSelection becomes a per-scope store factory, so panels hold
independent cursors and the store is handed its rundown instead of
reaching for the loaded one
- the cuesheet selection is generalised to useRundownSelection with a
namespace, so each surface persists its own choice
- the clipboard records the rundown an entry was copied from, leaving
room for pasting across rundowns
- removes useScopedRundown and the prop-drilled RundownSource
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011a5cbVjNC5XXF88b2PkUCa
* refactor: allow secondary rundowns
* ui: move dropdown
* feat: follow loaded
* ui: background edit warning
ui: fix disable radio button
* feat(ui): add loaded sufix in the rundown list
* feat(ui): add direct link to background edit from rundown manager
* fix: better fallback
* fix: default to is isCurrentRundown for nav bar colour
* chore: rename navigate to cuesheet
---------
Co-authored-by: alex-arc <ac@omnivox.dk>
* chore: migrate eslint to oxlint
* chore: migrate prettier to oxfmt
* chore: migrate typescript
* chore: toThrow should have a expected value
* chore: cast test value as Day
* chore: small title fix
* chore: mocks should be hoisted
* chore: incorrect async useage
* chore: test should be inside description
* chore: test sohuld include an expeced
* chore: oxfmt
---------
Co-authored-by: alex-Arc <omnivox@LAPTOP-RC5SNBVV.localdomain>
* refactor: use correct metadata in op view
* refactor: use correct metadata in backstage view
* remove uneeded test
* fix: correct offset colour
* refactor: use correct metadata in timline view
* refactor: schedule item dont pass the whole event
* chore: lint
* refactor: align header columns
* refactor: improve scrollbar visibility
* refactor: center align table elements
* refactor: make param elements stateful
* fix: issue with collapsed elements not loosing value
* fix: prevent search params containing multiple alias references
* fix: the issue where a file disappears if it is both migrated and recovered in the same load operation (#1744)
* refactor: disable group action for elements in groups
* refactor: move context menu items into the event element (#1747)
* feat: sheet import new features for v4 (#1730)
* import milestone
* fixup! import milestone
* test: milestone import
* add entries to group
stop on new group or on group-end type
* fixup! add entries to group
* cleanup
* add event target duration
* link start if undefined
* add skip import type
* extract some to the excel paresing functions
* tweaks to presentation
* move file
---------
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
* fix: notify runtimeStore of events bieng groupd
* fix: improve authentication and stage detection in demo
* chore: ship logo with project
* fix: client is referenced by name
* fix: prevent reflow in event editor
* fix: stale render on selected event due to ref mismatch
* Create/Load/Delete multiple rundowns (#1696)
* refactor: restore last loaded rundown
* refactor: initialise rundown in ProjectService
* feat: allow switching rundowns
ensure on coordination between the db object and the working object
server provide list of rundowns
implement switch in the UI
implement delete
implement new rundown button
* fix: render order for floating button
* refactor: appropriate names to service
* refactor: rundown endpoints
* refactor: save last loaded rundown ID
* refactor: rundown management UI
* refactor: emit refetch all on project load
---------
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
* feat: recover single event subscription
* fixup! feat: sheet import new features for v4 (#1730)
* fix: prevent dropping a group inside another
* fixup! refactor: move context menu items into the event element (#1747)
* fix: prevent stale references to custom fields
* fix: propagate updates to all rundowns
* refactor: client rundown metadata (#1728)
* generate metadata in the hook
* move test
* ensure there is always a last element
* use for-loop
* update metadata in useEfect
* fully extract metadata generation
* use direct assignment
* cleanup
---------
Co-authored-by: Carlos Valente <carlosvalente@pm.me>
* refactor: small imporvement and tests for coerce functions (#1752)
* refactor: small imporvement and tests for coerce functions
add test `coerceString`
add test `coerceBoolean`
add test `coerceColour`
* remove old todo
* fix: consistent quick add behaviour
* refactor: create flat rundown with metadata
* fix: show add buttons on top
* feat: allow editing milestones
* refactor: style tweaks to rundown elements
refactor: milestones are full width
refactor: cuesheet header alignment
fix: editor styling in cuesheet
* refactor: virtualise table
* refactor: improve overscan (#1758)
* bump version to 4.0.0-alpha.5
---------
Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
* Revert "refactor: add version to session endpoint"
This reverts commit cd40a6e55e.
* Revert "Remove public event feature (#1645)"
This reverts commit 08d9e24871.
* Revert "Fix: rearrange playing event (#1640)"
This reverts commit 0649678dca.
* Revert "refactor: style tweaks to edit css modal"
This reverts commit a00ec2d02a.
* Revert "refactor: remove usages of framer-motion"
This reverts commit 54a74ccc2a.
* Revert "Upgrade expressjs (#1633)"
This reverts commit 6f3ab274bd.
* Revert "Refactor: require trigger in all events objects (#1636)"
This reverts commit 90870ecfb6.
* Revert "Fix: Correct boundary condition in applyDelay"
This reverts commit b640e0e181.
* Revert "let vite be the proxy to the dev server (#1630)"
This reverts commit c41fe824cf.
* Revert "refactor: migrate custom fields to transactions"
This reverts commit 62c8319d70.
* Revert "refactor: simplify validations"
This reverts commit b1d23467a2.
* Revert "refactor: create transaction system and apply to adding entry (#1620)"
This reverts commit 9a62daf047.
* Revert "Refactor: better rounding (#1594)"
This reverts commit b9ab1c6fd7.
* Revert "refactor: improve reorder logic"
This reverts commit c1054711b0.
* Revert "chore: simplify URLs"
This reverts commit a4d4f29a37.
* Revert "refactor: order is single source of truth"
This reverts commit 2793aadea0.
* Revert "refactor: refetch targets is enum"
This reverts commit e7cfb7d9d9.
* Revert "refactor: small ux improvements"
This reverts commit 256a851c9b.
* Revert "refactor: remove trivially inferred numEvents"
This reverts commit 4ab9c81cb8.
* Revert "feat: duplicate groups"
This reverts commit 2f13d6c89e.
* Revert "feat: create group from entry selection"
This reverts commit f1f7bad25e.
* Revert "feat: create block from rundown empty"
This reverts commit a8b52a48f7.
* Revert "fix: collapsed blocks dont render children"
This reverts commit cd0999b2ab.
* Revert "refactor: type cleanup and test improvements"
This reverts commit b4c60f3f04.
* Revert "feat: allow dissolving a block"
This reverts commit 5cefad3666.
* Revert "fix: uncontrolled prop on controlled component"
This reverts commit 7a6ecd8c34.
* Revert "refactor: improve return of reorder"
This reverts commit ba96ecfd91.
* Revert "refactor: mutations on batch elements must have IDs"
This reverts commit 7bed3757f2.
* Revert "chore: upgrade dependencies"
This reverts commit e2e755b1d2.
* Revert "refactor: extract utility to merge two arrays"
This reverts commit a77d23109d.
* Revert "refactor: change network mode defaults"
This reverts commit 0eb3b8d382.
* Revert "fix: delete nested events"
This reverts commit 0021185288.
* Revert "fix: add event at end of block"
This reverts commit 94c72ff4f6.
* Revert "refactor: make finder available in exported rundown"
This reverts commit e4c08dc9b2.
* Revert "assert non null and update test (#1604)"
This reverts commit ec74af0d62.
* Revert "Fix project renumber (#1597)"
This reverts commit b6d72dd082.
* Revert "Refactor: WebSocket from flush queue to one patch (#1595)"
This reverts commit 31c311daf0.
* Revert "Refactor: ms for api calls (#1593)"
This reverts commit e9b3cc6090.
* Revert "fix test (#1601)"
This reverts commit 543b04a097.
* Revert "fix: rebase master"
This reverts commit d39b85b6e6.
* Revert "chore: correct test path"
This reverts commit bbe107bb2b.
* Revert "refactor: extract rundown parsing"
This reverts commit c616240db1.
* Revert "chore: improve convention entry <> event"
This reverts commit 166be66ce3.
* Revert "refactor: maintain flat orders"
This reverts commit 4180d0a337.
* Revert "refactor: implement operations on nested events"
This reverts commit 78108e316c.
* Revert "refactor: process events in rundown"
This reverts commit 3bb8b70915.
* Revert "chore: improve convention entry <> event"
This reverts commit 1c4f13a0ed.
* Revert "chore: rename currentBlock > parent"
This reverts commit 3ca0abad53.
* Revert "refactor: fix delay positioning in gaps"
This reverts commit 030c8f897f.
* Revert "refactor(e2e): skip flaky test"
This reverts commit 68175cfa3b.
* Revert "refactor: improve project loading"
This reverts commit fd8f757851.
* Revert "refactor: gather group metadata"
This reverts commit 876d111c61.
* Revert "refactor: swap maintains schedule"
This reverts commit 730cb95c04.
* Revert "chore: rename files"
This reverts commit 3c388d4fb5.
* Revert "refactor: restructure model to contain an object of rundowns"
This reverts commit 2e23718d73.
* Revert "refactor: clearer relationship on rundown elements"
This reverts commit 89ea8c470b.
* Revert "refactor: use strict typing"
This reverts commit 178640bfc4.
* Revert "refactor: remove stop as a possible end action"
This reverts commit 4ed38340e0.
* Revert "refactor: restructure model to contain an object of rundowns"
This reverts commit 69eb9a5eff.
* Revert "chore: remove IDE files"
This reverts commit 351425127a.
* Revert "refactor: remove unused and legacy code"
This reverts commit 95f2ba37cc.
refactor: improve empty state
refactor: review schedule design
- fit as many elements as possible
- expose cycle interval as an option
- stabilise rundown reference
- style tweaks