@quicdata/analytics 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/auth.d.ts +19 -0
- package/core/auth.d.ts.map +1 -0
- package/core/auth.js +34 -0
- package/core/fetch-data.d.ts +115 -0
- package/core/fetch-data.d.ts.map +1 -0
- package/core/fetch-data.js +210 -0
- package/core/index.d.ts +8 -1
- package/core/index.d.ts.map +1 -1
- package/core/index.js +4 -3
- package/core/types.d.ts +250 -0
- package/core/types.d.ts.map +1 -0
- package/core/types.js +1 -0
- package/core/viewport-observer.d.ts +26 -0
- package/core/viewport-observer.d.ts.map +1 -0
- package/core/viewport-observer.js +38 -0
- package/core/widget-transform-runner.d.ts +22 -0
- package/core/widget-transform-runner.d.ts.map +1 -0
- package/core/widget-transform-runner.js +102 -0
- package/dashboard/dashboard-container.d.ts +100 -0
- package/dashboard/dashboard-container.d.ts.map +1 -0
- package/dashboard/dashboard-container.js +315 -0
- package/dashboard/index.d.ts +4 -0
- package/dashboard/index.d.ts.map +1 -0
- package/dashboard/index.js +2 -0
- package/designer/analytics-designer.d.ts +40 -0
- package/designer/analytics-designer.d.ts.map +1 -0
- package/designer/analytics-designer.js +267 -0
- package/designer/index.d.ts +5 -0
- package/designer/index.d.ts.map +1 -0
- package/designer/index.js +3 -0
- package/filters/filter-bar.d.ts +34 -0
- package/filters/filter-bar.d.ts.map +1 -0
- package/filters/filter-bar.js +233 -0
- package/filters/filter-button.d.ts +22 -0
- package/filters/filter-button.d.ts.map +1 -0
- package/filters/filter-button.js +86 -0
- package/filters/index.d.ts +7 -0
- package/filters/index.d.ts.map +1 -0
- package/filters/index.js +6 -0
- package/filters/widget-toolbar.d.ts +24 -0
- package/filters/widget-toolbar.d.ts.map +1 -0
- package/filters/widget-toolbar.js +216 -0
- package/index.d.ts +9 -1
- package/index.d.ts.map +1 -1
- package/index.js +6 -1
- package/package.json +14 -8
- package/widgets/analytics-report.d.ts +49 -0
- package/widgets/analytics-report.d.ts.map +1 -0
- package/widgets/analytics-report.js +306 -0
- package/widgets/analytics-widget.d.ts +39 -0
- package/widgets/analytics-widget.d.ts.map +1 -0
- package/widgets/analytics-widget.js +230 -0
- package/widgets/bar-chart.d.ts +13 -0
- package/widgets/bar-chart.d.ts.map +1 -0
- package/widgets/bar-chart.js +77 -0
- package/widgets/base-chart.d.ts +94 -0
- package/widgets/base-chart.d.ts.map +1 -0
- package/widgets/base-chart.js +535 -0
- package/widgets/index.d.ts +13 -1
- package/widgets/index.d.ts.map +1 -1
- package/widgets/index.js +14 -3
- package/widgets/line-chart.d.ts +13 -0
- package/widgets/line-chart.d.ts.map +1 -0
- package/widgets/line-chart.js +71 -0
- package/widgets/pie-chart.d.ts +13 -0
- package/widgets/pie-chart.d.ts.map +1 -0
- package/widgets/pie-chart.js +55 -0
- package/widgets/table.d.ts +101 -0
- package/widgets/table.d.ts.map +1 -0
- package/widgets/table.js +740 -0
- package/workers/widget-transform.worker.d.ts +21 -0
- package/workers/widget-transform.worker.d.ts.map +1 -0
- package/workers/widget-transform.worker.js +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/core/types.ts"],"names":[],"mappings":"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"}
|
package/core/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewport observer for lazy rendering: only fetch/render when widget enters viewport.
|
|
3
|
+
* Uses IntersectionObserver with configurable rootMargin (prefetch_margin).
|
|
4
|
+
*/
|
|
5
|
+
export interface ViewportObserverOptions {
|
|
6
|
+
/** CSS margin around root to trigger "in view" earlier (e.g. '200px' for prefetch). */
|
|
7
|
+
rootMargin?: string;
|
|
8
|
+
/** Intersection ratio threshold (0–1). Default 0. */
|
|
9
|
+
threshold?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ViewportObserverCallbacks {
|
|
12
|
+
/** Called when element enters viewport (or is already visible). */
|
|
13
|
+
onEnter: () => void;
|
|
14
|
+
/** Called when element leaves viewport. */
|
|
15
|
+
onLeave?: () => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Observes an element for viewport visibility. When the element intersects the viewport
|
|
19
|
+
* (with optional rootMargin), onEnter is called; when it leaves, onLeave is called.
|
|
20
|
+
* @param element - DOM element to observe (e.g. widget container).
|
|
21
|
+
* @param options - rootMargin (e.g. '200px'), threshold.
|
|
22
|
+
* @param callbacks - onEnter (required), onLeave (optional).
|
|
23
|
+
* @returns Cleanup function (disconnect observer).
|
|
24
|
+
*/
|
|
25
|
+
export declare function observeViewport(element: Element, options: ViewportObserverOptions, callbacks: ViewportObserverCallbacks): () => void;
|
|
26
|
+
//# sourceMappingURL=viewport-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport-observer.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/core/viewport-observer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,uBAAuB;IACtC,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,mEAAmE;IACnE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,uBAAuB,EAChC,SAAS,EAAE,yBAAyB,GACnC,MAAM,IAAI,CA6BZ"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewport observer for lazy rendering: only fetch/render when widget enters viewport.
|
|
3
|
+
* Uses IntersectionObserver with configurable rootMargin (prefetch_margin).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Observes an element for viewport visibility. When the element intersects the viewport
|
|
7
|
+
* (with optional rootMargin), onEnter is called; when it leaves, onLeave is called.
|
|
8
|
+
* @param element - DOM element to observe (e.g. widget container).
|
|
9
|
+
* @param options - rootMargin (e.g. '200px'), threshold.
|
|
10
|
+
* @param callbacks - onEnter (required), onLeave (optional).
|
|
11
|
+
* @returns Cleanup function (disconnect observer).
|
|
12
|
+
*/
|
|
13
|
+
export function observeViewport(element, options, callbacks) {
|
|
14
|
+
if (typeof IntersectionObserver === 'undefined') {
|
|
15
|
+
callbacks.onEnter();
|
|
16
|
+
return () => { };
|
|
17
|
+
}
|
|
18
|
+
const { rootMargin = '0px', threshold = 0 } = options;
|
|
19
|
+
let connected = true;
|
|
20
|
+
const observer = new IntersectionObserver((entries) => {
|
|
21
|
+
if (!connected)
|
|
22
|
+
return;
|
|
23
|
+
const entry = entries[0];
|
|
24
|
+
if (!entry)
|
|
25
|
+
return;
|
|
26
|
+
if (entry.isIntersecting) {
|
|
27
|
+
callbacks.onEnter();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
callbacks.onLeave?.();
|
|
31
|
+
}
|
|
32
|
+
}, { root: null, rootMargin, threshold });
|
|
33
|
+
observer.observe(element);
|
|
34
|
+
return () => {
|
|
35
|
+
connected = false;
|
|
36
|
+
observer.disconnect();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs widget data transform in a Web Worker (optional) with fallback to main thread.
|
|
3
|
+
* Use for large datasets to avoid blocking the UI. Worker is lazy-loaded on first use.
|
|
4
|
+
*/
|
|
5
|
+
import type { WorkerWidgetOptions } from './types.js';
|
|
6
|
+
export interface WidgetTransformInput {
|
|
7
|
+
widgetDefinition: Record<string, unknown>;
|
|
8
|
+
data: Record<string, unknown>[];
|
|
9
|
+
}
|
|
10
|
+
export interface WidgetTransformOptions extends WorkerWidgetOptions {
|
|
11
|
+
/** Override worker script URL (for environments where import.meta.url is not available). */
|
|
12
|
+
workerUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Run widget data transform. Uses Web Worker when use_worker is true and data length >= worker_min_rows;
|
|
16
|
+
* otherwise runs on main thread.
|
|
17
|
+
* @param input - widgetDefinition and data
|
|
18
|
+
* @param options - use_worker, worker_min_rows, workerUrl
|
|
19
|
+
* @returns Promise resolving to widgetData (e.g. TableWidgetData)
|
|
20
|
+
*/
|
|
21
|
+
export declare function runWidgetTransform(input: WidgetTransformInput, options?: WidgetTransformOptions): Promise<unknown>;
|
|
22
|
+
//# sourceMappingURL=widget-transform-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-transform-runner.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/core/widget-transform-runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAuB,SAAQ,mBAAmB;IACjE,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,OAAO,CAAC,CA2BlB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs widget data transform in a Web Worker (optional) with fallback to main thread.
|
|
3
|
+
* Use for large datasets to avoid blocking the UI. Worker is lazy-loaded on first use.
|
|
4
|
+
*/
|
|
5
|
+
let _worker = null;
|
|
6
|
+
let _workerLoadPromise = null;
|
|
7
|
+
let _nextId = 0;
|
|
8
|
+
const _pending = new Map();
|
|
9
|
+
const DEFAULT_WORKER_MIN_ROWS = 500;
|
|
10
|
+
function mainThreadTransform(widgetDefinition, data) {
|
|
11
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
12
|
+
return { chartType: 'Table', columns: [], rows: [] };
|
|
13
|
+
}
|
|
14
|
+
const columns = Object.keys(data[0]);
|
|
15
|
+
return { chartType: 'Table', columns, rows: data };
|
|
16
|
+
}
|
|
17
|
+
function getWorkerUrl() {
|
|
18
|
+
try {
|
|
19
|
+
return new URL('../workers/widget-transform.worker.js', import.meta.url).href;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function loadWorker(workerUrl) {
|
|
26
|
+
if (_worker)
|
|
27
|
+
return Promise.resolve(_worker);
|
|
28
|
+
if (_workerLoadPromise)
|
|
29
|
+
return _workerLoadPromise;
|
|
30
|
+
const url = workerUrl ?? getWorkerUrl();
|
|
31
|
+
if (!url || typeof Worker === 'undefined') {
|
|
32
|
+
return Promise.reject(new Error('Worker not supported or URL not available'));
|
|
33
|
+
}
|
|
34
|
+
_workerLoadPromise = new Promise((resolve, reject) => {
|
|
35
|
+
try {
|
|
36
|
+
const w = new Worker(url, { type: 'module' });
|
|
37
|
+
w.onmessage = (e) => {
|
|
38
|
+
const d = e.data;
|
|
39
|
+
if (d?.type === 'result' && typeof d.id === 'number') {
|
|
40
|
+
const pending = _pending.get(d.id);
|
|
41
|
+
if (pending) {
|
|
42
|
+
clearTimeout(pending.timeoutId);
|
|
43
|
+
_pending.delete(d.id);
|
|
44
|
+
pending.resolve(d.widgetData);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (d?.type === 'error' && typeof d.id === 'number') {
|
|
48
|
+
const pending = _pending.get(d.id);
|
|
49
|
+
if (pending) {
|
|
50
|
+
clearTimeout(pending.timeoutId);
|
|
51
|
+
_pending.delete(d.id);
|
|
52
|
+
pending.reject(new Error(d.error ?? 'Worker error'));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
w.onerror = () => {
|
|
57
|
+
_workerLoadPromise = null;
|
|
58
|
+
reject(new Error('Worker failed to load'));
|
|
59
|
+
};
|
|
60
|
+
_worker = w;
|
|
61
|
+
resolve(w);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
_workerLoadPromise = null;
|
|
65
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return _workerLoadPromise;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Run widget data transform. Uses Web Worker when use_worker is true and data length >= worker_min_rows;
|
|
72
|
+
* otherwise runs on main thread.
|
|
73
|
+
* @param input - widgetDefinition and data
|
|
74
|
+
* @param options - use_worker, worker_min_rows, workerUrl
|
|
75
|
+
* @returns Promise resolving to widgetData (e.g. TableWidgetData)
|
|
76
|
+
*/
|
|
77
|
+
export function runWidgetTransform(input, options = {}) {
|
|
78
|
+
const { use_worker = false, worker_min_rows = DEFAULT_WORKER_MIN_ROWS, workerUrl } = options;
|
|
79
|
+
const { widgetDefinition, data } = input;
|
|
80
|
+
const rows = Array.isArray(data) ? data.length : 0;
|
|
81
|
+
const useWorker = use_worker && rows >= worker_min_rows;
|
|
82
|
+
if (!useWorker) {
|
|
83
|
+
return Promise.resolve(mainThreadTransform(widgetDefinition, data ?? []));
|
|
84
|
+
}
|
|
85
|
+
const id = ++_nextId;
|
|
86
|
+
return loadWorker(workerUrl)
|
|
87
|
+
.then((worker) => {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const timeoutId = setTimeout(() => {
|
|
90
|
+
if (_pending.has(id)) {
|
|
91
|
+
_pending.delete(id);
|
|
92
|
+
reject(new Error('Worker transform timeout'));
|
|
93
|
+
}
|
|
94
|
+
}, 60000);
|
|
95
|
+
_pending.set(id, { resolve, reject, timeoutId });
|
|
96
|
+
worker.postMessage({ type: 'transform', id, widgetDefinition, data: data ?? [] });
|
|
97
|
+
});
|
|
98
|
+
})
|
|
99
|
+
.catch(() => {
|
|
100
|
+
return mainThreadTransform(widgetDefinition, data ?? []);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import type { FilterDefinition } from '../core/types.js';
|
|
3
|
+
import '../filters/index.js';
|
|
4
|
+
import 'gridstack/dist/gridstack.min.css';
|
|
5
|
+
export interface DashboardSlot {
|
|
6
|
+
/** Widget type: analytics-bar-chart, analytics-line-chart, analytics-pie-chart, analytics-table, etc. */
|
|
7
|
+
type: string;
|
|
8
|
+
/** Data URL (e.g. /api/analytics/widgets/1/data). */
|
|
9
|
+
dataUrl?: string;
|
|
10
|
+
/** Query params for data-url. */
|
|
11
|
+
dataParams?: Record<string, string | number | boolean>;
|
|
12
|
+
/** Grid area: row start, col start, row span, col span. */
|
|
13
|
+
gridArea?: string;
|
|
14
|
+
/** Optional title. */
|
|
15
|
+
title?: string;
|
|
16
|
+
/** When true, only fetch/render when widget enters viewport. */
|
|
17
|
+
lazy?: boolean;
|
|
18
|
+
/** CSS margin for viewport prefetch (e.g. '200px'). Used when lazy is true. */
|
|
19
|
+
prefetch_margin?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Gridster/GridStack item: widget id + position/size. Stored in dashboard layout. */
|
|
22
|
+
export interface GridsterGridItem {
|
|
23
|
+
/** Widget id (used to build /widgets/{id}/data URL). */
|
|
24
|
+
widgetId: string;
|
|
25
|
+
/** Widget type: bar, line, pie, table (for rendering the right component). */
|
|
26
|
+
type?: string;
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
w: number;
|
|
30
|
+
h: number;
|
|
31
|
+
/** GridStack node id (optional; can use widgetId). */
|
|
32
|
+
id?: string;
|
|
33
|
+
/** Optional title. */
|
|
34
|
+
title?: string;
|
|
35
|
+
/** When true, only fetch/render when widget enters viewport. */
|
|
36
|
+
lazy?: boolean;
|
|
37
|
+
/** CSS margin for viewport prefetch (e.g. '200px'). Used when lazy is true. */
|
|
38
|
+
prefetch_margin?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface DashboardLayout {
|
|
41
|
+
/** API base URL (host + prefix, e.g. https://api.example.com/api/analytics). Used with widgetId to build data URL. */
|
|
42
|
+
apiUrl?: string;
|
|
43
|
+
/** Gridster/GridStack: number of columns (default 12). */
|
|
44
|
+
column?: number;
|
|
45
|
+
/** Gridster/GridStack: layout children (widgetId, type, x, y, w, h). When set, dashboard uses GridStack. */
|
|
46
|
+
children?: GridsterGridItem[];
|
|
47
|
+
/** Legacy: grid columns (e.g. "1fr 1fr"). */
|
|
48
|
+
columns?: string;
|
|
49
|
+
/** Legacy: grid rows (e.g. "auto 1fr"). */
|
|
50
|
+
rows?: string;
|
|
51
|
+
/** Legacy: gap between items. */
|
|
52
|
+
gap?: string;
|
|
53
|
+
/** Legacy: slots to render (when children is not set). */
|
|
54
|
+
slots?: DashboardSlot[];
|
|
55
|
+
/** Dashboard-level filter definitions (from API). */
|
|
56
|
+
filters?: FilterDefinition[];
|
|
57
|
+
/** When true, dashboard filter bar is hidden and dashboard params are not sent to widgets. */
|
|
58
|
+
hide_filter?: boolean;
|
|
59
|
+
/** Refresh interval in seconds (0 = no auto refresh). */
|
|
60
|
+
refresh_rate?: number;
|
|
61
|
+
}
|
|
62
|
+
export declare const EVENT_DASHBOARD_FILTER_CHANGE = "analytics-dashboard-filter-change";
|
|
63
|
+
export declare const EVENT_DASHBOARD_REFRESH = "analytics-dashboard-refresh";
|
|
64
|
+
export declare const EVENT_DASHBOARD_LAYOUT_CHANGE = "analytics-dashboard-layout-change";
|
|
65
|
+
/**
|
|
66
|
+
* Dashboard container: renders a grid of analytics widgets (Lit web components).
|
|
67
|
+
* Shows filter button and filter bar when layout.filters is set; dispatches filter-change and refresh
|
|
68
|
+
* When layout.children is set, uses GridStack (gridster); otherwise legacy slots + CSS grid.
|
|
69
|
+
* Passes apiUrl + widgetId to widgets; dispatches layout-change when grid layout changes.
|
|
70
|
+
*/
|
|
71
|
+
export declare class DashboardContainer extends LitElement {
|
|
72
|
+
static styles: import("lit").CSSResult;
|
|
73
|
+
layout: DashboardLayout;
|
|
74
|
+
private _dashboardParams;
|
|
75
|
+
private _filterBarOpen;
|
|
76
|
+
private _refreshIntervalId;
|
|
77
|
+
private _gridStack;
|
|
78
|
+
connectedCallback(): void;
|
|
79
|
+
disconnectedCallback(): void;
|
|
80
|
+
firstUpdated(): void;
|
|
81
|
+
updated(changed: Map<string, unknown>): void;
|
|
82
|
+
private _destroyGridStack;
|
|
83
|
+
private _initGridStack;
|
|
84
|
+
private _loadGridStackChildren;
|
|
85
|
+
private _startRefreshInterval;
|
|
86
|
+
private _stopRefreshInterval;
|
|
87
|
+
/** Current dashboard-level filter params (for widgets to merge). Returns {} when layout.hide_filter is true. */
|
|
88
|
+
getDashboardParams(): Record<string, string | number | boolean>;
|
|
89
|
+
private _onFilterChange;
|
|
90
|
+
private _onFilterClose;
|
|
91
|
+
private _onFilterToggle;
|
|
92
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
93
|
+
private _renderSlot;
|
|
94
|
+
}
|
|
95
|
+
declare global {
|
|
96
|
+
interface HTMLElementTagNameMap {
|
|
97
|
+
'analytics-dashboard': DashboardContainer;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=dashboard-container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-container.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/dashboard/dashboard-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAG5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,qBAAqB,CAAC;AAC7B,OAAO,kCAAkC,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,yGAAyG;IACzG,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACvD,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,sHAAsH;IACtH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4GAA4G;IAC5G,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,qDAAqD;IACrD,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,8FAA8F;IAC9F,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAWD,eAAO,MAAM,6BAA6B,sCAAsC,CAAC;AACjF,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AACrE,eAAO,MAAM,6BAA6B,sCAAsC,CAAC;AAYjF;;;;;GAKG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IAChD,OAAgB,MAAM,0BAmDpB;IAE0B,MAAM,EAAE,eAAe,CAAiB;IAE3D,OAAO,CAAC,gBAAgB,CAAiD;IACzE,OAAO,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,kBAAkB,CAA+C;IACzE,OAAO,CAAC,UAAU,CAA8C;IAEvD,iBAAiB,IAAI,IAAI;IAKzB,oBAAoB,IAAI,IAAI;IAM5B,YAAY,IAAI,IAAI;IAOpB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAWrD,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,sBAAsB;IAwC9B,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,oBAAoB;IAO5B,gHAAgH;IAChH,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAK/D,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,eAAe;IAId,MAAM;IAuDf,OAAO,CAAC,WAAW;CA+BpB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,kBAAkB,CAAC;KAC3C;CACF"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { LitElement, html, css } from 'lit';
|
|
3
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
|
+
import { GridStack } from 'gridstack';
|
|
5
|
+
import '../filters/index.js';
|
|
6
|
+
import 'gridstack/dist/gridstack.min.css';
|
|
7
|
+
/** Normalized layout: children always array (possibly empty), slots always array. */
|
|
8
|
+
function getLayoutChildren(layout) {
|
|
9
|
+
return layout.children ?? [];
|
|
10
|
+
}
|
|
11
|
+
function getLayoutSlots(layout) {
|
|
12
|
+
return layout.slots ?? [];
|
|
13
|
+
}
|
|
14
|
+
export const EVENT_DASHBOARD_FILTER_CHANGE = 'analytics-dashboard-filter-change';
|
|
15
|
+
export const EVENT_DASHBOARD_REFRESH = 'analytics-dashboard-refresh';
|
|
16
|
+
export const EVENT_DASHBOARD_LAYOUT_CHANGE = 'analytics-dashboard-layout-change';
|
|
17
|
+
/**
|
|
18
|
+
* Dashboard container: renders a grid of analytics widgets (Lit web components).
|
|
19
|
+
* Shows filter button and filter bar when layout.filters is set; dispatches filter-change and refresh
|
|
20
|
+
* When layout.children is set, uses GridStack (gridster); otherwise legacy slots + CSS grid.
|
|
21
|
+
* Passes apiUrl + widgetId to widgets; dispatches layout-change when grid layout changes.
|
|
22
|
+
*/
|
|
23
|
+
let DashboardContainer = class DashboardContainer extends LitElement {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(...arguments);
|
|
26
|
+
this.layout = { slots: [] };
|
|
27
|
+
this._dashboardParams = {};
|
|
28
|
+
this._filterBarOpen = false;
|
|
29
|
+
this._refreshIntervalId = null;
|
|
30
|
+
this._gridStack = null;
|
|
31
|
+
}
|
|
32
|
+
static { this.styles = css `
|
|
33
|
+
:host {
|
|
34
|
+
display: block;
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 100%;
|
|
37
|
+
}
|
|
38
|
+
.header {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
align-items: flex-start;
|
|
42
|
+
gap: 0.75rem;
|
|
43
|
+
margin-bottom: 0.75rem;
|
|
44
|
+
}
|
|
45
|
+
.header-row {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 0.75rem;
|
|
49
|
+
}
|
|
50
|
+
.grid {
|
|
51
|
+
display: grid;
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
min-height: 200px;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
}
|
|
57
|
+
.grid-stack {
|
|
58
|
+
min-height: 200px;
|
|
59
|
+
width: 100%;
|
|
60
|
+
}
|
|
61
|
+
.grid-stack-item-content {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
min-height: 0;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
}
|
|
67
|
+
.slot {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
min-height: 0;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
}
|
|
73
|
+
.slot-title {
|
|
74
|
+
font-size: 0.875rem;
|
|
75
|
+
font-weight: 600;
|
|
76
|
+
padding: 0.25rem 0.5rem;
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
}
|
|
79
|
+
.slot-chart {
|
|
80
|
+
flex: 1;
|
|
81
|
+
min-height: 0;
|
|
82
|
+
}
|
|
83
|
+
`; }
|
|
84
|
+
connectedCallback() {
|
|
85
|
+
super.connectedCallback();
|
|
86
|
+
this._startRefreshInterval();
|
|
87
|
+
}
|
|
88
|
+
disconnectedCallback() {
|
|
89
|
+
this._destroyGridStack();
|
|
90
|
+
this._stopRefreshInterval();
|
|
91
|
+
super.disconnectedCallback();
|
|
92
|
+
}
|
|
93
|
+
firstUpdated() {
|
|
94
|
+
const children = getLayoutChildren(this.layout);
|
|
95
|
+
if (children.length > 0) {
|
|
96
|
+
this._initGridStack();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
updated(changed) {
|
|
100
|
+
if (changed.has('layout')) {
|
|
101
|
+
this._stopRefreshInterval();
|
|
102
|
+
this._startRefreshInterval();
|
|
103
|
+
const children = getLayoutChildren(this.layout);
|
|
104
|
+
if (children.length > 0 && this._gridStack) {
|
|
105
|
+
this._loadGridStackChildren();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
_destroyGridStack() {
|
|
110
|
+
if (this._gridStack?.el) {
|
|
111
|
+
this._gridStack.destroy(false);
|
|
112
|
+
this._gridStack = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
_initGridStack() {
|
|
116
|
+
const el = this.renderRoot.querySelector('.grid-stack');
|
|
117
|
+
if (!el || this._gridStack)
|
|
118
|
+
return;
|
|
119
|
+
const column = this.layout.column ?? 12;
|
|
120
|
+
this._gridStack = GridStack.init({ column, float: false }, el);
|
|
121
|
+
const saveCB = (node, w) => {
|
|
122
|
+
w.type = node.type;
|
|
123
|
+
};
|
|
124
|
+
this._gridStack.on('change', () => {
|
|
125
|
+
const saved = this._gridStack?.save(false, false, saveCB);
|
|
126
|
+
if (saved) {
|
|
127
|
+
const children = saved.map((s) => ({
|
|
128
|
+
widgetId: String(s.id ?? ''),
|
|
129
|
+
type: s.type,
|
|
130
|
+
x: s.x ?? 0,
|
|
131
|
+
y: s.y ?? 0,
|
|
132
|
+
w: s.w ?? 1,
|
|
133
|
+
h: s.h ?? 1,
|
|
134
|
+
}));
|
|
135
|
+
this.dispatchEvent(new CustomEvent(EVENT_DASHBOARD_LAYOUT_CHANGE, {
|
|
136
|
+
bubbles: true,
|
|
137
|
+
composed: true,
|
|
138
|
+
detail: { children },
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
this._loadGridStackChildren();
|
|
143
|
+
}
|
|
144
|
+
_loadGridStackChildren() {
|
|
145
|
+
const children = getLayoutChildren(this.layout);
|
|
146
|
+
if (!this._gridStack || children.length === 0)
|
|
147
|
+
return;
|
|
148
|
+
const apiUrl = this.layout.apiUrl ?? '';
|
|
149
|
+
const dashboard = this;
|
|
150
|
+
const widgets = children.map((c) => ({
|
|
151
|
+
id: c.widgetId,
|
|
152
|
+
x: c.x,
|
|
153
|
+
y: c.y,
|
|
154
|
+
w: c.w,
|
|
155
|
+
h: c.h,
|
|
156
|
+
type: c.type,
|
|
157
|
+
lazy: c.lazy,
|
|
158
|
+
prefetch_margin: c.prefetch_margin,
|
|
159
|
+
}));
|
|
160
|
+
const addRemove = (parent, w, add, grid) => {
|
|
161
|
+
if (!add || grid)
|
|
162
|
+
return undefined;
|
|
163
|
+
const widget = w;
|
|
164
|
+
const item = document.createElement('div');
|
|
165
|
+
item.className = 'grid-stack-item';
|
|
166
|
+
const content = document.createElement('div');
|
|
167
|
+
content.className = 'grid-stack-item-content';
|
|
168
|
+
const type = (widget.type || 'bar').toLowerCase();
|
|
169
|
+
const tag = type === 'line' ? 'analytics-line-chart' : type === 'pie' ? 'analytics-pie-chart' : type === 'table' ? 'analytics-table' : 'analytics-bar-chart';
|
|
170
|
+
const widgetEl = document.createElement(tag);
|
|
171
|
+
widgetEl.setAttribute('widget-id', String(widget.id ?? ''));
|
|
172
|
+
widgetEl.setAttribute('api-url', apiUrl);
|
|
173
|
+
if (widget.lazy) {
|
|
174
|
+
widgetEl.setAttribute('lazy', '');
|
|
175
|
+
const margin = widget.prefetch_margin;
|
|
176
|
+
if (margin)
|
|
177
|
+
widgetEl.setAttribute('prefetch-margin', margin);
|
|
178
|
+
}
|
|
179
|
+
widgetEl.dashboard = dashboard;
|
|
180
|
+
content.appendChild(widgetEl);
|
|
181
|
+
item.appendChild(content);
|
|
182
|
+
return item;
|
|
183
|
+
};
|
|
184
|
+
this._gridStack.load(widgets, addRemove);
|
|
185
|
+
}
|
|
186
|
+
_startRefreshInterval() {
|
|
187
|
+
const rate = this.layout.refresh_rate ?? 0;
|
|
188
|
+
if (rate > 0) {
|
|
189
|
+
this._refreshIntervalId = setInterval(() => {
|
|
190
|
+
this.dispatchEvent(new CustomEvent(EVENT_DASHBOARD_REFRESH, {
|
|
191
|
+
bubbles: true,
|
|
192
|
+
composed: true,
|
|
193
|
+
}));
|
|
194
|
+
}, rate * 1000);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
_stopRefreshInterval() {
|
|
198
|
+
if (this._refreshIntervalId != null) {
|
|
199
|
+
clearInterval(this._refreshIntervalId);
|
|
200
|
+
this._refreshIntervalId = null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/** Current dashboard-level filter params (for widgets to merge). Returns {} when layout.hide_filter is true. */
|
|
204
|
+
getDashboardParams() {
|
|
205
|
+
if (this.layout?.hide_filter)
|
|
206
|
+
return {};
|
|
207
|
+
return { ...this._dashboardParams };
|
|
208
|
+
}
|
|
209
|
+
_onFilterChange(e) {
|
|
210
|
+
this._dashboardParams = { ...(e.detail?.params ?? {}) };
|
|
211
|
+
this.dispatchEvent(new CustomEvent(EVENT_DASHBOARD_FILTER_CHANGE, {
|
|
212
|
+
bubbles: true,
|
|
213
|
+
composed: true,
|
|
214
|
+
detail: { params: this._dashboardParams },
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
_onFilterClose() {
|
|
218
|
+
this._filterBarOpen = false;
|
|
219
|
+
}
|
|
220
|
+
_onFilterToggle() {
|
|
221
|
+
this._filterBarOpen = !this._filterBarOpen;
|
|
222
|
+
}
|
|
223
|
+
render() {
|
|
224
|
+
const children = getLayoutChildren(this.layout);
|
|
225
|
+
const slots = getLayoutSlots(this.layout);
|
|
226
|
+
const useGridster = children.length > 0;
|
|
227
|
+
const { columns = '1fr 1fr', rows = 'auto', gap = '1rem', filters = [], hide_filter = false } = this.layout;
|
|
228
|
+
const gridStyle = `grid-template-columns: ${columns}; grid-template-rows: ${rows}; gap: ${gap};`;
|
|
229
|
+
const hasFilters = filters.length > 0 && !hide_filter;
|
|
230
|
+
const activeCount = Object.keys(this._dashboardParams).filter((k) => this._dashboardParams[k] !== '' && this._dashboardParams[k] != null).length;
|
|
231
|
+
return html `
|
|
232
|
+
${hasFilters
|
|
233
|
+
? html `
|
|
234
|
+
<div class="header">
|
|
235
|
+
<div class="header-row">
|
|
236
|
+
<analytics-filter-button
|
|
237
|
+
.activeCount=${activeCount}
|
|
238
|
+
.open=${this._filterBarOpen}
|
|
239
|
+
@analytics-filter-toggle=${this._onFilterToggle}
|
|
240
|
+
></analytics-filter-button>
|
|
241
|
+
</div>
|
|
242
|
+
${this._filterBarOpen
|
|
243
|
+
? html `
|
|
244
|
+
<analytics-filter-bar
|
|
245
|
+
.filters=${filters}
|
|
246
|
+
.values=${this._dashboardParams}
|
|
247
|
+
.showClose=${true}
|
|
248
|
+
@analytics-filter-change=${this._onFilterChange}
|
|
249
|
+
@analytics-filter-close=${this._onFilterClose}
|
|
250
|
+
></analytics-filter-bar>
|
|
251
|
+
`
|
|
252
|
+
: ''}
|
|
253
|
+
</div>
|
|
254
|
+
`
|
|
255
|
+
: ''}
|
|
256
|
+
${useGridster
|
|
257
|
+
? html `<div class="grid-stack"></div>`
|
|
258
|
+
: html `
|
|
259
|
+
<div class="grid" style="${gridStyle}">
|
|
260
|
+
${slots.map((slot) => html `
|
|
261
|
+
<div class="slot" style="${slot.gridArea ? `grid-area: ${slot.gridArea};` : ''}">
|
|
262
|
+
${slot.title ? html `<div class="slot-title">${slot.title}</div>` : ''}
|
|
263
|
+
<div class="slot-chart">
|
|
264
|
+
${this._renderSlot(slot)}
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
`)}
|
|
268
|
+
</div>
|
|
269
|
+
`}
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
_renderSlot(slot) {
|
|
273
|
+
const dataUrl = slot.dataUrl ?? '';
|
|
274
|
+
const params = slot.dataParams ?? {};
|
|
275
|
+
const type = (slot.type || 'bar').toLowerCase();
|
|
276
|
+
const tag = type === 'line'
|
|
277
|
+
? 'analytics-line-chart'
|
|
278
|
+
: type === 'pie'
|
|
279
|
+
? 'analytics-pie-chart'
|
|
280
|
+
: type === 'table'
|
|
281
|
+
? 'analytics-table'
|
|
282
|
+
: type === 'analytics-line-chart'
|
|
283
|
+
? 'analytics-line-chart'
|
|
284
|
+
: type === 'analytics-pie-chart'
|
|
285
|
+
? 'analytics-pie-chart'
|
|
286
|
+
: type === 'analytics-table'
|
|
287
|
+
? 'analytics-table'
|
|
288
|
+
: 'analytics-bar-chart';
|
|
289
|
+
const lazy = slot.lazy ?? false;
|
|
290
|
+
const prefetchMargin = slot.prefetch_margin ?? '200px';
|
|
291
|
+
switch (tag) {
|
|
292
|
+
case 'analytics-line-chart':
|
|
293
|
+
return html `<analytics-line-chart data-url="${dataUrl}" .dataParams=${params} .dashboard=${this} .lazy=${lazy} prefetch-margin="${prefetchMargin}"></analytics-line-chart>`;
|
|
294
|
+
case 'analytics-pie-chart':
|
|
295
|
+
return html `<analytics-pie-chart data-url="${dataUrl}" .dataParams=${params} .dashboard=${this} .lazy=${lazy} prefetch-margin="${prefetchMargin}"></analytics-pie-chart>`;
|
|
296
|
+
case 'analytics-table':
|
|
297
|
+
return html `<analytics-table data-url="${dataUrl}" .dataParams=${params} .dashboard=${this} .lazy=${lazy} prefetch-margin="${prefetchMargin}"></analytics-table>`;
|
|
298
|
+
default:
|
|
299
|
+
return html `<analytics-bar-chart data-url="${dataUrl}" .dataParams=${params} .dashboard=${this} .lazy=${lazy} prefetch-margin="${prefetchMargin}"></analytics-bar-chart>`;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
__decorate([
|
|
304
|
+
property({ type: Object })
|
|
305
|
+
], DashboardContainer.prototype, "layout", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
state()
|
|
308
|
+
], DashboardContainer.prototype, "_dashboardParams", void 0);
|
|
309
|
+
__decorate([
|
|
310
|
+
state()
|
|
311
|
+
], DashboardContainer.prototype, "_filterBarOpen", void 0);
|
|
312
|
+
DashboardContainer = __decorate([
|
|
313
|
+
customElement('analytics-dashboard')
|
|
314
|
+
], DashboardContainer);
|
|
315
|
+
export { DashboardContainer };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DashboardContainer, EVENT_DASHBOARD_FILTER_CHANGE, EVENT_DASHBOARD_REFRESH, EVENT_DASHBOARD_LAYOUT_CHANGE, } from './dashboard-container.js';
|
|
2
|
+
export type { DashboardLayout, DashboardSlot, GridsterGridItem } from './dashboard-container.js';
|
|
3
|
+
import './dashboard-container.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/dashboard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjG,OAAO,0BAA0B,CAAC"}
|