Emptying a field which holds different values across the selection does not
submit, otherwise focusing it and tabbing away would wipe every entry. That
left no way to clear such a field, so text fields now offer an explicit
Clear action, shown only while the entries disagree. Once they agree the
field can be emptied by hand and the action is withdrawn.
Both of the fixes which multi edit depends on were unguarded, so the logic
moves into pure helpers alongside the existing hook helper convention:
- shouldSubmitValue covers an unknown initial value being submitted as an
empty string
- applyPatchToEvents covers the optimistic batch update, whose signature now
makes the original mistake of spreading the request body unrepresentable,
and pins the custom field merge
Both tests were confirmed to fail against the original behaviour.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDETGBrhwgAqgTHjmrmJGJ
Two follow ups on multi event editing.
Duration is now editable across a selection. The batch endpoint already
applies every mutation to a cloned rundown and calls processRundown once on
commit, so a batched duration cascades correctly through linked events with
a single recalculation, and the server infers the duration lock for entries
which were locked to their end.
Start and end times remain excluded: they are absolute points in time, so
giving several events the same value collapses every linked event to a zero
duration. Only the duration is offered in a multi selection.
The optimistic update is skipped when the patch carries a duration, since
the resulting schedule cannot be resolved on the client.
Conflicting values are now marked with a dedicated symbol rather than
undefined, which was doing double duty for "the entries disagree" and "the
field is absent". The distinction was already leaking into the custom field
merge, which needed a key lookup to tell the two apart. The symbol also
makes it a type error to assign a merged value into an entry patch, where it
would previously have been dropped silently on serialisation.
Components keep taking plain optional values: the conflict is resolved once
at the editor boundary, so no indeterminate handling spreads into the tree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDETGBrhwgAqgTHjmrmJGJ
Selecting several events in the editor now turns the entry editor into a
multi editor: fields shared by every selected event show their value,
fields which differ show as mixed, and editing a field applies it to the
whole selection through the existing batch endpoint.
Rather than branching between a single and a multi editor, the editor now
always renders a merged view of N events (N >= 1) where a field is
undefined when the events disagree. For a single event nothing is ever
undefined, so single event editing is unchanged by construction and the
composites carry no multi edit branching.
- add mergeEvents() to build the merged view over a selection
- EventEditor takes an events array and resolves the write path itself,
replacing the eventId threaded into the composites with a submit callback
- extract EventEditorSchedule, which is only rendered for a single event
since schedule values cascade through the rundown
- support indeterminate values in Switch, Select, SwatchSelect and TimeInput
- cue, event id, schedule and automations are not available in multi edit
Two related fixes which multi edit depends on:
- useReactiveTextInput submitted an empty string when the initial value was
undefined, so leaving a mixed field without editing it would have wiped
the value on every selected event
- the batch optimistic update spread the request body onto the entry
instead of the patch, and replaced custom fields rather than merging them
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PDETGBrhwgAqgTHjmrmJGJ
* fix: issue where a count-to-end would lead to incorrect expected times
* fix: include add time in overtime when countToEnd
* fix: ui and server use same calculation for expected end
The Stage Timer and PiP Timer views relied on `align-content: center` to
vertically center the timer digits inside `.timer-container`, which is a
plain block element. Aligning children of a block container via
`align-content` only works in Chromium 123+ (Firefox 125+, Safari 17.4+).
Embedded browsers such as vMix Browser Input (CEF V115) and other older
CEF/Chromium-based production tools ignore the property, so the digits
fall back to the top of the container while every other element renders
correctly.
Make `.timer-container` a real flex column and center with
`justify-content: center`, which is universally supported and matches the
centering approach used elsewhere in the codebase. The removed
`justify-self`/`align-self` were no-ops on a full-width flex item.
Fixes#2126
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014T6ENZ3r6JXZb1fpYw2oNY
Surface {{groupNow.*}} template variables (title, note, colour, times,
custom fields) in the automation template autocomplete so events inside a
group can reference their group. The runtime store already carries
groupNow, so substitution and filters worked already; this makes it
discoverable.
Extend the message-secondary action with an optional text field so an
automation can set the secondary message content, not just its source.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LZYPZVdZLWowU7DyzGkWyy
* feat: create the first event from the cuesheet
* chore: cleanup css
* test: cuesheet beckground edit from empty state
* feat: only show +event button when user is in edit mode and have full write perms
* 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>