ng-prime-tools 1.0.96 → 1.0.98
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.
|
@@ -61,6 +61,8 @@ import * as i2$2 from 'primeng/toast';
|
|
|
61
61
|
import { ToastModule } from 'primeng/toast';
|
|
62
62
|
import * as i2$3 from 'primeng/dialog';
|
|
63
63
|
import { DialogModule } from 'primeng/dialog';
|
|
64
|
+
import * as i5$1 from 'primeng/menu';
|
|
65
|
+
import { MenuModule } from 'primeng/menu';
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
* Calculates the width required for a column based on the header text (column title).
|
|
@@ -4223,14 +4225,24 @@ const createDefaultChartOptions = (chartType, theme, config) => {
|
|
|
4223
4225
|
label: (context) => config.tooltipLabel(context, isCircularChart),
|
|
4224
4226
|
},
|
|
4225
4227
|
},
|
|
4228
|
+
/*
|
|
4229
|
+
* Do not use `display: isCircularChart`.
|
|
4230
|
+
* For non-circular charts, this plugin version can still enter
|
|
4231
|
+
* its drawing lifecycle and throw `undefined.length`.
|
|
4232
|
+
*/
|
|
4226
4233
|
datalabels: {
|
|
4227
|
-
display: isCircularChart,
|
|
4234
|
+
display: () => isCircularChart,
|
|
4228
4235
|
color: theme.textColor,
|
|
4229
4236
|
anchor: isCircularChart ? 'center' : 'end',
|
|
4230
4237
|
align: isCircularChart ? 'center' : 'top',
|
|
4231
4238
|
clamp: true,
|
|
4232
4239
|
clip: false,
|
|
4233
|
-
formatter: (value, context) =>
|
|
4240
|
+
formatter: (value, context) => {
|
|
4241
|
+
if (!isCircularChart) {
|
|
4242
|
+
return '';
|
|
4243
|
+
}
|
|
4244
|
+
return config.dataLabel(value, context, true);
|
|
4245
|
+
},
|
|
4234
4246
|
font: {
|
|
4235
4247
|
family: config.fontFamily,
|
|
4236
4248
|
size: PT_CHART_FONT_SIZES.dataLabel,
|
|
@@ -4322,7 +4334,11 @@ class PTChartComponent {
|
|
|
4322
4334
|
this.colorSchemeChangeListener = () => {
|
|
4323
4335
|
this.refreshTheme();
|
|
4324
4336
|
};
|
|
4325
|
-
|
|
4337
|
+
/*
|
|
4338
|
+
* Do not register ChartDataLabels globally.
|
|
4339
|
+
* It must only be enabled for pie, doughnut and polar-area charts.
|
|
4340
|
+
*/
|
|
4341
|
+
Chart.register(...registerables);
|
|
4326
4342
|
}
|
|
4327
4343
|
ngAfterViewInit() {
|
|
4328
4344
|
this.viewInitialized = true;
|
|
@@ -4355,10 +4371,9 @@ class PTChartComponent {
|
|
|
4355
4371
|
if (!this.viewInitialized || !this.chartConfig) {
|
|
4356
4372
|
return;
|
|
4357
4373
|
}
|
|
4358
|
-
const canvas = this.canvasRef.nativeElement;
|
|
4359
4374
|
this.destroyChart();
|
|
4360
4375
|
const configuration = this.buildChartConfiguration();
|
|
4361
|
-
this.chart = new Chart(
|
|
4376
|
+
this.chart = new Chart(this.canvasRef.nativeElement, configuration);
|
|
4362
4377
|
this.currentChartType = this.chartConfig.type;
|
|
4363
4378
|
this.scheduleChartResize();
|
|
4364
4379
|
}
|
|
@@ -4392,6 +4407,12 @@ class PTChartComponent {
|
|
|
4392
4407
|
type: chartType,
|
|
4393
4408
|
data: this.cloneChartData(this.chartConfig.data),
|
|
4394
4409
|
options: this.mergeChartOptions(defaultOptions, consumerOptions, chartType),
|
|
4410
|
+
/*
|
|
4411
|
+
* ChartDataLabels is attached only for circular charts.
|
|
4412
|
+
* It is not registered globally, so it cannot break line,
|
|
4413
|
+
* bar, scatter, bubble or comparison charts.
|
|
4414
|
+
*/
|
|
4415
|
+
plugins: isCircularChartType(chartType) ? [ChartDataLabels] : [],
|
|
4395
4416
|
};
|
|
4396
4417
|
}
|
|
4397
4418
|
buildDefaultOptions(chartType, theme) {
|
|
@@ -4465,12 +4486,21 @@ class PTChartComponent {
|
|
|
4465
4486
|
...consumerPlugins?.tooltip?.callbacks,
|
|
4466
4487
|
},
|
|
4467
4488
|
},
|
|
4489
|
+
},
|
|
4490
|
+
};
|
|
4491
|
+
/*
|
|
4492
|
+
* Add datalabel options only to circular charts.
|
|
4493
|
+
* For Cartesian charts, the plugin is not installed at all.
|
|
4494
|
+
*/
|
|
4495
|
+
if (isCircularChartType(chartType)) {
|
|
4496
|
+
mergedOptions.plugins = {
|
|
4497
|
+
...mergedOptions.plugins,
|
|
4468
4498
|
datalabels: {
|
|
4469
4499
|
...defaultPlugins?.datalabels,
|
|
4470
4500
|
...consumerPlugins?.datalabels,
|
|
4471
4501
|
},
|
|
4472
|
-
}
|
|
4473
|
-
}
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4474
4504
|
if (isCartesianChartType(chartType)) {
|
|
4475
4505
|
mergedOptions.scales = this.mergeScales(defaultOptions.scales, consumerOptions.scales);
|
|
4476
4506
|
}
|
|
@@ -7621,9 +7651,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
7621
7651
|
|
|
7622
7652
|
// src/lib/components/pt-metric-panel/pt-metric-panel.component.ts
|
|
7623
7653
|
class PTMetricPanelComponent {
|
|
7654
|
+
/**
|
|
7655
|
+
* Controlled by the parent component.
|
|
7656
|
+
* The parent must set it to false when its request completes,
|
|
7657
|
+
* including error cases.
|
|
7658
|
+
*/
|
|
7659
|
+
set loading(value) {
|
|
7660
|
+
const previousLoading = this.dashboardLoading;
|
|
7661
|
+
this.dashboardLoading = value;
|
|
7662
|
+
if (value) {
|
|
7663
|
+
this.dashboardLoadingWasStarted = true;
|
|
7664
|
+
}
|
|
7665
|
+
if (previousLoading && !value && this.dashboardLoadingWasStarted) {
|
|
7666
|
+
this.localRefreshLoading = false;
|
|
7667
|
+
this.dashboardLoadingWasStarted = false;
|
|
7668
|
+
}
|
|
7669
|
+
this.rebuildActionMenuItems();
|
|
7670
|
+
}
|
|
7671
|
+
get loading() {
|
|
7672
|
+
return this.dashboardLoading;
|
|
7673
|
+
}
|
|
7624
7674
|
constructor(router) {
|
|
7625
7675
|
this.router = router;
|
|
7626
7676
|
this.cardConfig = this.getDefaultCardConfig();
|
|
7677
|
+
/**
|
|
7678
|
+
* Displays the refresh action in the panel header.
|
|
7679
|
+
*/
|
|
7680
|
+
this.showRefresh = false;
|
|
7681
|
+
/**
|
|
7682
|
+
* Displays the contextual actions menu in the panel header.
|
|
7683
|
+
*/
|
|
7684
|
+
this.showMenu = false;
|
|
7685
|
+
/**
|
|
7686
|
+
* Additional menu items supplied by the parent component.
|
|
7687
|
+
* "Actualiser" is automatically added when showRefresh is true.
|
|
7688
|
+
*/
|
|
7689
|
+
this.menuItems = [];
|
|
7690
|
+
/**
|
|
7691
|
+
* Emitted when the user clicks the refresh action.
|
|
7692
|
+
* The parent executes the API request.
|
|
7693
|
+
*/
|
|
7694
|
+
this.refresh = new EventEmitter();
|
|
7695
|
+
this.actionMenuItems = [];
|
|
7696
|
+
this.dashboardLoading = false;
|
|
7697
|
+
this.localRefreshLoading = false;
|
|
7698
|
+
this.dashboardLoadingWasStarted = false;
|
|
7699
|
+
}
|
|
7700
|
+
ngOnChanges(changes) {
|
|
7701
|
+
if (changes['showRefresh'] || changes['showMenu'] || changes['menuItems']) {
|
|
7702
|
+
this.rebuildActionMenuItems();
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
get isLoading() {
|
|
7706
|
+
return this.dashboardLoading || this.localRefreshLoading;
|
|
7707
|
+
}
|
|
7708
|
+
get hasCustomMenuItems() {
|
|
7709
|
+
return this.menuItems.length > 0;
|
|
7710
|
+
}
|
|
7711
|
+
get shouldShowMenu() {
|
|
7712
|
+
return this.showMenu || this.showRefresh || this.hasCustomMenuItems;
|
|
7627
7713
|
}
|
|
7628
7714
|
getDefaultCardConfig() {
|
|
7629
7715
|
return {
|
|
@@ -7694,32 +7780,83 @@ class PTMetricPanelComponent {
|
|
|
7694
7780
|
return typeof value === 'object' && value !== null && 'text' in value;
|
|
7695
7781
|
}
|
|
7696
7782
|
handleClick(url) {
|
|
7697
|
-
if (url) {
|
|
7783
|
+
if (url && !this.isLoading) {
|
|
7698
7784
|
this.router.navigate([url]);
|
|
7699
7785
|
}
|
|
7700
7786
|
}
|
|
7787
|
+
onRefreshClick(event) {
|
|
7788
|
+
event.preventDefault();
|
|
7789
|
+
event.stopPropagation();
|
|
7790
|
+
this.requestRefresh();
|
|
7791
|
+
}
|
|
7792
|
+
toggleMenu(event) {
|
|
7793
|
+
event.preventDefault();
|
|
7794
|
+
event.stopPropagation();
|
|
7795
|
+
if (this.isLoading) {
|
|
7796
|
+
return;
|
|
7797
|
+
}
|
|
7798
|
+
this.actionMenu?.toggle(event);
|
|
7799
|
+
}
|
|
7800
|
+
requestRefresh() {
|
|
7801
|
+
if (this.isLoading) {
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
this.localRefreshLoading = true;
|
|
7805
|
+
this.rebuildActionMenuItems();
|
|
7806
|
+
this.refresh.emit();
|
|
7807
|
+
}
|
|
7808
|
+
rebuildActionMenuItems() {
|
|
7809
|
+
const items = [];
|
|
7810
|
+
if (this.showRefresh) {
|
|
7811
|
+
items.push({
|
|
7812
|
+
label: 'Actualiser',
|
|
7813
|
+
icon: this.isLoading ? 'pi pi-spin pi-spinner' : 'pi pi-refresh',
|
|
7814
|
+
disabled: this.isLoading,
|
|
7815
|
+
command: () => this.requestRefresh(),
|
|
7816
|
+
});
|
|
7817
|
+
}
|
|
7818
|
+
if (this.showRefresh && this.hasCustomMenuItems) {
|
|
7819
|
+
items.push({
|
|
7820
|
+
separator: true,
|
|
7821
|
+
});
|
|
7822
|
+
}
|
|
7823
|
+
this.actionMenuItems = [...items, ...this.menuItems];
|
|
7824
|
+
}
|
|
7701
7825
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelComponent, deps: [{ token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7702
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PTMetricPanelComponent, isStandalone: false, selector: "pt-metric-panel", inputs: { panelData: "panelData", cardConfig: "cardConfig" }, ngImport: i0, template: "<pt-card [config]=\"cardConfig\">\n <div class=\"panel-header\" [ngStyle]=\"getTitleStyles()\">\n
|
|
7826
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PTMetricPanelComponent, isStandalone: false, selector: "pt-metric-panel", inputs: { panelData: "panelData", cardConfig: "cardConfig", showRefresh: "showRefresh", showMenu: "showMenu", menuItems: "menuItems", loading: "loading" }, outputs: { refresh: "refresh" }, viewQueries: [{ propertyName: "actionMenu", first: true, predicate: ["actionMenu"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- src/lib/components/pt-metric-panel/pt-metric-panel.component.html -->\n\n<pt-card [config]=\"cardConfig\">\n <div class=\"panel-header\">\n <div class=\"panel-title-container\" [ngStyle]=\"getTitleStyles()\">\n @if (getTitleIcon()) {\n <i\n class=\"panel-title-icon\"\n [ngClass]=\"getIconClass(getTitleIcon())\"\n ></i>\n }\n\n <span class=\"panel-title-text\">\n {{ getTitleText() }}\n </span>\n </div>\n\n @if (showRefresh || shouldShowMenu) {\n <div class=\"panel-actions\">\n @if (showRefresh) {\n <button\n type=\"button\"\n class=\"panel-action-button\"\n [class.panel-action-button-loading]=\"isLoading\"\n [disabled]=\"isLoading\"\n aria-label=\"Actualiser\"\n title=\"Actualiser\"\n (click)=\"onRefreshClick($event)\"\n >\n <i\n class=\"pi\"\n [ngClass]=\"isLoading ? 'pi-spin pi-spinner' : 'pi-refresh'\"\n ></i>\n </button>\n }\n\n @if (shouldShowMenu) {\n <button\n type=\"button\"\n class=\"panel-action-button\"\n [disabled]=\"isLoading\"\n aria-label=\"Plus d\u2019actions\"\n title=\"Plus d\u2019actions\"\n (click)=\"toggleMenu($event)\"\n >\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n\n <p-menu\n #actionMenu\n [model]=\"actionMenuItems\"\n [popup]=\"true\"\n appendTo=\"body\"\n ></p-menu>\n }\n </div>\n }\n </div>\n\n <div class=\"panel-separator\"></div>\n\n <div class=\"metric-content\">\n @if (isLoading) {\n <div\n class=\"metric-loading-overlay\"\n aria-live=\"polite\"\n aria-label=\"Chargement des donn\u00E9es\"\n >\n <i class=\"pi pi-spinner pi-spin metric-loading-spinner\"></i>\n <span>Chargement des donn\u00E9es...</span>\n </div>\n }\n\n <div\n class=\"metric-list\"\n [class.metric-list-loading]=\"isLoading\"\n [attr.aria-busy]=\"isLoading\"\n >\n @for (item of panelData.indicators; track $index) {\n <div\n class=\"metric-item\"\n [class.metric-item-clickable]=\"!!item.url && !isLoading\"\n [pTooltip]=\"item.tooltip || ''\"\n tooltipPosition=\"top\"\n [tooltipDisabled]=\"!item.tooltip || isLoading\"\n (click)=\"!isLoading && handleClick(item.url)\"\n >\n <div class=\"metric-left\">\n @if (item.icon) {\n <span class=\"metric-icon-wrapper\">\n <i\n [ngClass]=\"getIconClass(item.icon.code)\"\n [ngStyle]=\"getIconStyles(item.icon)\"\n ></i>\n </span>\n }\n\n <span class=\"metric-title\">\n {{ isTitleStyle(item.title) ? item.title.text : item.title }}\n </span>\n </div>\n\n <span\n class=\"metric-value\"\n [class.metric-value-highlighted]=\"item.highlighted && !isLoading\"\n [ngStyle]=\"getValueStyles(item.value)\"\n >\n {{ isTitleStyle(item.value) ? item.value.text : item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n</pt-card>\n", styles: [":host{display:block}.panel-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}.panel-title-container{display:flex;align-items:center;min-width:0;gap:12px;font-weight:800;line-height:1.2}.panel-title-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;min-width:38px;min-height:38px;padding:10px;color:#6734c9;background:#f0e7ff;border-radius:12px;font-size:1.05rem}.panel-title-text{overflow:hidden;color:inherit;text-overflow:ellipsis;white-space:nowrap}.panel-actions{display:flex;align-items:center;flex:0 0 auto;gap:4px}.panel-action-button{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;cursor:pointer;border:1px solid transparent;border-radius:10px;color:#667085;background:transparent;transition:background-color .16s ease,border-color .16s ease,color .16s ease,transform .16s ease}.panel-action-button:hover:not(:disabled){border-color:#e3d8fb;color:#6734c9;background:#f7f3ff}.panel-action-button:active:not(:disabled){transform:scale(.95)}.panel-action-button:disabled{cursor:wait;opacity:.65}.panel-action-button-loading{color:#6734c9}.panel-action-button:focus-visible{outline:2px solid #8b5cf6;outline-offset:2px}.panel-separator{width:100%;height:1px;margin:0 0 16px;background:#e7eaf0}.metric-list{display:flex;flex-direction:column;gap:12px}.metric-item{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:68px;padding:12px 14px;background:#fff;border:1px solid #edf0f5;border-radius:14px;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease}.metric-item:hover{border-color:#ddd2f8;box-shadow:0 5px 14px #4a209014}.metric-item-clickable{cursor:pointer}.metric-item-clickable:hover{transform:translateY(-1px)}.metric-left{display:flex;align-items:center;min-width:0;gap:12px}.metric-icon-wrapper{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}.metric-icon-wrapper i{display:inline-flex!important;align-items:center;justify-content:center;min-width:40px;min-height:40px;box-sizing:border-box}.metric-title{overflow:hidden;color:#344054;font-size:1rem;font-weight:700;line-height:1.3;text-overflow:ellipsis;white-space:nowrap}.metric-value{flex:0 0 auto;padding:7px 11px;color:#1f2937;background:#f8f9fc;border:1px solid #e8ebf1;border-radius:10px;font-size:.95rem;font-weight:800;line-height:1;text-align:right;white-space:nowrap}.metric-value-highlighted{color:#15803d!important;background:#dcfce7!important;border-color:#86efac!important;animation:metric-value-flash 1.8s ease-out}@keyframes metric-value-flash{0%{color:#166534;background:#bbf7d0;border-color:#4ade80;transform:scale(1.08)}to{color:#15803d;background:#dcfce7;border-color:#86efac;transform:scale(1)}}@media(max-width:576px){.panel-header,.panel-title-container{gap:8px}.panel-title-icon{min-width:34px;min-height:34px;padding:8px}.panel-action-button{width:32px;height:32px}.metric-item{min-height:60px;padding:10px}.metric-title{font-size:.92rem}.metric-value{padding:6px 8px;font-size:.85rem}}.metric-content{position:relative;min-height:120px}.metric-loading-overlay{position:absolute;z-index:2;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.7rem;min-height:120px;border-radius:14px;color:#6734c9;background:#ffffffd1;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);font-size:.9rem;font-weight:700}.metric-loading-spinner{font-size:1.5rem}.metric-list-loading{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:.42;filter:blur(.4px)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: PTCardComponent, selector: "pt-card", inputs: ["config"] }, { kind: "directive", type: i12.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i5$1.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo", "motionOptions"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }] }); }
|
|
7703
7827
|
}
|
|
7704
7828
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelComponent, decorators: [{
|
|
7705
7829
|
type: Component,
|
|
7706
|
-
args: [{ selector: 'pt-metric-panel', standalone: false, template: "<pt-card [config]=\"cardConfig\">\n <div class=\"panel-header\" [ngStyle]=\"getTitleStyles()\">\n
|
|
7830
|
+
args: [{ selector: 'pt-metric-panel', standalone: false, template: "<!-- src/lib/components/pt-metric-panel/pt-metric-panel.component.html -->\n\n<pt-card [config]=\"cardConfig\">\n <div class=\"panel-header\">\n <div class=\"panel-title-container\" [ngStyle]=\"getTitleStyles()\">\n @if (getTitleIcon()) {\n <i\n class=\"panel-title-icon\"\n [ngClass]=\"getIconClass(getTitleIcon())\"\n ></i>\n }\n\n <span class=\"panel-title-text\">\n {{ getTitleText() }}\n </span>\n </div>\n\n @if (showRefresh || shouldShowMenu) {\n <div class=\"panel-actions\">\n @if (showRefresh) {\n <button\n type=\"button\"\n class=\"panel-action-button\"\n [class.panel-action-button-loading]=\"isLoading\"\n [disabled]=\"isLoading\"\n aria-label=\"Actualiser\"\n title=\"Actualiser\"\n (click)=\"onRefreshClick($event)\"\n >\n <i\n class=\"pi\"\n [ngClass]=\"isLoading ? 'pi-spin pi-spinner' : 'pi-refresh'\"\n ></i>\n </button>\n }\n\n @if (shouldShowMenu) {\n <button\n type=\"button\"\n class=\"panel-action-button\"\n [disabled]=\"isLoading\"\n aria-label=\"Plus d\u2019actions\"\n title=\"Plus d\u2019actions\"\n (click)=\"toggleMenu($event)\"\n >\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n\n <p-menu\n #actionMenu\n [model]=\"actionMenuItems\"\n [popup]=\"true\"\n appendTo=\"body\"\n ></p-menu>\n }\n </div>\n }\n </div>\n\n <div class=\"panel-separator\"></div>\n\n <div class=\"metric-content\">\n @if (isLoading) {\n <div\n class=\"metric-loading-overlay\"\n aria-live=\"polite\"\n aria-label=\"Chargement des donn\u00E9es\"\n >\n <i class=\"pi pi-spinner pi-spin metric-loading-spinner\"></i>\n <span>Chargement des donn\u00E9es...</span>\n </div>\n }\n\n <div\n class=\"metric-list\"\n [class.metric-list-loading]=\"isLoading\"\n [attr.aria-busy]=\"isLoading\"\n >\n @for (item of panelData.indicators; track $index) {\n <div\n class=\"metric-item\"\n [class.metric-item-clickable]=\"!!item.url && !isLoading\"\n [pTooltip]=\"item.tooltip || ''\"\n tooltipPosition=\"top\"\n [tooltipDisabled]=\"!item.tooltip || isLoading\"\n (click)=\"!isLoading && handleClick(item.url)\"\n >\n <div class=\"metric-left\">\n @if (item.icon) {\n <span class=\"metric-icon-wrapper\">\n <i\n [ngClass]=\"getIconClass(item.icon.code)\"\n [ngStyle]=\"getIconStyles(item.icon)\"\n ></i>\n </span>\n }\n\n <span class=\"metric-title\">\n {{ isTitleStyle(item.title) ? item.title.text : item.title }}\n </span>\n </div>\n\n <span\n class=\"metric-value\"\n [class.metric-value-highlighted]=\"item.highlighted && !isLoading\"\n [ngStyle]=\"getValueStyles(item.value)\"\n >\n {{ isTitleStyle(item.value) ? item.value.text : item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n</pt-card>\n", styles: [":host{display:block}.panel-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}.panel-title-container{display:flex;align-items:center;min-width:0;gap:12px;font-weight:800;line-height:1.2}.panel-title-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;min-width:38px;min-height:38px;padding:10px;color:#6734c9;background:#f0e7ff;border-radius:12px;font-size:1.05rem}.panel-title-text{overflow:hidden;color:inherit;text-overflow:ellipsis;white-space:nowrap}.panel-actions{display:flex;align-items:center;flex:0 0 auto;gap:4px}.panel-action-button{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;padding:0;cursor:pointer;border:1px solid transparent;border-radius:10px;color:#667085;background:transparent;transition:background-color .16s ease,border-color .16s ease,color .16s ease,transform .16s ease}.panel-action-button:hover:not(:disabled){border-color:#e3d8fb;color:#6734c9;background:#f7f3ff}.panel-action-button:active:not(:disabled){transform:scale(.95)}.panel-action-button:disabled{cursor:wait;opacity:.65}.panel-action-button-loading{color:#6734c9}.panel-action-button:focus-visible{outline:2px solid #8b5cf6;outline-offset:2px}.panel-separator{width:100%;height:1px;margin:0 0 16px;background:#e7eaf0}.metric-list{display:flex;flex-direction:column;gap:12px}.metric-item{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:68px;padding:12px 14px;background:#fff;border:1px solid #edf0f5;border-radius:14px;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease}.metric-item:hover{border-color:#ddd2f8;box-shadow:0 5px 14px #4a209014}.metric-item-clickable{cursor:pointer}.metric-item-clickable:hover{transform:translateY(-1px)}.metric-left{display:flex;align-items:center;min-width:0;gap:12px}.metric-icon-wrapper{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}.metric-icon-wrapper i{display:inline-flex!important;align-items:center;justify-content:center;min-width:40px;min-height:40px;box-sizing:border-box}.metric-title{overflow:hidden;color:#344054;font-size:1rem;font-weight:700;line-height:1.3;text-overflow:ellipsis;white-space:nowrap}.metric-value{flex:0 0 auto;padding:7px 11px;color:#1f2937;background:#f8f9fc;border:1px solid #e8ebf1;border-radius:10px;font-size:.95rem;font-weight:800;line-height:1;text-align:right;white-space:nowrap}.metric-value-highlighted{color:#15803d!important;background:#dcfce7!important;border-color:#86efac!important;animation:metric-value-flash 1.8s ease-out}@keyframes metric-value-flash{0%{color:#166534;background:#bbf7d0;border-color:#4ade80;transform:scale(1.08)}to{color:#15803d;background:#dcfce7;border-color:#86efac;transform:scale(1)}}@media(max-width:576px){.panel-header,.panel-title-container{gap:8px}.panel-title-icon{min-width:34px;min-height:34px;padding:8px}.panel-action-button{width:32px;height:32px}.metric-item{min-height:60px;padding:10px}.metric-title{font-size:.92rem}.metric-value{padding:6px 8px;font-size:.85rem}}.metric-content{position:relative;min-height:120px}.metric-loading-overlay{position:absolute;z-index:2;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.7rem;min-height:120px;border-radius:14px;color:#6734c9;background:#ffffffd1;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);font-size:.9rem;font-weight:700}.metric-loading-spinner{font-size:1.5rem}.metric-list-loading{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:.42;filter:blur(.4px)}\n"] }]
|
|
7707
7831
|
}], ctorParameters: () => [{ type: i1$2.Router }], propDecorators: { panelData: [{
|
|
7708
7832
|
type: Input
|
|
7709
7833
|
}], cardConfig: [{
|
|
7710
7834
|
type: Input
|
|
7835
|
+
}], showRefresh: [{
|
|
7836
|
+
type: Input
|
|
7837
|
+
}], showMenu: [{
|
|
7838
|
+
type: Input
|
|
7839
|
+
}], menuItems: [{
|
|
7840
|
+
type: Input
|
|
7841
|
+
}], loading: [{
|
|
7842
|
+
type: Input
|
|
7843
|
+
}], refresh: [{
|
|
7844
|
+
type: Output
|
|
7845
|
+
}], actionMenu: [{
|
|
7846
|
+
type: ViewChild,
|
|
7847
|
+
args: ['actionMenu']
|
|
7711
7848
|
}] } });
|
|
7712
7849
|
|
|
7713
7850
|
class PTMetricPanelModule {
|
|
7714
7851
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
7715
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, declarations: [PTMetricPanelComponent], imports: [CommonModule, PTCardModule, TooltipModule], exports: [PTMetricPanelComponent] }); }
|
|
7716
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, imports: [CommonModule, PTCardModule, TooltipModule] }); }
|
|
7852
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, declarations: [PTMetricPanelComponent], imports: [CommonModule, PTCardModule, TooltipModule, MenuModule], exports: [PTMetricPanelComponent] }); }
|
|
7853
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, imports: [CommonModule, PTCardModule, TooltipModule, MenuModule] }); }
|
|
7717
7854
|
}
|
|
7718
7855
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTMetricPanelModule, decorators: [{
|
|
7719
7856
|
type: NgModule,
|
|
7720
7857
|
args: [{
|
|
7721
7858
|
declarations: [PTMetricPanelComponent],
|
|
7722
|
-
imports: [CommonModule, PTCardModule, TooltipModule],
|
|
7859
|
+
imports: [CommonModule, PTCardModule, TooltipModule, MenuModule],
|
|
7723
7860
|
exports: [PTMetricPanelComponent],
|
|
7724
7861
|
}]
|
|
7725
7862
|
}] });
|
|
@@ -7765,7 +7902,11 @@ class PTChartComparisonComponent {
|
|
|
7765
7902
|
this.xAxisTitle = PT_CHART_COMPARISON_DEFAULT_X_AXIS_TITLE;
|
|
7766
7903
|
this.yAxisTitle = PT_CHART_COMPARISON_DEFAULT_Y_AXIS_TITLE;
|
|
7767
7904
|
this.viewInitialized = false;
|
|
7768
|
-
|
|
7905
|
+
/*
|
|
7906
|
+
* Do not register ChartDataLabels here.
|
|
7907
|
+
* PTChartComparison is a line/comparison chart and does not use it.
|
|
7908
|
+
*/
|
|
7909
|
+
Chart.register(...registerables);
|
|
7769
7910
|
}
|
|
7770
7911
|
ngAfterViewInit() {
|
|
7771
7912
|
this.viewInitialized = true;
|
|
@@ -7807,19 +7948,19 @@ class PTChartComparisonComponent {
|
|
|
7807
7948
|
if (!this.chartConfig || !this.canvasRef) {
|
|
7808
7949
|
return;
|
|
7809
7950
|
}
|
|
7810
|
-
const canvas = this.canvasRef.nativeElement;
|
|
7811
7951
|
this.destroyChart();
|
|
7812
7952
|
const configuration = {
|
|
7813
7953
|
type: this.chartConfig.type || 'line',
|
|
7814
7954
|
data: this.getFormattedChartData(),
|
|
7815
7955
|
options: this.getChartOptions(),
|
|
7816
7956
|
};
|
|
7817
|
-
this.chart = new Chart(
|
|
7957
|
+
this.chart = new Chart(this.canvasRef.nativeElement, configuration);
|
|
7818
7958
|
this.scheduleResize();
|
|
7819
7959
|
}
|
|
7820
7960
|
getFormattedChartData() {
|
|
7961
|
+
const sourceDatasets = this.chartConfig.data.datasets ?? [];
|
|
7821
7962
|
return {
|
|
7822
|
-
labels: this.chartConfig.data.labels,
|
|
7963
|
+
labels: [...(this.chartConfig.data.labels ?? [])],
|
|
7823
7964
|
datasets: [
|
|
7824
7965
|
{
|
|
7825
7966
|
label: this.chartConfig.medianTitle?.trim() ||
|
|
@@ -7828,7 +7969,10 @@ class PTChartComparisonComponent {
|
|
|
7828
7969
|
data: this.calculateMedian(),
|
|
7829
7970
|
...PT_CHART_COMPARISON_MEDIAN_DATASET,
|
|
7830
7971
|
},
|
|
7831
|
-
...
|
|
7972
|
+
...sourceDatasets.map((dataset) => ({
|
|
7973
|
+
...dataset,
|
|
7974
|
+
data: [...(dataset.data ?? [])],
|
|
7975
|
+
})),
|
|
7832
7976
|
],
|
|
7833
7977
|
};
|
|
7834
7978
|
}
|
|
@@ -7837,7 +7981,7 @@ class PTChartComparisonComponent {
|
|
|
7837
7981
|
const labels = this.chartConfig.data.labels ?? [];
|
|
7838
7982
|
return labels.map((_, index) => {
|
|
7839
7983
|
const valuesAtTime = datasets
|
|
7840
|
-
.map((dataset) => dataset.data[index])
|
|
7984
|
+
.map((dataset) => dataset.data?.[index])
|
|
7841
7985
|
.filter((value) => typeof value === 'number' && Number.isFinite(value))
|
|
7842
7986
|
.sort((left, right) => left - right);
|
|
7843
7987
|
if (!valuesAtTime.length) {
|
|
@@ -7862,6 +8006,11 @@ class PTChartComparisonComponent {
|
|
|
7862
8006
|
...externalOptions,
|
|
7863
8007
|
responsive: true,
|
|
7864
8008
|
maintainAspectRatio: false,
|
|
8009
|
+
interaction: {
|
|
8010
|
+
mode: 'index',
|
|
8011
|
+
intersect: false,
|
|
8012
|
+
...(externalOptions.interaction ?? {}),
|
|
8013
|
+
},
|
|
7865
8014
|
plugins: {
|
|
7866
8015
|
...externalPlugins,
|
|
7867
8016
|
legend: {
|
|
@@ -7870,13 +8019,10 @@ class PTChartComparisonComponent {
|
|
|
7870
8019
|
...(externalPlugins.legend ?? {}),
|
|
7871
8020
|
},
|
|
7872
8021
|
tooltip: {
|
|
8022
|
+
enabled: true,
|
|
7873
8023
|
...PT_CHART_COMPARISON_DEFAULT_TOOLTIP,
|
|
7874
8024
|
...(externalPlugins.tooltip ?? {}),
|
|
7875
8025
|
},
|
|
7876
|
-
datalabels: {
|
|
7877
|
-
display: false,
|
|
7878
|
-
...(externalPlugins.datalabels ?? {}),
|
|
7879
|
-
},
|
|
7880
8026
|
},
|
|
7881
8027
|
scales: {
|
|
7882
8028
|
x: {
|