v0.1.0-pre.062
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||
// version: 4
|
||||
// version: 9
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -7,6 +7,7 @@ import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { frontendDebug, frontendError, frontendWarn, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import type { DemoExecutionDevnetStoreReadinessPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionDevnetStoreReadinessPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreGeneratedRecipientPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreGeneratedRecipientPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreOptionsPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreProfileOption } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreProfileOption.ts";
|
||||
@@ -36,6 +37,7 @@ import type { DemoSplToken2022FixturePayload } from "./bindings/kb_app_demo_desk
|
||||
const logLines: string[] = [];
|
||||
const maximumLogLines = 1200;
|
||||
let running = false;
|
||||
let profileStoreReady = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
let token_2022Fixture: DemoSplToken2022FixturePayload | null = null;
|
||||
|
||||
@@ -55,6 +57,61 @@ function integerValue(selector: string): number {
|
||||
return value;
|
||||
}
|
||||
|
||||
function parsedJson(value: string): unknown {
|
||||
try {
|
||||
return JSON.parse(value) as unknown;
|
||||
} catch {
|
||||
return { raw: value };
|
||||
}
|
||||
}
|
||||
|
||||
function writePanel(selector: string, title: string, payload: Record<string, unknown>): void {
|
||||
element<HTMLTextAreaElement>(selector).value = JSON.stringify({ title, ...payload }, null, 2);
|
||||
}
|
||||
|
||||
function writeJsonPanel(selector: string, title: string, value: string): void {
|
||||
const parsed = parsedJson(value);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
writePanel(selector, title, parsed as Record<string, unknown>);
|
||||
return;
|
||||
}
|
||||
writePanel(selector, title, { value: parsed });
|
||||
}
|
||||
|
||||
function writePlanPanel(preflightJson: string | null, planJson: string): void {
|
||||
const payload: Record<string, unknown> = { plan: parsedJson(planJson) };
|
||||
if (preflightJson !== null) {
|
||||
payload.preflight = parsedJson(preflightJson);
|
||||
}
|
||||
writePanel("#executionPlanOutput", "Plan exact", payload);
|
||||
}
|
||||
|
||||
function writeExecutionState(status: string, message: string, error: string | null = null): void {
|
||||
const summary: Record<string, unknown> = { status, message };
|
||||
if (error !== null) {
|
||||
summary.error = error;
|
||||
}
|
||||
writePanel("#executionSummaryOutput", "Résumé", summary);
|
||||
writePanel("#executionPlanOutput", "Plan exact", {
|
||||
status: status === "running" ? "pending" : "unavailable",
|
||||
reason: status,
|
||||
message: status === "running" ? "Préparation du plan en cours." : "Aucun plan exécutable n’a été produit.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
writePanel("#executionSimulationOutput", "Simulation exacte", {
|
||||
status: status === "running" ? "pending" : "not_started",
|
||||
reason: status,
|
||||
message: status === "running" ? "Simulation en attente du plan exact." : "La simulation n’a pas été lancée.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
writePanel("#executionDiagnosticsOutput", "Confirmation et replay", {
|
||||
status: status === "running" ? "pending" : "not_started",
|
||||
reason: status,
|
||||
message: status === "running" ? "En attente de la simulation et d’un éventuel envoi." : "La confirmation et le replay n’ont pas été exécutés.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
}
|
||||
|
||||
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}`);
|
||||
@@ -69,18 +126,19 @@ function appendLog(payload: DemoExecutionSolanaCoreProgressPayload | { timestamp
|
||||
function setRunning(value: boolean): void {
|
||||
running = value;
|
||||
const profile = selectedProfile();
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateMemoButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitMemoButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateTokenButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitTokenButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#deriveAtaButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#simulateAtaButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitAtaButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateToken2022Button").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitToken2022Button").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#loadToken2022FixtureButton").disabled = value || !profile;
|
||||
const unavailable = value || !profile || !profileStoreReady;
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateMemoButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitMemoButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateTokenButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitTokenButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#deriveAtaButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#simulateAtaButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitAtaButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateToken2022Button").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitToken2022Button").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#loadToken2022FixtureButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#generateRecipientButton").disabled = value;
|
||||
element<HTMLButtonElement>("#cancelExecutionButton").disabled = !value;
|
||||
const badge = element<HTMLElement>("#executionStatusBadge");
|
||||
@@ -146,10 +204,10 @@ function displaySummary(summary: DemoExecutionSolanaCoreSummaryPayload): void {
|
||||
decodeCompleted: summary.decodeCompleted,
|
||||
decodeFailedInputs: summary.decodeFailedInputs,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = summary.planJson;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(null, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function buildMemoRequest(submit: boolean): DemoExecutionMemoRequest {
|
||||
@@ -165,7 +223,7 @@ function buildMemoRequest(submit: boolean): DemoExecutionMemoRequest {
|
||||
|
||||
function displayMemoSummary(summary: DemoExecutionMemoSummaryPayload): void {
|
||||
const concise = {
|
||||
operation: "spl_memo_v4.add_memo",
|
||||
operation: "spl.memo.v4.add_memo",
|
||||
profileName: summary.profileName,
|
||||
cluster: summary.cluster,
|
||||
genesisHash: summary.genesisHash,
|
||||
@@ -183,10 +241,10 @@ function displayMemoSummary(summary: DemoExecutionMemoSummaryPayload): void {
|
||||
annotationCount: summary.annotationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = summary.planJson;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(null, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function requiredText(selector: string, label: string): string {
|
||||
@@ -247,10 +305,10 @@ function displayTokenSummary(summary: DemoExecutionSplTokenSummaryPayload): void
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.readinessJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(summary.readinessJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function ataDerivationRequest(): DemoSplAtaDerivationRequest {
|
||||
@@ -272,7 +330,7 @@ async function deriveAta(): Promise<DemoSplAtaDerivationPayload> {
|
||||
}
|
||||
|
||||
function displayAtaSummary(summary: DemoExecutionSplAtaSummaryPayload): void {
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({
|
||||
writePanel("#executionSummaryOutput", "Résumé", {
|
||||
operation: summary.operation,
|
||||
profileName: summary.profileName,
|
||||
walletPublicKey: summary.walletPublicKey,
|
||||
@@ -287,10 +345,10 @@ function displayAtaSummary(summary: DemoExecutionSplAtaSummaryPayload): void {
|
||||
confirmationStatus: summary.confirmationStatus,
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
}, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.readinessJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
});
|
||||
writePlanPanel(summary.readinessJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
async function executeAta(submit: boolean): Promise<void> {
|
||||
@@ -305,6 +363,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
stage: "ata_validation",
|
||||
message,
|
||||
});
|
||||
writeExecutionState("error", message, message);
|
||||
frontendError("kb-app-demo-desktop.frontend.execution_spl", message);
|
||||
return;
|
||||
}
|
||||
@@ -321,6 +380,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
forcePostValidationReplay: element<HTMLInputElement>("#executionForceReplayInput").checked,
|
||||
};
|
||||
setRunning(true);
|
||||
writeExecutionState("running", "Préflight et exécution SPL ATA en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -344,6 +404,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "ata_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `ATA execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -367,13 +428,23 @@ async function loadAtaJournal(): Promise<void> {
|
||||
button.disabled = true;
|
||||
try {
|
||||
const rows = await invoke<DemoSplAtaJournalRow[]>("demo_spl_ata_journal", { request: ataJournalRequest() });
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify(rows.map(row => ({
|
||||
...row,
|
||||
payloadJson: JSON.parse(row.payloadJson) as unknown,
|
||||
})), null, 2);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({
|
||||
title: "Journal lifecycle ATA",
|
||||
status: "success",
|
||||
count: rows.length,
|
||||
rows: rows.map(row => ({
|
||||
...row,
|
||||
payloadJson: parsedJson(row.payloadJson),
|
||||
})),
|
||||
}, null, 2);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({
|
||||
title: "Journal lifecycle ATA",
|
||||
status: "error",
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
@@ -387,7 +458,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
const request = buildRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi.";
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ warning: message }, null, 2);
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "warn",
|
||||
@@ -398,7 +469,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Exécution en cours...";
|
||||
writeExecutionState("running", "Exécution Solana Core en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -416,7 +487,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -432,12 +503,13 @@ async function executeMemo(submit: boolean): Promise<void> {
|
||||
const request = buildMemoRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi du Memo.";
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "warn", stage: "memo_policy", message });
|
||||
frontendWarn("kb-app-demo-desktop.frontend.demo_execution_spl", `Memo execution blocked by policy: ${message}`);
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Exécution Memo en cours...";
|
||||
writeExecutionState("running", "Exécution Memo v4 en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -455,7 +527,7 @@ async function executeMemo(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "memo_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Memo execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -471,12 +543,13 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
const request = buildTokenRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi Token.";
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "warn", stage: "spl_token_policy", message });
|
||||
frontendWarn("kb-app-demo-desktop.frontend.demo_execution_spl", `Token execution blocked by policy: ${message}`);
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Préflight et exécution SPL Token en cours...";
|
||||
writeExecutionState("running", "Préflight et exécution SPL Token en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -498,7 +571,7 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "spl_token_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -529,7 +602,11 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
cell.textContent = "Aucun événement correspondant.";
|
||||
row.append(cell);
|
||||
body.append(row);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = "Aucun événement sélectionné.";
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "empty",
|
||||
message: "Aucun événement sélectionné.",
|
||||
}, null, 2);
|
||||
return;
|
||||
}
|
||||
for (const item of rows) {
|
||||
@@ -550,7 +627,14 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
}
|
||||
row.title = item.signature;
|
||||
const select = (): void => {
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = item.payloadJson;
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "success",
|
||||
row: {
|
||||
...item,
|
||||
payloadJson: parsedJson(item.payloadJson),
|
||||
},
|
||||
}, null, 2);
|
||||
};
|
||||
row.addEventListener("click", select);
|
||||
row.addEventListener("keydown", event => {
|
||||
@@ -561,22 +645,32 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
});
|
||||
body.append(row);
|
||||
}
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = rows[0].payloadJson;
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "success",
|
||||
row: {
|
||||
...rows[0],
|
||||
payloadJson: parsedJson(rows[0].payloadJson),
|
||||
},
|
||||
}, null, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function token_2022ScenarioAmount(fixture: DemoSplToken2022FixturePayload, scenarioId: string): string {
|
||||
if (scenarioId === "token_2022_mint_to_checked") {
|
||||
return "1";
|
||||
return fixture.mintAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_transfer_checked") {
|
||||
return fixture.transferAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_approve_checked") {
|
||||
return "2";
|
||||
return fixture.approveAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_burn_checked") {
|
||||
return "1";
|
||||
return fixture.burnAmountRaw;
|
||||
}
|
||||
return fixture.defaultAmountRaw;
|
||||
return "0";
|
||||
}
|
||||
|
||||
function applyToken2022Fixture(): void {
|
||||
@@ -666,7 +760,7 @@ function buildToken2022Request(submit: boolean): DemoExecutionSplToken2022Reques
|
||||
}
|
||||
|
||||
function displayToken2022Summary(summary: DemoExecutionSplToken2022SummaryPayload): void {
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({
|
||||
writePanel("#executionSummaryOutput", "Résumé", {
|
||||
scenarioId: summary.scenarioId,
|
||||
operation: summary.operation,
|
||||
profileName: summary.profileName,
|
||||
@@ -684,10 +778,10 @@ function displayToken2022Summary(summary: DemoExecutionSplToken2022SummaryPayloa
|
||||
decodeReplayed: summary.decodeReplayed,
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
}, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.preflightJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
});
|
||||
writePlanPanel(summary.preflightJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
async function executeToken2022(submit: boolean): Promise<void> {
|
||||
@@ -699,17 +793,18 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
request = buildToken2022Request(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur est obligatoire avant signature Token-2022.";
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ warning: message }, null, 2);
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Préflight et exécution Token-2022 en cours...";
|
||||
writeExecutionState("running", "Préflight et exécution Token-2022 en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -728,7 +823,7 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token-2022 execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -750,7 +845,12 @@ async function loadTokenJournal(): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "error",
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token journal loading failed: ${message}`);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
@@ -788,6 +888,27 @@ async function cancelExecution(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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_spl", `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;
|
||||
@@ -803,6 +924,7 @@ async function loadOptions(): Promise<void> {
|
||||
element<HTMLInputElement>("#executionLamportsInput").value = String(options.defaultTransferLamports);
|
||||
updateProfileHelp();
|
||||
setRunning(options.running);
|
||||
await prepareSelectedProfile();
|
||||
if (profileOptions.length === 0) {
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = true;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = true;
|
||||
@@ -824,7 +946,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_spl");
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", "execution demo window loaded");
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(item => new bootstrap.Tooltip(item));
|
||||
element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", updateProfileHelp);
|
||||
element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", () => {
|
||||
updateProfileHelp();
|
||||
void prepareSelectedProfile();
|
||||
});
|
||||
element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click", () => {
|
||||
void generateRecipient();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user