S12 - turned schedule status into enum and some other review comments
All checks were successful
Build, test and publish / verify (push) Successful in 7m6s
All checks were successful
Build, test and publish / verify (push) Successful in 7m6s
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { SchedulingRun, SchedulingStatus } from './scheduling-status';
|
||||
import { SchedulingRun, SchedulingState, SchedulingStatus } from './scheduling-status';
|
||||
|
||||
class FakeEventSource {
|
||||
static current: FakeEventSource;
|
||||
@@ -14,7 +14,7 @@ class FakeEventSource {
|
||||
}
|
||||
}
|
||||
|
||||
function run(state: string, runId = 'run-1'): SchedulingRun {
|
||||
function run(state: SchedulingState, runId = 'run-1'): SchedulingRun {
|
||||
return {
|
||||
runId,
|
||||
schoolId: 1,
|
||||
@@ -82,6 +82,19 @@ describe('Scheduling status over SSE', () => {
|
||||
expect(status.notifications()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('announces a locally started run completed before the first SSE snapshot', () => {
|
||||
FakeEventSource.current.onerror?.();
|
||||
status.started(run('RUNNING'));
|
||||
vi.advanceTimersByTime(3000);
|
||||
FakeEventSource.current.send([run('OPTIMAL'), run('VALID', 'historical')]);
|
||||
expect(status.notifications().map((item) => item.runId)).toEqual(['run-1']);
|
||||
status.dismiss();
|
||||
FakeEventSource.current.onerror?.();
|
||||
vi.advanceTimersByTime(3000);
|
||||
FakeEventSource.current.send([run('OPTIMAL'), run('VALID', 'historical')]);
|
||||
expect(status.notifications()).toEqual([]);
|
||||
});
|
||||
|
||||
it('retains a fast completion when the start response arrives after SSE', () => {
|
||||
FakeEventSource.current.send([]);
|
||||
FakeEventSource.current.send([run('OPTIMAL')]);
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import { DestroyRef, inject, Injectable, signal } from '@angular/core';
|
||||
|
||||
export type SchedulingState =
|
||||
| 'RUNNING'
|
||||
| 'OPTIMAL'
|
||||
| 'VALID'
|
||||
| 'STALE'
|
||||
| 'INVALID_INPUT'
|
||||
| 'INFEASIBLE'
|
||||
| 'NO_SOLUTION'
|
||||
| 'SOLVER_FAILED';
|
||||
export type SchedulingPhase = 'PREPARING' | 'ATTENDANCE' | 'SPREAD' | 'VARIETY';
|
||||
|
||||
export interface SchedulingRun {
|
||||
runId: string;
|
||||
schoolId: number;
|
||||
@@ -7,8 +18,8 @@ export interface SchedulingRun {
|
||||
showName: string;
|
||||
startedAt: string;
|
||||
finishedAt: string | null;
|
||||
state: string;
|
||||
progress: { phase: string; feasible: boolean };
|
||||
state: SchedulingState;
|
||||
progress: { phase: SchedulingPhase; feasible: boolean };
|
||||
message: string;
|
||||
summary: {
|
||||
attendanceExcess: number;
|
||||
@@ -58,10 +69,16 @@ export class SchedulingStatus {
|
||||
}
|
||||
|
||||
private accept(runs: SchedulingRun[]): void {
|
||||
const activeRuns = new Set(
|
||||
this.runs()
|
||||
.filter((run) => run.state === 'RUNNING')
|
||||
.map((run) => run.runId),
|
||||
);
|
||||
for (const run of runs) {
|
||||
if (run.state === 'RUNNING' || this.seen.has(run.runId)) continue;
|
||||
this.seen.add(run.runId);
|
||||
if (this.initialized) this.notifications.update((items) => [...items, run]);
|
||||
if (this.initialized || activeRuns.has(run.runId))
|
||||
this.notifications.update((items) => [...items, run]);
|
||||
}
|
||||
this.initialized = true;
|
||||
this.runs.set(runs);
|
||||
@@ -96,7 +113,7 @@ export class SchedulingStatus {
|
||||
ATTENDANCE: 'Aanwezigheid',
|
||||
SPREAD: 'Spreiding',
|
||||
VARIETY: 'Variatie',
|
||||
} as Record<string, string>
|
||||
} satisfies Record<SchedulingPhase, string>
|
||||
)[run.progress.phase] ?? run.progress.phase
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user