v0.5.3-pre.005-fix010
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||
// version: 11
|
||||
// version: 13
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -19,13 +19,23 @@ import type { DemoExecutionMemoSummaryPayload } from "./bindings/kb_app_demo_des
|
||||
import type { DemoExecutionSplTokenRequest } from "./bindings/kb_app_demo_desktop/demo_spl_token/DemoExecutionSplTokenRequest.ts";
|
||||
import type { DemoExecutionSplTokenSummaryPayload } from "./bindings/kb_app_demo_desktop/demo_spl_token/DemoExecutionSplTokenSummaryPayload.ts";
|
||||
import type { DemoSplTokenJournalRequest } from "./bindings/kb_app_demo_desktop/demo_spl_token/DemoSplTokenJournalRequest.ts";
|
||||
import type { DemoSplTokenJournalPagePayload } from "./bindings/kb_app_demo_desktop/demo_spl_token/DemoSplTokenJournalPagePayload.ts";
|
||||
import type { DemoSplTokenJournalRow } from "./bindings/kb_app_demo_desktop/demo_spl_token/DemoSplTokenJournalRow.ts";
|
||||
import type { DemoExecutionSplAtaRequest } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoExecutionSplAtaRequest.ts";
|
||||
import type { DemoExecutionSplAtaSummaryPayload } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoExecutionSplAtaSummaryPayload.ts";
|
||||
import type { DemoSplAtaDerivationPayload } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaDerivationPayload.ts";
|
||||
import type { DemoSplAtaDerivationRequest } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaDerivationRequest.ts";
|
||||
import type { DemoSplAtaJournalRequest } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaJournalRequest.ts";
|
||||
import type { DemoSplAtaJournalRow } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaJournalRow.ts";
|
||||
import type { DemoSplAtaJournalPagePayload } from "./bindings/kb_app_demo_desktop/demo_spl_ata/DemoSplAtaJournalPagePayload.ts";
|
||||
import {
|
||||
applyStoreBlockMetadata,
|
||||
createStoreBlockState,
|
||||
cursorForBlock,
|
||||
markStoreBlockFiltersDirty,
|
||||
renderStoreBlockControls,
|
||||
resetStoreBlockState,
|
||||
type StoreBlockControls,
|
||||
} from "./demo_store_block_pagination";
|
||||
import type { DemoExecutionSplToken2022Request } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022Request.ts";
|
||||
import type { DemoExecutionSplToken2022SummaryPayload } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoExecutionSplToken2022SummaryPayload.ts";
|
||||
import type { DemoSplToken2022FixturePayload } from "./bindings/kb_app_demo_desktop/demo_spl_token_2022/DemoSplToken2022FixturePayload.ts";
|
||||
@@ -40,6 +50,24 @@ let running = false;
|
||||
let profileStoreReady = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
let token_2022Fixture: DemoSplToken2022FixturePayload | null = null;
|
||||
const tokenJournalBlockState = createStoreBlockState();
|
||||
const ataJournalBlockState = createStoreBlockState();
|
||||
const tokenJournalBlockControls: StoreBlockControls = {
|
||||
firstSelector: "#tokenJournalFirstBlockButton",
|
||||
previousSelector: "#tokenJournalPreviousBlockButton",
|
||||
nextSelector: "#tokenJournalNextBlockButton",
|
||||
summarySelector: "#tokenJournalBlockSummary",
|
||||
};
|
||||
const ataJournalBlockControls: StoreBlockControls = {
|
||||
firstSelector: "#ataJournalFirstBlockButton",
|
||||
previousSelector: "#ataJournalPreviousBlockButton",
|
||||
nextSelector: "#ataJournalNextBlockButton",
|
||||
summarySelector: "#ataJournalBlockSummary",
|
||||
};
|
||||
type TokenJournalBaseRequest = Omit<DemoSplTokenJournalRequest, "cursor" | "blockIndex">;
|
||||
type AtaJournalBaseRequest = Omit<DemoSplAtaJournalRequest, "cursor" | "blockIndex">;
|
||||
let tokenJournalBaseRequest: TokenJournalBaseRequest | null = null;
|
||||
let ataJournalBaseRequest: AtaJournalBaseRequest | null = null;
|
||||
|
||||
function element<T extends HTMLElement>(selector: string): T {
|
||||
const value = document.querySelector<T>(selector);
|
||||
@@ -400,7 +428,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
element<HTMLInputElement>("#ataJournalSignatureInput").value = summary.transactionSignature;
|
||||
element<HTMLInputElement>("#ataJournalMintInput").value = request.mint;
|
||||
element<HTMLInputElement>("#ataJournalAddressInput").value = summary.associatedTokenAccount;
|
||||
await loadAtaJournal();
|
||||
await startAtaJournalLoad();
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -412,27 +440,52 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
function ataJournalRequest(): DemoSplAtaJournalRequest {
|
||||
function ataJournalBaseFilters(): AtaJournalBaseRequest {
|
||||
return {
|
||||
profileName: element<HTMLSelectElement>("#executionProfileSelect").value,
|
||||
signatureContains: optionalText("#ataJournalSignatureInput"),
|
||||
mint: optionalText("#ataJournalMintInput"),
|
||||
associatedTokenAccount: optionalText("#ataJournalAddressInput"),
|
||||
operation: optionalText("#ataJournalOperationInput"),
|
||||
limit: integerValue("#ataJournalLimitInput"),
|
||||
};
|
||||
}
|
||||
|
||||
async function loadAtaJournal(): Promise<void> {
|
||||
async function startAtaJournalLoad(): Promise<void> {
|
||||
ataJournalBaseRequest = ataJournalBaseFilters();
|
||||
resetStoreBlockState(ataJournalBlockState);
|
||||
await loadAtaJournalBlock(1);
|
||||
}
|
||||
|
||||
async function loadAtaJournalBlock(blockIndex: number): Promise<void> {
|
||||
if (ataJournalBaseRequest === null) {
|
||||
markStoreBlockFiltersDirty(ataJournalBlockState, ataJournalBlockControls);
|
||||
return;
|
||||
}
|
||||
const cursor = cursorForBlock(ataJournalBlockState, blockIndex);
|
||||
if (cursor === undefined) {
|
||||
return;
|
||||
}
|
||||
const button = element<HTMLButtonElement>("#refreshAtaJournalButton");
|
||||
button.disabled = true;
|
||||
element<HTMLButtonElement>(ataJournalBlockControls.firstSelector).disabled = true;
|
||||
element<HTMLButtonElement>(ataJournalBlockControls.previousSelector).disabled = true;
|
||||
element<HTMLButtonElement>(ataJournalBlockControls.nextSelector).disabled = true;
|
||||
const request: DemoSplAtaJournalRequest = {
|
||||
...ataJournalBaseRequest,
|
||||
cursor,
|
||||
blockIndex,
|
||||
};
|
||||
try {
|
||||
const rows = await invoke<DemoSplAtaJournalRow[]>("demo_spl_ata_journal", { request: ataJournalRequest() });
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_spl_ata_journal block=${blockIndex}`);
|
||||
const payload = await invoke<DemoSplAtaJournalPagePayload>("demo_spl_ata_journal", { request });
|
||||
applyStoreBlockMetadata(ataJournalBlockState, payload.page, ataJournalBlockControls);
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_spl_ata_journal completed block=${payload.page.blockIndex}/${payload.page.totalBlocks} rows=${payload.rows.length}`);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({
|
||||
title: "Journal lifecycle ATA",
|
||||
status: "success",
|
||||
count: rows.length,
|
||||
rows: rows.map(row => ({
|
||||
block: payload.page,
|
||||
count: payload.rows.length,
|
||||
rows: payload.rows.map(row => ({
|
||||
...row,
|
||||
payloadJson: parsedJson(row.payloadJson),
|
||||
})),
|
||||
@@ -445,11 +498,17 @@ async function loadAtaJournal(): Promise<void> {
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
renderStoreBlockControls(ataJournalBlockState, ataJournalBlockControls);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function markAtaJournalFiltersDirty(): void {
|
||||
ataJournalBaseRequest = null;
|
||||
markStoreBlockFiltersDirty(ataJournalBlockState, ataJournalBlockControls);
|
||||
}
|
||||
|
||||
async function execute(submit: boolean): Promise<void> {
|
||||
if (running) {
|
||||
return;
|
||||
@@ -567,7 +626,7 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
});
|
||||
if (summary.transactionSignature) {
|
||||
element<HTMLInputElement>("#tokenJournalSignatureInput").value = summary.transactionSignature;
|
||||
await loadTokenJournal();
|
||||
await startTokenJournalLoad();
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -579,7 +638,7 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
function tokenJournalRequest(): DemoSplTokenJournalRequest {
|
||||
function tokenJournalBaseFilters(): TokenJournalBaseRequest {
|
||||
return {
|
||||
profileName: element<HTMLSelectElement>("#executionProfileSelect").value,
|
||||
signatureContains: optionalText("#tokenJournalSignatureInput"),
|
||||
@@ -587,7 +646,6 @@ function tokenJournalRequest(): DemoSplTokenJournalRequest {
|
||||
account: optionalText("#tokenJournalAccountInput"),
|
||||
family: element<HTMLSelectElement>("#tokenJournalFamilySelect").value || null,
|
||||
operation: optionalText("#tokenJournalOperationInput"),
|
||||
limit: integerValue("#tokenJournalLimitInput"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -831,17 +889,42 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTokenJournal(): Promise<void> {
|
||||
async function startTokenJournalLoad(): Promise<void> {
|
||||
tokenJournalBaseRequest = tokenJournalBaseFilters();
|
||||
resetStoreBlockState(tokenJournalBlockState);
|
||||
await loadTokenJournalBlock(1);
|
||||
}
|
||||
|
||||
async function loadTokenJournalBlock(blockIndex: number): Promise<void> {
|
||||
if (tokenJournalBaseRequest === null) {
|
||||
markStoreBlockFiltersDirty(tokenJournalBlockState, tokenJournalBlockControls);
|
||||
return;
|
||||
}
|
||||
const cursor = cursorForBlock(tokenJournalBlockState, blockIndex);
|
||||
if (cursor === undefined) {
|
||||
return;
|
||||
}
|
||||
const button = element<HTMLButtonElement>("#refreshTokenJournalButton");
|
||||
button.disabled = true;
|
||||
element<HTMLButtonElement>(tokenJournalBlockControls.firstSelector).disabled = true;
|
||||
element<HTMLButtonElement>(tokenJournalBlockControls.previousSelector).disabled = true;
|
||||
element<HTMLButtonElement>(tokenJournalBlockControls.nextSelector).disabled = true;
|
||||
const request: DemoSplTokenJournalRequest = {
|
||||
...tokenJournalBaseRequest,
|
||||
cursor,
|
||||
blockIndex,
|
||||
};
|
||||
try {
|
||||
const rows = await invoke<DemoSplTokenJournalRow[]>("demo_spl_token_journal", { request: tokenJournalRequest() });
|
||||
renderTokenJournal(rows);
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_spl_token_journal block=${blockIndex}`);
|
||||
const payload = await invoke<DemoSplTokenJournalPagePayload>("demo_spl_token_journal", { request });
|
||||
applyStoreBlockMetadata(tokenJournalBlockState, payload.page, tokenJournalBlockControls);
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_spl_token_journal completed block=${payload.page.blockIndex}/${payload.page.totalBlocks} rows=${payload.rows.length}`);
|
||||
renderTokenJournal(payload.rows);
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
stage: "spl_token_journal",
|
||||
message: `${rows.length} événement(s) matérialisé(s) chargé(s).`,
|
||||
message: `${payload.rows.length} événement(s) matérialisé(s) chargé(s) dans le bloc ${payload.page.blockIndex}/${payload.page.totalBlocks}.`,
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
@@ -851,12 +934,18 @@ async function loadTokenJournal(): Promise<void> {
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
renderStoreBlockControls(tokenJournalBlockState, tokenJournalBlockControls);
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token journal loading failed: ${message}`);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function markTokenJournalFiltersDirty(): void {
|
||||
tokenJournalBaseRequest = null;
|
||||
markStoreBlockFiltersDirty(tokenJournalBlockState, tokenJournalBlockControls);
|
||||
}
|
||||
|
||||
async function generateRecipient(): Promise<void> {
|
||||
try {
|
||||
const payload = await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");
|
||||
@@ -898,7 +987,9 @@ async function prepareSelectedProfile(): Promise<void> {
|
||||
}
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_prepare", message: `Vérification du store du profil ${profile.name}.` });
|
||||
try {
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_execution_devnet_prepare_profile profile=${profile.name}`);
|
||||
const readiness = await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile", { profileName: profile.name });
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", `Invoke demo_execution_devnet_prepare_profile completed profile=${profile.name} resources=${readiness.availableResourcesAfter}/${readiness.expectedResources}`);
|
||||
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) {
|
||||
@@ -948,6 +1039,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(item => new bootstrap.Tooltip(item));
|
||||
element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", () => {
|
||||
updateProfileHelp();
|
||||
markTokenJournalFiltersDirty();
|
||||
markAtaJournalFiltersDirty();
|
||||
void prepareSelectedProfile();
|
||||
});
|
||||
element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click", () => {
|
||||
@@ -982,8 +1075,27 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
void executeToken2022(true);
|
||||
});
|
||||
element<HTMLButtonElement>("#refreshTokenJournalButton").addEventListener("click", () => {
|
||||
void loadTokenJournal();
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", "Token journal load button clicked");
|
||||
void startTokenJournalLoad();
|
||||
});
|
||||
element<HTMLButtonElement>("#tokenJournalFirstBlockButton").addEventListener("click", () => {
|
||||
void loadTokenJournalBlock(1);
|
||||
});
|
||||
element<HTMLButtonElement>("#tokenJournalPreviousBlockButton").addEventListener("click", () => {
|
||||
void loadTokenJournalBlock(tokenJournalBlockState.currentBlock - 1);
|
||||
});
|
||||
element<HTMLButtonElement>("#tokenJournalNextBlockButton").addEventListener("click", () => {
|
||||
void loadTokenJournalBlock(tokenJournalBlockState.currentBlock + 1);
|
||||
});
|
||||
for (const selector of [
|
||||
"#tokenJournalSignatureInput",
|
||||
"#tokenJournalMintInput",
|
||||
"#tokenJournalAccountInput",
|
||||
"#tokenJournalOperationInput",
|
||||
]) {
|
||||
element<HTMLInputElement>(selector).addEventListener("input", markTokenJournalFiltersDirty);
|
||||
}
|
||||
element<HTMLSelectElement>("#tokenJournalFamilySelect").addEventListener("change", markTokenJournalFiltersDirty);
|
||||
element<HTMLButtonElement>("#deriveAtaButton").addEventListener("click", () => {
|
||||
void deriveAta();
|
||||
});
|
||||
@@ -994,8 +1106,26 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
void executeAta(true);
|
||||
});
|
||||
element<HTMLButtonElement>("#refreshAtaJournalButton").addEventListener("click", () => {
|
||||
void loadAtaJournal();
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", "ATA journal load button clicked");
|
||||
void startAtaJournalLoad();
|
||||
});
|
||||
element<HTMLButtonElement>("#ataJournalFirstBlockButton").addEventListener("click", () => {
|
||||
void loadAtaJournalBlock(1);
|
||||
});
|
||||
element<HTMLButtonElement>("#ataJournalPreviousBlockButton").addEventListener("click", () => {
|
||||
void loadAtaJournalBlock(ataJournalBlockState.currentBlock - 1);
|
||||
});
|
||||
element<HTMLButtonElement>("#ataJournalNextBlockButton").addEventListener("click", () => {
|
||||
void loadAtaJournalBlock(ataJournalBlockState.currentBlock + 1);
|
||||
});
|
||||
for (const selector of [
|
||||
"#ataJournalSignatureInput",
|
||||
"#ataJournalMintInput",
|
||||
"#ataJournalAddressInput",
|
||||
"#ataJournalOperationInput",
|
||||
]) {
|
||||
element<HTMLInputElement>(selector).addEventListener("input", markAtaJournalFiltersDirty);
|
||||
}
|
||||
element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click", () => {
|
||||
void cancelExecution();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user