v0.5.3-pre.002

This commit is contained in:
2026-08-11 22:22:40 +02:00
parent 01d78b5845
commit 8448ad1079
134 changed files with 4518 additions and 3595 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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 na été produit.",error:message},null,2); element<HTMLTextAreaElement>("#executionSimulationOutput").value=JSON.stringify({title:"Simulation exacte",status:"not_started",reason:"preflight_failed",message:"La simulation na 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, lenvoi, la confirmation et le replay nont pas été exécutés.":"La confirmation et le replay ne sappliquent 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 na été produit.", error: message }, null, 2); element<HTMLTextAreaElement>("#executionSimulationOutput").value = JSON.stringify({ title: "Simulation exacte", status: "not_started", reason: "preflight_failed", message: "La simulation na 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, lenvoi, la confirmation et le replay nont pas été exécutés." : "La confirmation et le replay ne sappliquent 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}`); } });

View File

@@ -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}`);

View File

@@ -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", () => {

View File

@@ -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", () => {

View File

@@ -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", () => {

View File

@@ -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]);

View File

@@ -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",
},
}));
}

View File

@@ -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}`);