From 2f7909ccc34079090a70e9a0eb0def7a86a1bdec Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Jul 2026 15:48:09 +0000 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01WCZejVTzuAY3tHTE6nB3JH --- .../src/common/models/OntimeSettings.ts | 1 + apps/client/src/common/utils/auxTimerUtils.ts | 11 +++ .../automations-panel/OntimeActionForm.tsx | 29 +++--- .../panel/settings-panel/AuxTimerSettings.tsx | 91 +++++++++++++++++++ .../panel/settings-panel/SettingsPanel.tsx | 5 + .../app-settings/useAppSettingsMenu.tsx | 1 + .../features/control/message/TimerPreview.tsx | 17 ++-- .../control/message/TimerViewControl.tsx | 9 +- .../playback/PlaybackControl.module.scss | 9 ++ .../control/playback/PlaybackControl.tsx | 22 +++++ .../control/playback/aux-timer/AuxTimer.tsx | 14 ++- apps/client/src/views/studio/Studio.tsx | 2 +- apps/client/src/views/studio/StudioTimers.tsx | 14 +-- .../api-data/db/migration/db.migration.v3.ts | 2 +- .../api-data/db/migration/db.migration.v4.ts | 2 + .../api-data/db/migration/migration.test.ts | 1 + .../__tests__/settings.parser.test.ts | 15 +++ .../src/api-data/settings/settings.parser.ts | 13 +++ .../api-data/settings/settings.validation.ts | 8 ++ apps/server/src/models/dataModel.ts | 1 + apps/server/src/models/demoProject.ts | 1 + .../src/definitions/core/Settings.type.ts | 2 + .../src/rundown-utils/rundownUtils.mock.ts | 1 + 23 files changed, 237 insertions(+), 34 deletions(-) create mode 100644 apps/client/src/common/utils/auxTimerUtils.ts create mode 100644 apps/client/src/features/app-settings/panel/settings-panel/AuxTimerSettings.tsx diff --git a/apps/client/src/common/models/OntimeSettings.ts b/apps/client/src/common/models/OntimeSettings.ts index 26470c7b0..a12319f64 100644 --- a/apps/client/src/common/models/OntimeSettings.ts +++ b/apps/client/src/common/models/OntimeSettings.ts @@ -6,4 +6,5 @@ export const ontimePlaceholderSettings: Settings = { operatorKey: null, timeFormat: '24', language: 'en', + auxTimerNames: ['', '', ''], }; diff --git a/apps/client/src/common/utils/auxTimerUtils.ts b/apps/client/src/common/utils/auxTimerUtils.ts new file mode 100644 index 000000000..2a2485707 --- /dev/null +++ b/apps/client/src/common/utils/auxTimerUtils.ts @@ -0,0 +1,11 @@ +/** + * Resolves the display label for an aux timer. + * Falls back to the provided default when no custom name is set. + * @param names - the auxTimerNames array from settings (indexed 0-based) + * @param index - 1-based aux timer index (1, 2, 3) + * @param fallback - label to use when no custom name is set + */ +export function getAuxTimerLabel(names: string[] | undefined, index: number, fallback: string): string { + const custom = names?.[index - 1]?.trim(); + return custom ? custom : fallback; +} diff --git a/apps/client/src/features/app-settings/panel/automations-panel/OntimeActionForm.tsx b/apps/client/src/features/app-settings/panel/automations-panel/OntimeActionForm.tsx index 11f6413b4..24e982d01 100644 --- a/apps/client/src/features/app-settings/panel/automations-panel/OntimeActionForm.tsx +++ b/apps/client/src/features/app-settings/panel/automations-panel/OntimeActionForm.tsx @@ -4,6 +4,8 @@ import { UseFormRegister, UseFormSetValue, UseFormWatch } from 'react-hook-form' import Input from '../../../../common/components/input/input/Input'; import Select from '../../../../common/components/select/Select'; +import useSettings from '../../../../common/hooks-query/useSettings'; +import { getAuxTimerLabel } from '../../../../common/utils/auxTimerUtils'; import * as Panel from '../../panel-utils/PanelUtils'; import TemplateInput from './template-input/TemplateInput'; @@ -34,12 +36,15 @@ export default function OntimeActionForm({ watch, }: PropsWithChildren) { const [selectedAction, setSelectedAction] = useState(value); + const { data: settings } = useSettings(); const handleSetAction = (value: OntimeActionKey) => { setValue(`outputs.${index}.action`, value, { shouldDirty: true }); setSelectedAction(value); }; + const auxLabel = (auxIndex: number) => getAuxTimerLabel(settings.auxTimerNames, auxIndex, `Aux ${auxIndex}`); + return (