Processor: Chart-Support und Dashboard-Block-Prozessor
logfire-sql Bloecke unterstuetzen jetzt -- chart: Direktiven fuer Inline-Visualisierung. Neuer logfire-dashboard Block- Prozessor rendert Multi-Widget-Dashboards direkt in Notizen. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eec66b738d
commit
aba060f3a5
1 changed files with 78 additions and 2 deletions
|
|
@ -3,6 +3,9 @@ import { QueryConfig, TimeRange, EventType, EventCategory } from '../types';
|
|||
import { buildQuery } from '../core/query-builder';
|
||||
import { DatabaseManager } from '../core/database';
|
||||
import { renderTable, renderTimeline, renderSummary, renderMetric, renderList, renderHeatmap, formatValue } from '../viz/table-renderer';
|
||||
import { renderChart, parseChartConfig } from '../viz/chart-renderer';
|
||||
import { parseDashboardBlock, DashboardView, DASHBOARD_VIEW_TYPE } from '../viz/dashboard';
|
||||
import type LogfirePlugin from '../main';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Refresh timer management
|
||||
|
|
@ -84,13 +87,20 @@ export function registerLogfireSqlBlock(
|
|||
return;
|
||||
}
|
||||
|
||||
const chartConfig = parseChartConfig(source);
|
||||
|
||||
try {
|
||||
const rows = db.queryReadOnly(sql) as Record<string, unknown>[];
|
||||
if (!Array.isArray(rows) || rows.length === 0) {
|
||||
el.createEl('p', { text: 'Keine Ergebnisse.', cls: 'logfire-empty' });
|
||||
return;
|
||||
}
|
||||
renderTable(el, rows);
|
||||
|
||||
if (chartConfig) {
|
||||
renderChart(el, rows, chartConfig);
|
||||
} else {
|
||||
renderTable(el, rows);
|
||||
}
|
||||
|
||||
if (refresh && refresh > 0) {
|
||||
setupRefreshTimer(el, () => {
|
||||
|
|
@ -101,7 +111,11 @@ export function registerLogfireSqlBlock(
|
|||
el.createEl('p', { text: 'Keine Ergebnisse.', cls: 'logfire-empty' });
|
||||
return;
|
||||
}
|
||||
renderTable(el, freshRows);
|
||||
if (chartConfig) {
|
||||
renderChart(el, freshRows, chartConfig);
|
||||
} else {
|
||||
renderTable(el, freshRows);
|
||||
}
|
||||
} catch (err) {
|
||||
renderError(el, err);
|
||||
}
|
||||
|
|
@ -113,6 +127,68 @@ export function registerLogfireSqlBlock(
|
|||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// `logfire-dashboard` block — Dashboard Code-Block
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function registerLogfireDashboardBlock(
|
||||
plugin: LogfirePlugin,
|
||||
db: DatabaseManager,
|
||||
registerFn: (language: string, handler: (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => void) => void,
|
||||
): void {
|
||||
registerFn('logfire-dashboard', (source, el, ctx) => {
|
||||
const dashboard = parseDashboardBlock(source);
|
||||
if (!dashboard) {
|
||||
renderError(el, new Error('Ungültige Dashboard-Definition.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Render dashboard inline
|
||||
const wrapper = el.createDiv({ cls: 'logfire-dash-inline' });
|
||||
|
||||
if (dashboard.name) {
|
||||
wrapper.createDiv({ cls: 'logfire-dash-inline-title', text: dashboard.name });
|
||||
}
|
||||
|
||||
const grid = wrapper.createDiv({ cls: 'logfire-dash-grid' });
|
||||
grid.style.gridTemplateColumns = `repeat(${dashboard.columns}, 1fr)`;
|
||||
|
||||
for (const widget of dashboard.widgets) {
|
||||
const widgetEl = grid.createDiv({ cls: 'logfire-dash-widget' });
|
||||
widgetEl.style.gridColumn = `${widget.position.col + 1} / span ${widget.position.width}`;
|
||||
widgetEl.style.gridRow = `${widget.position.row + 1} / span ${widget.position.height}`;
|
||||
|
||||
if (widget.title) {
|
||||
widgetEl.createDiv({ cls: 'logfire-dash-widget-title', text: widget.title });
|
||||
}
|
||||
|
||||
const content = widgetEl.createDiv({ cls: 'logfire-dash-widget-content' });
|
||||
|
||||
try {
|
||||
if (widget.type === 'text' && widget.text) {
|
||||
content.createDiv({ text: widget.text });
|
||||
} else if (widget.sql) {
|
||||
const rows = db.queryReadOnly(widget.sql) as Record<string, unknown>[];
|
||||
if (rows.length === 0) {
|
||||
content.createDiv({ cls: 'logfire-empty', text: 'Keine Ergebnisse.' });
|
||||
} else if (widget.type === 'chart' && widget.chartConfig) {
|
||||
renderChart(content, rows, widget.chartConfig);
|
||||
} else if (widget.type === 'stat') {
|
||||
renderMetric(content, rows);
|
||||
} else {
|
||||
renderTable(content, rows);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
content.createDiv({
|
||||
cls: 'logfire-error',
|
||||
text: `Fehler: ${err instanceof Error ? err.message : String(err)}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// YAML config parsing
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue