318 lines
23 KiB
HTML
318 lines
23 KiB
HTML
<!-- file: crates/ksp-app-config-desk/frontend/main.html -->
|
|
<!-- version: 7 -->
|
|
<!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>Config Desk — Vue d'ensemble</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">Config 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">Vue d'ensemble</span>
|
|
</div>
|
|
<div class="app-nav nav nav-pills flex-nowrap gap-1 ms-auto" aria-label="Navigation Config Desk">
|
|
<button class="nav-link app-nav-button active" type="button" data-view="overview">Vue d'ensemble</button>
|
|
<button class="nav-link app-nav-button" type="button" data-view="documents">Documents</button>
|
|
<button class="nav-link app-nav-button" type="button" data-view="profiles">Profils</button>
|
|
<button class="nav-link app-nav-button" type="button" data-view="environment">Environnement / .env</button>
|
|
<button class="nav-link app-nav-button" type="button" data-view="logging">Logging</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="app-main">
|
|
<div class="app-scrollable" 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">
|
|
<h1 id="viewTitle" class="h3 mb-2">Vue d'ensemble</h1>
|
|
<p id="viewDescription" class="text-body-secondary mb-4">État sûr du bootstrap Config Desk et du runtime Logging actuellement actif.</p>
|
|
|
|
<section id="overviewPanel" aria-label="Vue d'ensemble">
|
|
<dl class="row mb-4 app-overview-list">
|
|
<dt class="col-sm-5">Version application</dt>
|
|
<dd id="overviewVersion" class="col-sm-7 text-sm-end">—</dd>
|
|
<dt class="col-sm-5">Descripteurs Config enregistrés</dt>
|
|
<dd id="overviewDocuments" class="col-sm-7 text-sm-end">—</dd>
|
|
<dt class="col-sm-5">Profil Logging actif</dt>
|
|
<dd id="overviewLoggingProfile" class="col-sm-7 text-sm-end">—</dd>
|
|
<dt class="col-sm-5">Génération Logging</dt>
|
|
<dd id="overviewLoggingGeneration" class="col-sm-7 text-sm-end">—</dd>
|
|
<dt class="col-sm-5 mb-0">Fallback Logging actif</dt>
|
|
<dd id="overviewLoggingFallback" class="col-sm-7 text-sm-end mb-0">—</dd>
|
|
</dl>
|
|
</section>
|
|
|
|
|
|
<section id="documentsPanel" hidden aria-label="Documents Config">
|
|
<div class="d-flex flex-wrap gap-2 align-items-center justify-content-between mb-3">
|
|
<div>
|
|
<h2 class="h5 mb-1">Documents enregistrés</h2>
|
|
<p class="text-body-secondary small mb-0">Le registre, la validation et la persistence restent exclusivement sous contrôle de ksp-config-lib.</p>
|
|
</div>
|
|
<button id="refreshDocuments" class="btn btn-outline-primary btn-sm" type="button">
|
|
<i class="fa-solid fa-rotate me-1" aria-hidden="true"></i>
|
|
Rafraîchir
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-responsive mb-4">
|
|
<table id="configDocumentsTable" class="table table-striped table-hover align-middle w-100">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">file_id</th>
|
|
<th scope="col">Fichier</th>
|
|
<th scope="col">Schema</th>
|
|
<th scope="col">État</th>
|
|
<th scope="col">Étape</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<section id="documentDetailPanel" hidden class="border rounded p-3 mb-4 bg-body-tertiary" aria-label="Détail du document Config">
|
|
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-start mb-3">
|
|
<div>
|
|
<h2 class="h5 mb-1">Détail du document</h2>
|
|
<span id="documentDetailStatus" class="badge text-bg-secondary">—</span>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<button id="reloadDocumentSource" class="btn btn-outline-secondary btn-sm" type="button">Recharger</button>
|
|
<button id="saveDocumentSource" class="btn btn-primary btn-sm" type="button">Valider et sauvegarder</button>
|
|
</div>
|
|
</div>
|
|
<dl class="row small mb-3 app-document-metadata">
|
|
<dt class="col-lg-3">file_id</dt>
|
|
<dd id="documentDetailFileId" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Fichier mappé</dt>
|
|
<dd id="documentDetailFilename" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Schema</dt>
|
|
<dd id="documentDetailSchema" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Path résolu</dt>
|
|
<dd id="documentDetailPath" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Étape diagnostic</dt>
|
|
<dd id="documentDetailStage" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3 mb-0">Diagnostic</dt>
|
|
<dd id="documentDetailDiagnostic" class="col-lg-9 mb-0">—</dd>
|
|
</dl>
|
|
<label class="form-label fw-semibold" for="documentSourceEditor">Source brut Config</label>
|
|
<textarea id="documentSourceEditor" class="form-control app-document-source" rows="18" spellcheck="false" autocomplete="off"></textarea>
|
|
<div class="form-text">La sauvegarde est refusée tant que le candidat échoue au parsing JSON, au schema ou aux invariants sémantiques backend.</div>
|
|
</section>
|
|
|
|
<div id="documentsStatus" class="alert alert-primary mb-0" role="status" aria-live="polite">Chargement de l'inventaire Config...</div>
|
|
</section>
|
|
|
|
|
|
<section id="profilesPanel" hidden aria-label="Profils Config">
|
|
<div class="d-flex flex-wrap gap-3 align-items-end justify-content-between mb-3">
|
|
<div class="flex-grow-1">
|
|
<h2 class="h5 mb-2">Inspection des profils</h2>
|
|
<p class="text-body-secondary small mb-3">La sélection, la fusion global/profil et la résolution environnementale restent sous contrôle de ksp-config-lib.</p>
|
|
<div class="row g-2">
|
|
<div class="col-xl-6">
|
|
<label class="form-label" for="profileDocumentSelect">Document Config</label>
|
|
<select id="profileDocumentSelect" class="form-select" disabled></select>
|
|
</div>
|
|
<div class="col-xl-6">
|
|
<label class="form-label" for="profileIdSelect">Profil inspecté</label>
|
|
<select id="profileIdSelect" class="form-select" disabled></select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-2">
|
|
<button id="inspectDefaultProfile" class="btn btn-outline-secondary btn-sm" type="button">Profil par défaut</button>
|
|
<button id="reloadProfileDetail" class="btn btn-outline-secondary btn-sm" type="button">Recharger</button>
|
|
<button id="refreshProfiles" class="btn btn-outline-primary btn-sm" type="button">
|
|
<i class="fa-solid fa-rotate me-1" aria-hidden="true"></i>
|
|
Rafraîchir
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<section id="profileDetailPanel" hidden class="border rounded p-3 mb-4 bg-body-tertiary" aria-label="Détail du profil Config">
|
|
<dl class="row small mb-4 app-profile-metadata">
|
|
<dt class="col-lg-3">file_id</dt>
|
|
<dd id="profileDetailFileId" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Path résolu</dt>
|
|
<dd id="profileDetailPath" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">default_profile</dt>
|
|
<dd id="profileDetailDefault" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Profil sélectionné</dt>
|
|
<dd id="profileDetailSelected" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3">Source de sélection</dt>
|
|
<dd id="profileDetailSelectionSource" class="col-lg-9">—</dd>
|
|
<dt class="col-lg-3 mb-0">Sensibilité effective</dt>
|
|
<dd id="profileDetailSensitivity" class="col-lg-9 mb-0">—</dd>
|
|
</dl>
|
|
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-xxl-4">
|
|
<h3 class="h6">Globals source</h3>
|
|
<pre id="profileGlobalsJson" class="app-profile-json mb-0"></pre>
|
|
</div>
|
|
<div class="col-xxl-4">
|
|
<h3 class="h6">Profil source</h3>
|
|
<pre id="profileSourceJson" class="app-profile-json mb-0"></pre>
|
|
</div>
|
|
<div class="col-xxl-4">
|
|
<h3 class="h6">Effective sûre</h3>
|
|
<pre id="profileEffectiveJson" class="app-profile-json mb-0"></pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-xl-5">
|
|
<h3 class="h6">Provenance top-level</h3>
|
|
<div class="table-responsive">
|
|
<table id="profileOriginsTable" class="table table-sm table-striped align-middle mb-0">
|
|
<thead>
|
|
<tr><th scope="col">Clé</th><th scope="col">Origine</th></tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-7">
|
|
<h3 class="h6">Provenance environnement</h3>
|
|
<div class="table-responsive">
|
|
<table id="profileEnvironmentProvenanceTable" class="table table-sm table-striped align-middle mb-0">
|
|
<thead>
|
|
<tr><th scope="col">JSON Pointer</th><th scope="col">Variable</th><th scope="col">Source</th><th scope="col">Sensibilité</th></tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="form-text mt-3">L'effective affichée utilise exclusivement la représentation sûre/redacted de Config ; aucune valeur réelle Secret n'est projetée.</div>
|
|
</section>
|
|
|
|
<div id="profilesStatus" class="alert alert-primary mb-0" role="status" aria-live="polite">Chargement des profils Config...</div>
|
|
</section>
|
|
|
|
<section id="environmentPanel" hidden aria-label="Environnement Config">
|
|
<div class="d-flex flex-wrap gap-2 align-items-center justify-content-between mb-3">
|
|
<div>
|
|
<h2 class="h5 mb-1">Rapport Environnement / .env</h2>
|
|
<p class="text-body-secondary small mb-0">Valeurs desired/effective sûres, provenance externe, shadowing et mutations persistées exclusivement par ksp-config-lib.</p>
|
|
</div>
|
|
<button id="refreshEnvironment" class="btn btn-outline-primary btn-sm" type="button">
|
|
<i class="fa-solid fa-rotate me-1" aria-hidden="true"></i>
|
|
Rafraîchir
|
|
</button>
|
|
</div>
|
|
|
|
<div class="alert alert-light border small" role="note">
|
|
Priorité effective : <code>process > .env > fallback</code>. Une mutation ne modifie jamais l'environnement process déjà hérité. Les valeurs Secret restent redacted dans le rapport.
|
|
</div>
|
|
|
|
<div class="table-responsive mb-4">
|
|
<table id="environmentReportTable" class="table table-striped table-hover align-middle w-100">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">Variable</th>
|
|
<th scope="col">Namespace</th>
|
|
<th scope="col">Sensibilité</th>
|
|
<th scope="col">Desired .env (safe)</th>
|
|
<th scope="col">Effective (safe)</th>
|
|
<th scope="col">Source</th>
|
|
<th scope="col">Shadowed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div id="environmentStatus" class="alert alert-primary mb-4" role="status" aria-live="polite">Chargement du rapport environnement...</div>
|
|
|
|
<section class="border rounded p-3 bg-body-tertiary" aria-label="Management .env">
|
|
<div class="d-flex flex-wrap gap-2 align-items-center justify-content-between mb-3">
|
|
<div>
|
|
<h2 class="h5 mb-1">Management / test .env</h2>
|
|
<p class="text-body-secondary small mb-0">Cliquer une ligne du rapport sélectionne son nom uniquement. Aucune ancienne valeur réelle n'est préchargée dans le formulaire.</p>
|
|
</div>
|
|
<button id="clearEnvironmentEditor" class="btn btn-outline-secondary btn-sm" type="button">Vider le formulaire</button>
|
|
</div>
|
|
|
|
<div class="row g-3 align-items-end mb-3">
|
|
<div class="col-xl-5">
|
|
<label class="form-label" for="environmentVariableName">Variable KSP/KSPB</label>
|
|
<input id="environmentVariableName" class="form-control font-monospace" type="text" list="environmentVariableSuggestions" autocomplete="off" placeholder="KSP_... ou KSPB_...">
|
|
<datalist id="environmentVariableSuggestions"></datalist>
|
|
</div>
|
|
<div class="col-xl-5">
|
|
<label class="form-label" for="environmentVariableValue">Nouvelle valeur</label>
|
|
<input id="environmentVariableValue" class="form-control font-monospace" type="text" autocomplete="new-password" spellcheck="false">
|
|
<div id="environmentEditorSensitivity" class="form-text">La valeur saisie n'est jamais préchargée depuis .env.</div>
|
|
</div>
|
|
<div class="col-xl-2 d-grid gap-2">
|
|
<button id="setEnvironmentValue" class="btn btn-primary btn-sm" type="button">Créer / Modifier</button>
|
|
<button id="removeEnvironmentValue" class="btn btn-outline-danger btn-sm" type="button">Supprimer</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="environmentMutationStatus" class="alert alert-secondary mb-3" role="status" aria-live="polite">
|
|
Aucune mutation effectuée pendant ce lancement.
|
|
</div>
|
|
|
|
<div id="environmentMutationResult" hidden>
|
|
<h3 class="h6">Dernier résultat ConfigEnvironmentChangeReport</h3>
|
|
<dl class="row small mb-0 app-profile-metadata">
|
|
<dt class="col-md-4">Opération</dt>
|
|
<dd id="environmentMutationOperation" class="col-md-8">—</dd>
|
|
<dt class="col-md-4">Variable</dt>
|
|
<dd id="environmentMutationVariable" class="col-md-8 font-monospace">—</dd>
|
|
<dt class="col-md-4">source_changed</dt>
|
|
<dd id="environmentMutationSourceChanged" class="col-md-8 font-monospace">—</dd>
|
|
<dt class="col-md-4">effective_changed</dt>
|
|
<dd id="environmentMutationEffectiveChanged" class="col-md-8 font-monospace">—</dd>
|
|
<dt class="col-md-4">shadowed_by_process</dt>
|
|
<dd id="environmentMutationShadowed" class="col-md-8 font-monospace">—</dd>
|
|
<dt class="col-md-4 mb-0">reload_required</dt>
|
|
<dd id="environmentMutationReload" class="col-md-8 mb-0 font-monospace">—</dd>
|
|
</dl>
|
|
<div class="form-text mt-2">Le rapport est rechargé après chaque mutation. Un consumer qui conserve son propre snapshot doit respecter <code>reload_required</code>.</div>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="placeholderPanel" hidden aria-live="polite">
|
|
<div class="alert alert-secondary mb-4" role="status">
|
|
Cette route du shell est prête ; son contenu fonctionnel sera ajouté dans la prerelease prévue par le plan 0.1.4.
|
|
</div>
|
|
</section>
|
|
|
|
<div class="alert alert-primary mb-0" role="status">
|
|
<i class="fa-solid fa-desktop me-2" aria-hidden="true"></i>
|
|
<span id="shellStatus" class="app-shell-status">Initialisation du frontend...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="app-footer bg-dark text-light">
|
|
<div class="container h-100 d-flex align-items-center justify-content-center">
|
|
<small>© 2026 SASEDEV</small>
|
|
</div>
|
|
</footer>
|
|
<script type="module" src="ts/main.ts" defer></script>
|
|
</body>
|
|
|
|
</html>
|