From 2f7ee27e9b958a86ecef63323a1a436b22b2a478 Mon Sep 17 00:00:00 2001 From: tolvitty Date: Thu, 12 Feb 2026 11:17:28 +0100 Subject: [PATCH] Visualisierung in main.ts verdrahtet, Chart/Dashboard CSS Dashboard-View registriert, Ribbon-Icon, Befehl und logfire-dashboard Block-Prozessor eingebunden. CSS fuer SVG-Charts, Legenden, Dashboard-Grid und Widgets ergaenzt. Co-Authored-By: Claude Opus 4.6 --- src/main.ts | 40 ++++++++- styles.css | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 283 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index a1809c3..c6991db 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,9 +13,10 @@ import { LogfireSettingTab } from './ui/settings-tab'; import { InitialScanModal } from './ui/initial-scan-modal'; import { StatusBar } from './ui/status-bar'; import { EventStreamView, EVENT_STREAM_VIEW_TYPE } from './ui/event-stream-view'; -import { registerLogfireBlock, registerLogfireSqlBlock, cleanupAllRefreshTimers } from './query/processor'; +import { registerLogfireBlock, registerLogfireSqlBlock, registerLogfireDashboardBlock, cleanupAllRefreshTimers } from './query/processor'; import { QueryModal } from './query/query-modal'; import { VirtualTableManager } from './query/virtual-tables'; +import { DashboardView, DASHBOARD_VIEW_TYPE } from './viz/dashboard'; export default class LogfirePlugin extends Plugin { settings!: LogfireSettings; @@ -90,6 +91,12 @@ export default class LogfirePlugin extends Plugin { (leaf) => new EventStreamView(leaf, this.eventBus), ); + // UI: Dashboard view + this.registerView( + DASHBOARD_VIEW_TYPE, + (leaf) => new DashboardView(leaf, this), + ); + // UI: Status bar this.statusBar = new StatusBar(this); this.statusBar.start(); @@ -101,11 +108,17 @@ export default class LogfirePlugin extends Plugin { registerLogfireSqlBlock(this.db, (lang, handler) => { this.registerMarkdownCodeBlockProcessor(lang, handler); }); + registerLogfireDashboardBlock(this, this.db, (lang, handler) => { + this.registerMarkdownCodeBlockProcessor(lang, handler); + }); - // Ribbon icon + // Ribbon icons this.addRibbonIcon('activity', 'Logfire: Event-Stream', () => { this.activateEventStream(); }); + this.addRibbonIcon('layout-dashboard', 'Logfire: Dashboard', () => { + this.activateDashboard(); + }); // Commands this.registerCommands(); @@ -298,6 +311,12 @@ export default class LogfirePlugin extends Plugin { }, }); + this.addCommand({ + id: 'show-dashboard', + name: 'Dashboard anzeigen', + callback: () => this.activateDashboard(), + }); + this.addCommand({ id: 'open-query', name: 'Query-Editor \u00f6ffnen', @@ -340,6 +359,23 @@ export default class LogfirePlugin extends Plugin { } } + // --------------------------------------------------------------------------- + // Dashboard view + // --------------------------------------------------------------------------- + + private async activateDashboard(): Promise { + const existing = this.app.workspace.getLeavesOfType(DASHBOARD_VIEW_TYPE); + if (existing.length > 0) { + this.app.workspace.revealLeaf(existing[0]); + return; + } + const leaf = this.app.workspace.getRightLeaf(false); + if (leaf) { + await leaf.setViewState({ type: DASHBOARD_VIEW_TYPE, active: true }); + this.app.workspace.revealLeaf(leaf); + } + } + // --------------------------------------------------------------------------- // Settings // --------------------------------------------------------------------------- diff --git a/styles.css b/styles.css index 6c23a8a..d12233c 100644 --- a/styles.css +++ b/styles.css @@ -679,3 +679,248 @@ white-space: pre-wrap; word-break: break-word; } + +/* ═══════════════════════════════════════════════════════════════════════════ + Charts — SVG Visualization + ═══════════════════════════════════════════════════════════════════════════ */ + +.logfire-chart-wrapper { + padding: 8px 0; +} + +.logfire-chart-title { + font-family: var(--font-monospace); + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; + text-transform: uppercase; + color: var(--text-muted); + padding: 0 0 6px 0; +} + +.logfire-chart-svg { + display: block; + max-width: 100%; + height: auto; +} + +.logfire-chart-svg text { + font-family: var(--font-monospace); + font-size: 10px; + fill: var(--text-muted); +} + +.logfire-chart-svg .logfire-chart-label { + font-size: 9.5px; + fill: var(--text-faint); +} + +.logfire-chart-svg .logfire-chart-axis-label { + font-size: 9px; + fill: var(--text-faint); + font-variant-numeric: tabular-nums; +} + +.logfire-chart-svg .logfire-chart-value { + font-size: 10px; + fill: var(--text-normal); + font-variant-numeric: tabular-nums; +} + +.logfire-chart-svg .logfire-chart-center { + font-size: 18px; + font-weight: 700; + fill: var(--text-normal); +} + +.logfire-chart-svg .logfire-chart-gauge-value { + font-size: 22px; + font-weight: 700; + fill: var(--text-normal); +} + +.logfire-chart-svg .logfire-chart-bar { + transition: opacity 100ms ease; +} + +.logfire-chart-svg .logfire-chart-bar:hover { + opacity: 0.8; +} + +.logfire-chart-svg .logfire-chart-point { + transition: r 100ms ease; +} + +.logfire-chart-svg .logfire-chart-point:hover { + r: 5.5; +} + +.logfire-chart-svg .logfire-chart-slice { + transition: opacity 100ms ease; +} + +.logfire-chart-svg .logfire-chart-slice:hover { + opacity: 0.85; +} + +/* --------------------------------------------------------------------------- + Chart Legend + --------------------------------------------------------------------------- */ + +.logfire-chart-legend { + display: flex; + flex-wrap: wrap; + gap: 4px 12px; + padding: 6px 0 0 0; + font-family: var(--font-monospace); + font-size: 10px; + color: var(--text-muted); +} + +.logfire-legend-item { + display: inline-flex; + align-items: center; + gap: 4px; +} + +.logfire-legend-swatch { + width: 8px; + height: 8px; + border-radius: 2px; + flex-shrink: 0; +} + +/* ═══════════════════════════════════════════════════════════════════════════ + Dashboard — View & Inline + ═══════════════════════════════════════════════════════════════════════════ */ + +.logfire-dashboard-view { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + background: var(--background-primary); +} + +/* --------------------------------------------------------------------------- + Dashboard Header + --------------------------------------------------------------------------- */ + +.logfire-dash-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 8px 10px; + border-bottom: 1px solid var(--background-modifier-border); + background: var(--background-secondary); + flex-shrink: 0; +} + +.logfire-dash-title { + font-family: var(--font-monospace); + font-size: 13px; + font-weight: 600; + color: var(--text-normal); + letter-spacing: -0.01em; +} + +.logfire-dash-actions { + display: flex; + gap: 4px; +} + +.logfire-dash-btn { + padding: 3px 8px; + border: 1px solid var(--background-modifier-border); + border-radius: 4px; + background: var(--background-primary); + color: var(--text-muted); + font-family: var(--font-monospace); + font-size: 13px; + cursor: pointer; + transition: background 100ms ease, color 100ms ease; +} + +.logfire-dash-btn:hover { + background: var(--background-modifier-hover); + color: var(--text-normal); +} + +/* --------------------------------------------------------------------------- + Dashboard Content & Grid + --------------------------------------------------------------------------- */ + +.logfire-dash-content { + flex: 1; + overflow: auto; + padding: 10px; +} + +.logfire-dash-grid { + display: grid; + gap: 8px; + min-height: 0; +} + +/* --------------------------------------------------------------------------- + Dashboard Widget + --------------------------------------------------------------------------- */ + +.logfire-dash-widget { + border: 1px solid var(--background-modifier-border); + border-radius: 4px; + background: var(--background-primary); + overflow: hidden; + display: flex; + flex-direction: column; +} + +.logfire-dash-widget-title { + padding: 5px 10px; + font-family: var(--font-monospace); + font-size: 10px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--text-muted); + background: var(--background-secondary); + border-bottom: 1px solid var(--background-modifier-border); +} + +.logfire-dash-widget-content { + flex: 1; + overflow: auto; + min-height: 0; +} + +.logfire-dash-widget-content::-webkit-scrollbar { + width: 4px; + height: 4px; +} + +.logfire-dash-widget-content::-webkit-scrollbar-track { + background: transparent; +} + +.logfire-dash-widget-content::-webkit-scrollbar-thumb { + background: var(--background-modifier-border); + border-radius: 2px; +} + +/* --------------------------------------------------------------------------- + Dashboard Inline (Code-Block Rendering) + --------------------------------------------------------------------------- */ + +.logfire-dash-inline { + padding: 4px 0; +} + +.logfire-dash-inline-title { + font-family: var(--font-monospace); + font-size: 13px; + font-weight: 600; + color: var(--text-normal); + padding: 0 0 8px 0; + letter-spacing: -0.01em; +}