From 2f29060fa4dc7697bad768ed6e279ede00733d66 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Jul 2026 08:49:51 +0000 Subject: [PATCH] refactor: expose aux timer names via runtime store, index in automations Addresses review feedback on the aux timer naming feature: - Automation action labels now reference the timers by index ("Aux timer 1: start") rather than the custom names, keeping the automation config stable regardless of naming. - Expose the custom names through the consumer-facing runtime interface: the aux timer objects broadcast over the websocket now carry a `name` field. Names are seeded from the persisted settings at bootstrap and kept in sync whenever the settings change, so every consumer (views and integrations) reads them from the same runtime data. - The client control and view consumers now read the name from the runtime store instead of querying settings directly; the settings form remains the persisted editing source. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WCZejVTzuAY3tHTE6nB3JH --- apps/client/src/common/hooks/useSocket.ts | 11 +++++ apps/client/src/common/utils/auxTimerUtils.ts | 7 ++-- .../automations-panel/OntimeActionForm.tsx | 29 ++++++------- .../features/control/message/TimerPreview.tsx | 11 +++-- .../control/message/TimerViewControl.tsx | 11 +++-- .../control/playback/aux-timer/AuxTimer.tsx | 6 +-- apps/client/src/views/studio/Studio.tsx | 2 +- apps/client/src/views/studio/StudioTimers.tsx | 16 ++++---- .../src/api-data/settings/settings.router.ts | 5 +++ apps/server/src/app.ts | 8 ++++ .../__tests__/DataProvider.utils.test.ts | 1 + .../src/classes/simple-timer/SimpleTimer.ts | 11 +++++ .../__tests__/SimpleTimer.test.ts | 13 ++++++ .../aux-timer-service/AuxTimerService.ts | 14 +++++++ .../__tests__/AuxTimerService.test.ts | 41 +++++++++++++++++++ .../src/definitions/runtime/AuxTimer.type.ts | 2 + .../src/definitions/runtime/RuntimeStore.ts | 3 ++ 17 files changed, 145 insertions(+), 46 deletions(-) create mode 100644 apps/server/src/services/aux-timer-service/__tests__/AuxTimerService.test.ts diff --git a/apps/client/src/common/hooks/useSocket.ts b/apps/client/src/common/hooks/useSocket.ts index 97f9b9448..24753b5df 100644 --- a/apps/client/src/common/hooks/useSocket.ts +++ b/apps/client/src/common/hooks/useSocket.ts @@ -95,6 +95,14 @@ export const useAuxTimersTime = createSelector((state: RuntimeStore) => { }; }); +export const useAuxTimersName = createSelector((state: RuntimeStore) => { + return { + aux1: state.auxtimer1.name, + aux2: state.auxtimer2.name, + aux3: state.auxtimer3.name, + }; +}); + export const useAuxTimerTime = (index: number) => createSelector((state: RuntimeStore) => { if (index === 1) return state.auxtimer1.current; @@ -108,15 +116,18 @@ export const useAuxTimerControl = (index: number) => return { playback: state.auxtimer1.playback, direction: state.auxtimer1.direction, + name: state.auxtimer1.name, }; if (index === 2) return { playback: state.auxtimer2.playback, direction: state.auxtimer2.direction, + name: state.auxtimer2.name, }; return { playback: state.auxtimer3.playback, direction: state.auxtimer3.direction, + name: state.auxtimer3.name, }; })(); diff --git a/apps/client/src/common/utils/auxTimerUtils.ts b/apps/client/src/common/utils/auxTimerUtils.ts index 2a2485707..4acf8caf3 100644 --- a/apps/client/src/common/utils/auxTimerUtils.ts +++ b/apps/client/src/common/utils/auxTimerUtils.ts @@ -1,11 +1,10 @@ /** * 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 name - the aux timer's custom name (from the runtime store) * @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(); +export function getAuxTimerLabel(name: string | undefined, fallback: string): string { + const custom = name?.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 24e982d01..c7527d1ab 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,8 +4,6 @@ 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'; @@ -36,15 +34,12 @@ 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 (