0.7.22
This commit is contained in:
420
kb_app/frontend/ts/demo_pipeline.ts
Normal file
420
kb_app/frontend/ts/demo_pipeline.ts
Normal file
@@ -0,0 +1,420 @@
|
||||
// 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<HTMLButtonElement>('#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<HTMLAnchorElement>('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<HTMLInputElement>("#demoPipelineSignatureInput");
|
||||
const customTimeframeInput = document.querySelector<HTMLInputElement>("#demoPipelineCustomTimeframeInput");
|
||||
const inspectButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectButton");
|
||||
const clearButton = document.querySelector<HTMLButtonElement>("#demoPipelineClearButton");
|
||||
const clearLogButton = document.querySelector<HTMLButtonElement>("#demoPipelineClearLogButton");
|
||||
|
||||
const summaryTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineSummaryTextarea");
|
||||
const transactionTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineTransactionTextarea");
|
||||
const decodedEventsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineDecodedEventsTextarea");
|
||||
const poolsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePoolsTextarea");
|
||||
const pairsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairsTextarea");
|
||||
const launchAttributionsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineLaunchAttributionsTextarea");
|
||||
const poolOriginsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePoolOriginsTextarea");
|
||||
const walletsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineWalletsTextarea");
|
||||
const tradeEventsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineTradeEventsTextarea");
|
||||
const pairMetricsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairMetricsTextarea");
|
||||
const pairCandlesTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairCandlesTextarea");
|
||||
const pairAnalyticSignalsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairAnalyticSignalsTextarea");
|
||||
const logTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineLogTextarea");
|
||||
const tokenMintInput = document.querySelector<HTMLInputElement>("#demoPipelineTokenMintInput");
|
||||
const inspectTokenButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectTokenButton");
|
||||
const pairIdInput = document.querySelector<HTMLInputElement>("#demoPipelinePairIdInput");
|
||||
const inspectPairButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectPairButton");
|
||||
const poolAddressInput = document.querySelector<HTMLInputElement>("#demoPipelinePoolAddressInput");
|
||||
const inspectPoolButton = document.querySelector<HTMLButtonElement>("#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<DemoPipelineInspectPayload>("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<DemoPipelineInspectPayload>("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<DemoPipelineInspectPayload>("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<DemoPipelineInspectPayload>("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)}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user