// file: kb_app/frontend/ts/demo_pipeline.ts import * as bootstrap from "bootstrap"; import "simplebar"; import ResizeObserver from "resize-observer-polyfill"; import { invoke } from "@tauri-apps/api/core"; import { debug, takeoverConsole } from "@fltsci/tauri-plugin-tracing"; (window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap; (window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver; interface DemoPipelineInspectRequest { signature: string; customTimeframeSeconds: number | null; } interface DemoPipelineInspectPayload { signature: string; summaryJson: string; transactionJson: string; decodedEventsJson: string; poolsJson: string; pairsJson: string; launchAttributionsJson: string; poolOriginsJson: string; walletsJson: string; tradeEventsJson: string; pairMetricsJson: string; pairCandlesJson: string; pairAnalyticSignalsJson: string; } interface DemoPipelineInspectTokenRequest { tokenMint: string; customTimeframeSeconds: number | null; } interface DemoPipelineInspectPairRequest { pairId: number; customTimeframeSeconds: number | null; } interface DemoPipelineInspectPoolRequest { poolAddress: string; customTimeframeSeconds: number | null; } function appendLogLine(textarea: HTMLTextAreaElement, line: string): void { const now = new Date(); const timestamp = now.toLocaleTimeString("fr-CH", { hour12: false }); const lines = textarea.value === "" ? [] : textarea.value.split("\n"); lines.push(`[${timestamp}] ${line}`); const maxLines = 300; textarea.value = lines.slice(-maxLines).join("\n"); textarea.scrollTop = textarea.scrollHeight; } function clearInspection( summaryTextarea: HTMLTextAreaElement, transactionTextarea: HTMLTextAreaElement, decodedEventsTextarea: HTMLTextAreaElement, poolsTextarea: HTMLTextAreaElement, pairsTextarea: HTMLTextAreaElement, launchAttributionsTextarea: HTMLTextAreaElement, poolOriginsTextarea: HTMLTextAreaElement, walletsTextarea: HTMLTextAreaElement, tradeEventsTextarea: HTMLTextAreaElement, pairMetricsTextarea: HTMLTextAreaElement, pairCandlesTextarea: HTMLTextAreaElement, pairAnalyticSignalsTextarea: HTMLTextAreaElement, ): void { summaryTextarea.value = ""; transactionTextarea.value = ""; decodedEventsTextarea.value = ""; poolsTextarea.value = ""; pairsTextarea.value = ""; launchAttributionsTextarea.value = ""; poolOriginsTextarea.value = ""; walletsTextarea.value = ""; tradeEventsTextarea.value = ""; pairMetricsTextarea.value = ""; pairCandlesTextarea.value = ""; pairAnalyticSignalsTextarea.value = ""; } function readCustomTimeframeSeconds( input: HTMLInputElement, logTextarea: HTMLTextAreaElement, ): number | null | undefined { const customTimeframeText = input.value.trim(); if (customTimeframeText === "") { return null; } const parsed = Number.parseInt(customTimeframeText, 10); if (Number.isNaN(parsed) || parsed <= 0) { appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`); return undefined; } return parsed; } document.addEventListener("DOMContentLoaded", async () => { void takeoverConsole(); debug("demo_pipeline window loaded"); const sidebarToggle = document.querySelector('#sidebarToggle'); if (sidebarToggle) { // restaurer l’état depuis localStorage if (localStorage.getItem('sidebar-toggle') === 'true') { document.body.classList.add('sidenav-toggled'); } sidebarToggle.addEventListener('click', (event) => { event.preventDefault(); document.body.classList.toggle('sidenav-toggled'); localStorage.setItem('sidebar-toggle', document.body.classList.contains('sidenav-toggled') ? 'true' : 'false'); }); } const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); const toastElList = document.querySelectorAll('.toast'); Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl)); const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]'); Array.from(popoverTriggerList).map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)); const gobackto = location.pathname + location.search; document.querySelectorAll('a[data-setlang]').forEach((a) => { const href = a.getAttribute("href"); if (!href) return; // pas de href => on ignore const url = new URL(href, location.origin); url.searchParams.set("gobackto", gobackto); // conserve une URL relative (path + query) a.setAttribute("href", url.pathname + "?" + url.searchParams.toString()); }); const signatureInput = document.querySelector("#demoPipelineSignatureInput"); const customTimeframeInput = document.querySelector("#demoPipelineCustomTimeframeInput"); const inspectButton = document.querySelector("#demoPipelineInspectButton"); const clearButton = document.querySelector("#demoPipelineClearButton"); const clearLogButton = document.querySelector("#demoPipelineClearLogButton"); const summaryTextarea = document.querySelector("#demoPipelineSummaryTextarea"); const transactionTextarea = document.querySelector("#demoPipelineTransactionTextarea"); const decodedEventsTextarea = document.querySelector("#demoPipelineDecodedEventsTextarea"); const poolsTextarea = document.querySelector("#demoPipelinePoolsTextarea"); const pairsTextarea = document.querySelector("#demoPipelinePairsTextarea"); const launchAttributionsTextarea = document.querySelector("#demoPipelineLaunchAttributionsTextarea"); const poolOriginsTextarea = document.querySelector("#demoPipelinePoolOriginsTextarea"); const walletsTextarea = document.querySelector("#demoPipelineWalletsTextarea"); const tradeEventsTextarea = document.querySelector("#demoPipelineTradeEventsTextarea"); const pairMetricsTextarea = document.querySelector("#demoPipelinePairMetricsTextarea"); const pairCandlesTextarea = document.querySelector("#demoPipelinePairCandlesTextarea"); const pairAnalyticSignalsTextarea = document.querySelector("#demoPipelinePairAnalyticSignalsTextarea"); const logTextarea = document.querySelector("#demoPipelineLogTextarea"); const tokenMintInput = document.querySelector("#demoPipelineTokenMintInput"); const inspectTokenButton = document.querySelector("#demoPipelineInspectTokenButton"); const pairIdInput = document.querySelector("#demoPipelinePairIdInput"); const inspectPairButton = document.querySelector("#demoPipelineInspectPairButton"); const poolAddressInput = document.querySelector("#demoPipelinePoolAddressInput"); const inspectPoolButton = document.querySelector("#demoPipelineInspectPoolButton"); if ( !pairIdInput || !inspectPairButton || !poolAddressInput || !inspectPoolButton || !tokenMintInput || !inspectTokenButton || !signatureInput || !customTimeframeInput || !inspectButton || !clearButton || !clearLogButton || !summaryTextarea || !transactionTextarea || !decodedEventsTextarea || !poolsTextarea || !pairsTextarea || !launchAttributionsTextarea || !poolOriginsTextarea || !walletsTextarea || !tradeEventsTextarea || !pairMetricsTextarea || !pairCandlesTextarea || !pairAnalyticSignalsTextarea || !logTextarea ) { console.error("demo_pipeline DOM is incomplete"); return; } clearButton.addEventListener("click", () => { clearInspection( summaryTextarea, transactionTextarea, decodedEventsTextarea, poolsTextarea, pairsTextarea, launchAttributionsTextarea, poolOriginsTextarea, walletsTextarea, tradeEventsTextarea, pairMetricsTextarea, pairCandlesTextarea, pairAnalyticSignalsTextarea, ); signatureInput.value = ""; customTimeframeInput.value = ""; tokenMintInput.value = ""; pairIdInput.value = ""; poolAddressInput.value = ""; appendLogLine(logTextarea, "[ui] inspection state cleared"); }); clearLogButton.addEventListener("click", () => { logTextarea.value = ""; }); inspectButton.addEventListener("click", async () => { const signature = signatureInput.value.trim(); if (signature === "") { appendLogLine(logTextarea, "[ui] signature is required"); return; } let customTimeframeSeconds: number | null = null; const customTimeframeText = customTimeframeInput.value.trim(); if (customTimeframeText !== "") { const parsed = Number.parseInt(customTimeframeText, 10); if (Number.isNaN(parsed) || parsed <= 0) { appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`); return; } customTimeframeSeconds = parsed; } appendLogLine( logTextarea, `[ui] inspecting signature '${signature}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`, ); const request: DemoPipelineInspectRequest = { signature, customTimeframeSeconds, }; try { const payload = await invoke("demo_pipeline_inspect_signature", { request }); summaryTextarea.value = payload.summaryJson; transactionTextarea.value = payload.transactionJson; decodedEventsTextarea.value = payload.decodedEventsJson; poolsTextarea.value = payload.poolsJson; pairsTextarea.value = payload.pairsJson; launchAttributionsTextarea.value = payload.launchAttributionsJson; poolOriginsTextarea.value = payload.poolOriginsJson; walletsTextarea.value = payload.walletsJson; tradeEventsTextarea.value = payload.tradeEventsJson; pairMetricsTextarea.value = payload.pairMetricsJson; pairCandlesTextarea.value = payload.pairCandlesJson; pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson; appendLogLine(logTextarea, `[ui] inspection completed for '${payload.signature}'`); } catch (error) { appendLogLine(logTextarea, `[ui] inspect error: ${String(error)}`); } }); inspectTokenButton.addEventListener("click", async () => { const tokenMint = tokenMintInput.value.trim(); if (tokenMint === "") { appendLogLine(logTextarea, "[ui] token mint is required"); return; } let customTimeframeSeconds: number | null = null; const customTimeframeText = customTimeframeInput.value.trim(); if (customTimeframeText !== "") { const parsed = Number.parseInt(customTimeframeText, 10); if (Number.isNaN(parsed) || parsed <= 0) { appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`); return; } customTimeframeSeconds = parsed; } appendLogLine( logTextarea, `[ui] inspecting token mint '${tokenMint}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`, ); const request: DemoPipelineInspectTokenRequest = { tokenMint, customTimeframeSeconds, }; try { const payload = await invoke("demo_pipeline_inspect_token_mint", { request }); summaryTextarea.value = payload.summaryJson; transactionTextarea.value = payload.transactionJson; decodedEventsTextarea.value = payload.decodedEventsJson; poolsTextarea.value = payload.poolsJson; pairsTextarea.value = payload.pairsJson; launchAttributionsTextarea.value = payload.launchAttributionsJson; poolOriginsTextarea.value = payload.poolOriginsJson; walletsTextarea.value = payload.walletsJson; tradeEventsTextarea.value = payload.tradeEventsJson; pairMetricsTextarea.value = payload.pairMetricsJson; pairCandlesTextarea.value = payload.pairCandlesJson; pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson; appendLogLine(logTextarea, `[ui] token inspection completed for '${payload.signature}'`); } catch (error) { appendLogLine(logTextarea, `[ui] token inspect error: ${String(error)}`); } }); inspectPairButton.addEventListener("click", async () => { const pairIdText = pairIdInput.value.trim(); if (pairIdText === "") { appendLogLine(logTextarea, "[ui] pair id is required"); return; } const parsedPairId = Number.parseInt(pairIdText, 10); if (Number.isNaN(parsedPairId) || parsedPairId <= 0) { appendLogLine(logTextarea, `[ui] invalid pair id '${pairIdText}'`); return; } const customTimeframeSeconds = readCustomTimeframeSeconds(customTimeframeInput, logTextarea); if (customTimeframeSeconds === undefined) { return; } appendLogLine( logTextarea, `[ui] inspecting pair id '${parsedPairId}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`, ); const request: DemoPipelineInspectPairRequest = { pairId: parsedPairId, customTimeframeSeconds, }; try { const payload = await invoke("demo_pipeline_inspect_pair_id", { request }); summaryTextarea.value = payload.summaryJson; transactionTextarea.value = payload.transactionJson; decodedEventsTextarea.value = payload.decodedEventsJson; poolsTextarea.value = payload.poolsJson; pairsTextarea.value = payload.pairsJson; launchAttributionsTextarea.value = payload.launchAttributionsJson; poolOriginsTextarea.value = payload.poolOriginsJson; walletsTextarea.value = payload.walletsJson; tradeEventsTextarea.value = payload.tradeEventsJson; pairMetricsTextarea.value = payload.pairMetricsJson; pairCandlesTextarea.value = payload.pairCandlesJson; pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson; appendLogLine(logTextarea, `[ui] pair inspection completed for '${payload.signature}'`); } catch (error) { appendLogLine(logTextarea, `[ui] pair inspect error: ${String(error)}`); } }); inspectPoolButton.addEventListener("click", async () => { const poolAddress = poolAddressInput.value.trim(); if (poolAddress === "") { appendLogLine(logTextarea, "[ui] pool address is required"); return; } const customTimeframeSeconds = readCustomTimeframeSeconds(customTimeframeInput, logTextarea); if (customTimeframeSeconds === undefined) { return; } appendLogLine( logTextarea, `[ui] inspecting pool '${poolAddress}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`, ); const request: DemoPipelineInspectPoolRequest = { poolAddress, customTimeframeSeconds, }; try { const payload = await invoke("demo_pipeline_inspect_pool_address", { request }); summaryTextarea.value = payload.summaryJson; transactionTextarea.value = payload.transactionJson; decodedEventsTextarea.value = payload.decodedEventsJson; poolsTextarea.value = payload.poolsJson; pairsTextarea.value = payload.pairsJson; launchAttributionsTextarea.value = payload.launchAttributionsJson; poolOriginsTextarea.value = payload.poolOriginsJson; walletsTextarea.value = payload.walletsJson; tradeEventsTextarea.value = payload.tradeEventsJson; pairMetricsTextarea.value = payload.pairMetricsJson; pairCandlesTextarea.value = payload.pairCandlesJson; pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson; appendLogLine(logTextarea, `[ui] pool inspection completed for '${payload.signature}'`); } catch (error) { appendLogLine(logTextarea, `[ui] pool inspect error: ${String(error)}`); } }); });