mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-16 19:43:06 +00:00
feat(automation): improve definition and trigger editing
This commit is contained in:
committed by
Carlos Valente
parent
79c21daf73
commit
b07544ab84
@@ -0,0 +1,25 @@
|
||||
import { maybeAxiosError } from '../utils';
|
||||
|
||||
describe('maybeAxiosError', () => {
|
||||
it('shows the validation message without echoing the submitted value', () => {
|
||||
const error = {
|
||||
isAxiosError: true,
|
||||
response: {
|
||||
statusText: 'Unprocessable Entity',
|
||||
data: {
|
||||
errors: [
|
||||
{
|
||||
type: 'field',
|
||||
value: { title: 'Automation definition', outputs: [{ targetIP: 'not a host' }] },
|
||||
msg: 'Invalid OSC target',
|
||||
path: '',
|
||||
location: 'body',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(maybeAxiosError(error)).toBe('Unprocessable Entity: Invalid OSC target');
|
||||
});
|
||||
});
|
||||
@@ -18,6 +18,15 @@ export function maybeAxiosError(error: unknown) {
|
||||
if (typeof data === 'object') {
|
||||
if ('message' in data) {
|
||||
data = JSON.stringify(data.message);
|
||||
} else if ('errors' in data && Array.isArray(data.errors)) {
|
||||
const firstError = data.errors.at(0);
|
||||
data =
|
||||
typeof firstError === 'object' &&
|
||||
firstError !== null &&
|
||||
'msg' in firstError &&
|
||||
typeof firstError.msg === 'string'
|
||||
? firstError.msg
|
||||
: JSON.stringify(data);
|
||||
} else {
|
||||
data = JSON.stringify(data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { TimerLifeCycle } from 'ontime-types';
|
||||
|
||||
import { getLifecycleLabel } from '../timerLifecycle';
|
||||
|
||||
describe('getLifecycleLabel', () => {
|
||||
it('returns the shared label for known lifecycle values', () => {
|
||||
expect(getLifecycleLabel(TimerLifeCycle.onClock)).toBe('Every second');
|
||||
});
|
||||
|
||||
it('keeps unknown lifecycle values visible', () => {
|
||||
expect(getLifecycleLabel('future-lifecycle')).toBe('future-lifecycle');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { TimerLifeCycle } from 'ontime-types';
|
||||
|
||||
export const lifecycleLabels: Record<TimerLifeCycle, string> = {
|
||||
[TimerLifeCycle.onLoad]: 'On Load',
|
||||
[TimerLifeCycle.onStart]: 'On Start',
|
||||
[TimerLifeCycle.onPause]: 'On Pause',
|
||||
[TimerLifeCycle.onStop]: 'On Stop',
|
||||
[TimerLifeCycle.onClock]: 'Every second',
|
||||
[TimerLifeCycle.onUpdate]: 'On Timer Update',
|
||||
[TimerLifeCycle.onFinish]: 'On Finish',
|
||||
[TimerLifeCycle.onWarning]: 'On Warning',
|
||||
[TimerLifeCycle.onDanger]: 'On Danger',
|
||||
};
|
||||
|
||||
export function getLifecycleLabel(cycle: TimerLifeCycle | string): string {
|
||||
return lifecycleLabels[cycle as TimerLifeCycle] ?? cycle;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { AutomationOutput } from 'ontime-types';
|
||||
|
||||
import { summariseOutputs } from '../automationOutputs';
|
||||
|
||||
describe('summariseOutputs', () => {
|
||||
it('returns an empty list when there are no outputs', () => {
|
||||
expect(summariseOutputs([])).toEqual([]);
|
||||
});
|
||||
|
||||
it('counts repeated output kinds', () => {
|
||||
const outputs: AutomationOutput[] = [
|
||||
{ type: 'osc', targetIP: '127.0.0.1', targetPort: 8000, address: '/go', args: '' },
|
||||
{ type: 'osc', targetIP: '127.0.0.1', targetPort: 8000, address: '/stop', args: '' },
|
||||
{ type: 'http', url: 'http://127.0.0.1/start' },
|
||||
];
|
||||
|
||||
expect(summariseOutputs(outputs)).toEqual([
|
||||
{ type: 'osc', label: 'OSC', count: 2 },
|
||||
{ type: 'http', label: 'HTTP', count: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('presents kinds in a stable order regardless of insertion order', () => {
|
||||
const outputs: AutomationOutput[] = [
|
||||
{ type: 'ontime', action: 'aux1-start' },
|
||||
{ type: 'http', url: 'http://127.0.0.1/start' },
|
||||
{ type: 'osc', targetIP: '127.0.0.1', targetPort: 8000, address: '/go', args: '' },
|
||||
];
|
||||
|
||||
expect(summariseOutputs(outputs).map(({ type }) => type)).toEqual(['osc', 'http', 'ontime']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { AutomationOutput } from 'ontime-types';
|
||||
|
||||
const outputLabels: Record<AutomationOutput['type'], string> = {
|
||||
osc: 'OSC',
|
||||
http: 'HTTP',
|
||||
ontime: 'Ontime',
|
||||
};
|
||||
|
||||
export type OutputSummary = {
|
||||
type: AutomationOutput['type'];
|
||||
label: string;
|
||||
count: number;
|
||||
};
|
||||
|
||||
export function summariseOutputs(outputs: AutomationOutput[]): OutputSummary[] {
|
||||
const counts = new Map<AutomationOutput['type'], number>();
|
||||
|
||||
for (const output of outputs) {
|
||||
counts.set(output.type, (counts.get(output.type) ?? 0) + 1);
|
||||
}
|
||||
|
||||
const order: AutomationOutput['type'][] = ['osc', 'http', 'ontime'];
|
||||
return order
|
||||
.filter((type) => counts.has(type))
|
||||
.map((type) => ({ type, label: outputLabels[type], count: counts.get(type) as number }));
|
||||
}
|
||||
Reference in New Issue
Block a user