v0.3.7-pre.009

This commit is contained in:
2026-09-02 17:40:03 +02:00
parent ed72aaba67
commit ec8875e864
15 changed files with 699 additions and 21 deletions

View File

@@ -1,10 +1,12 @@
// file: crates/ksp-app-backfill-desk/frontend/ts/main.ts
// version: 4
// version: 5
import "bootstrap";
import ResizeObserver from "resize-observer-polyfill";
import "simplebar";
import { listen } from "@tauri-apps/api/event";
import { getCurrentWindow } from "@tauri-apps/api/window";
import type { BackfillRunStatusDto } from "./bindings/ksp_app_backfill_desk/backfill_status/BackfillRunStatusDto.ts";
import type { BackfillRequestPreviewDto } from "./bindings/ksp_app_backfill_desk/dto_backfill/BackfillRequestPreviewDto.ts";
import type { BackfillStartRequestDto } from "./bindings/ksp_app_backfill_desk/dto_backfill/BackfillStartRequestDto.ts";
import type { BackfillStartResponseDto } from "./bindings/ksp_app_backfill_desk/dto_backfill/BackfillStartResponseDto.ts";
@@ -320,8 +322,9 @@ async function startBackfillRequest(): Promise<void> {
status.hidden = false;
status.classList.remove("alert-secondary", "alert-danger");
status.classList.add("alert-success");
status.textContent = `Job ${started.jobId} démarré (${started.state}). Le monitoring détaillé arrive en pre.009.`;
status.textContent = `Job ${started.jobId} démarré (${started.state}).`;
}
await syncBackfillStatus("start");
frontendInfo("main", "Backfill Desk campaign Start accepted", { jobId: started.jobId, state: started.state });
} catch (caughtError) {
renderRequestValidationError(caughtError);
@@ -447,6 +450,76 @@ function bindBackfillRouteSelection(): void {
frontendTrace("main", "Backfill Desk HTTP route selection handler installed");
}
function renderBackfillRunStatus(status: BackfillRunStatusDto | null, source: "event" | "startup" | "start" | "user"): void {
const card = document.querySelector<HTMLElement>("#backfillRunStatusCard");
if (!status) {
runStartAccepted = false;
refreshStartButton();
if (card) {
card.hidden = true;
}
frontendTrace("main", "Backfill Desk latest-value status cleared", { source });
return;
}
runStartAccepted = status.active;
refreshStartButton();
if (card) {
card.hidden = false;
}
const values: Record<string, string> = {
runStatusJobId: status.jobId,
runStatusLifecycle: status.completion === null ? status.state : `${status.state} / ${status.completion}`,
runStatusPhase: status.phase,
runStatusSequence: status.sequence,
runStatusScope: status.scopeKind,
runStatusBoundary: status.discoveryBoundary ?? "—",
runStatusCandidates: `${status.candidatesSelected} / ${status.candidatesAdmitted} / ${status.candidatesFinished}`,
runStatusFrontier: `${status.contiguousCompleted} (holes ${status.holes})`,
runStatusEntities: `${status.entitiesInserted} / ${status.entitiesExisting} / ${status.entitiesPurged}`,
runStatusObservations: `${status.observationsInserted} / ${status.observationsExisting}`,
runStatusAnomalies: `missing ${status.missing} / conflits ${status.conflicts} / annulés ${status.cancelledCandidates}`,
runStatusConcurrency: status.maximumInFlight.toString(),
runStatusCheckpoint: status.checkpointPresent ? "présent" : "absent",
runStatusFailure: status.failureDomain === null || status.failureCode === null ? "—" : `${status.failureDomain}/${status.failureCode}`,
};
for (const [id, value] of Object.entries(values)) {
const element = document.querySelector<HTMLElement>(`#${id}`);
if (element) {
element.textContent = value;
}
}
frontendTrace("main", "Backfill Desk latest-value status rendered", {
active: status.active,
phase: status.phase,
sequence: status.sequence,
source,
state: status.state,
terminal: status.terminal,
});
}
async function syncBackfillStatus(source: "startup" | "start" | "user"): Promise<void> {
frontendDebug("main", "Backfill Desk latest-value status resynchronization started", { source });
const status = await invokeKsp<BackfillRunStatusDto | null>("main", "backfill_status");
renderBackfillRunStatus(status, source);
frontendDebug("main", "Backfill Desk latest-value status resynchronization completed", { source, statusPresent: status !== null });
}
async function bindBackfillStatusMonitoring(): Promise<void> {
await listen<BackfillRunStatusDto>("ksp-backfill-status", event => {
renderBackfillRunStatus(event.payload, "event");
});
const button = document.querySelector<HTMLButtonElement>("#refreshBackfillStatus");
if (button) {
button.addEventListener("click", () => {
frontendDebug("main", "Backfill Desk latest-value status refresh button clicked");
void syncBackfillStatus("user").catch(() => frontendWarn("main", "Backfill Desk latest-value status refresh failed"));
});
}
frontendTrace("main", "Backfill Desk latest-value monitoring listener installed");
}
function renderRuntimeStatus(status: ShellStatusDto): void {
const values: Record<string, string> = {
runtimeVersion: status.applicationVersion,
@@ -503,9 +576,10 @@ async function initializeMain(): Promise<void> {
bindRuntimeStatusRefresh();
bindBackfillRouteSelection();
bindCampaignForm();
await bindBackfillStatusMonitoring();
activateView("backfill", "startup");
try {
await Promise.all([loadRuntimeStatus("startup"), loadBackfillOptions("startup")]);
await Promise.all([loadRuntimeStatus("startup"), loadBackfillOptions("startup"), syncBackfillStatus("startup")]);
} catch {
frontendWarn("main", "Backfill Desk startup runtime status load failed");
}