feat: allow naming aux timers

This commit is contained in:
Carlos Valente
2026-08-25 21:45:58 +02:00
parent b9683f00dc
commit be99fbdcb9
36 changed files with 482 additions and 16 deletions
@@ -6,4 +6,9 @@ export type Settings = {
operatorKey: null | string;
timeFormat: TimeFormat;
language: string;
/**
* Custom names for the aux timers, one entry per aux timer in order (index 0 is aux timer 1).
* An empty string means the timer is unnamed and consumers show the default label
*/
auxTimerNames: string[];
};
@@ -14,4 +14,6 @@ export type SimpleTimerState = {
current: number;
playback: SimplePlayback;
direction: SimpleDirection;
/** Custom name for the aux timer. Empty string when unnamed */
name: string;
};
@@ -53,18 +53,21 @@ export const runtimeStorePlaceholder: Readonly<RuntimeStore> = {
direction: SimpleDirection.CountUp,
duration: 0,
playback: SimplePlayback.Stop,
name: '',
},
auxtimer2: {
current: 0,
direction: SimpleDirection.CountUp,
duration: 0,
playback: SimplePlayback.Stop,
name: '',
},
auxtimer3: {
current: 0,
direction: SimpleDirection.CountUp,
duration: 0,
playback: SimplePlayback.Stop,
name: '',
},
ping: 1,
};
+3
View File
@@ -99,6 +99,9 @@ export {
export { isPlaybackActive } from './src/playback-utils/playbackstate.js';
// aux timers
export { auxTimerNameMaxLength, sanitiseAuxTimerNames } from './src/aux-timer-utils/auxTimerUtils.js';
//Colour
export {
colourToHex,
@@ -0,0 +1,30 @@
import { auxTimerNameMaxLength, sanitiseAuxTimerNames } from './auxTimerUtils.js';
describe('sanitiseAuxTimerNames()', () => {
it('generates the default value when given nothing', () => {
expect(sanitiseAuxTimerNames()).toStrictEqual(['', '', '']);
});
it('always returns exactly three entries', () => {
expect(sanitiseAuxTimerNames(['a', 'b', 'c', 'extra'])).toStrictEqual(['a', 'b', 'c']);
});
it('pads missing entries with an empty string', () => {
expect(sanitiseAuxTimerNames(['Speaker'])).toStrictEqual(['Speaker', '', '']);
});
it('trims whitespace', () => {
expect(sanitiseAuxTimerNames([' Speaker ', '', ''])).toStrictEqual(['Speaker', '', '']);
});
it('caps the name length', () => {
const tooLong = 'a'.repeat(auxTimerNameMaxLength + 10);
expect(sanitiseAuxTimerNames([tooLong])[0]).toHaveLength(auxTimerNameMaxLength);
});
it('falls back to defaults for malformed data', () => {
expect(sanitiseAuxTimerNames('not-an-array')).toStrictEqual(['', '', '']);
expect(sanitiseAuxTimerNames(null)).toStrictEqual(['', '', '']);
expect(sanitiseAuxTimerNames([42, {}, undefined])).toStrictEqual(['', '', '']);
});
});
@@ -0,0 +1,16 @@
/** Maximum length of a user given aux timer name */
export const auxTimerNameMaxLength = 30;
function sanitiseAuxTimerName(value: unknown): string {
return typeof value === 'string' ? value.trim().slice(0, auxTimerNameMaxLength) : '';
}
/**
* Ontime has three aux timers. Given whatever was found on disk or in a request body,
* returns a name for each of them, so callers never need to deal with a missing
* or malformed auxTimerNames (eg. a project file saved before this feature existed).
*/
export function sanitiseAuxTimerNames(names?: unknown): [string, string, string] {
const source = Array.isArray(names) ? names : [];
return [sanitiseAuxTimerName(source[0]), sanitiseAuxTimerName(source[1]), sanitiseAuxTimerName(source[2])];
}
@@ -342,6 +342,7 @@ export const demoDb: DatabaseModel = {
operatorKey: null,
timeFormat: '24',
language: 'en',
auxTimerNames: ['', '', ''],
},
viewSettings: {
dangerColor: '#ff7300',