v0.5.3-pre.002
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_core_extraction.html -->
|
||||
<!-- version: 10 -->
|
||||
<!-- version: 11 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h1 class="h3 card-title">Extraction transactionnelle canonical vers core</h1>
|
||||
<p class="text-body-secondary mb-0">Chaque transaction canonique sélectionnée est validée, normalisée dans les tables core et enregistrée dans le ledger de traitement au sein d'une seule transaction PostgreSQL.</p>
|
||||
<p class="text-body-secondary mb-0">Chaque transaction canonique sélectionnée est validée, normalisée dans les tables core et enregistrée dans le ledger de traitement au sein d'une seule transaction de stockage atomique.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -163,4 +163,4 @@
|
||||
<script defer="" src="ts/demo_core_extraction.ts" type="module"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_decode_replay.html -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 9 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<label class="form-label" for="decodeReplaySignaturesTextarea">Signatures explicites, une par ligne</label>
|
||||
<textarea id="decodeReplaySignaturesTextarea" class="form-control font-monospace" rows="7" placeholder="Copier depuis demo_sql_replay_candidates"></textarea>
|
||||
<textarea id="decodeReplaySignaturesTextarea" class="form-control font-monospace" rows="7" placeholder="Copier depuis demo_store_replay_candidates"></textarea>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6">
|
||||
<label class="form-label" for="decodeReplayPathsTextarea">Instruction paths exacts, un par ligne</label>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_sql_pg_core.html -->
|
||||
<!-- version: 6 -->
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_store_core.html -->
|
||||
<!-- version: 8 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<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>Khadhroony Bot3 — PostgreSQL core store</title>
|
||||
<title>Khadhroony Bot3 — Core store diagnostics</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="container-fluid px-4 my-0">
|
||||
<div class="navbar-brand d-flex align-items-center">
|
||||
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">PostgreSQL core store</span></span>
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Core store diagnostics</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -36,11 +36,11 @@
|
||||
</div>
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-3">Statut</dt>
|
||||
<dd class="col-sm-9"><code id="sqlCoreStatus">Chargement...</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeCoreStatus">Chargement...</code></dd>
|
||||
<dt class="col-sm-3">Profil</dt>
|
||||
<dd class="col-sm-9"><code id="sqlCoreProfile">—</code></dd>
|
||||
<dt class="col-sm-3">DSN</dt>
|
||||
<dd class="col-sm-9"><code id="sqlCoreDsn">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeCoreProfile">—</code></dd>
|
||||
<dt class="col-sm-3">Connexion</dt>
|
||||
<dd class="col-sm-9"><code id="storeCoreConnection">—</code></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,13 +49,13 @@
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Tables core</h2>
|
||||
<h2 class="h5 card-title mb-3">Ressources Core</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlCoreTable">
|
||||
<table class="table table-sm align-middle mb-0" id="storeCoreTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
<th>Domaine</th>
|
||||
<th>Ressource</th>
|
||||
<th>Modèle</th>
|
||||
<th>Rôle</th>
|
||||
<th>Existe</th>
|
||||
<th>Lignes</th>
|
||||
@@ -64,7 +64,7 @@
|
||||
<th>Dernière insertion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="sqlCoreTableBody"></tbody>
|
||||
<tbody id="storeCoreTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlCoreJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
<div id="storeCoreJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données du store."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script type="module" src="ts/demo_sql_pg_core.ts" defer></script>
|
||||
<script type="module" src="ts/demo_store_core.ts" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_sql_diag.html -->
|
||||
<!-- version: 5 -->
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_store_diag.html -->
|
||||
<!-- version: 7 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<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>Khadhroony Bot3 — SQL diagnostics</title>
|
||||
<title>Khadhroony Bot3 — Store diagnostics</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="container-fluid px-4 my-0">
|
||||
<div class="navbar-brand d-flex align-items-center">
|
||||
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">SQL diagnostics</span></span>
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Store diagnostics</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-between align-items-center mb-3">
|
||||
<h1 class="h3 card-title mb-0">Diagnostic PostgreSQL</h1>
|
||||
<h1 class="h3 card-title mb-0">Diagnostic du store</h1>
|
||||
<div class="d-flex gap-2">
|
||||
<button id="refreshSqlDiagButton" class="btn btn-primary" type="button">Rafraîchir</button>
|
||||
<button id="copySqlDiagButton" class="btn btn-outline-secondary" type="button">Copier JSON</button>
|
||||
@@ -39,21 +39,21 @@
|
||||
</div>
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-3">Statut</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagStatus">Chargement...</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagStatus">Chargement...</code></dd>
|
||||
<dt class="col-sm-3">Fichier config</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagConfigPath">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagConfigPath">—</code></dd>
|
||||
<dt class="col-sm-3">Profil</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagProfile">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagProfile">—</code></dd>
|
||||
<dt class="col-sm-3">Backend</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagBackend">—</code></dd>
|
||||
<dt class="col-sm-3">DSN</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagDsn">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagBackend">—</code></dd>
|
||||
<dt class="col-sm-3">Connexion</dt>
|
||||
<dd class="col-sm-9"><code id="storeDiagConnection">—</code></dd>
|
||||
<dt class="col-sm-3">Schema courant</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagSchema">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagSchema">—</code></dd>
|
||||
<dt class="col-sm-3">Healthcheck</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagHealth">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagHealth">—</code></dd>
|
||||
<dt class="col-sm-3">Migrations</dt>
|
||||
<dd class="col-sm-9"><code id="sqlDiagMigration">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeDiagMigration">—</code></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,13 +62,13 @@
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Tables raw/core connues</h2>
|
||||
<h2 class="h5 card-title mb-3">Ressources store connues</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlDiagTable">
|
||||
<table class="table table-sm align-middle mb-0" id="storeDiagTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
<th>Domaine</th>
|
||||
<th>Ressource</th>
|
||||
<th>Modèle</th>
|
||||
<th>Rôle</th>
|
||||
<th>Existe</th>
|
||||
<th>Lignes</th>
|
||||
@@ -77,7 +77,7 @@
|
||||
<th>Dernière insertion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="sqlDiagTableBody"></tbody>
|
||||
<tbody id="storeDiagTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlDiagJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
<div id="storeDiagJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données du store."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,7 +104,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script type="module" src="ts/demo_sql_diag.ts" defer></script>
|
||||
<script type="module" src="ts/demo_store_diag.ts" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_sql_pg_raw.html -->
|
||||
<!-- version: 7 -->
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_store_raw.html -->
|
||||
<!-- version: 9 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<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>Khadhroony Bot3 — PostgreSQL canonical acquisition</title>
|
||||
<title>Khadhroony Bot3 — Raw store diagnostics</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="container-fluid px-4 my-0">
|
||||
<div class="navbar-brand d-flex align-items-center">
|
||||
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">PostgreSQL canonical acquisition</span></span>
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Raw store diagnostics</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -36,11 +36,11 @@
|
||||
</div>
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-3">Statut</dt>
|
||||
<dd class="col-sm-9"><code id="sqlRawStatus">Chargement...</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeRawStatus">Chargement...</code></dd>
|
||||
<dt class="col-sm-3">Profil</dt>
|
||||
<dd class="col-sm-9"><code id="sqlRawProfile">—</code></dd>
|
||||
<dt class="col-sm-3">DSN</dt>
|
||||
<dd class="col-sm-9"><code id="sqlRawDsn">—</code></dd>
|
||||
<dd class="col-sm-9"><code id="storeRawProfile">—</code></dd>
|
||||
<dt class="col-sm-3">Connexion</dt>
|
||||
<dd class="col-sm-9"><code id="storeRawConnection">—</code></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,11 +51,11 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Transactions canoniques et observations</h2>
|
||||
<div class="table-responsive app-table-full-width">
|
||||
<table class="table table-sm align-middle mb-0" id="sqlRawTable">
|
||||
<table class="table table-sm align-middle mb-0" id="storeRawTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Table</th>
|
||||
<th>Domaine</th>
|
||||
<th>Ressource</th>
|
||||
<th>Modèle</th>
|
||||
<th>Rôle</th>
|
||||
<th>Existe</th>
|
||||
<th>Lignes</th>
|
||||
@@ -64,7 +64,7 @@
|
||||
<th>Dernière insertion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="sqlRawTableBody"></tbody>
|
||||
<tbody id="storeRawTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title mb-3">Payload JSON</h2>
|
||||
<div id="sqlRawJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données SQL."}</div>
|
||||
<div id="storeRawJson" class="app-config-box app-json-viewer mb-0">{"status":"loading","message":"Chargement des données du store."}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script type="module" src="ts/demo_sql_pg_raw.ts" defer></script>
|
||||
<script type="module" src="ts/demo_store_raw.ts" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_sql_replay_candidates.html -->
|
||||
<!-- version: 11 -->
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_store_replay_candidates.html -->
|
||||
<!-- version: 15 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<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>Khadhroony Bot3 — Candidats de replay SQL</title>
|
||||
<title>Khadhroony Bot3 — Candidats de replay du store</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="container-fluid px-4 my-0">
|
||||
<div class="navbar-brand d-flex align-items-center">
|
||||
<img alt="Logo" src="imgs/logo.png" class="app-logo">
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">SQL replay candidates</span></span>
|
||||
<span class="ps-2 fs-4 fw-bold text-primary font-logo">Bot3 — <span class="badge text-bg-primary">Store replay candidates</span></span>
|
||||
</div>
|
||||
<div class="ms-auto d-flex align-items-center gap-2">
|
||||
<span id="replayCandidateProfileBadge" class="badge text-bg-info">Profil —</span>
|
||||
@@ -36,9 +36,9 @@
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<h1 class="h3 card-title">Exploration read-only des candidats</h1>
|
||||
<p class="text-body-secondary mb-2">Les requêtes sont paramétrées, bornées et sans SQL libre. Utilisez les cases à cocher pour sélectionner les lignes. La case du header sélectionne ou désélectionne toutes les lignes correspondant au filtre local. Sans sélection explicite, la copie et l’export CSV utilisent toutes les lignes filtrées. Les CSV UTF-8 avec BOM et séparateur point-virgule sont écrits par le backend Tauri dans <code>./data/exports_csv/</code>. LibreOffice Calc peut toujours afficher son dialogue d’import, car le format CSV ne décrit pas formellement son encodage ni son séparateur.</p>
|
||||
<p class="text-body-secondary mb-2">Les requêtes sont paramétrées, bornées et indépendantes du backend concret. Utilisez les cases à cocher pour sélectionner les lignes. La case du header sélectionne ou désélectionne toutes les lignes correspondant au filtre local. Sans sélection explicite, la copie et l’export CSV utilisent toutes les lignes filtrées. Les CSV UTF-8 avec BOM et séparateur point-virgule sont écrits par le backend Tauri dans <code>./data/exports_csv/</code>. LibreOffice Calc peut toujours afficher son dialogue d’import, car le format CSV ne décrit pas formellement son encodage ni son séparateur.</p>
|
||||
<div class="small text-body-secondary">
|
||||
<span class="fw-semibold">DSN :</span>
|
||||
<span class="fw-semibold">Connexion :</span>
|
||||
<code id="replayCandidateDsn">—</code>
|
||||
<span class="ms-3 fw-semibold">Limite serveur maximale :</span>
|
||||
<code id="replayCandidateMaximumLimit">—</code>
|
||||
@@ -68,7 +68,7 @@
|
||||
<section class="tab-pane fade show active" id="transactionsTabPane" role="tabpanel" aria-labelledby="transactionsTabButton" tabindex="0">
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 card-title">Filtres PostgreSQL bornés</h2>
|
||||
<h2 class="h5 card-title">Filtres store bornés</h2>
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-12 col-xl-4">
|
||||
<label for="transactionSignatureContainsInput" class="form-label">Signature contient</label>
|
||||
@@ -110,8 +110,8 @@
|
||||
<div class="col-6 col-md-3 col-xl-2">
|
||||
<label for="transactionProgramScopeSelect" class="form-label">Portée programme</label>
|
||||
<select id="transactionProgramScopeSelect" class="form-select">
|
||||
<option value="any">outer + inner + logs</option>
|
||||
<option value="outer">outer uniquement</option>
|
||||
<option value="any">top-level + inner + logs</option>
|
||||
<option value="top_level">top-level uniquement</option>
|
||||
<option value="inner">inner uniquement</option>
|
||||
<option value="logs">logs liés uniquement</option>
|
||||
</select>
|
||||
@@ -441,7 +441,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<script type="module" src="ts/demo_sql_replay_candidates.ts" defer></script>
|
||||
<script type="module" src="ts/demo_store_replay_candidates.ts" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/main.html -->
|
||||
<!-- version: 12 -->
|
||||
<!-- version: 14 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -48,12 +48,12 @@
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li>
|
||||
<h6 class="dropdown-header">SQL</h6>
|
||||
<h6 class="dropdown-header">Store</h6>
|
||||
</li>
|
||||
<li><a id="openDemoSqlDiagLink" class="dropdown-item" href="#">SQL diagnostics</a></li>
|
||||
<li><a id="openDemoSqlPgRawLink" class="dropdown-item" href="#">SQL PostgreSQL raw</a></li>
|
||||
<li><a id="openDemoSqlPgCoreLink" class="dropdown-item" href="#">SQL PostgreSQL core</a></li>
|
||||
<li><a id="openDemoSqlReplayCandidatesLink" class="dropdown-item" href="#">SQL replay candidates</a></li>
|
||||
<li><a id="openDemoStoreDiagLink" class="dropdown-item" href="#">Store diagnostics</a></li>
|
||||
<li><a id="openDemoStoreRawLink" class="dropdown-item" href="#">Raw store</a></li>
|
||||
<li><a id="openDemoStoreCoreLink" class="dropdown-item" href="#">Core store</a></li>
|
||||
<li><a id="openDemoStoreReplayCandidatesLink" class="dropdown-item" href="#">Store replay candidates</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
@@ -100,4 +100,4 @@
|
||||
<script type="module" src="ts/main.ts" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_core_extraction.ts
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -127,7 +127,7 @@ async function cancelCoreExtraction(): Promise<void> {
|
||||
}
|
||||
|
||||
|
||||
async function openDiagnostics(command: "open_demo_sql_pg_raw_window" | "open_demo_sql_pg_core_window" | "open_demo_sql_replay_candidates_window", label: string): Promise<void> {
|
||||
async function openDiagnostics(command: "open_demo_store_raw_window" | "open_demo_store_core_window" | "open_demo_store_replay_candidates_window", label: string): Promise<void> {
|
||||
try {
|
||||
await invoke(command);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", message: `${label} ouvert.` });
|
||||
@@ -166,13 +166,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
});
|
||||
element<HTMLButtonElement>("#openRawDiagnosticsButton").addEventListener("click", () => {
|
||||
void openDiagnostics("open_demo_sql_pg_raw_window", "Diagnostic raw");
|
||||
void openDiagnostics("open_demo_store_raw_window", "Diagnostic raw");
|
||||
});
|
||||
element<HTMLButtonElement>("#openCoreDiagnosticsButton").addEventListener("click", () => {
|
||||
void openDiagnostics("open_demo_sql_pg_core_window", "Diagnostic core");
|
||||
void openDiagnostics("open_demo_store_core_window", "Diagnostic core");
|
||||
});
|
||||
element<HTMLButtonElement>("#openReplayCandidatesButton").addEventListener("click", () => {
|
||||
void openDiagnostics("open_demo_sql_replay_candidates_window", "Sélecteur de candidats replay");
|
||||
void openDiagnostics("open_demo_store_replay_candidates_window", "Sélecteur de candidats replay");
|
||||
});
|
||||
element<HTMLButtonElement>("#cancelCoreExtractionButton").addEventListener("click", () => {
|
||||
void cancelCoreExtraction();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_decode_replay.ts
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -204,7 +204,7 @@ async function loadDiagnostics(): Promise<void> {
|
||||
try {
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_decode_replay", "Invoke demo_decode_replay_diagnostics");
|
||||
const diagnostics = await invoke<DemoDecodeDiagnosticsPayload>("demo_decode_replay_diagnostics");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_decode_replay", `Invoke demo_decode_replay_diagnostics completed tables=${diagnostics.tables.length} coverage=${diagnostics.coverage.length}`);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_decode_replay", `Invoke demo_decode_replay_diagnostics completed resources=${diagnostics.resources.length} coverage=${diagnostics.coverage.length}`);
|
||||
element<HTMLTextAreaElement>("#decodeReplayDiagnosticsOutput").value = JSON.stringify(diagnostics, null, 2);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -282,7 +282,7 @@ async function loadAnnotations(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function openWindow(command: "open_demo_sql_pg_core_window" | "open_demo_sql_replay_candidates_window"): Promise<void> {
|
||||
async function openWindow(command: "open_demo_store_core_window" | "open_demo_store_replay_candidates_window"): Promise<void> {
|
||||
try {
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_decode_replay", `Invoke ${command}`);
|
||||
await invoke(command);
|
||||
@@ -358,8 +358,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
element<HTMLButtonElement>("#cancelDecodeReplayButton").addEventListener("click", () => void cancelDecodeReplay());
|
||||
element<HTMLButtonElement>("#loadDecodeDiagnosticsButton").addEventListener("click", () => void loadDiagnostics());
|
||||
element<HTMLButtonElement>("#loadAnnotationsButton").addEventListener("click", () => void loadAnnotations());
|
||||
element<HTMLButtonElement>("#openReplayCandidatesFromDecodeButton").addEventListener("click", () => void openWindow("open_demo_sql_replay_candidates_window"));
|
||||
element<HTMLButtonElement>("#openCoreDiagnosticsFromDecodeButton").addEventListener("click", () => void openWindow("open_demo_sql_pg_core_window"));
|
||||
element<HTMLButtonElement>("#openReplayCandidatesFromDecodeButton").addEventListener("click", () => void openWindow("open_demo_store_replay_candidates_window"));
|
||||
element<HTMLButtonElement>("#openCoreDiagnosticsFromDecodeButton").addEventListener("click", () => void openWindow("open_demo_store_core_window"));
|
||||
void listen<DemoDecodeReplayProgressPayload>("demo-decode-replay-progress", event => appendLog(event.payload));
|
||||
void loadOptions().catch(caughtError => {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_solana_core.ts
|
||||
// version: 10
|
||||
// version: 11
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -20,18 +20,18 @@ const logLines: string[] = [];
|
||||
let running = false;
|
||||
let profileStoreReady = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
function element<T extends HTMLElement>(selector: string): T { const value=document.querySelector<T>(selector); if(!value){throw new Error(`Missing UI element: ${selector}`);} return value; }
|
||||
function integerValue(selector: string): number { const value=Number.parseInt(element<HTMLInputElement>(selector).value,10); if(!Number.isFinite(value)||value<0){throw new Error(`Valeur numérique invalide pour ${selector}`);} return value; }
|
||||
function selectedProfile(): DemoExecutionSolanaCoreProfileOption|null { const name=element<HTMLSelectElement>("#executionProfileSelect").value; return profileOptions.find(profile=>profile.name===name)??null; }
|
||||
function appendLog(payload: DemoExecutionSolanaCoreProgressPayload|{timestamp:string;level:string;stage:string;message:string;signature?:string|null}):void { const signature=payload.signature?` signature=${payload.signature}`:""; logLines.push(`${payload.timestamp} ${payload.level.toUpperCase()} [${payload.stage}] ${payload.message}${signature}`); const output=element<HTMLTextAreaElement>("#executionLogOutput"); output.value=logLines.join("\n"); output.scrollTop=output.scrollHeight; }
|
||||
function setRunning(value:boolean):void { running=value; const profile=selectedProfile(); element<HTMLButtonElement>("#simulateExecutionButton").disabled=value||!profile||!profileStoreReady; element<HTMLButtonElement>("#submitExecutionButton").disabled=value||!profile||!profileStoreReady||!profile.sendEnabled; element<HTMLButtonElement>("#generateRecipientButton").disabled=value; element<HTMLButtonElement>("#cancelExecutionButton").disabled=!value; const badge=element<HTMLElement>("#executionStatusBadge"); badge.textContent=value?"Exécution en cours":"Prêt"; badge.className=value?"badge text-bg-warning":"badge text-bg-success"; }
|
||||
function updateProfileHelp():void { const profile=selectedProfile(); const help=element<HTMLElement>("#executionProfileHelp"); if(!profile){help.textContent="Aucun profil Devnet compatible.";return;} help.textContent=`wallet=${profile.walletAlias}, spendMax=${profile.maxSpendLamports}, airdropMax=${profile.maxAirdropLamports}, send=${profile.sendEnabled?"enabled":"disabled"}`; element<HTMLInputElement>("#executionAirdropInput").max=String(profile.maxAirdropLamports); element<HTMLInputElement>("#executionLamportsInput").max=String(profile.maxSpendLamports); setRunning(running); }
|
||||
function buildRequest(submit:boolean):DemoExecutionSolanaCoreRequest { const recipient=element<HTMLInputElement>("#executionRecipientInput").value.trim(); if(recipient.length===0){throw new Error("Le destinataire est obligatoire.");} return {profileName:element<HTMLSelectElement>("#executionProfileSelect").value,recipient,lamports:integerValue("#executionLamportsInput"),airdropLamports:integerValue("#executionAirdropInput"),submit,operatorConfirmed:element<HTMLInputElement>("#executionOperatorConfirmedInput").checked,forcePostValidationReplay:element<HTMLInputElement>("#executionForceReplayInput").checked,materializeAfterDecode:element<HTMLInputElement>("#executionMaterializeInput").checked}; }
|
||||
function titledJson(title:string,value:string):string { try { const parsed:unknown=JSON.parse(value); if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed)){return JSON.stringify({title,...parsed},null,2);} return JSON.stringify({title,value:parsed},null,2); } catch { return JSON.stringify({title,status:"invalid_json",raw:value},null,2); } }
|
||||
function displaySummary(summary:DemoExecutionSolanaCoreSummaryPayload):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify({title:"Résumé",...summary},null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=titledJson("Plan exact",summary.planJson); element<HTMLTextAreaElement>("#executionSimulationOutput").value=titledJson("Simulation exacte",summary.simulationJson); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=titledJson("Confirmation et replay",summary.diagnosticsJson); }
|
||||
function displayExecutionFailure(message:string,submit:boolean):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify({title:"Résumé",status:"error",message},null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=JSON.stringify({title:"Plan exact",status:"unavailable",reason:"preflight_failed",message:"Aucun plan exécutable n’a été produit.",error:message},null,2); element<HTMLTextAreaElement>("#executionSimulationOutput").value=JSON.stringify({title:"Simulation exacte",status:"not_started",reason:"preflight_failed",message:"La simulation n’a pas été lancée.",error:message},null,2); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=JSON.stringify({title:"Confirmation et replay",status:"not_started",reason:"execution_failed_before_submission",message:submit?"La signature, l’envoi, la confirmation et le replay n’ont pas été exécutés.":"La confirmation et le replay ne s’appliquent pas à cette simulation refusée.",error:message},null,2); appendLog({timestamp:new Date().toISOString(),level:"error",stage:"failed",message}); }
|
||||
async function execute(submit:boolean):Promise<void>{if(running){return;}try{const request=buildRequest(submit);if(submit&&!request.operatorConfirmed){const message="La confirmation opérateur explicite est obligatoire avant signature et envoi.";displayExecutionFailure(message,submit);frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core","Submission blocked: operator confirmation missing");return;}setRunning(true);const summary=await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute",{request});displaySummary(summary);}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);displayExecutionFailure(message,submit);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Execution failed: ${message}`);}finally{setRunning(false);}}
|
||||
function element<T extends HTMLElement>(selector: string): T { const value = document.querySelector<T>(selector); if (!value) { throw new Error(`Missing UI element: ${selector}`); } return value; }
|
||||
function integerValue(selector: string): number { const value = Number.parseInt(element<HTMLInputElement>(selector).value, 10); if (!Number.isFinite(value) || value < 0) { throw new Error(`Valeur numérique invalide pour ${selector}`); } return value; }
|
||||
function selectedProfile(): DemoExecutionSolanaCoreProfileOption | null { const name = element<HTMLSelectElement>("#executionProfileSelect").value; return profileOptions.find(profile => profile.name === name) ?? null; }
|
||||
function appendLog(payload: DemoExecutionSolanaCoreProgressPayload | { timestamp: string; level: string; stage: string; message: string; signature?: string | null }): void { const signature = payload.signature ? ` signature=${payload.signature}` : ""; logLines.push(`${payload.timestamp} ${payload.level.toUpperCase()} [${payload.stage}] ${payload.message}${signature}`); const output = element<HTMLTextAreaElement>("#executionLogOutput"); output.value = logLines.join("\n"); output.scrollTop = output.scrollHeight; }
|
||||
function setRunning(value: boolean): void { running = value; const profile = selectedProfile(); element<HTMLButtonElement>("#simulateExecutionButton").disabled = value || !profile || !profileStoreReady; element<HTMLButtonElement>("#submitExecutionButton").disabled = value || !profile || !profileStoreReady || !profile.sendEnabled; element<HTMLButtonElement>("#generateRecipientButton").disabled = value; element<HTMLButtonElement>("#cancelExecutionButton").disabled = !value; const badge = element<HTMLElement>("#executionStatusBadge"); badge.textContent = value ? "Exécution en cours" : "Prêt"; badge.className = value ? "badge text-bg-warning" : "badge text-bg-success"; }
|
||||
function updateProfileHelp(): void { const profile = selectedProfile(); const help = element<HTMLElement>("#executionProfileHelp"); if (!profile) { help.textContent = "Aucun profil Devnet compatible."; return; } help.textContent = `wallet=${profile.walletAlias}, spendMax=${profile.maxSpendLamports}, airdropMax=${profile.maxAirdropLamports}, send=${profile.sendEnabled ? "enabled" : "disabled"}`; element<HTMLInputElement>("#executionAirdropInput").max = String(profile.maxAirdropLamports); element<HTMLInputElement>("#executionLamportsInput").max = String(profile.maxSpendLamports); setRunning(running); }
|
||||
function buildRequest(submit: boolean): DemoExecutionSolanaCoreRequest { const recipient = element<HTMLInputElement>("#executionRecipientInput").value.trim(); if (recipient.length === 0) { throw new Error("Le destinataire est obligatoire."); } return { profileName: element<HTMLSelectElement>("#executionProfileSelect").value, recipient, lamports: integerValue("#executionLamportsInput"), airdropLamports: integerValue("#executionAirdropInput"), submit, operatorConfirmed: element<HTMLInputElement>("#executionOperatorConfirmedInput").checked, forcePostValidationReplay: element<HTMLInputElement>("#executionForceReplayInput").checked, materializeAfterDecode: element<HTMLInputElement>("#executionMaterializeInput").checked }; }
|
||||
function titledJson(title: string, value: string): string { try { const parsed: unknown = JSON.parse(value); if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) { return JSON.stringify({ title, ...parsed }, null, 2); } return JSON.stringify({ title, value: parsed }, null, 2); } catch { return JSON.stringify({ title, status: "invalid_json", raw: value }, null, 2); } }
|
||||
function displaySummary(summary: DemoExecutionSolanaCoreSummaryPayload): void { element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ title: "Résumé", ...summary }, null, 2); element<HTMLTextAreaElement>("#executionPlanOutput").value = titledJson("Plan exact", summary.planJson); element<HTMLTextAreaElement>("#executionSimulationOutput").value = titledJson("Simulation exacte", summary.simulationJson); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = titledJson("Confirmation et replay", summary.diagnosticsJson); }
|
||||
function displayExecutionFailure(message: string, submit: boolean): void { element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ title: "Résumé", status: "error", message }, null, 2); element<HTMLTextAreaElement>("#executionPlanOutput").value = JSON.stringify({ title: "Plan exact", status: "unavailable", reason: "preflight_failed", message: "Aucun plan exécutable n’a été produit.", error: message }, null, 2); element<HTMLTextAreaElement>("#executionSimulationOutput").value = JSON.stringify({ title: "Simulation exacte", status: "not_started", reason: "preflight_failed", message: "La simulation n’a pas été lancée.", error: message }, null, 2); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = JSON.stringify({ title: "Confirmation et replay", status: "not_started", reason: "execution_failed_before_submission", message: submit ? "La signature, l’envoi, la confirmation et le replay n’ont pas été exécutés." : "La confirmation et le replay ne s’appliquent pas à cette simulation refusée.", error: message }, null, 2); appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "failed", message }); }
|
||||
async function execute(submit: boolean): Promise<void> { if (running) { return; } try { const request = buildRequest(submit); if (submit && !request.operatorConfirmed) { const message = "La confirmation opérateur explicite est obligatoire avant signature et envoi."; displayExecutionFailure(message, submit); frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core", "Submission blocked: operator confirmation missing"); return; } setRunning(true); const summary = await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute", { request }); displaySummary(summary); } catch (caughtError) { const message = caughtError instanceof Error ? caughtError.message : String(caughtError); displayExecutionFailure(message, submit); frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core", `Execution failed: ${message}`); } finally { setRunning(false); } }
|
||||
|
||||
async function prepareSelectedProfile():Promise<void>{const profile=selectedProfile();profileStoreReady=false;setRunning(running);if(!profile){return;}appendLog({timestamp:new Date().toISOString(),level:"info",stage:"store_prepare",message:`Vérification PostgreSQL du profil ${profile.name}.`});try{const readiness=await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile",{profileName:profile.name});profileStoreReady=true;appendLog({timestamp:new Date().toISOString(),level:"info",stage:"store_ready",message:`PostgreSQL prêt: ${readiness.existingTablesAfter}/${readiness.expectedTables} tables, créées=${readiness.createdTables}, autoInit=${readiness.autoInitializeSchema}.`});}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Devnet store preparation failed: ${message}`);}finally{setRunning(running);}}
|
||||
async function loadOptions():Promise<void>{const options=await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");profileOptions=options.profiles;const select=element<HTMLSelectElement>("#executionProfileSelect");select.replaceChildren();for(const profile of profileOptions){const option=document.createElement("option");option.value=profile.name;option.textContent=profile.name;option.selected=profile.name===options.defaultProfileName;select.append(option);}element<HTMLInputElement>("#executionLamportsInput").value=String(options.defaultTransferLamports);updateProfileHelp();setRunning(options.running);await prepareSelectedProfile();}
|
||||
document.addEventListener("DOMContentLoaded",async()=>{installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core");frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core","Solana Core execution window loaded");await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress",event=>appendLog(event.payload));element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change",()=>{updateProfileHelp();void prepareSelectedProfile();});element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click",async()=>{const payload=await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");element<HTMLInputElement>("#executionRecipientInput").value=payload.publicKey;});element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click",()=>void execute(false));element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click",()=>void execute(true));element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click",()=>void invoke("demo_execution_solana_core_cancel"));element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear",()=>{logLines.length=0;});try{await loadOptions();}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Options loading failed: ${message}`);}});
|
||||
async function prepareSelectedProfile(): Promise<void> { const profile = selectedProfile(); profileStoreReady = false; setRunning(running); if (!profile) { return; } appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_prepare", message: `Vérification du store du profil ${profile.name}.` }); try { const readiness = await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile", { profileName: profile.name }); profileStoreReady = true; appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_ready", message: `Store ${readiness.backend} prêt: ${readiness.availableResourcesAfter}/${readiness.expectedResources} ressources, créées=${readiness.createdResources}, autoInit=${readiness.autoInitializeSchema}.` }); } catch (caughtError) { const message = caughtError instanceof Error ? caughtError.message : String(caughtError); frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core", `Devnet store preparation failed: ${message}`); } finally { setRunning(running); } }
|
||||
async function loadOptions(): Promise<void> { const options = await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options"); profileOptions = options.profiles; const select = element<HTMLSelectElement>("#executionProfileSelect"); select.replaceChildren(); for (const profile of profileOptions) { const option = document.createElement("option"); option.value = profile.name; option.textContent = profile.name; option.selected = profile.name === options.defaultProfileName; select.append(option); } element<HTMLInputElement>("#executionLamportsInput").value = String(options.defaultTransferLamports); updateProfileHelp(); setRunning(options.running); await prepareSelectedProfile(); }
|
||||
document.addEventListener("DOMContentLoaded", async () => { installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core"); frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core", "Solana Core execution window loaded"); await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress", event => appendLog(event.payload)); element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", () => { updateProfileHelp(); void prepareSelectedProfile(); }); element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click", async () => { const payload = await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient"); element<HTMLInputElement>("#executionRecipientInput").value = payload.publicKey; }); element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click", () => void execute(false)); element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click", () => void execute(true)); element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click", () => void invoke("demo_execution_solana_core_cancel")); element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear", () => { logLines.length = 0; }); try { await loadOptions(); } catch (caughtError) { const message = caughtError instanceof Error ? caughtError.message : String(caughtError); frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core", `Options loading failed: ${message}`); } });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||
// version: 10
|
||||
// version: 11
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -896,11 +896,11 @@ async function prepareSelectedProfile(): Promise<void> {
|
||||
if (!profile) {
|
||||
return;
|
||||
}
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_prepare", message: `Vérification PostgreSQL du profil ${profile.name}.` });
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_prepare", message: `Vérification du store du profil ${profile.name}.` });
|
||||
try {
|
||||
const readiness = await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile", { profileName: profile.name });
|
||||
profileStoreReady = true;
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_ready", message: `PostgreSQL prêt: ${readiness.existingTablesAfter}/${readiness.expectedTables} tables, créées=${readiness.createdTables}, autoInit=${readiness.autoInitializeSchema}.` });
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_ready", message: `Store ${readiness.backend} prêt: ${readiness.availableResourcesAfter}/${readiness.expectedResources} ressources, créées=${readiness.createdResources}, autoInit=${readiness.autoInitializeSchema}.` });
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Devnet store preparation failed: ${message}`);
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_pg_core.ts
|
||||
// version: 4
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_store_core.ts
|
||||
// version: 6
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import { renderJsonViewer, renderTables, setText } from "./demo_sql_tables";
|
||||
import type { DemoSqlPgCorePayload } from "./bindings/kb_app_demo_desktop/demo_sql_pg_core/DemoSqlPgCorePayload";
|
||||
import { renderJsonViewer, renderTables, setText } from "./demo_store_tables";
|
||||
import type { DemoStoreCorePayload } from "./bindings/kb_app_demo_desktop/demo_store_core/DemoStoreCorePayload";
|
||||
|
||||
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
|
||||
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
||||
|
||||
async function refreshCore(): Promise<void> {
|
||||
setText("#sqlCoreStatus", "Chargement...");
|
||||
setText("#storeCoreStatus", "Chargement...");
|
||||
try {
|
||||
const payload = await invoke<DemoSqlPgCorePayload>("load_demo_sql_pg_core");
|
||||
setText("#sqlCoreProfile", payload.activeProfileName);
|
||||
setText("#sqlCoreDsn", payload.maskedDsn);
|
||||
setText("#sqlCoreStatus", "OK");
|
||||
renderTables("#sqlCoreTable", "#sqlCoreTableBody", payload.tables);
|
||||
renderJsonViewer("#sqlCoreJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_pg_core", "PostgreSQL core diagnostics refreshed");
|
||||
const payload = await invoke<DemoStoreCorePayload>("load_demo_store_core");
|
||||
setText("#storeCoreProfile", payload.activeProfileName);
|
||||
setText("#storeCoreConnection", payload.connectionDescriptor);
|
||||
setText("#storeCoreStatus", "OK");
|
||||
renderTables("#storeCoreTable", "#storeCoreTableBody", payload.resources);
|
||||
renderJsonViewer("#storeCoreJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_core", "Core store diagnostics refreshed");
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
setText("#sqlCoreStatus", `Erreur : ${message}`);
|
||||
renderJsonViewer("#sqlCoreJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_sql_pg_core", `PostgreSQL core diagnostics loading failed: ${message}`);
|
||||
setText("#storeCoreStatus", `Erreur : ${message}`);
|
||||
renderJsonViewer("#storeCoreJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_store_core", `Core store diagnostics loading failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_sql_pg_core");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_pg_core", "PostgreSQL core demo window loaded");
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_store_core");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_core", "Core store demo window loaded");
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||
document.querySelector<HTMLButtonElement>("#refreshSqlCoreButton")?.addEventListener("click", () => {
|
||||
@@ -1,41 +1,41 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_diag.ts
|
||||
// version: 3
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_store_diag.ts
|
||||
// version: 5
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import { jsonText, renderJsonViewer, renderTables, setText } from "./demo_sql_tables";
|
||||
import type { DemoSqlDiagPayload } from "./bindings/kb_app_demo_desktop/demo_sql_diag/DemoSqlDiagPayload";
|
||||
import { jsonText, renderJsonViewer, renderTables, setText } from "./demo_store_tables";
|
||||
import type { DemoStoreDiagPayload } from "./bindings/kb_app_demo_desktop/demo_store_diag/DemoStoreDiagPayload";
|
||||
|
||||
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
|
||||
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
||||
|
||||
let latestPayload: DemoSqlDiagPayload | null = null;
|
||||
let latestPayload: DemoStoreDiagPayload | null = null;
|
||||
|
||||
async function refreshDiagnostics(): Promise<void> {
|
||||
setText("#sqlDiagStatus", "Chargement...");
|
||||
setText("#storeDiagStatus", "Chargement...");
|
||||
try {
|
||||
const payload = await invoke<DemoSqlDiagPayload>("load_demo_sql_diag");
|
||||
setText("#sqlDiagConfigPath", payload.configPath);
|
||||
setText("#sqlDiagProfile", payload.activeProfileName);
|
||||
setText("#sqlDiagBackend", payload.backend);
|
||||
setText("#sqlDiagDsn", payload.maskedDsn);
|
||||
setText("#sqlDiagSchema", payload.currentSchema ?? "—");
|
||||
setText("#sqlDiagHealth", payload.healthStatus);
|
||||
setText("#sqlDiagMigration", payload.migrationStatus);
|
||||
setText("#sqlDiagStatus", "OK");
|
||||
renderTables("#sqlDiagTable", "#sqlDiagTableBody", payload.tables);
|
||||
const payload = await invoke<DemoStoreDiagPayload>("load_demo_store_diag");
|
||||
setText("#storeDiagConfigPath", payload.configPath);
|
||||
setText("#storeDiagProfile", payload.activeProfileName);
|
||||
setText("#storeDiagBackend", payload.backend);
|
||||
setText("#storeDiagConnection", payload.connectionDescriptor);
|
||||
setText("#storeDiagSchema", payload.namespace ?? "—");
|
||||
setText("#storeDiagHealth", payload.healthStatus);
|
||||
setText("#storeDiagMigration", payload.migrationStatus);
|
||||
setText("#storeDiagStatus", "OK");
|
||||
renderTables("#storeDiagTable", "#storeDiagTableBody", payload.resources);
|
||||
latestPayload = payload;
|
||||
renderJsonViewer("#sqlDiagJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_diag", "SQL diagnostics refreshed");
|
||||
renderJsonViewer("#storeDiagJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_diag", "Store diagnostics refreshed");
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
setText("#sqlDiagStatus", `Erreur : ${message}`);
|
||||
setText("#storeDiagStatus", `Erreur : ${message}`);
|
||||
latestPayload = null;
|
||||
renderJsonViewer("#sqlDiagJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_sql_diag", `SQL diagnostics loading failed: ${message}`);
|
||||
renderJsonViewer("#storeDiagJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_store_diag", `Store diagnostics loading failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ async function copyDiagnostics(): Promise<void> {
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_sql_diag");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_diag", "SQL diagnostics demo window loaded");
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_store_diag");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_diag", "Store diagnostics demo window loaded");
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||
document.querySelector<HTMLButtonElement>("#refreshSqlDiagButton")?.addEventListener("click", () => {
|
||||
@@ -1,38 +1,38 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_pg_raw.ts
|
||||
// version: 4
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_store_raw.ts
|
||||
// version: 6
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import { renderJsonViewer, renderTables, setText } from "./demo_sql_tables";
|
||||
import type { DemoSqlPgRawPayload } from "./bindings/kb_app_demo_desktop/demo_sql_pg_raw/DemoSqlPgRawPayload";
|
||||
import { renderJsonViewer, renderTables, setText } from "./demo_store_tables";
|
||||
import type { DemoStoreRawPayload } from "./bindings/kb_app_demo_desktop/demo_store_raw/DemoStoreRawPayload";
|
||||
|
||||
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
|
||||
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
||||
|
||||
async function refreshRaw(): Promise<void> {
|
||||
setText("#sqlRawStatus", "Chargement...");
|
||||
setText("#storeRawStatus", "Chargement...");
|
||||
try {
|
||||
const payload = await invoke<DemoSqlPgRawPayload>("load_demo_sql_pg_raw");
|
||||
setText("#sqlRawProfile", payload.activeProfileName);
|
||||
setText("#sqlRawDsn", payload.maskedDsn);
|
||||
setText("#sqlRawStatus", "OK");
|
||||
renderTables("#sqlRawTable", "#sqlRawTableBody", payload.tables);
|
||||
renderJsonViewer("#sqlRawJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_pg_raw", "PostgreSQL raw diagnostics refreshed");
|
||||
const payload = await invoke<DemoStoreRawPayload>("load_demo_store_raw");
|
||||
setText("#storeRawProfile", payload.activeProfileName);
|
||||
setText("#storeRawConnection", payload.connectionDescriptor);
|
||||
setText("#storeRawStatus", "OK");
|
||||
renderTables("#storeRawTable", "#storeRawTableBody", payload.resources);
|
||||
renderJsonViewer("#storeRawJson", payload);
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_raw", "Raw store diagnostics refreshed");
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
setText("#sqlRawStatus", `Erreur : ${message}`);
|
||||
renderJsonViewer("#sqlRawJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_sql_pg_raw", `PostgreSQL raw diagnostics loading failed: ${message}`);
|
||||
setText("#storeRawStatus", `Erreur : ${message}`);
|
||||
renderJsonViewer("#storeRawJson", { error: message });
|
||||
frontendError("kb_app_demo_desktop.frontend.demo_store_raw", `Raw store diagnostics loading failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_sql_pg_raw");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_sql_pg_raw", "PostgreSQL raw demo window loaded");
|
||||
installFrontendConsoleBridge("kb_app_demo_desktop.frontend.demo_store_raw");
|
||||
frontendDebug("kb_app_demo_desktop.frontend.demo_store_raw", "Raw store demo window loaded");
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||
document.querySelector<HTMLButtonElement>("#refreshSqlRawButton")?.addEventListener("click", () => {
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_replay_candidates.ts
|
||||
// version: 9
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_store_replay_candidates.ts
|
||||
// version: 11
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -10,14 +10,14 @@ import "datatables.net-select-bs5";
|
||||
import "datatables.net-select-bs5/css/select.bootstrap5.css";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { frontendDebug, frontendError, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import type { DemoSqlReplayEntityRequest } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayEntityRequest";
|
||||
import type { DemoSqlReplayEntityRow } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayEntityRow";
|
||||
import type { DemoSqlReplayKnownProgramOption } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayKnownProgramOption";
|
||||
import type { DemoSqlReplayOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayOptionsPayload";
|
||||
import type { DemoSqlReplayProgramRequest } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayProgramRequest";
|
||||
import type { DemoSqlReplayProgramRow } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayProgramRow";
|
||||
import type { DemoSqlReplayTransactionRequest } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayTransactionRequest";
|
||||
import type { DemoSqlReplayTransactionRow } from "./bindings/kb_app_demo_desktop/demo_sql_replay_candidates/DemoSqlReplayTransactionRow";
|
||||
import type { DemoStoreReplayEntityRequest } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayEntityRequest";
|
||||
import type { DemoStoreReplayEntityRow } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayEntityRow";
|
||||
import type { DemoStoreReplayKnownProgramOption } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayKnownProgramOption";
|
||||
import type { DemoStoreReplayOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayOptionsPayload";
|
||||
import type { DemoStoreReplayProgramRequest } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayProgramRequest";
|
||||
import type { DemoStoreReplayProgramRow } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayProgramRow";
|
||||
import type { DemoStoreReplayTransactionRequest } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayTransactionRequest";
|
||||
import type { DemoStoreReplayTransactionRow } from "./bindings/kb_app_demo_desktop/demo_store_replay_candidates/DemoStoreReplayTransactionRow";
|
||||
|
||||
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
|
||||
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
||||
@@ -40,7 +40,7 @@ type EntityViewConfig = {
|
||||
fileName: string;
|
||||
};
|
||||
|
||||
const tracingTarget = "kb_app_demo_desktop.frontend.demo_sql_replay_candidates";
|
||||
const tracingTarget = "kb_app_demo_desktop.frontend.demo_store_replay_candidates";
|
||||
const entityViewConfigs: EntityViewConfig[] = [
|
||||
{
|
||||
kind: "mint",
|
||||
@@ -88,11 +88,11 @@ const entityViewConfigs: EntityViewConfig[] = [
|
||||
fileName: "replay_account_keys.csv",
|
||||
},
|
||||
];
|
||||
let transactionTable: Api<DemoSqlReplayTransactionRow> | null = null;
|
||||
let programTable: Api<DemoSqlReplayProgramRow> | null = null;
|
||||
let mintTable: Api<DemoSqlReplayEntityRow> | null = null;
|
||||
let ownerTable: Api<DemoSqlReplayEntityRow> | null = null;
|
||||
let accountTable: Api<DemoSqlReplayEntityRow> | null = null;
|
||||
let transactionTable: Api<DemoStoreReplayTransactionRow> | null = null;
|
||||
let programTable: Api<DemoStoreReplayProgramRow> | null = null;
|
||||
let mintTable: Api<DemoStoreReplayEntityRow> | null = null;
|
||||
let ownerTable: Api<DemoStoreReplayEntityRow> | null = null;
|
||||
let accountTable: Api<DemoStoreReplayEntityRow> | null = null;
|
||||
let busyOperationCount = 0;
|
||||
let maximumReplayCandidateLimit = 100_000;
|
||||
|
||||
@@ -199,7 +199,7 @@ function badgeDisplay(value: unknown, type: string): string {
|
||||
return `<span class="badge ${className}">${escapeHtml(text)}</span>`;
|
||||
}
|
||||
|
||||
function coreStatusText(row: DemoSqlReplayTransactionRow): string {
|
||||
function coreStatusText(row: DemoStoreReplayTransactionRow): string {
|
||||
if (!row.hasCoreTransaction) {
|
||||
return "absent";
|
||||
}
|
||||
@@ -209,7 +209,7 @@ function coreStatusText(row: DemoSqlReplayTransactionRow): string {
|
||||
return "présent";
|
||||
}
|
||||
|
||||
function coreDisplay(_value: unknown, type: string, row: DemoSqlReplayTransactionRow): string | number {
|
||||
function coreDisplay(_value: unknown, type: string, row: DemoStoreReplayTransactionRow): string | number {
|
||||
if (type === "display") {
|
||||
if (!row.hasCoreTransaction) {
|
||||
return '<span class="badge text-bg-secondary">absent</span>';
|
||||
@@ -228,7 +228,7 @@ function coreDisplay(_value: unknown, type: string, row: DemoSqlReplayTransactio
|
||||
return row.hasCoreTransaction ? 1 : 2;
|
||||
}
|
||||
|
||||
function occurrenceRatioDisplay(_value: unknown, type: string, row: DemoSqlReplayEntityRow): string | number {
|
||||
function occurrenceRatioDisplay(_value: unknown, type: string, row: DemoStoreReplayEntityRow): string | number {
|
||||
const ratio = row.transactionCount > 0 ? row.occurrenceCount / row.transactionCount : 0;
|
||||
if (type === "display" || type === "filter") {
|
||||
return ratio.toFixed(2);
|
||||
@@ -236,7 +236,7 @@ function occurrenceRatioDisplay(_value: unknown, type: string, row: DemoSqlRepla
|
||||
return ratio;
|
||||
}
|
||||
|
||||
function slotSpanDisplay(_value: unknown, type: string, row: DemoSqlReplayEntityRow): string | number {
|
||||
function slotSpanDisplay(_value: unknown, type: string, row: DemoStoreReplayEntityRow): string | number {
|
||||
const span = Math.max(0, row.maxSlot - row.minSlot);
|
||||
if (type === "display" || type === "filter") {
|
||||
return String(span);
|
||||
@@ -258,8 +258,8 @@ function commonLanguage(emptyTable: string, infoLabel: string, zeroRecords: stri
|
||||
};
|
||||
}
|
||||
|
||||
function createTransactionTable(): Api<DemoSqlReplayTransactionRow> {
|
||||
return new DataTable<DemoSqlReplayTransactionRow>("#transactionCandidateTable", {
|
||||
function createTransactionTable(): Api<DemoStoreReplayTransactionRow> {
|
||||
return new DataTable<DemoStoreReplayTransactionRow>("#transactionCandidateTable", {
|
||||
data: [],
|
||||
columns: [
|
||||
{
|
||||
@@ -277,9 +277,9 @@ function createTransactionTable(): Api<DemoSqlReplayTransactionRow> {
|
||||
{ data: "ledgerStatus", render: badgeDisplay },
|
||||
{ data: "processorVersion", defaultContent: "—", render: codeDisplay },
|
||||
{ data: "attemptCount" },
|
||||
{ data: "outerInstructionCount" },
|
||||
{ data: "topLevelInstructionCount" },
|
||||
{ data: "innerInstructionCount" },
|
||||
{ data: "outerProgramCount" },
|
||||
{ data: "topLevelProgramCount" },
|
||||
{ data: "innerProgramCount" },
|
||||
{ data: "updatedAt" },
|
||||
],
|
||||
@@ -296,8 +296,8 @@ function createTransactionTable(): Api<DemoSqlReplayTransactionRow> {
|
||||
});
|
||||
}
|
||||
|
||||
function createProgramTable(): Api<DemoSqlReplayProgramRow> {
|
||||
return new DataTable<DemoSqlReplayProgramRow>("#programCandidateTable", {
|
||||
function createProgramTable(): Api<DemoStoreReplayProgramRow> {
|
||||
return new DataTable<DemoStoreReplayProgramRow>("#programCandidateTable", {
|
||||
data: [],
|
||||
columns: [
|
||||
{
|
||||
@@ -311,7 +311,7 @@ function createProgramTable(): Api<DemoSqlReplayProgramRow> {
|
||||
{ data: "programCode", defaultContent: "—", render: codeDisplay },
|
||||
{ data: "programId", render: copyableCodeDisplay("le program ID") },
|
||||
{ data: "transactionCount" },
|
||||
{ data: "outerInstructionCount" },
|
||||
{ data: "topLevelInstructionCount" },
|
||||
{ data: "innerInstructionCount" },
|
||||
{ data: "logCount" },
|
||||
{ data: "minSlot" },
|
||||
@@ -330,8 +330,8 @@ function createProgramTable(): Api<DemoSqlReplayProgramRow> {
|
||||
});
|
||||
}
|
||||
|
||||
function createEntityTable(config: EntityViewConfig): Api<DemoSqlReplayEntityRow> {
|
||||
return new DataTable<DemoSqlReplayEntityRow>(config.tableSelector, {
|
||||
function createEntityTable(config: EntityViewConfig): Api<DemoStoreReplayEntityRow> {
|
||||
return new DataTable<DemoStoreReplayEntityRow>(config.tableSelector, {
|
||||
data: [],
|
||||
columns: [
|
||||
{
|
||||
@@ -363,7 +363,7 @@ function createEntityTable(config: EntityViewConfig): Api<DemoSqlReplayEntityRow
|
||||
});
|
||||
}
|
||||
|
||||
function entityTable(kind: EntityKindCode): Api<DemoSqlReplayEntityRow> | null {
|
||||
function entityTable(kind: EntityKindCode): Api<DemoStoreReplayEntityRow> | null {
|
||||
if (kind === "mint") {
|
||||
return mintTable;
|
||||
}
|
||||
@@ -425,7 +425,7 @@ function setBusy(busy: boolean, message: string): void {
|
||||
});
|
||||
}
|
||||
|
||||
function buildTransactionRequest(): DemoSqlReplayTransactionRequest {
|
||||
function buildTransactionRequest(): DemoStoreReplayTransactionRequest {
|
||||
const entityKind = optionalInputValue("#transactionEntityKindSelect");
|
||||
const entityValue = optionalInputValue("#transactionEntityValueInput");
|
||||
if ((entityKind === null) !== (entityValue === null)) {
|
||||
@@ -484,9 +484,9 @@ async function loadTransactions(): Promise<void> {
|
||||
try {
|
||||
setBusy(true, "Chargement transactions");
|
||||
const request = buildTransactionRequest();
|
||||
const rows = await invoke<DemoSqlReplayTransactionRow[]>("load_demo_sql_replay_transactions", { request });
|
||||
const rows = await invoke<DemoStoreReplayTransactionRow[]>("load_demo_store_replay_transactions", { request });
|
||||
replaceRows(transactionTable, rows);
|
||||
element<HTMLElement>("#transactionResultSummary").textContent = `${rows.length} transaction(s) chargée(s) depuis PostgreSQL.`;
|
||||
element<HTMLElement>("#transactionResultSummary").textContent = `${rows.length} transaction(s) chargée(s) depuis le store actif.`;
|
||||
frontendDebug(tracingTarget, `loaded ${rows.length} replay transaction candidates`);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -503,13 +503,13 @@ async function loadPrograms(): Promise<void> {
|
||||
}
|
||||
try {
|
||||
setBusy(true, "Chargement programmes");
|
||||
const request: DemoSqlReplayProgramRequest = {
|
||||
const request: DemoStoreReplayProgramRequest = {
|
||||
programIdContains: optionalInputValue("#programContainsInput"),
|
||||
limit: boundedPositiveIntegerValue("#programLimitInput"),
|
||||
};
|
||||
const rows = await invoke<DemoSqlReplayProgramRow[]>("load_demo_sql_replay_programs", { request });
|
||||
const rows = await invoke<DemoStoreReplayProgramRow[]>("load_demo_store_replay_programs", { request });
|
||||
replaceRows(programTable, rows);
|
||||
element<HTMLElement>("#programResultSummary").textContent = `${rows.length} programme(s) chargé(s), avec occurrences outer, inner et logs liés.`;
|
||||
element<HTMLElement>("#programResultSummary").textContent = `${rows.length} programme(s) chargé(s), avec occurrences top-level, inner et logs liés.`;
|
||||
frontendDebug(tracingTarget, `loaded ${rows.length} replay program summaries`);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -527,14 +527,14 @@ async function loadEntity(config: EntityViewConfig): Promise<void> {
|
||||
}
|
||||
try {
|
||||
setBusy(true, `Chargement ${config.pluralLabel}`);
|
||||
const request: DemoSqlReplayEntityRequest = {
|
||||
const request: DemoStoreReplayEntityRequest = {
|
||||
entityKind: config.kind,
|
||||
entityValueContains: optionalInputValue(config.containsSelector),
|
||||
limit: boundedPositiveIntegerValue(config.limitSelector),
|
||||
};
|
||||
const rows = await invoke<DemoSqlReplayEntityRow[]>("load_demo_sql_replay_entities", { request });
|
||||
const rows = await invoke<DemoStoreReplayEntityRow[]>("load_demo_store_replay_entities", { request });
|
||||
replaceRows(table, rows);
|
||||
element<HTMLElement>(config.summarySelector).textContent = `${rows.length} ${config.pluralLabel} chargé(s) depuis PostgreSQL.`;
|
||||
element<HTMLElement>(config.summarySelector).textContent = `${rows.length} ${config.pluralLabel} chargé(s) depuis le store actif.`;
|
||||
frontendDebug(tracingTarget, `loaded ${rows.length} replay ${config.kind} summaries`);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -567,7 +567,7 @@ async function saveCsv(fileName: string, content: string, rowCount: number): Pro
|
||||
if (rowCount === 0) {
|
||||
throw new Error("Aucune ligne à exporter.");
|
||||
}
|
||||
const path = await invoke<string>("export_demo_sql_replay_csv", { fileName, content });
|
||||
const path = await invoke<string>("export_demo_store_replay_csv", { fileName, content });
|
||||
const badge = element<HTMLElement>("#replayCandidateStatusBadge");
|
||||
badge.textContent = `${rowCount} ligne(s) exportée(s) : ${path}`;
|
||||
badge.className = "badge text-bg-success";
|
||||
@@ -577,8 +577,8 @@ async function saveCsv(fileName: string, content: string, rowCount: number): Pro
|
||||
async function exportTransactionsCsv(): Promise<void> {
|
||||
const rows = transactionRowsForExport();
|
||||
const content = csvContent(
|
||||
["signature", "slot", "raw_processing_state", "retention_state", "core_status", "ledger_status", "processor_version", "attempt_count", "outer_instruction_count", "inner_instruction_count", "outer_program_count", "inner_program_count", "updated_at"],
|
||||
rows.map(row => [row.signature, row.slot, row.rawProcessingState, row.retentionState, coreStatusText(row), row.ledgerStatus, row.processorVersion, row.attemptCount, row.outerInstructionCount, row.innerInstructionCount, row.outerProgramCount, row.innerProgramCount, row.updatedAt]),
|
||||
["signature", "slot", "raw_processing_state", "retention_state", "core_status", "ledger_status", "processor_version", "attempt_count", "top_level_instruction_count", "inner_instruction_count", "top_level_program_count", "inner_program_count", "updated_at"],
|
||||
rows.map(row => [row.signature, row.slot, row.rawProcessingState, row.retentionState, coreStatusText(row), row.ledgerStatus, row.processorVersion, row.attemptCount, row.topLevelInstructionCount, row.innerInstructionCount, row.topLevelProgramCount, row.innerProgramCount, row.updatedAt]),
|
||||
);
|
||||
await saveCsv("replay_transactions.csv", content, rows.length);
|
||||
}
|
||||
@@ -586,8 +586,8 @@ async function exportTransactionsCsv(): Promise<void> {
|
||||
async function exportProgramsCsv(): Promise<void> {
|
||||
const rows = programRowsForExport();
|
||||
const content = csvContent(
|
||||
["program_code", "program_id", "transaction_count", "outer_instruction_count", "inner_instruction_count", "log_count", "min_slot", "max_slot"],
|
||||
rows.map(row => [row.programCode, row.programId, row.transactionCount, row.outerInstructionCount, row.innerInstructionCount, row.logCount, row.minSlot, row.maxSlot]),
|
||||
["program_code", "program_id", "transaction_count", "top_level_instruction_count", "inner_instruction_count", "log_count", "min_slot", "max_slot"],
|
||||
rows.map(row => [row.programCode, row.programId, row.transactionCount, row.topLevelInstructionCount, row.innerInstructionCount, row.logCount, row.minSlot, row.maxSlot]),
|
||||
);
|
||||
await saveCsv("replay_programs.csv", content, rows.length);
|
||||
}
|
||||
@@ -601,21 +601,21 @@ async function exportEntityCsv(config: EntityViewConfig): Promise<void> {
|
||||
await saveCsv(config.fileName, content, rows.length);
|
||||
}
|
||||
|
||||
function transactionRowsForExport(): DemoSqlReplayTransactionRow[] {
|
||||
function transactionRowsForExport(): DemoStoreReplayTransactionRow[] {
|
||||
if (transactionTable === null) {
|
||||
return [];
|
||||
}
|
||||
return selectedOrFilteredRows(transactionTable);
|
||||
}
|
||||
|
||||
function programRowsForExport(): DemoSqlReplayProgramRow[] {
|
||||
function programRowsForExport(): DemoStoreReplayProgramRow[] {
|
||||
if (programTable === null) {
|
||||
return [];
|
||||
}
|
||||
return selectedOrFilteredRows(programTable);
|
||||
}
|
||||
|
||||
function entityRowsForExport(kind: EntityKindCode): DemoSqlReplayEntityRow[] {
|
||||
function entityRowsForExport(kind: EntityKindCode): DemoStoreReplayEntityRow[] {
|
||||
const table = entityTable(kind);
|
||||
if (table === null) {
|
||||
return [];
|
||||
@@ -660,13 +660,13 @@ async function openCoreExtraction(): Promise<void> {
|
||||
}
|
||||
|
||||
async function loadOptions(): Promise<void> {
|
||||
const options = await invoke<DemoSqlReplayOptionsPayload>("demo_sql_replay_options");
|
||||
const options = await invoke<DemoStoreReplayOptionsPayload>("demo_store_replay_options");
|
||||
if (!Number.isSafeInteger(options.maximumLimit) || options.maximumLimit <= 0) {
|
||||
throw new Error("La limite maximale des candidats replay retournée par le backend est invalide.");
|
||||
}
|
||||
maximumReplayCandidateLimit = options.maximumLimit;
|
||||
element<HTMLElement>("#replayCandidateProfileBadge").textContent = `Profil ${options.activeProfileName}`;
|
||||
element<HTMLElement>("#replayCandidateDsn").textContent = options.maskedDsn;
|
||||
element<HTMLElement>("#replayCandidateDsn").textContent = options.connectionDescriptor;
|
||||
element<HTMLElement>("#replayCandidateMaximumLimit").textContent = String(options.maximumLimit);
|
||||
document.querySelectorAll<HTMLInputElement>("input[type=number][max]").forEach(input => {
|
||||
input.max = String(options.maximumLimit);
|
||||
@@ -674,7 +674,7 @@ async function loadOptions(): Promise<void> {
|
||||
populateKnownPrograms(options.knownPrograms);
|
||||
}
|
||||
|
||||
function populateKnownPrograms(programs: DemoSqlReplayKnownProgramOption[]): void {
|
||||
function populateKnownPrograms(programs: DemoStoreReplayKnownProgramOption[]): void {
|
||||
const select = element<HTMLSelectElement>("#knownProgramSelect");
|
||||
const datalist = element<HTMLDataListElement>("#knownProgramDatalist");
|
||||
select.replaceChildren(new Option("Tous les programmes connus", ""));
|
||||
@@ -779,7 +779,7 @@ function installHandlers(): void {
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge(tracingTarget);
|
||||
frontendDebug(tracingTarget, "SQL replay candidate browser loaded");
|
||||
frontendDebug(tracingTarget, "Store replay candidate browser loaded");
|
||||
transactionTable = createTransactionTable();
|
||||
programTable = createProgramTable();
|
||||
mintTable = createEntityTable(entityViewConfigs[0]);
|
||||
@@ -1,10 +1,10 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_sql_tables.ts
|
||||
// version: 4
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_store_tables.ts
|
||||
// version: 6
|
||||
|
||||
import DataTable, { type Api } from "datatables.net-bs5";
|
||||
import "datatables.net-bs5/css/dataTables.bootstrap5.css";
|
||||
import { jsonText, renderJsonViewer } from "./json_viewer.ts";
|
||||
import type { DemoSqlTableSnapshot } from "./bindings/kb_app_demo_desktop/demo_sql/DemoSqlTableSnapshot";
|
||||
import type { DemoStoreResourceSnapshot } from "./bindings/kb_app_demo_desktop/demo_store/DemoStoreResourceSnapshot";
|
||||
|
||||
const tableInstances = new Map<string, Api>();
|
||||
|
||||
@@ -15,7 +15,7 @@ export function setText(selector: string, value: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function renderTables(tableSelector: string, bodySelector: string, tables: DemoSqlTableSnapshot[]): void {
|
||||
export function renderTables(tableSelector: string, bodySelector: string, resources: DemoStoreResourceSnapshot[]): void {
|
||||
const existing = tableInstances.get(tableSelector);
|
||||
if (existing) {
|
||||
existing.destroy();
|
||||
@@ -26,16 +26,16 @@ export function renderTables(tableSelector: string, bodySelector: string, tables
|
||||
return;
|
||||
}
|
||||
tbody.textContent = "";
|
||||
for (const table of tables) {
|
||||
for (const resource of resources) {
|
||||
const row = document.createElement("tr");
|
||||
row.appendChild(cell(table.tableName, true));
|
||||
row.appendChild(cell(table.domain, false));
|
||||
row.appendChild(cell(table.role, false));
|
||||
row.appendChild(cell(table.exists ? "oui" : "non", false));
|
||||
row.appendChild(cell(table.rowCount === null ? "—" : String(table.rowCount), false));
|
||||
row.appendChild(cell(table.minSlot === null ? "—" : String(table.minSlot), false));
|
||||
row.appendChild(cell(table.maxSlot === null ? "—" : String(table.maxSlot), false));
|
||||
row.appendChild(cell(table.latestCreatedAt ?? "—", false));
|
||||
row.appendChild(cell(resource.resourceCode, true));
|
||||
row.appendChild(cell(resource.modelCode, false));
|
||||
row.appendChild(cell(resource.role, false));
|
||||
row.appendChild(cell(resource.available ? "oui" : "non", false));
|
||||
row.appendChild(cell(resource.recordCount === null ? "—" : String(resource.recordCount), false));
|
||||
row.appendChild(cell(resource.minSlot === null ? "—" : String(resource.minSlot), false));
|
||||
row.appendChild(cell(resource.maxSlot === null ? "—" : String(resource.maxSlot), false));
|
||||
row.appendChild(cell(resource.latestCreatedAt ?? "—", false));
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
const tableElement = document.querySelector<HTMLTableElement>(tableSelector);
|
||||
@@ -48,12 +48,12 @@ export function renderTables(tableSelector: string, bodySelector: string, tables
|
||||
lengthMenu: [10, 25, 50, 100],
|
||||
order: [[0, "asc"]],
|
||||
language: {
|
||||
emptyTable: "Aucune table disponible",
|
||||
info: "Tables _START_ à _END_ sur _TOTAL_",
|
||||
infoEmpty: "Aucune table",
|
||||
lengthMenu: "Afficher _MENU_ tables",
|
||||
emptyTable: "Aucune ressource disponible",
|
||||
info: "Ressources _START_ à _END_ sur _TOTAL_",
|
||||
infoEmpty: "Aucune ressource",
|
||||
lengthMenu: "Afficher _MENU_ ressources",
|
||||
search: "Rechercher :",
|
||||
zeroRecords: "Aucune table correspondante",
|
||||
zeroRecords: "Aucune ressource correspondante",
|
||||
},
|
||||
}));
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/main.ts
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import MarkdownIt from "markdown-it";
|
||||
@@ -97,10 +97,10 @@ for (const [elementId, command] of pipelineDemoLinks) {
|
||||
}
|
||||
|
||||
const sqlDemoLinks: ReadonlyArray<readonly [string, string]> = [
|
||||
["openDemoSqlDiagLink", "open_demo_sql_diag_window"],
|
||||
["openDemoSqlPgRawLink", "open_demo_sql_pg_raw_window"],
|
||||
["openDemoSqlPgCoreLink", "open_demo_sql_pg_core_window"],
|
||||
["openDemoSqlReplayCandidatesLink", "open_demo_sql_replay_candidates_window"],
|
||||
["openDemoStoreDiagLink", "open_demo_store_diag_window"],
|
||||
["openDemoStoreRawLink", "open_demo_store_raw_window"],
|
||||
["openDemoStoreCoreLink", "open_demo_store_core_window"],
|
||||
["openDemoStoreReplayCandidatesLink", "open_demo_store_replay_candidates_window"],
|
||||
];
|
||||
for (const [elementId, command] of sqlDemoLinks) {
|
||||
const link = document.querySelector<HTMLAnchorElement>(`#${elementId}`);
|
||||
|
||||
Reference in New Issue
Block a user