191 lines
8.1 KiB
TypeScript
191 lines
8.1 KiB
TypeScript
// file: crates/ksp-app-config-desk/frontend/ts/logging.ts
|
|
// version: 1
|
|
|
|
//! Read-only typed Logging editor backed exclusively by ConfigManagement.
|
|
|
|
import type { LoggingDocumentDto } from "./bindings/ksp_app_config_desk/logging/LoggingDocumentDto";
|
|
import type { LoggingOutputFilterDto } from "./bindings/ksp_app_config_desk/logging/LoggingOutputFilterDto";
|
|
import type { LoggingProfileDto } from "./bindings/ksp_app_config_desk/logging/LoggingProfileDto";
|
|
import { frontendDebug, frontendTrace } from "./frontend_log";
|
|
import { invokeKsp } from "./invoke";
|
|
|
|
let loggingDocument: LoggingDocumentDto | null = null;
|
|
|
|
function setLoggingStatus(message: string, tone: "primary" | "success" | "danger" = "primary"): void {
|
|
const status = document.querySelector<HTMLElement>("#loggingStatus");
|
|
if (!status) {
|
|
return;
|
|
}
|
|
status.className = `alert alert-${tone} mb-0`;
|
|
status.textContent = message;
|
|
frontendTrace("main", "Logging editor status replaced", { tone });
|
|
}
|
|
|
|
function setText(selector: string, value: string): void {
|
|
const element = document.querySelector<HTMLElement>(selector);
|
|
if (element) {
|
|
element.textContent = value;
|
|
}
|
|
}
|
|
|
|
function boolLabel(value: boolean): string {
|
|
return value ? "oui" : "non";
|
|
}
|
|
|
|
function selectorsLabel(values: string[]): string {
|
|
return values.length > 0 ? values.join(", ") : "—";
|
|
}
|
|
|
|
function filterSummary(filter: LoggingOutputFilterDto): { level: string; targets: string; domains: string } {
|
|
return { level: filter.level, targets: selectorsLabel(filter.targets), domains: selectorsLabel(filter.domains) };
|
|
}
|
|
|
|
function appendCell(row: HTMLTableRowElement, value: string, className?: string): void {
|
|
const cell = document.createElement("td");
|
|
cell.textContent = value;
|
|
if (className) {
|
|
cell.className = className;
|
|
}
|
|
row.append(cell);
|
|
}
|
|
|
|
function renderProfileSelect(documentDto: LoggingDocumentDto): void {
|
|
const select = document.querySelector<HTMLSelectElement>("#loggingProfileSelect");
|
|
if (!select) {
|
|
return;
|
|
}
|
|
const previous = select.value;
|
|
select.replaceChildren();
|
|
for (const profile of documentDto.profiles) {
|
|
const option = document.createElement("option");
|
|
option.value = profile.profileId;
|
|
option.textContent = profile.profileId === documentDto.defaultProfile ? `${profile.profileId} (default)` : profile.profileId;
|
|
select.append(option);
|
|
}
|
|
const previousExists = documentDto.profiles.some(profile => profile.profileId === previous);
|
|
select.value = previousExists ? previous : documentDto.defaultProfile;
|
|
if (!documentDto.profiles.some(profile => profile.profileId === select.value) && documentDto.profiles.length > 0) {
|
|
select.value = documentDto.profiles[0].profileId;
|
|
}
|
|
select.disabled = documentDto.profiles.length === 0;
|
|
frontendTrace("main", "Logging editor profile select replaced", { profileCount: documentDto.profiles.length });
|
|
}
|
|
|
|
function renderConsole(profile: LoggingProfileDto): void {
|
|
const summary = filterSummary(profile.console.filter);
|
|
setText("#loggingConsoleEnabled", boolLabel(profile.console.enabled));
|
|
setText("#loggingConsoleOutput", profile.console.output);
|
|
setText("#loggingConsoleAnsi", boolLabel(profile.console.ansi));
|
|
setText("#loggingConsoleFormat", profile.console.format);
|
|
setText("#loggingConsoleLevel", summary.level);
|
|
setText("#loggingConsoleTargets", summary.targets);
|
|
setText("#loggingConsoleDomains", summary.domains);
|
|
}
|
|
|
|
function renderFiles(profile: LoggingProfileDto): void {
|
|
const body = document.querySelector<HTMLTableSectionElement>("#loggingFilesTable tbody");
|
|
if (!body) {
|
|
return;
|
|
}
|
|
body.replaceChildren();
|
|
for (const file of profile.files) {
|
|
const summary = filterSummary(file.filter);
|
|
const row = document.createElement("tr");
|
|
appendCell(row, file.outputId, "font-monospace");
|
|
appendCell(row, boolLabel(file.enabled));
|
|
appendCell(row, file.path, "font-monospace text-break");
|
|
appendCell(row, file.rotation);
|
|
appendCell(row, file.format);
|
|
appendCell(row, boolLabel(file.ansi));
|
|
appendCell(row, summary.level);
|
|
appendCell(row, summary.targets, "font-monospace text-break");
|
|
appendCell(row, summary.domains, "font-monospace text-break");
|
|
body.append(row);
|
|
}
|
|
frontendTrace("main", "Logging file sink table DOM replaced", { fileCount: profile.files.length });
|
|
}
|
|
|
|
function renderTargetFilters(profile: LoggingProfileDto): void {
|
|
const body = document.querySelector<HTMLTableSectionElement>("#loggingTargetFiltersTable tbody");
|
|
if (!body) {
|
|
return;
|
|
}
|
|
body.replaceChildren();
|
|
for (const filter of profile.targetFilters) {
|
|
const row = document.createElement("tr");
|
|
appendCell(row, filter.targetPrefix, "font-monospace");
|
|
appendCell(row, filter.level);
|
|
body.append(row);
|
|
}
|
|
frontendTrace("main", "Logging target override table DOM replaced", { targetFilterCount: profile.targetFilters.length });
|
|
}
|
|
|
|
function renderSelectedProfile(source: "load" | "selection"): void {
|
|
const documentDto = loggingDocument;
|
|
const select = document.querySelector<HTMLSelectElement>("#loggingProfileSelect");
|
|
if (!documentDto || !select) {
|
|
return;
|
|
}
|
|
const profile = documentDto.profiles.find(candidate => candidate.profileId === select.value);
|
|
if (!profile) {
|
|
setLoggingStatus("Le profil Logging sélectionné n'existe plus dans le document chargé.", "danger");
|
|
return;
|
|
}
|
|
setText("#loggingProfileDefaultFilter", profile.defaultFilter);
|
|
setText("#loggingProfileSpanEvents", profile.spanEvents);
|
|
renderConsole(profile);
|
|
renderFiles(profile);
|
|
renderTargetFilters(profile);
|
|
frontendTrace("main", "Logging profile read-only view rendered", {
|
|
profileId: profile.profileId,
|
|
source,
|
|
fileCount: profile.files.length,
|
|
targetFilterCount: profile.targetFilters.length,
|
|
});
|
|
}
|
|
|
|
function renderDocument(documentDto: LoggingDocumentDto): void {
|
|
loggingDocument = documentDto;
|
|
setText("#loggingFileId", documentDto.fileId);
|
|
setText("#loggingPath", documentDto.path);
|
|
setText("#loggingFormatVersion", documentDto.formatVersion.toString());
|
|
setText("#loggingLogsDirectory", documentDto.logsDirectory);
|
|
setText("#loggingDefaultProfile", documentDto.defaultProfile);
|
|
renderProfileSelect(documentDto);
|
|
renderSelectedProfile("load");
|
|
frontendTrace("main", "Logging document read-only view rendered", { profileCount: documentDto.profiles.length });
|
|
}
|
|
|
|
async function refreshLoggingDocument(source: "startup" | "user"): Promise<void> {
|
|
if (source === "user") {
|
|
frontendDebug("main", "Logging document refresh requested");
|
|
}
|
|
setLoggingStatus("Chargement du document Logging typé...");
|
|
try {
|
|
const documentDto = await invokeKsp<LoggingDocumentDto>("main", "get_logging_document");
|
|
renderDocument(documentDto);
|
|
setLoggingStatus(`${documentDto.profiles.length} profil(s) Logging chargé(s) en lecture seule.`, "success");
|
|
frontendDebug("main", "Logging document refresh completed", {
|
|
profileCount: documentDto.profiles.length,
|
|
defaultProfile: documentDto.defaultProfile,
|
|
});
|
|
} catch {
|
|
loggingDocument = null;
|
|
setLoggingStatus("Le document Logging typé n'a pas pu être chargé. Consulte les diagnostics backend.", "danger");
|
|
}
|
|
}
|
|
|
|
/// Initializes the read-only Logging editor surface.
|
|
export function initializeLoggingPanel(): void {
|
|
document.querySelector<HTMLButtonElement>("#refreshLoggingDocument")?.addEventListener("click", () => {
|
|
void refreshLoggingDocument("user");
|
|
});
|
|
document.querySelector<HTMLSelectElement>("#loggingProfileSelect")?.addEventListener("change", event => {
|
|
const profileId = (event.currentTarget as HTMLSelectElement).value;
|
|
frontendDebug("main", "Logging read-only profile selection changed", { profileId });
|
|
renderSelectedProfile("selection");
|
|
});
|
|
frontendTrace("main", "Logging editor handlers installed");
|
|
void refreshLoggingDocument("startup");
|
|
}
|