Files
khadhroony-solana-project/crates/ksp-app-backfill-desk/frontend/main.html
2026-09-02 20:29:50 +02:00

232 lines
21 KiB
HTML

<!-- file: crates/ksp-app-backfill-desk/frontend/main.html -->
<!-- version: 8 -->
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link rel="icon" href="imgs/logo.png">
<link rel="stylesheet" href="sass/main.scss">
<title>Backfill Desk — Backfill</title>
</head>
<body>
<header class="app-header">
<nav class="navbar h-100 py-0 bg-light text-dark">
<div class="container-fluid px-4 flex-nowrap">
<div class="navbar-brand d-flex align-items-center me-4 flex-nowrap">
<img alt="KSP" src="imgs/logo.png" class="app-logo">
<span class="ps-2 fs-4 fw-semibold text-primary text-nowrap">Backfill Desk</span>
<span class="mx-2 fs-5 text-body-secondary" aria-hidden="true"></span>
<span id="headerViewTitle" class="fs-5 text-body text-nowrap">Backfill</span>
</div>
</div>
</nav>
</header>
<main class="app-main container-fluid p-0">
<div class="row g-0 h-100 flex-nowrap">
<aside class="col-auto app-sidebar border-end bg-body-tertiary">
<div class="app-sidebar-scroll h-100" data-simplebar>
<nav class="nav nav-pills flex-column gap-1 p-3" aria-label="Navigation Backfill Desk">
<button class="nav-link text-start active" type="button" data-view="backfill">
<i class="fa-solid fa-clock-rotate-left me-2" aria-hidden="true"></i>Backfill
</button>
<button class="nav-link text-start" type="button" data-view="diagnostics">
<i class="fa-solid fa-stethoscope me-2" aria-hidden="true"></i>Diagnostics
</button>
</nav>
</div>
</aside>
<section class="col app-content app-scrollable h-100" data-simplebar>
<div class="container-fluid px-4 py-4">
<div class="card app-shell-card mx-auto shadow-sm border-0">
<div class="card-body p-4">
<section data-view-panel="backfill">
<div class="d-flex align-items-center justify-content-between gap-3 flex-wrap mb-4">
<div>
<h1 class="h3 mb-1">Backfill</h1>
<p class="text-body-secondary mb-0">Mainnet par défaut, transport HTTP sélectionnable et mapping de campagne validé côté Rust avant tout démarrage de job.</p>
</div>
<span id="appVersionBadge" class="badge text-bg-secondary"></span>
</div>
<div class="row g-4">
<div class="col-xl-4">
<div class="card shadow-sm h-100">
<div class="card-header fw-semibold">Transport HTTP</div>
<div class="card-body">
<label for="backfillHttpRoute" class="form-label">Route de lecture</label>
<select id="backfillHttpRoute" class="form-select" disabled>
<option value="">Chargement des routes…</option>
</select>
<div id="backfillHttpRouteHelp" class="form-text">Le choix reste logique : aucune URL ni clé provider n'est exposée au frontend.</div>
<dl class="row mt-4 mb-0 app-runtime-list">
<dt class="col-sm-5">Réseau</dt><dd id="backfillNetwork" class="col-sm-7"></dd>
<dt class="col-sm-5">Transport</dt><dd id="backfillTransportReady" class="col-sm-7"></dd>
<dt class="col-sm-5">Store</dt><dd id="backfillStoreReady" class="col-sm-7"></dd>
<dt class="col-sm-5">Composition</dt><dd id="backfillCompositionReady" class="col-sm-7"></dd>
</dl>
<div id="backfillOptionsDiagnostic" class="alert alert-warning mt-3 mb-0" role="status" aria-live="polite" hidden></div>
</div>
</div>
</div>
<div class="col-xl-8">
<div class="card shadow-sm h-100">
<div class="card-header fw-semibold">Campagne Backfill</div>
<div class="card-body">
<form id="backfillCampaignForm" novalidate>
<div class="row g-3">
<div class="col-lg-6">
<label for="backfillScopeKind" class="form-label">Scope</label>
<select id="backfillScopeKind" class="form-select" disabled></select>
</div>
<div class="col-lg-6">
<label for="backfillCommitment" class="form-label">Commitment</label>
<select id="backfillCommitment" class="form-select" disabled></select>
</div>
<div id="backfillAddressGroup" class="col-12">
<label for="backfillAddress" class="form-label">Adresse Solana</label>
<input id="backfillAddress" class="form-control font-monospace" type="text" list="backfillProgramIds" autocomplete="off" spellcheck="false" aria-describedby="backfillProgramIdAutocompleteHelp">
<datalist id="backfillProgramIds"></datalist>
<div id="backfillProgramIdAutocompleteHelp" class="form-text">Suggestions issues du registre canonique KSP ; toute adresse Solana valide reste acceptée.</div>
</div>
<div id="backfillAnchorGroup" class="col-12" hidden>
<label for="backfillAnchorSignature" class="form-label">Signature d'ancrage exclusive</label>
<input id="backfillAnchorSignature" class="form-control font-monospace" type="text" autocomplete="off" spellcheck="false">
</div>
<div id="backfillExplicitSignaturesGroup" class="col-12" hidden>
<label for="backfillExplicitSignatures" class="form-label">Signatures explicites</label>
<textarea id="backfillExplicitSignatures" class="form-control font-monospace" rows="5" autocomplete="off" spellcheck="false"></textarea>
<div id="backfillExplicitSignaturesHelp" class="form-text">Une signature par ligne.</div>
</div>
<div class="col-md-6 col-xxl-3">
<label for="backfillPageSize" class="form-label">Page size</label>
<input id="backfillPageSize" class="form-control" type="number" step="1">
</div>
<div class="col-md-6 col-xxl-3">
<label for="backfillMaxPages" class="form-label">Max pages</label>
<input id="backfillMaxPages" class="form-control" type="number" step="1">
</div>
<div class="col-md-6 col-xxl-3">
<label for="backfillMaxCandidates" class="form-label">Max candidates</label>
<input id="backfillMaxCandidates" class="form-control" type="number" step="1">
</div>
<div class="col-md-6 col-xxl-3">
<label for="backfillHydrationConcurrency" class="form-label">Concurrence</label>
<input id="backfillHydrationConcurrency" class="form-control" type="number" step="1">
</div>
<div id="backfillMinContextSlotGroup" class="col-lg-6">
<label for="backfillMinContextSlot" class="form-label">Min context slot</label>
<input id="backfillMinContextSlot" class="form-control font-monospace" type="text" inputmode="numeric" autocomplete="off" spellcheck="false" placeholder="optionnel">
<div class="form-text">Chaîne décimale validée côté Rust pour préserver la précision u64.</div>
</div>
</div>
<div class="d-flex align-items-center gap-3 flex-wrap mt-4">
<button id="validateBackfillRequest" class="btn btn-outline-primary" type="submit" disabled>
<i class="fa-solid fa-shield-halved me-2" aria-hidden="true"></i>Valider la requête
</button>
<button id="startBackfillRequest" class="btn btn-primary" type="button" disabled>
<i class="fa-solid fa-play me-2" aria-hidden="true"></i>Démarrer le backfill
</button>
<span class="text-body-secondary small">Un seul run peut être actif ; le monitoring latest-value est coalescé côté backend.</span>
</div>
</form>
<div id="backfillRequestValidation" class="alert alert-secondary mt-4 mb-0" role="status" aria-live="polite" hidden></div>
<div id="backfillRunStatusCard" class="card shadow-sm mt-4" hidden>
<div class="card-header d-flex align-items-center justify-content-between gap-3 flex-wrap">
<span class="fw-semibold">Monitoring latest-value</span>
<div class="d-flex align-items-center gap-2 flex-wrap">
<button id="cancelBackfillRun" class="btn btn-outline-danger btn-sm" type="button" disabled>
<i class="fa-solid fa-ban me-2" aria-hidden="true"></i>Annuler
</button>
<button id="resumeBackfillRun" class="btn btn-outline-success btn-sm" type="button" disabled>
<i class="fa-solid fa-forward-step me-2" aria-hidden="true"></i>Reprendre
</button>
<button id="refreshBackfillStatus" class="btn btn-outline-primary btn-sm" type="button">
<i class="fa-solid fa-rotate me-2" aria-hidden="true"></i>Resynchroniser
</button>
</div>
</div>
<div class="card-body">
<div id="backfillCancelFeedback" class="alert alert-secondary py-2" role="status" aria-live="polite" hidden></div>
<div id="backfillResumeFeedback" class="alert alert-secondary py-2" role="status" aria-live="polite" hidden></div>
<div id="backfillTerminalSummary" class="alert alert-secondary py-2" role="status" aria-live="polite" hidden></div>
<dl class="row mb-0 app-runtime-list">
<dt class="col-sm-5">Job</dt><dd id="runStatusJobId" class="col-sm-7 font-monospace"></dd>
<dt class="col-sm-5">Lifecycle</dt><dd id="runStatusLifecycle" class="col-sm-7"></dd>
<dt class="col-sm-5">Phase</dt><dd id="runStatusPhase" class="col-sm-7"></dd>
<dt class="col-sm-5">Séquence</dt><dd id="runStatusSequence" class="col-sm-7 font-monospace"></dd>
<dt class="col-sm-5">Scope</dt><dd id="runStatusScope" class="col-sm-7"></dd>
<dt class="col-sm-5">Boundary</dt><dd id="runStatusBoundary" class="col-sm-7"></dd>
<dt class="col-sm-5">Candidates sel./adm./fin.</dt><dd id="runStatusCandidates" class="col-sm-7"></dd>
<dt class="col-sm-5">Frontier / holes</dt><dd id="runStatusFrontier" class="col-sm-7"></dd>
<dt class="col-sm-5">RAW ins./exist./purged</dt><dd id="runStatusEntities" class="col-sm-7"></dd>
<dt class="col-sm-5">Observations ins./exist.</dt><dd id="runStatusObservations" class="col-sm-7"></dd>
<dt class="col-sm-5">Anomalies</dt><dd id="runStatusAnomalies" class="col-sm-7"></dd>
<dt class="col-sm-5">Max in-flight</dt><dd id="runStatusConcurrency" class="col-sm-7"></dd>
<dt class="col-sm-5">Checkpoint</dt><dd id="runStatusCheckpoint" class="col-sm-7"></dd>
<dt class="col-sm-5">Failure</dt><dd id="runStatusFailure" class="col-sm-7"></dd>
</dl>
</div>
</div>
<div id="backfillRequestPreview" class="card bg-body-tertiary border-0 mt-3" hidden>
<div class="card-body">
<h2 class="h6 mb-3">Projection backend sûre</h2>
<dl class="row mb-0 app-runtime-list">
<dt class="col-sm-5">Réseau</dt><dd id="validatedNetwork" class="col-sm-7"></dd>
<dt class="col-sm-5">Route HTTP</dt><dd id="validatedHttpRole" class="col-sm-7"></dd>
<dt class="col-sm-5">Commitment</dt><dd id="validatedCommitment" class="col-sm-7"></dd>
<dt class="col-sm-5">Scope</dt><dd id="validatedScopeKind" class="col-sm-7"></dd>
<dt class="col-sm-5">Signatures explicites</dt><dd id="validatedExplicitSignatureCount" class="col-sm-7"></dd>
<dt class="col-sm-5">page/pages/candidates/concurrence</dt><dd id="validatedBounds" class="col-sm-7"></dd>
<dt class="col-sm-5">Min context slot</dt><dd id="validatedMinContextSlot" class="col-sm-7"></dd>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section data-view-panel="diagnostics" hidden>
<div class="d-flex align-items-center justify-content-between gap-3 flex-wrap mb-4">
<div>
<h1 class="h3 mb-1">Diagnostics</h1>
<p class="text-body-secondary mb-0">État sûr du scaffold Config, Logging et desktop.</p>
</div>
<button id="refreshRuntimeStatus" class="btn btn-outline-primary btn-sm" type="button">
<i class="fa-solid fa-rotate me-2" aria-hidden="true"></i>Refresh
</button>
</div>
<div class="card shadow-sm">
<div class="card-header fw-semibold">Runtime</div>
<div class="card-body">
<dl class="row mb-0 app-runtime-list">
<dt class="col-sm-5">Version</dt><dd id="runtimeVersion" class="col-sm-7"></dd>
<dt class="col-sm-5">Phase</dt><dd id="runtimeShellPhase" class="col-sm-7"></dd>
<dt class="col-sm-5">Documents Config</dt><dd id="runtimeConfigDocuments" class="col-sm-7"></dd>
<dt class="col-sm-5">Profil Logging</dt><dd id="runtimeLoggingProfile" class="col-sm-7"></dd>
<dt class="col-sm-5">Fallback Logging</dt><dd id="runtimeLoggingFallback" class="col-sm-7"></dd>
</dl>
<div id="runtimeDiagnostic" class="alert alert-warning mt-3 mb-0" role="status" aria-live="polite" hidden></div>
</div>
</div>
</section>
</div>
</div>
</div>
</section>
</div>
</main>
<footer class="app-footer bg-dark text-light">
<div class="container h-100 d-flex align-items-center justify-content-center">
<small>&copy; 2026 SASEDEV</small>
</div>
</footer>
<script type="module" src="ts/main.ts" defer></script>
</body>
</html>