S12 - Async feedback for scheduling
All checks were successful
Build, test and publish / verify (push) Successful in 7m25s

This commit is contained in:
2026-11-03 23:18:44 +01:00
parent f1785ed174
commit c241392132
34 changed files with 1310 additions and 79 deletions

View File

@@ -1,5 +1,5 @@
import { SchoolTransfer } from '../shared/school-transfer';
import { Component, computed, DestroyRef, inject, OnInit, signal } from '@angular/core';
import { Component, computed, DestroyRef, effect, inject, OnInit, signal } from '@angular/core';
import { DatePipe } from '@angular/common';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router, RouterLink, RouterLinkActive } from '@angular/router';
@@ -14,6 +14,7 @@ import {
Show,
} from '../core/api-models';
import { apiError } from '../core/api-error';
import { SchedulingStatus } from '../core/scheduling-status';
import { SchoolApi } from '../core/school-api';
import { EntityEditor } from '../shared/entity-editor';
import { ConfirmDialog } from '../shared/confirm-dialog';
@@ -57,7 +58,30 @@ export class SchoolPage implements OnInit {
readonly scheduleEditing = signal<Show | null>(null);
readonly members = signal<DanceGroup | null>(null);
readonly deleting = signal<DeleteTarget | null>(null);
readonly scheduling = signal<number[]>([]);
readonly schedulingStatus = inject(SchedulingStatus);
private readonly starting = signal<number[]>([]);
readonly scheduling = computed(() => [
...this.starting(),
...this.schedulingStatus
.runs()
.filter((run) => run.schoolId === this.data()?.school.id && run.state === 'RUNNING')
.map((run) => run.showId),
]);
private readonly completed = new Set<string>();
constructor() {
effect(() => {
const schoolId = this.data()?.school.id;
let changed = false;
for (const run of this.schedulingStatus.runs()) {
if (run.schoolId !== schoolId || run.state === 'RUNNING' || this.completed.has(run.runId))
continue;
this.completed.add(run.runId);
changed = true;
}
if (changed) void this.reload();
});
}
readonly deleteBusy = signal(false);
readonly deleteError = signal('');
readonly search = signal('');
@@ -151,20 +175,15 @@ export class SchoolPage implements OnInit {
)
)
return;
this.scheduling.update((ids) => [...ids, show.id]);
this.starting.update((ids) => [...ids, show.id]);
this.error.set('');
try {
const result = await firstValueFrom(this.api.schedule(schoolId, show.id));
this.notice.set(
result.optimal
? 'Optimaal conceptrooster.'
: 'Geldig conceptrooster; optimaliteit niet bewezen.',
);
await this.reload();
this.schedulingStatus.started(result);
} catch (error: unknown) {
this.error.set(apiError(error));
} finally {
this.scheduling.update((ids) => ids.filter((id) => id !== show.id));
this.starting.update((ids) => ids.filter((id) => id !== show.id));
}
}
async reload(): Promise<void> {