feat: allow naming aux timers

Adds custom, persisted names for the three aux timers, editable in the
editor settings and surfaced everywhere an aux title is shown.

- Persist `auxTimerNames` on the Settings object (default empty, falls
  back to the stock "Aux N" label when unset). Reuses the existing
  settings pipeline: validation sanitises to a fixed-length trimmed
  array, the parser normalises loaded/legacy data, and migrations carry
  the field forward.
- New "Aux timers" settings section to name each timer, plus a shortcut
  button next to the aux timers in the playback control that jumps
  straight to it.
- Resolve names via a shared getAuxTimerLabel helper in the aux timer
  control, Studio view, secondary-source selector and preview, and the
  automation action labels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCZejVTzuAY3tHTE6nB3JH
This commit is contained in:
Claude
2026-07-23 15:48:09 +00:00
parent 5f040092cb
commit 2f7909ccc3
23 changed files with 237 additions and 34 deletions
@@ -3,7 +3,9 @@ import { millisToString, parseUserTime } from 'ontime-utils';
import { IoArrowDown, IoArrowUp, IoPause, IoPlay, IoStop } from 'react-icons/io5';
import TimeInput from '../../../../common/components/input/time-input/TimeInput';
import useSettings from '../../../../common/hooks-query/useSettings';
import { setAuxTimer, useAuxTimerControl, useAuxTimerTime } from '../../../../common/hooks/useSocket';
import { getAuxTimerLabel } from '../../../../common/utils/auxTimerUtils';
import TapButton from '../tap-button/TapButton';
import style from './AuxTimer.module.scss';
@@ -14,9 +16,12 @@ interface AuxTimerProps {
export function AuxTimer({ index }: AuxTimerProps) {
const { playback, direction } = useAuxTimerControl(index);
const { data: settings } = useSettings();
const { stop, setDirection } = setAuxTimer;
const label = getAuxTimerLabel(settings.auxTimerNames, index, `Aux Timer ${index}`);
const toggleDirection = () => {
const newDirection = direction === SimpleDirection.CountDown ? SimpleDirection.CountUp : SimpleDirection.CountDown;
setDirection(index, newDirection);
@@ -27,10 +32,10 @@ export function AuxTimer({ index }: AuxTimerProps) {
return (
<label className={style.label}>
Aux Timer {index}
{label}
<div className={style.controls}>
<div className={style.input}>
<AuxTimerInput index={index} isActive={isActive} />
<AuxTimerInput index={index} isActive={isActive} placeholder={label} />
<TapButton onClick={toggleDirection} aspect='tight' disabled={isActive}>
{direction === SimpleDirection.CountDown && <IoArrowDown data-testid={`aux-timer-direction-${index}`} />}
{direction === SimpleDirection.CountUp && <IoArrowUp data-testid={`aux-timer-direction-${index}`} />}
@@ -50,9 +55,10 @@ export function AuxTimer({ index }: AuxTimerProps) {
interface AuxTimerInputProps {
index: number;
isActive: boolean;
placeholder: string;
}
function AuxTimerInput({ index, isActive }: AuxTimerInputProps) {
function AuxTimerInput({ index, isActive, placeholder }: AuxTimerInputProps) {
const newTimeInMs = useAuxTimerTime(index);
const { setDuration } = setAuxTimer;
@@ -70,7 +76,7 @@ function AuxTimerInput({ index, isActive }: AuxTimerInputProps) {
}
return (
<TimeInput submitHandler={handleTimeUpdate} name={`aux${index}`} time={newTimeInMs} placeholder={`Aux ${index}`} />
<TimeInput submitHandler={handleTimeUpdate} name={`aux${index}`} time={newTimeInMs} placeholder={placeholder} />
);
}