@quicdata/analytics 0.0.12 → 0.0.14
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/package.json
CHANGED
package/widgets/number-kpi.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
import type { WidgetDefinitionSubset } from '../core/fetch-data.js';
|
|
3
3
|
import type { DashboardContainer } from '../dashboard/dashboard-container.js';
|
|
4
|
+
import '../filters/index.js';
|
|
4
5
|
/**
|
|
5
6
|
* Number KPI widget. Displays one or more large formatted numbers with labels.
|
|
6
7
|
* Data shape from backend transformNumber(): { chartType: 'Number', values, labels, options }.
|
|
@@ -21,10 +22,14 @@ export declare class NumberKpiWidget extends LitElement {
|
|
|
21
22
|
private _loading;
|
|
22
23
|
private _error;
|
|
23
24
|
private _dashboardParams;
|
|
25
|
+
private _widgetFilters;
|
|
26
|
+
private _widgetFilterParams;
|
|
27
|
+
private _hideFilter;
|
|
24
28
|
private _viewportVisible;
|
|
25
29
|
private _definitionTitle;
|
|
26
30
|
private _loadGeneration;
|
|
27
31
|
private _hasLoadedOnce;
|
|
32
|
+
private _ignoreNextFilterChange;
|
|
28
33
|
private _dashboardEl;
|
|
29
34
|
private _viewportUnobserve;
|
|
30
35
|
private _loadDataInFlight;
|
|
@@ -45,6 +50,7 @@ export declare class NumberKpiWidget extends LitElement {
|
|
|
45
50
|
private _defer;
|
|
46
51
|
private _loadData;
|
|
47
52
|
private _onRefresh;
|
|
53
|
+
private _onWidgetFilterChange;
|
|
48
54
|
/** Format a number: apply decimal places, optionally shorten (1234 → 1.2K). */
|
|
49
55
|
private _formatValue;
|
|
50
56
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-kpi.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/number-kpi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAGrD,OAAO,KAAK,EAA0B,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAM5F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"number-kpi.d.ts","sourceRoot":"","sources":["../../../../libs/analytics/src/widgets/number-kpi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAGrD,OAAO,KAAK,EAA0B,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAM5F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAM9E,OAAO,qBAAqB,CAAC;AAE7B;;;GAGG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,OAAgB,MAAM,0BA2MpB;IAEkC,KAAK,EAAE,MAAM,CAAC;IACqB,iBAAiB,EAAE,OAAO,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACtD,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,IAAI,EAAE,OAAO,CAAC;IACe,cAAc,EAAE,MAAM,CAAC;IACrD,iBAAiB,EAAE,sBAAsB,GAAG,SAAS,CAAC;IAE1F,QAAyB,QAAQ,CAA6B;IAC9D,QAAyB,QAAQ,CAAU;IAC3C,QAAyB,MAAM,CAAgB;IAC/C,QAAyB,gBAAgB,CAA4C;IACrF,QAAyB,cAAc,CAAqB;IAC5D,QAAyB,mBAAmB,CAA4C;IACxF,QAAyB,WAAW,CAAU;IAC9C,QAAyB,gBAAgB,CAAU;IACnD,QAAyB,gBAAgB,CAAS;IAElD,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,kBAAkB,CAAS;;IAyBnC,OAAO,CAAC,6BAA6B,CAInC;IAEF,OAAO,CAAC,wBAAwB,CAG9B;IAEO,iBAAiB,IAAI,IAAI;IAKzB,oBAAoB,IAAI,IAAI;IAO5B,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAuC5C,YAAY,IAAI,IAAI;IAkB7B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,CAAC,MAAM;YAQA,SAAS;IA6EvB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,qBAAqB;IAI7B,+EAA+E;IAC/E,OAAO,CAAC,YAAY;IAsBX,MAAM;CAmGhB"}
|
package/widgets/number-kpi.js
CHANGED
|
@@ -4,6 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js';
|
|
|
4
4
|
import { buildWidgetDataUrl, fetchWidgetData, fetchWidgetDefinition, } from '../core/fetch-data.js';
|
|
5
5
|
import { EVENT_DASHBOARD_FILTER_CHANGE, EVENT_DASHBOARD_REFRESH, } from '../dashboard/index.js';
|
|
6
6
|
import { observeViewport } from '../core/viewport-observer.js';
|
|
7
|
+
import '../filters/index.js';
|
|
7
8
|
/**
|
|
8
9
|
* Number KPI widget. Displays one or more large formatted numbers with labels.
|
|
9
10
|
* Data shape from backend transformNumber(): { chartType: 'Number', values, labels, options }.
|
|
@@ -24,6 +25,11 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
24
25
|
display: flex;
|
|
25
26
|
flex-direction: column;
|
|
26
27
|
min-height: 0;
|
|
28
|
+
--analytics-widget-toolbar-top: 2.5rem;
|
|
29
|
+
}
|
|
30
|
+
.widget-wrap:hover analytics-widget-toolbar {
|
|
31
|
+
opacity: 1;
|
|
32
|
+
pointer-events: auto;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
.widget-header {
|
|
@@ -212,6 +218,7 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
212
218
|
super();
|
|
213
219
|
this._loadGeneration = 0;
|
|
214
220
|
this._hasLoadedOnce = false;
|
|
221
|
+
this._ignoreNextFilterChange = false;
|
|
215
222
|
this._dashboardEl = null;
|
|
216
223
|
this._viewportUnobserve = null;
|
|
217
224
|
this._loadDataInFlight = false;
|
|
@@ -241,6 +248,9 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
241
248
|
this._loading = false;
|
|
242
249
|
this._error = null;
|
|
243
250
|
this._dashboardParams = {};
|
|
251
|
+
this._widgetFilters = [];
|
|
252
|
+
this._widgetFilterParams = {};
|
|
253
|
+
this._hideFilter = false;
|
|
244
254
|
this._viewportVisible = true;
|
|
245
255
|
this._definitionTitle = '';
|
|
246
256
|
}
|
|
@@ -261,11 +271,23 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
261
271
|
}
|
|
262
272
|
if (changed.has('widgetId') || changed.has('apiUrl')) {
|
|
263
273
|
this._definitionTitle = '';
|
|
274
|
+
this._widgetFilters = [];
|
|
275
|
+
this._widgetFilterParams = {};
|
|
276
|
+
this._ignoreNextFilterChange = true;
|
|
277
|
+
}
|
|
278
|
+
const onlyFilterState = (changed.has('_widgetFilterParams') || changed.has('_widgetFilters')) &&
|
|
279
|
+
!changed.has('dataUrl') &&
|
|
280
|
+
!changed.has('dataParams') &&
|
|
281
|
+
!changed.has('widgetId') &&
|
|
282
|
+
!changed.has('apiUrl');
|
|
283
|
+
if (onlyFilterState && this._ignoreNextFilterChange) {
|
|
284
|
+
this._ignoreNextFilterChange = false;
|
|
264
285
|
}
|
|
265
|
-
if (changed.has('dataUrl') ||
|
|
286
|
+
else if (changed.has('dataUrl') ||
|
|
266
287
|
changed.has('dataParams') ||
|
|
267
288
|
changed.has('widgetId') ||
|
|
268
|
-
changed.has('apiUrl')
|
|
289
|
+
changed.has('apiUrl') ||
|
|
290
|
+
changed.has('_widgetFilterParams')) {
|
|
269
291
|
if (this._getEffectiveDataUrl() && !this._loadDataScheduled) {
|
|
270
292
|
this._loadDataScheduled = true;
|
|
271
293
|
queueMicrotask(() => {
|
|
@@ -321,7 +343,26 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
321
343
|
return this.dataUrl;
|
|
322
344
|
}
|
|
323
345
|
_getEffectiveParams() {
|
|
324
|
-
|
|
346
|
+
let widgetFilterParams = {};
|
|
347
|
+
if (this._hideFilter) {
|
|
348
|
+
for (const f of this._widgetFilters) {
|
|
349
|
+
if (f.default_value !== undefined && f.default_value !== null) {
|
|
350
|
+
widgetFilterParams[f.param_name] = f.default_value;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else if (this._widgetFilters.length > 0) {
|
|
355
|
+
for (const f of this._widgetFilters) {
|
|
356
|
+
const setByUser = f.param_name in this._widgetFilterParams;
|
|
357
|
+
widgetFilterParams[f.param_name] = setByUser
|
|
358
|
+
? (this._widgetFilterParams[f.param_name] ?? '')
|
|
359
|
+
: (f.default_value ?? '');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
widgetFilterParams = { ...this._widgetFilterParams };
|
|
364
|
+
}
|
|
365
|
+
const out = { ...widgetFilterParams, ...(this.dataParams ?? {}) };
|
|
325
366
|
if (Object.keys(this._dashboardParams).length > 0) {
|
|
326
367
|
out.dashboard_params = this._dashboardParams;
|
|
327
368
|
}
|
|
@@ -358,17 +399,27 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
358
399
|
try {
|
|
359
400
|
const useWidgetApi = Boolean(this.apiUrl && this.widgetId);
|
|
360
401
|
let params;
|
|
361
|
-
if (useWidgetApi &&
|
|
402
|
+
if (useWidgetApi && this._widgetFilters.length === 0) {
|
|
362
403
|
const def = this.initialDefinition ?? (await fetchWidgetDefinition(this.apiUrl, this.widgetId));
|
|
363
404
|
this._definitionTitle = def.title ?? '';
|
|
364
|
-
|
|
405
|
+
this._widgetFilters = def.filters ?? [];
|
|
406
|
+
this._hideFilter = def.hide_filter ?? false;
|
|
407
|
+
const defaultParams = {};
|
|
408
|
+
for (const f of (def.filters ?? [])) {
|
|
409
|
+
if (f.default_value !== undefined && f.default_value !== null) {
|
|
410
|
+
defaultParams[f.param_name] = f.default_value;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
this._widgetFilterParams = { ...defaultParams, ...this._widgetFilterParams };
|
|
414
|
+
this._ignoreNextFilterChange = true;
|
|
415
|
+
params = { ...defaultParams, ...(this.dataParams ?? {}) };
|
|
416
|
+
if (Object.keys(this._dashboardParams).length > 0) {
|
|
417
|
+
params.dashboard_params = this._dashboardParams;
|
|
418
|
+
}
|
|
365
419
|
}
|
|
366
420
|
else {
|
|
367
421
|
params = this._getEffectiveParams();
|
|
368
422
|
}
|
|
369
|
-
if (Object.keys(this._dashboardParams).length > 0) {
|
|
370
|
-
params.dashboard_params = this._dashboardParams;
|
|
371
|
-
}
|
|
372
423
|
const res = await fetchWidgetData(dataUrl, params);
|
|
373
424
|
if (gen !== this._loadGeneration)
|
|
374
425
|
return;
|
|
@@ -376,11 +427,17 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
376
427
|
const kpiData = wd && wd.chartType === 'Number'
|
|
377
428
|
? { chartType: 'Number', values: wd.values ?? [], labels: wd.labels ?? [], options: wd.options, shorten_numbers: wd.shorten_numbers }
|
|
378
429
|
: null;
|
|
430
|
+
const filters = res.filters;
|
|
431
|
+
const hideFilter = res.hide_filter;
|
|
379
432
|
this._defer(() => {
|
|
380
433
|
if (gen !== this._loadGeneration)
|
|
381
434
|
return;
|
|
382
435
|
this._loadDataInFlight = false;
|
|
383
436
|
this._kpiData = kpiData;
|
|
437
|
+
if (filters?.length)
|
|
438
|
+
this._widgetFilters = filters;
|
|
439
|
+
if (hideFilter !== undefined)
|
|
440
|
+
this._hideFilter = hideFilter;
|
|
384
441
|
this._hasLoadedOnce = true;
|
|
385
442
|
this._loading = false;
|
|
386
443
|
if (this._loadDataPendingRefresh) {
|
|
@@ -410,6 +467,9 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
410
467
|
return;
|
|
411
468
|
this._loadData();
|
|
412
469
|
}
|
|
470
|
+
_onWidgetFilterChange(e) {
|
|
471
|
+
this._widgetFilterParams = { ...(e.detail?.params ?? {}) };
|
|
472
|
+
}
|
|
413
473
|
/** Format a number: apply decimal places, optionally shorten (1234 → 1.2K). */
|
|
414
474
|
_formatValue(value, decimal, shorten) {
|
|
415
475
|
const dec = decimal != null && decimal !== '' ? parseInt(decimal, 10) : undefined;
|
|
@@ -436,6 +496,8 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
436
496
|
}
|
|
437
497
|
render() {
|
|
438
498
|
const canRefresh = Boolean(this._getEffectiveDataUrl()) && !this.hideRefreshButton;
|
|
499
|
+
const hasWidgetFilters = this._widgetFilters.length > 0 && !this._hideFilter;
|
|
500
|
+
const widgetActiveCount = Object.keys(this._widgetFilterParams).filter((k) => this._widgetFilterParams[k] !== '' && this._widgetFilterParams[k] != null).length;
|
|
439
501
|
const showSkeleton = this._loading && !this._hasLoadedOnce;
|
|
440
502
|
const showSpinnerOverlay = this._loading && this._hasLoadedOnce;
|
|
441
503
|
const showTitlePlaceholder = !this._effectiveTitle && !this.hideRefreshButton;
|
|
@@ -512,6 +574,16 @@ let NumberKpiWidget = class NumberKpiWidget extends LitElement {
|
|
|
512
574
|
<div class="loading-spinner" aria-hidden="true"></div>
|
|
513
575
|
</div>`
|
|
514
576
|
: nothing}
|
|
577
|
+
${hasWidgetFilters
|
|
578
|
+
? html `
|
|
579
|
+
<analytics-widget-toolbar
|
|
580
|
+
.filters=${this._widgetFilters}
|
|
581
|
+
.values=${this._widgetFilterParams}
|
|
582
|
+
.activeCount=${widgetActiveCount}
|
|
583
|
+
@analytics-filter-change=${this._onWidgetFilterChange}
|
|
584
|
+
></analytics-widget-toolbar>
|
|
585
|
+
`
|
|
586
|
+
: ''}
|
|
515
587
|
</div>
|
|
516
588
|
`;
|
|
517
589
|
}
|
|
@@ -558,6 +630,15 @@ __decorate([
|
|
|
558
630
|
__decorate([
|
|
559
631
|
state()
|
|
560
632
|
], NumberKpiWidget.prototype, "_dashboardParams", void 0);
|
|
633
|
+
__decorate([
|
|
634
|
+
state()
|
|
635
|
+
], NumberKpiWidget.prototype, "_widgetFilters", void 0);
|
|
636
|
+
__decorate([
|
|
637
|
+
state()
|
|
638
|
+
], NumberKpiWidget.prototype, "_widgetFilterParams", void 0);
|
|
639
|
+
__decorate([
|
|
640
|
+
state()
|
|
641
|
+
], NumberKpiWidget.prototype, "_hideFilter", void 0);
|
|
561
642
|
__decorate([
|
|
562
643
|
state()
|
|
563
644
|
], NumberKpiWidget.prototype, "_viewportVisible", void 0);
|