wuic-framework-lib 1.0.7 → 1.0.10
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/fesm2022/{wuic-framework-lib-chart-list.component-j1eRaGZV.mjs → wuic-framework-lib-chart-list.component-vuzmQW9F.mjs} +56 -4
- package/fesm2022/{wuic-framework-lib-code-editor.component-CNREC7r_.mjs → wuic-framework-lib-code-editor.component-BjbIkm4g.mjs} +4 -4
- package/fesm2022/wuic-framework-lib-core.mjs +1 -1
- package/fesm2022/{wuic-framework-lib-designer.component-Bb4B6eDu.mjs → wuic-framework-lib-designer.component-BM3elB-a.mjs} +49 -33
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-CQTs6hR6.mjs → wuic-framework-lib-first-run-wizard.component-5tcl67dK.mjs} +31 -12
- package/fesm2022/{wuic-framework-lib-framework-docs.component-CzyQHVAV.mjs → wuic-framework-lib-framework-docs.component-BGcJ7k1X.mjs} +484 -13
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-ms-x0Yob.mjs → wuic-framework-lib-pivot-builder.component-ChNyMAfi.mjs} +29 -16
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-mXhyuLAE.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-DFLR_EmK.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-designer.component-BjUmOBU3.mjs → wuic-framework-lib-report-designer.component-B_SC7VkW.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-viewer.component-BOenTSd2.mjs → wuic-framework-lib-report-viewer.component-BTK-p8xF.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scheduler-list.component-DHcLQ_X7.mjs → wuic-framework-lib-scheduler-list.component-CIoGVf4O.mjs} +12 -4
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-AFm6hAX4.mjs → wuic-framework-lib-spreadsheet-list-sf.component-DQ5OxO4j.mjs} +10 -4
- package/fesm2022/{wuic-framework-lib-workflow-designer.component-Bn6ocOVw.mjs → wuic-framework-lib-workflow-designer.component-BHLT4MER.mjs} +29 -3
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-KFbUlRIT.mjs → wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs} +2130 -491
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +1 -1
- package/types/wuic-framework-lib-core.d.ts +1 -1
- package/types/wuic-framework-lib.d.ts +458 -15
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { HostBinding, Input, Component, EventEmitter, inject, ChangeDetectorRef, ViewChild, Output } from '@angular/core';
|
|
3
|
-
import * as i1 from '@angular/forms';
|
|
3
|
+
import * as i1$1 from '@angular/forms';
|
|
4
4
|
import { FormsModule } from '@angular/forms';
|
|
5
|
-
import * as
|
|
5
|
+
import * as i1 from '@angular/common';
|
|
6
6
|
import { CommonModule, NgClass } from '@angular/common';
|
|
7
|
-
import * as i2$
|
|
7
|
+
import * as i2$1 from '@ngx-translate/core';
|
|
8
8
|
import { TranslateModule } from '@ngx-translate/core';
|
|
9
9
|
import { firstValueFrom, BehaviorSubject } from 'rxjs';
|
|
10
|
-
import * as i2
|
|
10
|
+
import * as i2 from 'primeng/autocomplete';
|
|
11
11
|
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
12
12
|
import * as i4 from 'primeng/button';
|
|
13
13
|
import { ButtonModule } from 'primeng/button';
|
|
@@ -18,14 +18,14 @@ import { SelectModule } from 'primeng/select';
|
|
|
18
18
|
import * as i9 from 'primeng/splitter';
|
|
19
19
|
import { SplitterModule } from 'primeng/splitter';
|
|
20
20
|
import { AccordionModule } from 'primeng/accordion';
|
|
21
|
-
import * as i2$
|
|
21
|
+
import * as i2$2 from 'primeng/dialog';
|
|
22
22
|
import { DialogModule } from 'primeng/dialog';
|
|
23
23
|
import * as i8 from 'primeng/table';
|
|
24
24
|
import { TableModule } from 'primeng/table';
|
|
25
25
|
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'primeng/tabs';
|
|
26
|
-
import * as i1$
|
|
26
|
+
import * as i1$3 from '@materia-ui/ngx-monaco-editor';
|
|
27
27
|
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
|
|
28
|
-
import { U as UserInfoService, T as TranslationManagerService, W as WtoolboxService, M as MetadataProviderService, f as DataProviderService,
|
|
28
|
+
import { U as UserInfoService, T as TranslationManagerService, W as WtoolboxService, M as MetadataProviderService, f as DataProviderService, m as MetaInfo, e as MetadatiColonna, o as FilterInfo, G as GlobalHandler, k as WuicClientException, l as WuicErrorCodes, b as DataSourceComponent, F as FilterBarComponent } from './wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs';
|
|
29
29
|
import * as i3 from 'primeng/tooltip';
|
|
30
30
|
import { TooltipModule } from 'primeng/tooltip';
|
|
31
31
|
import { ClassicPreset, NodeEditor } from 'rete';
|
|
@@ -33,8 +33,8 @@ import { AreaExtensions, AreaPlugin } from 'rete-area-plugin';
|
|
|
33
33
|
import { ConnectionPlugin, Presets } from 'rete-connection-plugin';
|
|
34
34
|
import { RefDirective, AngularPlugin, Presets as Presets$1 } from 'rete-angular-plugin/21';
|
|
35
35
|
import { HttpClient } from '@angular/common/http';
|
|
36
|
-
import * as i1$
|
|
37
|
-
import * as
|
|
36
|
+
import * as i1$2 from '@angular/router';
|
|
37
|
+
import * as i3$1 from 'primeng/api';
|
|
38
38
|
|
|
39
39
|
class ViewBuilderNodeComponent {
|
|
40
40
|
cdr;
|
|
@@ -239,7 +239,7 @@ class ViewBuilderNodeComponent {
|
|
|
239
239
|
</div>
|
|
240
240
|
</div>
|
|
241
241
|
</div>
|
|
242
|
-
`, isInline: true, styles: [":host{display:block}.vb-node{background:var(--surface-card, #fff);border:2px solid var(--surface-border, #dee2e6);border-radius:8px;min-width:240px;max-width:320px;font-size:.85rem;box-shadow:0 2px 8px #00000014;overflow:hidden}.vb-node--selected{border-color:var(--primary-color, #3B82F6)}.vb-node__header{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--primary-color, #3B82F6);color:#fff;font-weight:600}.vb-node__alias{opacity:.7;font-size:.75rem}.vb-node__col-count{margin-left:auto;opacity:.8;font-size:.75rem}.vb-node__remove-btn{font-size:.7rem;opacity:.6;padding:2px 4px;cursor:pointer}.vb-node__remove-btn:hover{opacity:1}.vb-node__toggle-all{margin:0 4px 0 2px;cursor:pointer;vertical-align:middle}.vb-node__columns{max-height:260px;overflow-y:auto;padding:4px 0}.vb-node__col-row{display:flex;align-items:center;padding:2px 10px;position:relative;-webkit-user-select:none;user-select:none}.vb-node__col-row:hover{background:var(--surface-hover, #f4f4f4)}.vb-node__col-row--virtual{opacity:.45}.vb-node__col-row--has-formula{background:#eff6ff;border-left:2px solid var(--primary-color, #3B82F6)}.vb-node__col-row--virtual .vb-node__col-label{cursor:default}.vb-node__col-label{display:flex;align-items:center;gap:4px;flex:1;cursor:pointer;font-size:.8rem}.vb-node__col-fk{font-style:italic}.vb-node__col-formula{color:var(--primary-color, #3B82F6);font-weight:600}.vb-node__formula-icon{font-size:.65rem;color:#f59e0b;margin-right:1px}.vb-node__fk-icon{font-size:.7rem;color:var(--primary-color, #3B82F6)}.vb-node__socket-out,.vb-node__socket-in{width:16px;height:16px;border-radius:50%;border:2px solid var(--primary-color, #3B82F6);background:#fff;position:absolute;top:50%;transform:translateY(-50%);cursor:crosshair;z-index:10}.vb-node__socket-out{right:-8px}.vb-node__socket-out:hover{background:var(--primary-color, #3B82F6);border-color:#1d4ed8}.vb-node__socket-in{left:-8px}.vb-node__socket-in:hover{background:#4ade80;border-color:#16a34a}.vb-node__socket-out ::ng-deep>*,.vb-node__socket-in ::ng-deep>*{opacity:0;width:16px!important;height:16px!important;margin:0!important;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);cursor:crosshair}.vb-node__collapsed-sockets{position:relative;height:0;overflow:visible}.vb-node__socket-collapsed{position:absolute!important;top:-16px!important}.vb-node__socket-collapsed.vb-node__socket-out{right:-6px!important;pointer-events:none!important;cursor:default!important}.vb-node__socket-collapsed.vb-node__socket-in{left:-6px!important;pointer-events:none!important;cursor:default!important}.vb-node__socket-collapsed ::ng-deep>*{pointer-events:none!important}.vb-node__socket--connected ::ng-deep>*{opacity:1;background:#4ade80!important;border:2px solid #16a34a!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type:
|
|
242
|
+
`, isInline: true, styles: [":host{display:block}.vb-node{background:var(--surface-card, #fff);border:2px solid var(--surface-border, #dee2e6);border-radius:8px;min-width:240px;max-width:320px;font-size:.85rem;box-shadow:0 2px 8px #00000014;overflow:hidden}.vb-node--selected{border-color:var(--primary-color, #3B82F6)}.vb-node__header{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--primary-color, #3B82F6);color:#fff;font-weight:600}.vb-node__alias{opacity:.7;font-size:.75rem}.vb-node__col-count{margin-left:auto;opacity:.8;font-size:.75rem}.vb-node__remove-btn{font-size:.7rem;opacity:.6;padding:2px 4px;cursor:pointer}.vb-node__remove-btn:hover{opacity:1}.vb-node__toggle-all{margin:0 4px 0 2px;cursor:pointer;vertical-align:middle}.vb-node__columns{max-height:260px;overflow-y:auto;padding:4px 0}.vb-node__col-row{display:flex;align-items:center;padding:2px 10px;position:relative;-webkit-user-select:none;user-select:none}.vb-node__col-row:hover{background:var(--surface-hover, #f4f4f4)}.vb-node__col-row--virtual{opacity:.45}.vb-node__col-row--has-formula{background:#eff6ff;border-left:2px solid var(--primary-color, #3B82F6)}.vb-node__col-row--virtual .vb-node__col-label{cursor:default}.vb-node__col-label{display:flex;align-items:center;gap:4px;flex:1;cursor:pointer;font-size:.8rem}.vb-node__col-fk{font-style:italic}.vb-node__col-formula{color:var(--primary-color, #3B82F6);font-weight:600}.vb-node__formula-icon{font-size:.65rem;color:#f59e0b;margin-right:1px}.vb-node__fk-icon{font-size:.7rem;color:var(--primary-color, #3B82F6)}.vb-node__socket-out,.vb-node__socket-in{width:16px;height:16px;border-radius:50%;border:2px solid var(--primary-color, #3B82F6);background:#fff;position:absolute;top:50%;transform:translateY(-50%);cursor:crosshair;z-index:10}.vb-node__socket-out{right:-8px}.vb-node__socket-out:hover{background:var(--primary-color, #3B82F6);border-color:#1d4ed8}.vb-node__socket-in{left:-8px}.vb-node__socket-in:hover{background:#4ade80;border-color:#16a34a}.vb-node__socket-out ::ng-deep>*,.vb-node__socket-in ::ng-deep>*{opacity:0;width:16px!important;height:16px!important;margin:0!important;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);cursor:crosshair}.vb-node__collapsed-sockets{position:relative;height:0;overflow:visible}.vb-node__socket-collapsed{position:absolute!important;top:-16px!important}.vb-node__socket-collapsed.vb-node__socket-out{right:-6px!important;pointer-events:none!important;cursor:default!important}.vb-node__socket-collapsed.vb-node__socket-in{left:-6px!important;pointer-events:none!important;cursor:default!important}.vb-node__socket-collapsed ::ng-deep>*{pointer-events:none!important}.vb-node__socket--connected ::ng-deep>*{opacity:1;background:#4ade80!important;border:2px solid #16a34a!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: RefDirective, selector: "[refComponent]", inputs: ["data", "emit"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.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"] }] });
|
|
243
243
|
}
|
|
244
244
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ViewBuilderNodeComponent, decorators: [{
|
|
245
245
|
type: Component,
|
|
@@ -1672,7 +1672,7 @@ class ViewBuilderComponent {
|
|
|
1672
1672
|
}
|
|
1673
1673
|
}
|
|
1674
1674
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ViewBuilderComponent, deps: [{ token: i0.Injector }, { token: DataProviderService }, { token: MetadataProviderService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1675
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ViewBuilderComponent, isStandalone: true, selector: "wuic-view-builder", inputs: { autoReflowLayout: "autoReflowLayout" }, outputs: { viewDefinitionChange: "viewDefinitionChange" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["vbCanvas"], descendants: true }], ngImport: i0, template: "<div class=\"view-builder\">\n <!-- Palette: route search + drag -->\n <div class=\"view-builder__palette\">\n <h3>{{ 'view_builder.tables_heading' | translate }}</h3>\n <div class=\"view-builder__palette-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedRouteOption\"\n [suggestions]=\"filteredRouteOptions\"\n (completeMethod)=\"filterRouteOptions($event)\"\n (onSelect)=\"selectedRouteOption = $event.value\"\n [dropdown]=\"true\"\n [forceSelection]=\"true\"\n optionLabel=\"label\"\n [placeholder]=\"t('view_builder.search_route_placeholder','Search route...')\"\n styleClass=\"w-full\">\n </p-autoComplete>\n <p-button icon=\"pi pi-plus\" severity=\"success\" size=\"small\"\n [disabled]=\"!selectedRouteOption\"\n (onClick)=\"addSelectedRoute()\"\n [pTooltip]=\"t('view_builder.add_to_canvas_tooltip','Add to canvas')\">\n </p-button>\n </div>\n @if (hasCanvasNodes) {\n <div class=\"view-builder__palette-filter\">\n <label>\n <input type=\"checkbox\" [(ngModel)]=\"showRelatedOnly\" />\n {{ 'view_builder.show_related_only' | translate }}\n </label>\n </div>\n }\n <div class=\"view-builder__palette-list\">\n @for (opt of displayedRouteOptions; track opt.value) {\n <div class=\"view-builder__palette-item\"\n [class.view-builder__palette-item--on-canvas]=\"isRouteOnCanvas(opt.value)\"\n draggable=\"true\"\n (dragstart)=\"onPaletteDragStart($event, opt)\"\n [title]=\"isRouteOnCanvas(opt.value) ? 'Gia presente sul canvas \u2014 droppabile di nuovo con nuovo alias' : opt.label\">\n <i class=\"pi pi-table\"></i>\n <span>{{ opt.label }}</span>\n @if (isRouteOnCanvas(opt.value)) {\n <i class=\"pi pi-check view-builder__palette-item-check\"></i>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Canvas -->\n <div class=\"view-builder__canvas-area\">\n <div class=\"view-builder__canvas-toolbar\">\n <p-button icon=\"pi pi-search-plus\" size=\"small\" severity=\"secondary\" [text]=\"true\"\n (onClick)=\"zoomToFit()\" [pTooltip]=\"t('view_builder.zoom_to_fit','Zoom to fit')\">\n </p-button>\n </div>\n <div #vbCanvas class=\"view-builder__canvas\"\n (dragover)=\"onCanvasDragOver($event)\"\n (drop)=\"onCanvasDrop($event)\"\n (click)=\"hideContextMenu()\">\n </div>\n </div>\n\n <!-- Connection context menu (join type) -->\n @if (contextMenuVisible) {\n <div class=\"vb-context-menu\"\n [style.left.px]=\"contextMenuX\"\n [style.top.px]=\"contextMenuY\">\n @for (opt of joinTypeOptions; track opt.value) {\n <div class=\"vb-context-menu__item\"\n [class.vb-context-menu__item--active]=\"getJoinType(contextMenuConnectionId!) === opt.value\"\n (click)=\"setJoinType(opt.value)\">\n {{ opt.label }}\n </div>\n }\n <div class=\"vb-context-menu__separator\"></div>\n <div class=\"vb-context-menu__item vb-context-menu__item--danger\"\n (click)=\"removeConnection()\">\n {{ 'view_builder.remove_join' | translate }}\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0;overflow:hidden}.view-builder{display:grid;grid-template-columns:220px 1fr;height:100%;min-height:0;gap:0}.view-builder__palette{border-right:1px solid var(--surface-border, #dee2e6);display:flex;flex-direction:column;overflow:hidden}.view-builder__palette h3{margin:0;padding:8px 12px;font-size:.85rem;background:var(--surface-ground, #f8f9fa);border-bottom:1px solid var(--surface-border, #dee2e6)}.view-builder__palette-search{display:flex;gap:4px;padding:6px 8px;border-bottom:1px solid var(--surface-border, #dee2e6)}.view-builder__palette-list{flex:1;overflow-y:auto;padding:4px 0;min-height:0}.view-builder__palette-item{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none}.view-builder__palette-item:hover{background:var(--surface-hover, #f4f4f4)}.view-builder__palette-item:active{cursor:grabbing}.view-builder__palette-item--on-canvas{background:color-mix(in srgb,var(--p-primary-color, #3b82f6) 10%,transparent);border-left:3px solid var(--p-primary-color, #3b82f6);padding-left:9px;font-weight:500}.view-builder__palette-item--on-canvas:hover{background:color-mix(in srgb,var(--p-primary-color, #3b82f6) 18%,transparent)}.view-builder__palette-item-check{margin-left:auto;font-size:.7rem;color:var(--p-primary-color, #3b82f6)}.view-builder__canvas-area{display:flex;flex-direction:column;overflow:hidden;position:relative}.view-builder__canvas-toolbar{display:flex;justify-content:flex-end;padding:4px 8px;border-bottom:1px solid var(--surface-border, #dee2e6);background:var(--surface-ground, #f8f9fa)}.view-builder__canvas{flex:1;position:relative;overflow:hidden;background:radial-gradient(circle,var(--surface-border, #e0e0e0) 1px,transparent 1px);background-size:20px 20px}.view-builder__palette-filter{border-bottom:solid 1px}.vb-context-menu{position:fixed;z-index:10000;background:var(--surface-card, #fff);border:1px solid var(--surface-border, #dee2e6);border-radius:6px;box-shadow:0 4px 16px #00000026;min-width:160px;padding:4px 0;font-size:.85rem}.vb-context-menu__item{padding:6px 14px;cursor:pointer;display:flex;align-items:center;gap:6px}.vb-context-menu__item:hover{background:var(--surface-hover, #f4f4f4)}.vb-context-menu__item--active{font-weight:600;color:var(--primary-color, #3B82F6)}.vb-context-menu__item--active:before{content:\"\\2713\";margin-right:2px}.vb-context-menu__item--danger{color:#dc3545}.vb-context-menu__item--danger:hover{background:#fee2e5}.vb-context-menu__separator{height:1px;background:var(--surface-border, #dee2e6);margin:4px 0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2
|
|
1675
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: ViewBuilderComponent, isStandalone: true, selector: "wuic-view-builder", inputs: { autoReflowLayout: "autoReflowLayout" }, outputs: { viewDefinitionChange: "viewDefinitionChange" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["vbCanvas"], descendants: true }], ngImport: i0, template: "<div class=\"view-builder\">\n <!-- Palette: route search + drag -->\n <div class=\"view-builder__palette\">\n <h3>{{ 'view_builder.tables_heading' | translate }}</h3>\n <div class=\"view-builder__palette-search\">\n <p-autoComplete\n [(ngModel)]=\"selectedRouteOption\"\n [suggestions]=\"filteredRouteOptions\"\n (completeMethod)=\"filterRouteOptions($event)\"\n (onSelect)=\"selectedRouteOption = $event.value\"\n [dropdown]=\"true\"\n [forceSelection]=\"true\"\n optionLabel=\"label\"\n [placeholder]=\"t('view_builder.search_route_placeholder','Search route...')\"\n styleClass=\"w-full\">\n </p-autoComplete>\n <p-button icon=\"pi pi-plus\" severity=\"success\" size=\"small\"\n [disabled]=\"!selectedRouteOption\"\n (onClick)=\"addSelectedRoute()\"\n [pTooltip]=\"t('view_builder.add_to_canvas_tooltip','Add to canvas')\">\n </p-button>\n </div>\n @if (hasCanvasNodes) {\n <div class=\"view-builder__palette-filter\">\n <label>\n <input type=\"checkbox\" [(ngModel)]=\"showRelatedOnly\" />\n {{ 'view_builder.show_related_only' | translate }}\n </label>\n </div>\n }\n <div class=\"view-builder__palette-list\">\n @for (opt of displayedRouteOptions; track opt.value) {\n <div class=\"view-builder__palette-item\"\n [class.view-builder__palette-item--on-canvas]=\"isRouteOnCanvas(opt.value)\"\n draggable=\"true\"\n (dragstart)=\"onPaletteDragStart($event, opt)\"\n [title]=\"isRouteOnCanvas(opt.value) ? 'Gia presente sul canvas \u2014 droppabile di nuovo con nuovo alias' : opt.label\">\n <i class=\"pi pi-table\"></i>\n <span>{{ opt.label }}</span>\n @if (isRouteOnCanvas(opt.value)) {\n <i class=\"pi pi-check view-builder__palette-item-check\"></i>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Canvas -->\n <div class=\"view-builder__canvas-area\">\n <div class=\"view-builder__canvas-toolbar\">\n <p-button icon=\"pi pi-search-plus\" size=\"small\" severity=\"secondary\" [text]=\"true\"\n (onClick)=\"zoomToFit()\" [pTooltip]=\"t('view_builder.zoom_to_fit','Zoom to fit')\">\n </p-button>\n </div>\n <div #vbCanvas class=\"view-builder__canvas\"\n (dragover)=\"onCanvasDragOver($event)\"\n (drop)=\"onCanvasDrop($event)\"\n (click)=\"hideContextMenu()\">\n </div>\n </div>\n\n <!-- Connection context menu (join type) -->\n @if (contextMenuVisible) {\n <div class=\"vb-context-menu\"\n [style.left.px]=\"contextMenuX\"\n [style.top.px]=\"contextMenuY\">\n @for (opt of joinTypeOptions; track opt.value) {\n <div class=\"vb-context-menu__item\"\n [class.vb-context-menu__item--active]=\"getJoinType(contextMenuConnectionId!) === opt.value\"\n (click)=\"setJoinType(opt.value)\">\n {{ opt.label }}\n </div>\n }\n <div class=\"vb-context-menu__separator\"></div>\n <div class=\"vb-context-menu__item vb-context-menu__item--danger\"\n (click)=\"removeConnection()\">\n {{ 'view_builder.remove_join' | translate }}\n </div>\n </div>\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0;overflow:hidden}.view-builder{display:grid;grid-template-columns:220px 1fr;height:100%;min-height:0;gap:0}.view-builder__palette{border-right:1px solid var(--surface-border, #dee2e6);display:flex;flex-direction:column;overflow:hidden}.view-builder__palette h3{margin:0;padding:8px 12px;font-size:.85rem;background:var(--surface-ground, #f8f9fa);border-bottom:1px solid var(--surface-border, #dee2e6)}.view-builder__palette-search{display:flex;gap:4px;padding:6px 8px;border-bottom:1px solid var(--surface-border, #dee2e6)}.view-builder__palette-list{flex:1;overflow-y:auto;padding:4px 0;min-height:0}.view-builder__palette-item{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:.8rem;cursor:grab;-webkit-user-select:none;user-select:none}.view-builder__palette-item:hover{background:var(--surface-hover, #f4f4f4)}.view-builder__palette-item:active{cursor:grabbing}.view-builder__palette-item--on-canvas{background:color-mix(in srgb,var(--p-primary-color, #3b82f6) 10%,transparent);border-left:3px solid var(--p-primary-color, #3b82f6);padding-left:9px;font-weight:500}.view-builder__palette-item--on-canvas:hover{background:color-mix(in srgb,var(--p-primary-color, #3b82f6) 18%,transparent)}.view-builder__palette-item-check{margin-left:auto;font-size:.7rem;color:var(--p-primary-color, #3b82f6)}.view-builder__canvas-area{display:flex;flex-direction:column;overflow:hidden;position:relative}.view-builder__canvas-toolbar{display:flex;justify-content:flex-end;padding:4px 8px;border-bottom:1px solid var(--surface-border, #dee2e6);background:var(--surface-ground, #f8f9fa)}.view-builder__canvas{flex:1;position:relative;overflow:hidden;background:radial-gradient(circle,var(--surface-border, #e0e0e0) 1px,transparent 1px);background-size:20px 20px}.view-builder__palette-filter{border-bottom:solid 1px}.vb-context-menu{position:fixed;z-index:10000;background:var(--surface-card, #fff);border:1px solid var(--surface-border, #dee2e6);border-radius:6px;box-shadow:0 4px 16px #00000026;min-width:160px;padding:4px 0;font-size:.85rem}.vb-context-menu__item{padding:6px 14px;cursor:pointer;display:flex;align-items:center;gap:6px}.vb-context-menu__item:hover{background:var(--surface-hover, #f4f4f4)}.vb-context-menu__item--active{font-weight:600;color:var(--primary-color, #3B82F6)}.vb-context-menu__item--active:before{content:\"\\2713\";margin-right:2px}.vb-context-menu__item--danger{color:#dc3545}.vb-context-menu__item--danger:hover{background:#fee2e5}.vb-context-menu__separator{height:1px;background:var(--surface-border, #dee2e6);margin:4px 0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.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: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$1.TranslatePipe, name: "translate" }] });
|
|
1676
1676
|
}
|
|
1677
1677
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ViewBuilderComponent, decorators: [{
|
|
1678
1678
|
type: Component,
|
|
@@ -3074,7 +3074,20 @@ class PivotBuilderComponent {
|
|
|
3074
3074
|
try {
|
|
3075
3075
|
return JSON.parse(raw);
|
|
3076
3076
|
}
|
|
3077
|
-
catch {
|
|
3077
|
+
catch (err) {
|
|
3078
|
+
// skills/typed-localized-exceptions: distingui "config corrotto" da
|
|
3079
|
+
// "config legittimamente vuoto". Senza questo emit l'utente vedeva
|
|
3080
|
+
// solo "Nessuna definizione vista trovata" (toast generico) anche
|
|
3081
|
+
// quando il pivot_config_json salvato era JSON malformato.
|
|
3082
|
+
try {
|
|
3083
|
+
GlobalHandler.emitClientException(new WuicClientException(WuicErrorCodes.MetadataPropsBagMalformed, {
|
|
3084
|
+
route: this.selectedRouteName || 'pivot',
|
|
3085
|
+
field: 'pivot_config_json',
|
|
3086
|
+
parserMessage: (err instanceof Error ? err.message : String(err)).slice(0, 500),
|
|
3087
|
+
phase: 'pivot.parseConfig',
|
|
3088
|
+
}, { surface: 'component', targetName: 'PivotBuilderComponent.parseConfig', cause: err }));
|
|
3089
|
+
}
|
|
3090
|
+
catch { /* noop */ }
|
|
3078
3091
|
return {};
|
|
3079
3092
|
}
|
|
3080
3093
|
}
|
|
@@ -4032,13 +4045,13 @@ class PivotBuilderComponent {
|
|
|
4032
4045
|
ngOnDestroy() {
|
|
4033
4046
|
this.pivotDatasourceSub?.unsubscribe();
|
|
4034
4047
|
}
|
|
4035
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PivotBuilderComponent, deps: [{ token: DataProviderService }, { token: MetadataProviderService }, { token: TranslationManagerService }, { token: i1$
|
|
4036
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PivotBuilderComponent, isStandalone: true, selector: "wuic-pivot-builder", viewQueries: [{ propertyName: "nestedSource", first: true, predicate: ["nestedSource"], descendants: true }, { propertyName: "viewBuilderRef", first: true, predicate: ["viewBuilderRef"], descendants: true }], ngImport: i0, template: "<div class=\"pivot-builder\">\n <!-- ===== Global header (just title) ===== -->\n <div class=\"pivot-toolbar\">\n <h2>{{ 'pivot_builder.title' | translate }}</h2>\n </div>\n\n <wuic-data-source #nestedSource class=\"pivot-hidden-datasource\" [route]=\"pivotRoute$\" [autoload]=\"true\">\n </wuic-data-source>\n\n <!-- ===== Tabs ===== -->\n <p-tabs [(value)]=\"activeTab\">\n <p-tablist>\n <p-tab [value]=\"0\">\n <i class=\"pi pi-sitemap mr-2\"></i>\n <span>{{ 'pivot_builder.tab.view_builder' | translate }}</span>\n </p-tab>\n <p-tab [value]=\"1\">\n <i class=\"pi pi-th-large mr-2\"></i>\n <span>{{ 'pivot_builder.tab.pivot_config' | translate }}</span>\n </p-tab>\n </p-tablist>\n <p-tabpanels>\n\n <!-- ==================== Tab 0: View Builder ==================== -->\n <p-tabpanel [value]=\"0\">\n <!-- View Builder toolbar -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar: tutti i button uniformati al tema selezionato\n (primary color della palette attiva \u2014 es. Aura Blu/Teal/...).\n Rimosse severity override per evitare mix `contrast/success/\n secondary` che rompeva la coerenza visiva.\n \"Create View\", \"Save Definition\", \"Open\" + \"Delete\" sono\n raggruppati nello split-button \"Definition\". -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.vb.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingViewDefSql\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"generateSqlFromViewDefinition()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.vb.execute_query' | translate\" icon=\"pi pi-bolt\" [loading]=\"executingViewDefQuery\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"executeViewDefinitionQuery()\">\n </p-button>\n <p-splitButton #definitionSplitBtn\n [label]=\"'pivot_builder.vb.definition' | translate\"\n icon=\"pi pi-database\"\n [model]=\"definitionMenuItems\"\n styleClass=\"pivot-actions-definition-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.definition' | translate) }\"\n (onClick)=\"openDefinitionMenu(definitionSplitBtn, $event)\">\n </p-splitButton>\n </div>\n <!-- Chip della view creata: se c'e' una `createdViewRoute` rendiamo\n un anchor cliccabile verso `#/<route>/list` (apertura in nuovo\n tab, pattern standard del framework \u2014 vedi list-grid.component\n `mc_logic_navigate_new_window`). Altrimenti ricadiamo su uno\n span semplice (es. view creata senza scaffold, o payload\n legacy senza route). -->\n @if (createdViewName) {\n @if (createdViewRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + createdViewRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition') + ' \u2014 ' + createdViewRoute + '/list'\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\" [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition')\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n </span>\n }\n }\n <!-- Settings split-button (pattern \"Azioni designer\"): ogni voce\n del menu e' un toggle con icona check/stop che riflette lo\n stato corrente (auto-generate, manual SQL, all-filterable,\n auto-reflow). Click sulla voce inverte il flag.\n Allineato a destra della toolbar tramite\n `.pivot-actions-settings` (margin-left: auto). -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #settingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"settingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openSettingsMenu(settingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <!-- Filter bar for View Builder (multi-table or single-table) \u2014 hidden in manual SQL mode -->\n @if (!manualSqlMode && (viewBuilderFilterMetas.length || viewBuilderFilterRoute)) {\n <div class=\"pivot-filter-full\">\n <wuic-filter-bar\n [multiDatasourceMetas]=\"viewBuilderFilterMetas\"\n [hardcodedDatasource]=\"viewBuilderFilterMetas.length ? null! : nestedSource\"\n [skipUrlSync]=\"true\"\n (filterApplied)=\"onViewBuilderFilterApplied()\"\n (onFilterApplied)=\"onViewBuilderMultiFilterApplied($event)\">\n </wuic-filter-bar>\n </div>\n }\n\n <div style=\"flex: 1; min-height: 0; width: 100%;\" [class.pivot-disabled-overlay]=\"manualSqlMode\">\n <wuic-view-builder #viewBuilderRef [autoReflowLayout]=\"autoReflowLayout\"\n (viewDefinitionChange)=\"onViewDefinitionChange($event)\">\n </wuic-view-builder>\n </div>\n </p-tabpanel>\n\n <!-- ==================== Tab 1: Pivot Configuration ==================== -->\n <p-tabpanel [value]=\"1\">\n <!-- Pivot toolbar: route selector + actions -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar uniformata al tema selezionato (stessa regola della\n tab View Builder: nessuna severity override).\n \"Create View\", \"Create Materialized Table\",\n \"Save Configuration\", \"Open Pivot\" sono raggruppati nello\n split-button \"Actions\" (stesso pattern del Definition\n split-button del tab View Builder). -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingSql\"\n [disabled]=\"!canExecutePivot\" (onClick)=\"generatePivotSql()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.execute_query' | translate\" icon=\"pi pi-bolt\"\n [loading]=\"executingQuery\" [disabled]=\"!canExecutePivot\" (onClick)=\"executePivotSql()\">\n </p-button>\n <p-splitButton #pivotConfigSplitBtn\n [label]=\"'pivot_builder.actions' | translate\"\n [icon]=\"(creatingView || creatingMaterializedTable || savingConfiguration || reopeningPivotList || deletingPivot)\n ? 'pi pi-spin pi-spinner'\n : 'pi pi-ellipsis-v'\"\n [model]=\"pivotConfigMenuItems\"\n styleClass=\"pivot-actions-config-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.actions' | translate) }\"\n (onClick)=\"openPivotConfigMenu(pivotConfigSplitBtn, $event)\">\n </p-splitButton>\n <!-- Chip cliccabile della view/materialized-table scaffoldata\n dal pivot (pattern identico al chip createdViewName del\n tab View Builder). Apre `#/<route>/list` in nuovo tab.\n Tooltip include il tipo (view o table) serializzato. -->\n @if (pivotCreatedName) {\n @if (pivotCreatedRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + pivotCreatedRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"(pivotCreatedKind === 'table'\n ? t('pivot_builder.pivot_table_created_tooltip','Materialized table created from this pivot')\n : t('pivot_builder.pivot_view_created_tooltip','DB view created from this pivot'))\n + ' \u2014 ' + pivotCreatedRoute + '/list'\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n </span>\n }\n }\n </div>\n <!-- Settings split-button del tab Pivot Config: stessi 3 toggle\n del View Builder Settings (auto-generate, manual SQL,\n all-filterable) meno il `auto-reflow` che e' specifico del\n canvas. Allineato a destra con `.pivot-actions-settings`. -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #pivotSettingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"pivotSettingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openPivotSettingsMenu(pivotSettingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <table style=\"width: 100%;\">\n <tr>\n <td>\n <p-autoComplete [(ngModel)]=\"selectedRouteOption\" [suggestions]=\"filteredRouteOptions\"\n (completeMethod)=\"filterRouteOptions($event)\" (onSelect)=\"onRouteOptionSelected($event.value)\"\n [dropdown]=\"true\" [forceSelection]=\"true\" optionLabel=\"label\"\n [placeholder]=\"'pivot_builder.select_route_placeholder' | translate\"\n styleClass=\"pivot-route-autocomplete\">\n </p-autoComplete>\n </td>\n <td>\n <label>{{ 'aggregation' | translate }}</label>\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"aggregateFunction\">\n </p-select>\n </td>\n <td>\n <label>{{ 'pivot_builder.top_rows' | translate }}</label>\n <input type=\"number\" min=\"0\" step=\"1\" [(ngModel)]=\"topRows\"\n (ngModelChange)=\"topRows = normalizeTopRows($event)\" />\n </td>\n </tr>\n </table>\n\n <!-- Filter panel -->\n <div class=\"pivot-filter-full\">\n\n @if (selectedRouteName) {\n <wuic-filter-bar [hardcodedDatasource]=\"nestedSource\" [skipUrlSync]=\"true\"\n (filterApplied)=\"onFilterBarApplied()\"></wuic-filter-bar>\n }\n\n </div>\n\n <!-- 4-panel splitter: source cols | rows | columns | values -->\n <div class=\"pivot-buckets-row\">\n <p-splitter [panelSizes]=\"[28, 24, 24, 24]\" [style]=\"{ height: '100%', width: '100%' }\"\n styleClass=\"pivot-buckets-splitter\">\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.route_columns' | translate }}</h3>\n <div class=\"pivot-columns-list\" [ngClass]=\"{ 'is-loading': loadingRouteColumns }\">\n @for (col of sourceColumns; track col.alias) {\n <div class=\"pivot-column-item\" draggable=\"true\" (dragstart)=\"onDragStart($event, col)\">\n <span>{{ col.label }}</span>\n <div class=\"pivot-column-actions\">\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToRows(col)\">{{ 'row' | translate }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToColumns(col)\">{{ 'column' | translate\n }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToValues(col)\">{{ 'value' | translate\n }}</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.rows_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToRows($event)\">\n @if (!rowColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_rows_here' | translate }}</div>\n }\n @for (col of rowColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setRowCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setRowDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromRows(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.columns_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToColumns($event)\">\n @if (!columnColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_columns_here' | translate }}</div>\n }\n @for (col of columnColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setColumnCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setColumnDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromColumns(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.values' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToValues($event)\">\n @if (!valueColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_values_here' | translate }}</div>\n }\n @for (col of valueColumns; track col.id) {\n <div class=\"pivot-chip\">\n <input class=\"pivot-value-caption\" type=\"text\" [ngModel]=\"col.caption\"\n (ngModelChange)=\"setValueCaption(col.id, $event)\" [title]=\"col.label\"\n [placeholder]=\"'pivot_builder.metric_caption' | translate\" />\n <div class=\"pivot-chip-actions\">\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"getValueAggregate(col.id)\" (ngModelChange)=\"setValueAggregate(col.id, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n <button type=\"button\" (click)=\"removeFromValues(col.id)\">x</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </p-splitter>\n </div>\n </p-tabpanel>\n </p-tabpanels>\n </p-tabs>\n\n <!-- ===== Output row (below tabs, always visible) ===== -->\n <div class=\"pivot-output-row\">\n @if (!showQueryResults) {\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n } @else {\n <p-splitter [panelSizes]=\"[50, 50]\" [style]=\"{ height: '100%', width: '100%' }\" styleClass=\"pivot-result-splitter\">\n <ng-template #panel>\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n </ng-template>\n <ng-template #panel>\n <div class=\"pivot-result-panel\">\n <h3>{{ 'pivot_builder.query_results' | translate }}</h3>\n <p-table [value]=\"queryResultRows\" [scrollable]=\"true\" scrollHeight=\"flex\" styleClass=\"pivot-result-table\">\n <ng-template pTemplate=\"header\">\n <tr>\n @for (c of queryResultColumns; track c) {\n <th>{{ c }}</th>\n }\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n @for (c of queryResultColumns; track c) {\n <td>{{ formatQueryCellValue(row?.[c], c) }}</td>\n }\n </tr>\n </ng-template>\n </p-table>\n </div>\n </ng-template>\n </p-splitter>\n }\n </div>\n</div>\n\n<p-dialog [header]=\"viewBuilderOpenMode ? t('pivot_builder.vb.open_view_definition','Open View Definition') : ('pivot_builder.reopen_pivot' | translate)\" [(visible)]=\"reopenPivotDialogVisible\" [modal]=\"true\"\n [closable]=\"true\" [draggable]=\"false\" [resizable]=\"false\" [appendTo]=\"'body'\" [style]=\"{ width: '34rem' }\"\n (onHide)=\"cancelReopenPivotDialog()\">\n <div class=\"route-popup-form\">\n <label for=\"pivot-reopen-select\">{{ viewBuilderOpenMode ? t('pivot_builder.vb.saved_view_definitions','Saved view definitions') : ('pivot_builder.saved_pivots' | translate) }}</label>\n <p-select inputId=\"pivot-reopen-select\" [options]=\"savedPivotOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"reopenDialogSelectedPivotName\" [filter]=\"true\" [showClear]=\"true\" [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelReopenPivotDialog()\">{{ 'cancel' | translate\n }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmReopenPivotDialog()\"\n [disabled]=\"!reopenDialogSelectedPivotName\">{{ 'open' | translate }}</button>\n </div>\n </div>\n</p-dialog>", styles: [":host{display:block;height:100%;min-height:0}.pivot-builder{height:100%;min-height:0;padding:.5rem;box-sizing:border-box;display:grid;grid-template-rows:auto minmax(250px,1fr) clamp(120px,25vh,300px);gap:.5rem;overflow:auto}.pivot-toolbar{display:flex;align-items:center;gap:.6rem}.pivot-toolbar h2{margin:0;font-size:1.55rem;white-space:nowrap}.pivot-route-select{min-width:22rem;max-width:34rem;width:100%}.pivot-actions-row{height:40px;display:flex;align-items:center;gap:.75rem}.pivot-created-view-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;color:#16a34a;font-weight:600;padding:2px 8px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:4px}a.pivot-created-view-link{text-decoration:none;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}a.pivot-created-view-link:hover,a.pivot-created-view-link:focus-visible{background:#dcfce7;border-color:#86efac;outline:none}.pivot-created-view-ext{font-size:.72rem;opacity:.6}a.pivot-created-view-link:hover .pivot-created-view-ext{opacity:1}.pivot-disabled-overlay{opacity:.4;pointer-events:none;filter:grayscale(.5)}.pivot-manual-sql-label{color:#dc3545;font-weight:600}.pivot-auto-generate-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;margin-left:auto}.pivot-actions-settings{margin-left:auto;display:inline-flex;align-items:center}.pivot-settings-menu{display:flex;flex-direction:column;gap:10px;min-width:240px;padding:4px 2px}.pivot-settings-item{display:flex;align-items:center;gap:8px;font-size:.85rem;cursor:pointer;-webkit-user-select:none;user-select:none}.pivot-config-group{display:grid;grid-template-columns:minmax(200px,1fr) minmax(160px,200px);gap:.6rem;align-items:end}.pivot-config-item{display:inline;flex-direction:column;gap:.2rem}.pivot-config-item input[type=number]{width:100%;box-sizing:border-box;height:2.45rem;border:1px solid #d4d8e2;border-radius:6px;padding:.35rem .55rem}.pivot-actions{display:inline-flex;gap:.45rem;flex-wrap:wrap}.pivot-hidden-datasource{display:none}.pivot-filter-full{flex:0 0 auto;max-height:40%;max-width:100%;overflow:auto;position:relative;box-sizing:border-box;display:flex;flex-direction:column}.pivot-buckets-row{flex:1;min-height:120px;overflow:hidden}.pivot-output-row{min-height:0;overflow:hidden}.pivot-panel{height:100%;min-height:0;overflow:hidden;border:1px solid #d4d8e2;border-radius:10px;background:#fff;padding:.5rem;box-sizing:border-box;display:flex;flex-direction:column;gap:.4rem}.pivot-panel h3,.pivot-sql-editor h3,.pivot-result-panel h3{margin:0;font-size:.96rem}.pivot-columns-list{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:.3rem}.pivot-column-item{border:1px solid #d4d8e2;border-radius:8px;padding:.3rem .4rem;background:#f8faff;cursor:grab;display:flex;align-items:center;justify-content:space-between;gap:.3rem}.pivot-column-actions{display:inline-flex;gap:.2rem}.mini-btn{border:1px solid #c8d0e1;background:#fff;border-radius:6px;font-size:.72rem;padding:.15rem .32rem;cursor:pointer}.pivot-dropzone{min-height:0;flex:1 1 auto;overflow:auto;border:1px dashed #9db0d8;border-radius:8px;padding:.4rem;display:flex;flex-direction:column;gap:.3rem;background:#fbfcff}.pivot-empty{color:#7f8797;font-size:.85rem}.pivot-chip{display:flex;align-items:center;justify-content:space-between;gap:.35rem;border:1px solid #cfd7ea;border-radius:8px;padding:.25rem .4rem;background:#fff}.pivot-value-caption{flex:1 1 auto;min-width:0;border:1px solid #cfd7ea;border-radius:6px;padding:.2rem .35rem;font-size:.82rem}.pivot-chip button{border:none;background:transparent;color:#6d7688;cursor:pointer}.pivot-chip-actions{display:inline-flex;align-items:center;gap:.25rem}:host ::ng-deep .pivot-chip-agg-select{min-width:6.2rem}.pivot-sql-editor,.pivot-result-panel{height:100%;min-height:0;border:1px solid #d4d8e2;border-radius:10px;overflow:hidden;background:#fff;display:flex;flex-direction:column;position:relative}.pivot-sql-busy{position:absolute;inset:0;background:#fffc;display:flex;align-items:center;justify-content:center;gap:.5rem;z-index:5;font-size:.9rem;color:var(--primary-color, #3B82F6)}.pivot-sql-editor h3,.pivot-result-panel h3{padding:.5rem .65rem;border-bottom:1px solid #d4d8e2;background:#f5f7fb}.pivot-sql-editor ngx-monaco-editor{display:block;min-height:0;flex:1 1 auto}:host ::ng-deep .pivot-result-table,:host ::ng-deep .pivot-result-table .p-datatable-wrapper{height:100%;overflow:auto}:host ::ng-deep .pivot-result-table td,:host ::ng-deep .pivot-result-table th{white-space:nowrap}:host ::ng-deep .pivot-buckets-splitter,:host ::ng-deep .pivot-result-splitter{height:100%}:host ::ng-deep .pivot-builder>p-tabs{display:flex;flex-direction:column;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels,:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels{flex:1;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels>.p-tabpanel:not([hidden]),:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;min-height:0;overflow:hidden;display:flex!important;flex-direction:column}:host ::ng-deep .pivot-filter-full .p-accordion,:host ::ng-deep .pivot-filter-full .p-accordionpanel,:host ::ng-deep .pivot-filter-full .p-accordioncontent,:host ::ng-deep .pivot-filter-full .p-accordionpanel-content,:host ::ng-deep .pivot-filter-full .p-accordioncontent-content{position:relative;height:auto!important;max-height:none!important;overflow:visible;max-width:100%}:host ::ng-deep .pivot-filter-full p-tablist,:host ::ng-deep .pivot-filter-full .p-tablist{position:sticky;top:0;z-index:2;background:var(--p-content-background, #fff)}:host ::ng-deep .pivot-filter-full p-tabpanels,:host ::ng-deep .pivot-filter-full .p-tabpanels,:host ::ng-deep .pivot-filter-full p-tabpanel,:host ::ng-deep .pivot-filter-full .p-tabpanel{overflow:visible;max-width:100%}.route-popup-form{display:flex;flex-direction:column;gap:.75rem}.route-popup-form label{font-size:.9rem;font-weight:600}.route-popup-actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem}.route-popup-btn{border:1px solid #d4d8e2;background:#fff;color:#22314d;border-radius:8px;padding:.45rem .9rem;cursor:pointer}.route-popup-btn-primary{border-color:#2f74f2;background:#2f74f2;color:#fff}.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;width:100%;display:inline-block}@media(max-width:1200px){.pivot-builder{grid-template-rows:auto minmax(0,1fr) clamp(120px,25vh,300px)}.pivot-route-select{min-width:14rem}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2$1.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SplitButtonModule }, { kind: "component", type: i11.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "motionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i9.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: AccordionModule }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$4.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i8.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: TabList, selector: "p-tablist" }, { kind: "component", type: Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: TabPanels, selector: "p-tabpanels" }, { kind: "component", type: TabPanel, selector: "p-tabpanel", inputs: ["lazy", "value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: MonacoEditorModule }, { kind: "component", type: i1$2.MonacoEditorComponent, selector: "ngx-monaco-editor", inputs: ["options", "uri"], outputs: ["init"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: DataSourceComponent, selector: "wuic-data-source", inputs: ["route", "routeFromRouting", "hardcodedRoute", "autoload", "loading", "changeTracking", "parentRecord", "parentMetaInfo", "parentDatasource", "useComboEndpoint", "comboFormulaLookup", "comboMcId", "comboField", "comboExtraFields", "comboCurrentRecord", "componentRef"] }, { kind: "component", type: FilterBarComponent, selector: "wuic-filter-bar", inputs: ["datasource", "hardcodedDatasource", "multiDatasourceMetas", "skipUrlSync"], outputs: ["filterApplied", "onFilterApplied", "onSortingApplied", "onPageSizeApplied", "onGroupingChanged", "onFilterBarCollapseChanged"] }, { kind: "component", type: ViewBuilderComponent, selector: "wuic-view-builder", inputs: ["autoReflowLayout"], outputs: ["viewDefinitionChange"] }, { kind: "pipe", type: i2$2.TranslatePipe, name: "translate" }] });
|
|
4048
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PivotBuilderComponent, deps: [{ token: DataProviderService }, { token: MetadataProviderService }, { token: TranslationManagerService }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
4049
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: PivotBuilderComponent, isStandalone: true, selector: "wuic-pivot-builder", viewQueries: [{ propertyName: "nestedSource", first: true, predicate: ["nestedSource"], descendants: true }, { propertyName: "viewBuilderRef", first: true, predicate: ["viewBuilderRef"], descendants: true }], ngImport: i0, template: "<div class=\"pivot-builder\">\n <!-- ===== Global header (just title) ===== -->\n <div class=\"pivot-toolbar\">\n <h2>{{ 'pivot_builder.title' | translate }}</h2>\n </div>\n\n <wuic-data-source #nestedSource class=\"pivot-hidden-datasource\" [route]=\"pivotRoute$\" [autoload]=\"true\">\n </wuic-data-source>\n\n <!-- ===== Tabs ===== -->\n <p-tabs [(value)]=\"activeTab\">\n <p-tablist>\n <p-tab [value]=\"0\">\n <i class=\"pi pi-sitemap mr-2\"></i>\n <span>{{ 'pivot_builder.tab.view_builder' | translate }}</span>\n </p-tab>\n <p-tab [value]=\"1\">\n <i class=\"pi pi-th-large mr-2\"></i>\n <span>{{ 'pivot_builder.tab.pivot_config' | translate }}</span>\n </p-tab>\n </p-tablist>\n <p-tabpanels>\n\n <!-- ==================== Tab 0: View Builder ==================== -->\n <p-tabpanel [value]=\"0\">\n <!-- View Builder toolbar -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar: tutti i button uniformati al tema selezionato\n (primary color della palette attiva \u2014 es. Aura Blu/Teal/...).\n Rimosse severity override per evitare mix `contrast/success/\n secondary` che rompeva la coerenza visiva.\n \"Create View\", \"Save Definition\", \"Open\" + \"Delete\" sono\n raggruppati nello split-button \"Definition\". -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.vb.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingViewDefSql\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"generateSqlFromViewDefinition()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.vb.execute_query' | translate\" icon=\"pi pi-bolt\" [loading]=\"executingViewDefQuery\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"executeViewDefinitionQuery()\">\n </p-button>\n <p-splitButton #definitionSplitBtn\n [label]=\"'pivot_builder.vb.definition' | translate\"\n icon=\"pi pi-database\"\n [model]=\"definitionMenuItems\"\n styleClass=\"pivot-actions-definition-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.definition' | translate) }\"\n (onClick)=\"openDefinitionMenu(definitionSplitBtn, $event)\">\n </p-splitButton>\n </div>\n <!-- Chip della view creata: se c'e' una `createdViewRoute` rendiamo\n un anchor cliccabile verso `#/<route>/list` (apertura in nuovo\n tab, pattern standard del framework \u2014 vedi list-grid.component\n `mc_logic_navigate_new_window`). Altrimenti ricadiamo su uno\n span semplice (es. view creata senza scaffold, o payload\n legacy senza route). -->\n @if (createdViewName) {\n @if (createdViewRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + createdViewRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition') + ' \u2014 ' + createdViewRoute + '/list'\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\" [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition')\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n </span>\n }\n }\n <!-- Settings split-button (pattern \"Azioni designer\"): ogni voce\n del menu e' un toggle con icona check/stop che riflette lo\n stato corrente (auto-generate, manual SQL, all-filterable,\n auto-reflow). Click sulla voce inverte il flag.\n Allineato a destra della toolbar tramite\n `.pivot-actions-settings` (margin-left: auto). -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #settingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"settingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openSettingsMenu(settingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <!-- Filter bar for View Builder (multi-table or single-table) \u2014 hidden in manual SQL mode -->\n @if (!manualSqlMode && (viewBuilderFilterMetas.length || viewBuilderFilterRoute)) {\n <div class=\"pivot-filter-full\">\n <wuic-filter-bar\n [multiDatasourceMetas]=\"viewBuilderFilterMetas\"\n [hardcodedDatasource]=\"viewBuilderFilterMetas.length ? null! : nestedSource\"\n [skipUrlSync]=\"true\"\n (filterApplied)=\"onViewBuilderFilterApplied()\"\n (onFilterApplied)=\"onViewBuilderMultiFilterApplied($event)\">\n </wuic-filter-bar>\n </div>\n }\n\n <div style=\"flex: 1; min-height: 0; width: 100%;\" [class.pivot-disabled-overlay]=\"manualSqlMode\">\n <wuic-view-builder #viewBuilderRef [autoReflowLayout]=\"autoReflowLayout\"\n (viewDefinitionChange)=\"onViewDefinitionChange($event)\">\n </wuic-view-builder>\n </div>\n </p-tabpanel>\n\n <!-- ==================== Tab 1: Pivot Configuration ==================== -->\n <p-tabpanel [value]=\"1\">\n <!-- Pivot toolbar: route selector + actions -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar uniformata al tema selezionato (stessa regola della\n tab View Builder: nessuna severity override).\n \"Create View\", \"Create Materialized Table\",\n \"Save Configuration\", \"Open Pivot\" sono raggruppati nello\n split-button \"Actions\" (stesso pattern del Definition\n split-button del tab View Builder). -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingSql\"\n [disabled]=\"!canExecutePivot\" (onClick)=\"generatePivotSql()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.execute_query' | translate\" icon=\"pi pi-bolt\"\n [loading]=\"executingQuery\" [disabled]=\"!canExecutePivot\" (onClick)=\"executePivotSql()\">\n </p-button>\n <p-splitButton #pivotConfigSplitBtn\n [label]=\"'pivot_builder.actions' | translate\"\n [icon]=\"(creatingView || creatingMaterializedTable || savingConfiguration || reopeningPivotList || deletingPivot)\n ? 'pi pi-spin pi-spinner'\n : 'pi pi-ellipsis-v'\"\n [model]=\"pivotConfigMenuItems\"\n styleClass=\"pivot-actions-config-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.actions' | translate) }\"\n (onClick)=\"openPivotConfigMenu(pivotConfigSplitBtn, $event)\">\n </p-splitButton>\n <!-- Chip cliccabile della view/materialized-table scaffoldata\n dal pivot (pattern identico al chip createdViewName del\n tab View Builder). Apre `#/<route>/list` in nuovo tab.\n Tooltip include il tipo (view o table) serializzato. -->\n @if (pivotCreatedName) {\n @if (pivotCreatedRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + pivotCreatedRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"(pivotCreatedKind === 'table'\n ? t('pivot_builder.pivot_table_created_tooltip','Materialized table created from this pivot')\n : t('pivot_builder.pivot_view_created_tooltip','DB view created from this pivot'))\n + ' \u2014 ' + pivotCreatedRoute + '/list'\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n </span>\n }\n }\n </div>\n <!-- Settings split-button del tab Pivot Config: stessi 3 toggle\n del View Builder Settings (auto-generate, manual SQL,\n all-filterable) meno il `auto-reflow` che e' specifico del\n canvas. Allineato a destra con `.pivot-actions-settings`. -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #pivotSettingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"pivotSettingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openPivotSettingsMenu(pivotSettingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <table style=\"width: 100%;\">\n <tr>\n <td>\n <p-autoComplete [(ngModel)]=\"selectedRouteOption\" [suggestions]=\"filteredRouteOptions\"\n (completeMethod)=\"filterRouteOptions($event)\" (onSelect)=\"onRouteOptionSelected($event.value)\"\n [dropdown]=\"true\" [forceSelection]=\"true\" optionLabel=\"label\"\n [placeholder]=\"'pivot_builder.select_route_placeholder' | translate\"\n styleClass=\"pivot-route-autocomplete\">\n </p-autoComplete>\n </td>\n <td>\n <label>{{ 'aggregation' | translate }}</label>\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"aggregateFunction\">\n </p-select>\n </td>\n <td>\n <label>{{ 'pivot_builder.top_rows' | translate }}</label>\n <input type=\"number\" min=\"0\" step=\"1\" [(ngModel)]=\"topRows\"\n (ngModelChange)=\"topRows = normalizeTopRows($event)\" />\n </td>\n </tr>\n </table>\n\n <!-- Filter panel -->\n <div class=\"pivot-filter-full\">\n\n @if (selectedRouteName) {\n <wuic-filter-bar [hardcodedDatasource]=\"nestedSource\" [skipUrlSync]=\"true\"\n (filterApplied)=\"onFilterBarApplied()\"></wuic-filter-bar>\n }\n\n </div>\n\n <!-- 4-panel splitter: source cols | rows | columns | values -->\n <div class=\"pivot-buckets-row\">\n <p-splitter [panelSizes]=\"[28, 24, 24, 24]\" [style]=\"{ height: '100%', width: '100%' }\"\n styleClass=\"pivot-buckets-splitter\">\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.route_columns' | translate }}</h3>\n <div class=\"pivot-columns-list\" [ngClass]=\"{ 'is-loading': loadingRouteColumns }\">\n @for (col of sourceColumns; track col.alias) {\n <div class=\"pivot-column-item\" draggable=\"true\" (dragstart)=\"onDragStart($event, col)\">\n <span>{{ col.label }}</span>\n <div class=\"pivot-column-actions\">\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToRows(col)\">{{ 'row' | translate }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToColumns(col)\">{{ 'column' | translate\n }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToValues(col)\">{{ 'value' | translate\n }}</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.rows_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToRows($event)\">\n @if (!rowColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_rows_here' | translate }}</div>\n }\n @for (col of rowColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setRowCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setRowDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromRows(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.columns_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToColumns($event)\">\n @if (!columnColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_columns_here' | translate }}</div>\n }\n @for (col of columnColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setColumnCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setColumnDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromColumns(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.values' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToValues($event)\">\n @if (!valueColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_values_here' | translate }}</div>\n }\n @for (col of valueColumns; track col.id) {\n <div class=\"pivot-chip\">\n <input class=\"pivot-value-caption\" type=\"text\" [ngModel]=\"col.caption\"\n (ngModelChange)=\"setValueCaption(col.id, $event)\" [title]=\"col.label\"\n [placeholder]=\"'pivot_builder.metric_caption' | translate\" />\n <div class=\"pivot-chip-actions\">\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"getValueAggregate(col.id)\" (ngModelChange)=\"setValueAggregate(col.id, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n <button type=\"button\" (click)=\"removeFromValues(col.id)\">x</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </p-splitter>\n </div>\n </p-tabpanel>\n </p-tabpanels>\n </p-tabs>\n\n <!-- ===== Output row (below tabs, always visible) ===== -->\n <div class=\"pivot-output-row\">\n @if (!showQueryResults) {\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n } @else {\n <p-splitter [panelSizes]=\"[50, 50]\" [style]=\"{ height: '100%', width: '100%' }\" styleClass=\"pivot-result-splitter\">\n <ng-template #panel>\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n </ng-template>\n <ng-template #panel>\n <div class=\"pivot-result-panel\">\n <h3>{{ 'pivot_builder.query_results' | translate }}</h3>\n <p-table [value]=\"queryResultRows\" [scrollable]=\"true\" scrollHeight=\"flex\" styleClass=\"pivot-result-table\">\n <ng-template pTemplate=\"header\">\n <tr>\n @for (c of queryResultColumns; track c) {\n <th>{{ c }}</th>\n }\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n @for (c of queryResultColumns; track c) {\n <td>{{ formatQueryCellValue(row?.[c], c) }}</td>\n }\n </tr>\n </ng-template>\n </p-table>\n </div>\n </ng-template>\n </p-splitter>\n }\n </div>\n</div>\n\n<p-dialog [header]=\"viewBuilderOpenMode ? t('pivot_builder.vb.open_view_definition','Open View Definition') : ('pivot_builder.reopen_pivot' | translate)\" [(visible)]=\"reopenPivotDialogVisible\" [modal]=\"true\"\n [closable]=\"true\" [draggable]=\"false\" [resizable]=\"false\" [appendTo]=\"'body'\" [style]=\"{ width: '34rem' }\"\n (onHide)=\"cancelReopenPivotDialog()\">\n <div class=\"route-popup-form\">\n <label for=\"pivot-reopen-select\">{{ viewBuilderOpenMode ? t('pivot_builder.vb.saved_view_definitions','Saved view definitions') : ('pivot_builder.saved_pivots' | translate) }}</label>\n <p-select inputId=\"pivot-reopen-select\" [options]=\"savedPivotOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"reopenDialogSelectedPivotName\" [filter]=\"true\" [showClear]=\"true\" [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelReopenPivotDialog()\">{{ 'cancel' | translate\n }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmReopenPivotDialog()\"\n [disabled]=\"!reopenDialogSelectedPivotName\">{{ 'open' | translate }}</button>\n </div>\n </div>\n</p-dialog>", styles: [":host{display:block;height:100%;min-height:0}.pivot-builder{height:100%;min-height:0;padding:.5rem;box-sizing:border-box;display:grid;grid-template-rows:auto minmax(250px,1fr) clamp(120px,25vh,300px);gap:.5rem;overflow:auto}.pivot-toolbar{display:flex;align-items:center;gap:.6rem}.pivot-toolbar h2{margin:0;font-size:1.55rem;white-space:nowrap}.pivot-route-select{min-width:22rem;max-width:34rem;width:100%}.pivot-actions-row{height:40px;display:flex;align-items:center;gap:.75rem}.pivot-created-view-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;color:#16a34a;font-weight:600;padding:2px 8px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:4px}a.pivot-created-view-link{text-decoration:none;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}a.pivot-created-view-link:hover,a.pivot-created-view-link:focus-visible{background:#dcfce7;border-color:#86efac;outline:none}.pivot-created-view-ext{font-size:.72rem;opacity:.6}a.pivot-created-view-link:hover .pivot-created-view-ext{opacity:1}.pivot-disabled-overlay{opacity:.4;pointer-events:none;filter:grayscale(.5)}.pivot-manual-sql-label{color:#dc3545;font-weight:600}.pivot-auto-generate-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;margin-left:auto}.pivot-actions-settings{margin-left:auto;display:inline-flex;align-items:center}.pivot-settings-menu{display:flex;flex-direction:column;gap:10px;min-width:240px;padding:4px 2px}.pivot-settings-item{display:flex;align-items:center;gap:8px;font-size:.85rem;cursor:pointer;-webkit-user-select:none;user-select:none}.pivot-config-group{display:grid;grid-template-columns:minmax(200px,1fr) minmax(160px,200px);gap:.6rem;align-items:end}.pivot-config-item{display:inline;flex-direction:column;gap:.2rem}.pivot-config-item input[type=number]{width:100%;box-sizing:border-box;height:2.45rem;border:1px solid #d4d8e2;border-radius:6px;padding:.35rem .55rem}.pivot-actions{display:inline-flex;gap:.45rem;flex-wrap:wrap}.pivot-hidden-datasource{display:none}.pivot-filter-full{flex:0 0 auto;max-height:40%;max-width:100%;overflow:auto;position:relative;box-sizing:border-box;display:flex;flex-direction:column}.pivot-buckets-row{flex:1;min-height:120px;overflow:hidden}.pivot-output-row{min-height:0;overflow:hidden}.pivot-panel{height:100%;min-height:0;overflow:hidden;border:1px solid #d4d8e2;border-radius:10px;background:#fff;padding:.5rem;box-sizing:border-box;display:flex;flex-direction:column;gap:.4rem}.pivot-panel h3,.pivot-sql-editor h3,.pivot-result-panel h3{margin:0;font-size:.96rem}.pivot-columns-list{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:.3rem}.pivot-column-item{border:1px solid #d4d8e2;border-radius:8px;padding:.3rem .4rem;background:#f8faff;cursor:grab;display:flex;align-items:center;justify-content:space-between;gap:.3rem}.pivot-column-actions{display:inline-flex;gap:.2rem}.mini-btn{border:1px solid #c8d0e1;background:#fff;border-radius:6px;font-size:.72rem;padding:.15rem .32rem;cursor:pointer}.pivot-dropzone{min-height:0;flex:1 1 auto;overflow:auto;border:1px dashed #9db0d8;border-radius:8px;padding:.4rem;display:flex;flex-direction:column;gap:.3rem;background:#fbfcff}.pivot-empty{color:#7f8797;font-size:.85rem}.pivot-chip{display:flex;align-items:center;justify-content:space-between;gap:.35rem;border:1px solid #cfd7ea;border-radius:8px;padding:.25rem .4rem;background:#fff}.pivot-value-caption{flex:1 1 auto;min-width:0;border:1px solid #cfd7ea;border-radius:6px;padding:.2rem .35rem;font-size:.82rem}.pivot-chip button{border:none;background:transparent;color:#6d7688;cursor:pointer}.pivot-chip-actions{display:inline-flex;align-items:center;gap:.25rem}:host ::ng-deep .pivot-chip-agg-select{min-width:6.2rem}.pivot-sql-editor,.pivot-result-panel{height:100%;min-height:0;border:1px solid #d4d8e2;border-radius:10px;overflow:hidden;background:#fff;display:flex;flex-direction:column;position:relative}.pivot-sql-busy{position:absolute;inset:0;background:#fffc;display:flex;align-items:center;justify-content:center;gap:.5rem;z-index:5;font-size:.9rem;color:var(--primary-color, #3B82F6)}.pivot-sql-editor h3,.pivot-result-panel h3{padding:.5rem .65rem;border-bottom:1px solid #d4d8e2;background:#f5f7fb}.pivot-sql-editor ngx-monaco-editor{display:block;min-height:0;flex:1 1 auto}:host ::ng-deep .pivot-result-table,:host ::ng-deep .pivot-result-table .p-datatable-wrapper{height:100%;overflow:auto}:host ::ng-deep .pivot-result-table td,:host ::ng-deep .pivot-result-table th{white-space:nowrap}:host ::ng-deep .pivot-buckets-splitter,:host ::ng-deep .pivot-result-splitter{height:100%}:host ::ng-deep .pivot-builder>p-tabs{display:flex;flex-direction:column;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels,:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels{flex:1;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels>.p-tabpanel:not([hidden]),:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;min-height:0;overflow:hidden;display:flex!important;flex-direction:column}:host ::ng-deep .pivot-filter-full .p-accordion,:host ::ng-deep .pivot-filter-full .p-accordionpanel,:host ::ng-deep .pivot-filter-full .p-accordioncontent,:host ::ng-deep .pivot-filter-full .p-accordionpanel-content,:host ::ng-deep .pivot-filter-full .p-accordioncontent-content{position:relative;height:auto!important;max-height:none!important;overflow:visible;max-width:100%}:host ::ng-deep .pivot-filter-full p-tablist,:host ::ng-deep .pivot-filter-full .p-tablist{position:sticky;top:0;z-index:2;background:var(--p-content-background, #fff)}:host ::ng-deep .pivot-filter-full p-tabpanels,:host ::ng-deep .pivot-filter-full .p-tabpanels,:host ::ng-deep .pivot-filter-full p-tabpanel,:host ::ng-deep .pivot-filter-full .p-tabpanel{overflow:visible;max-width:100%}.route-popup-form{display:flex;flex-direction:column;gap:.75rem}.route-popup-form label{font-size:.9rem;font-weight:600}.route-popup-actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem}.route-popup-btn{border:1px solid #d4d8e2;background:#fff;color:#22314d;border-radius:8px;padding:.45rem .9rem;cursor:pointer}.route-popup-btn-primary{border-color:#2f74f2;background:#2f74f2;color:#fff}.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;width:100%;display:inline-block}@media(max-width:1200px){.pivot-builder{grid-template-rows:auto minmax(0,1fr) clamp(120px,25vh,300px)}.pivot-route-select{min-width:14rem}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i3$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SplitButtonModule }, { kind: "component", type: i11.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "motionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: SplitterModule }, { kind: "component", type: i9.Splitter, selector: "p-splitter", inputs: ["styleClass", "panelStyleClass", "panelStyle", "stateStorage", "stateKey", "layout", "gutterSize", "step", "minSizes", "panelSizes"], outputs: ["onResizeEnd", "onResizeStart"] }, { kind: "ngmodule", type: AccordionModule }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i8.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: TabList, selector: "p-tablist" }, { kind: "component", type: Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: TabPanels, selector: "p-tabpanels" }, { kind: "component", type: TabPanel, selector: "p-tabpanel", inputs: ["lazy", "value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: MonacoEditorModule }, { kind: "component", type: i1$3.MonacoEditorComponent, selector: "ngx-monaco-editor", inputs: ["options", "uri"], outputs: ["init"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: DataSourceComponent, selector: "wuic-data-source", inputs: ["route", "routeFromRouting", "hardcodedRoute", "autoload", "loading", "changeTracking", "parentRecord", "parentMetaInfo", "parentDatasource", "useComboEndpoint", "comboFormulaLookup", "comboMcId", "comboField", "comboExtraFields", "comboCurrentRecord", "componentRef"] }, { kind: "component", type: FilterBarComponent, selector: "wuic-filter-bar", inputs: ["datasource", "hardcodedDatasource", "multiDatasourceMetas", "skipUrlSync"], outputs: ["filterApplied", "onFilterApplied", "onSortingApplied", "onPageSizeApplied", "onGroupingChanged", "onFilterBarCollapseChanged"] }, { kind: "component", type: ViewBuilderComponent, selector: "wuic-view-builder", inputs: ["autoReflowLayout"], outputs: ["viewDefinitionChange"] }, { kind: "pipe", type: i2$1.TranslatePipe, name: "translate" }] });
|
|
4037
4050
|
}
|
|
4038
4051
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: PivotBuilderComponent, decorators: [{
|
|
4039
4052
|
type: Component,
|
|
4040
4053
|
args: [{ selector: 'wuic-pivot-builder', imports: [NgClass, FormsModule, AutoCompleteModule, ButtonModule, SplitButtonModule, SelectModule, SplitterModule, AccordionModule, DialogModule, TableModule, Tabs, TabList, Tab, TabPanels, TabPanel, MonacoEditorModule, TranslateModule, DataSourceComponent, FilterBarComponent, ViewBuilderComponent], template: "<div class=\"pivot-builder\">\n <!-- ===== Global header (just title) ===== -->\n <div class=\"pivot-toolbar\">\n <h2>{{ 'pivot_builder.title' | translate }}</h2>\n </div>\n\n <wuic-data-source #nestedSource class=\"pivot-hidden-datasource\" [route]=\"pivotRoute$\" [autoload]=\"true\">\n </wuic-data-source>\n\n <!-- ===== Tabs ===== -->\n <p-tabs [(value)]=\"activeTab\">\n <p-tablist>\n <p-tab [value]=\"0\">\n <i class=\"pi pi-sitemap mr-2\"></i>\n <span>{{ 'pivot_builder.tab.view_builder' | translate }}</span>\n </p-tab>\n <p-tab [value]=\"1\">\n <i class=\"pi pi-th-large mr-2\"></i>\n <span>{{ 'pivot_builder.tab.pivot_config' | translate }}</span>\n </p-tab>\n </p-tablist>\n <p-tabpanels>\n\n <!-- ==================== Tab 0: View Builder ==================== -->\n <p-tabpanel [value]=\"0\">\n <!-- View Builder toolbar -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar: tutti i button uniformati al tema selezionato\n (primary color della palette attiva \u2014 es. Aura Blu/Teal/...).\n Rimosse severity override per evitare mix `contrast/success/\n secondary` che rompeva la coerenza visiva.\n \"Create View\", \"Save Definition\", \"Open\" + \"Delete\" sono\n raggruppati nello split-button \"Definition\". -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.vb.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingViewDefSql\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"generateSqlFromViewDefinition()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.vb.execute_query' | translate\" icon=\"pi pi-bolt\" [loading]=\"executingViewDefQuery\"\n [disabled]=\"!hasViewDefinition\" (onClick)=\"executeViewDefinitionQuery()\">\n </p-button>\n <p-splitButton #definitionSplitBtn\n [label]=\"'pivot_builder.vb.definition' | translate\"\n icon=\"pi pi-database\"\n [model]=\"definitionMenuItems\"\n styleClass=\"pivot-actions-definition-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.definition' | translate) }\"\n (onClick)=\"openDefinitionMenu(definitionSplitBtn, $event)\">\n </p-splitButton>\n </div>\n <!-- Chip della view creata: se c'e' una `createdViewRoute` rendiamo\n un anchor cliccabile verso `#/<route>/list` (apertura in nuovo\n tab, pattern standard del framework \u2014 vedi list-grid.component\n `mc_logic_navigate_new_window`). Altrimenti ricadiamo su uno\n span semplice (es. view creata senza scaffold, o payload\n legacy senza route). -->\n @if (createdViewName) {\n @if (createdViewRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + createdViewRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition') + ' \u2014 ' + createdViewRoute + '/list'\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\" [title]=\"t('pivot_builder.vb.view_created_tooltip','DB View created from this definition')\">\n <i class=\"pi pi-database\"></i> {{ createdViewName }}\n </span>\n }\n }\n <!-- Settings split-button (pattern \"Azioni designer\"): ogni voce\n del menu e' un toggle con icona check/stop che riflette lo\n stato corrente (auto-generate, manual SQL, all-filterable,\n auto-reflow). Click sulla voce inverte il flag.\n Allineato a destra della toolbar tramite\n `.pivot-actions-settings` (margin-left: auto). -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #settingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"settingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openSettingsMenu(settingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <!-- Filter bar for View Builder (multi-table or single-table) \u2014 hidden in manual SQL mode -->\n @if (!manualSqlMode && (viewBuilderFilterMetas.length || viewBuilderFilterRoute)) {\n <div class=\"pivot-filter-full\">\n <wuic-filter-bar\n [multiDatasourceMetas]=\"viewBuilderFilterMetas\"\n [hardcodedDatasource]=\"viewBuilderFilterMetas.length ? null! : nestedSource\"\n [skipUrlSync]=\"true\"\n (filterApplied)=\"onViewBuilderFilterApplied()\"\n (onFilterApplied)=\"onViewBuilderMultiFilterApplied($event)\">\n </wuic-filter-bar>\n </div>\n }\n\n <div style=\"flex: 1; min-height: 0; width: 100%;\" [class.pivot-disabled-overlay]=\"manualSqlMode\">\n <wuic-view-builder #viewBuilderRef [autoReflowLayout]=\"autoReflowLayout\"\n (viewDefinitionChange)=\"onViewDefinitionChange($event)\">\n </wuic-view-builder>\n </div>\n </p-tabpanel>\n\n <!-- ==================== Tab 1: Pivot Configuration ==================== -->\n <p-tabpanel [value]=\"1\">\n <!-- Pivot toolbar: route selector + actions -->\n <div class=\"pivot-actions-row\">\n <!-- Toolbar uniformata al tema selezionato (stessa regola della\n tab View Builder: nessuna severity override).\n \"Create View\", \"Create Materialized Table\",\n \"Save Configuration\", \"Open Pivot\" sono raggruppati nello\n split-button \"Actions\" (stesso pattern del Definition\n split-button del tab View Builder). -->\n <div class=\"pivot-actions\">\n <p-button [label]=\"'pivot_builder.generate_query' | translate\" icon=\"pi pi-play\" [loading]=\"generatingSql\"\n [disabled]=\"!canExecutePivot\" (onClick)=\"generatePivotSql()\">\n </p-button>\n <p-button [label]=\"'pivot_builder.execute_query' | translate\" icon=\"pi pi-bolt\"\n [loading]=\"executingQuery\" [disabled]=\"!canExecutePivot\" (onClick)=\"executePivotSql()\">\n </p-button>\n <p-splitButton #pivotConfigSplitBtn\n [label]=\"'pivot_builder.actions' | translate\"\n [icon]=\"(creatingView || creatingMaterializedTable || savingConfiguration || reopeningPivotList || deletingPivot)\n ? 'pi pi-spin pi-spinner'\n : 'pi pi-ellipsis-v'\"\n [model]=\"pivotConfigMenuItems\"\n styleClass=\"pivot-actions-config-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.actions' | translate) }\"\n (onClick)=\"openPivotConfigMenu(pivotConfigSplitBtn, $event)\">\n </p-splitButton>\n <!-- Chip cliccabile della view/materialized-table scaffoldata\n dal pivot (pattern identico al chip createdViewName del\n tab View Builder). Apre `#/<route>/list` in nuovo tab.\n Tooltip include il tipo (view o table) serializzato. -->\n @if (pivotCreatedName) {\n @if (pivotCreatedRoute) {\n <a class=\"pivot-created-view-label pivot-created-view-link\"\n [href]=\"'#/' + pivotCreatedRoute + '/list'\"\n target=\"_blank\" rel=\"noopener\"\n [title]=\"(pivotCreatedKind === 'table'\n ? t('pivot_builder.pivot_table_created_tooltip','Materialized table created from this pivot')\n : t('pivot_builder.pivot_view_created_tooltip','DB view created from this pivot'))\n + ' \u2014 ' + pivotCreatedRoute + '/list'\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n <i class=\"pi pi-external-link pivot-created-view-ext\"></i>\n </a>\n } @else {\n <span class=\"pivot-created-view-label\">\n <i [ngClass]=\"pivotCreatedKind === 'table' ? 'pi pi-table' : 'pi pi-database'\"></i>\n {{ pivotCreatedName }}\n </span>\n }\n }\n </div>\n <!-- Settings split-button del tab Pivot Config: stessi 3 toggle\n del View Builder Settings (auto-generate, manual SQL,\n all-filterable) meno il `auto-reflow` che e' specifico del\n canvas. Allineato a destra con `.pivot-actions-settings`. -->\n <div class=\"pivot-actions-settings\">\n <p-splitButton #pivotSettingsSplitBtn\n [label]=\"'pivot_builder.vb.settings' | translate\"\n icon=\"pi pi-cog\"\n [model]=\"pivotSettingsMenuItems\"\n styleClass=\"pivot-actions-settings-split\"\n [menuButtonProps]=\"{ ariaLabel: ('pivot_builder.vb.settings' | translate) }\"\n (onClick)=\"openPivotSettingsMenu(pivotSettingsSplitBtn, $event)\">\n </p-splitButton>\n </div>\n </div>\n\n <table style=\"width: 100%;\">\n <tr>\n <td>\n <p-autoComplete [(ngModel)]=\"selectedRouteOption\" [suggestions]=\"filteredRouteOptions\"\n (completeMethod)=\"filterRouteOptions($event)\" (onSelect)=\"onRouteOptionSelected($event.value)\"\n [dropdown]=\"true\" [forceSelection]=\"true\" optionLabel=\"label\"\n [placeholder]=\"'pivot_builder.select_route_placeholder' | translate\"\n styleClass=\"pivot-route-autocomplete\">\n </p-autoComplete>\n </td>\n <td>\n <label>{{ 'aggregation' | translate }}</label>\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"aggregateFunction\">\n </p-select>\n </td>\n <td>\n <label>{{ 'pivot_builder.top_rows' | translate }}</label>\n <input type=\"number\" min=\"0\" step=\"1\" [(ngModel)]=\"topRows\"\n (ngModelChange)=\"topRows = normalizeTopRows($event)\" />\n </td>\n </tr>\n </table>\n\n <!-- Filter panel -->\n <div class=\"pivot-filter-full\">\n\n @if (selectedRouteName) {\n <wuic-filter-bar [hardcodedDatasource]=\"nestedSource\" [skipUrlSync]=\"true\"\n (filterApplied)=\"onFilterBarApplied()\"></wuic-filter-bar>\n }\n\n </div>\n\n <!-- 4-panel splitter: source cols | rows | columns | values -->\n <div class=\"pivot-buckets-row\">\n <p-splitter [panelSizes]=\"[28, 24, 24, 24]\" [style]=\"{ height: '100%', width: '100%' }\"\n styleClass=\"pivot-buckets-splitter\">\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.route_columns' | translate }}</h3>\n <div class=\"pivot-columns-list\" [ngClass]=\"{ 'is-loading': loadingRouteColumns }\">\n @for (col of sourceColumns; track col.alias) {\n <div class=\"pivot-column-item\" draggable=\"true\" (dragstart)=\"onDragStart($event, col)\">\n <span>{{ col.label }}</span>\n <div class=\"pivot-column-actions\">\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToRows(col)\">{{ 'row' | translate }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToColumns(col)\">{{ 'column' | translate\n }}</button>\n <button type=\"button\" class=\"mini-btn\" (click)=\"addToValues(col)\">{{ 'value' | translate\n }}</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.rows_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToRows($event)\">\n @if (!rowColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_rows_here' | translate }}</div>\n }\n @for (col of rowColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setRowCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setRowDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromRows(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.columns_axis' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToColumns($event)\">\n @if (!columnColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_columns_here' | translate }}</div>\n }\n @for (col of columnColumns; track col.alias) {\n <div class=\"pivot-chip\">\n <span>{{ col.label }}</span>\n @if (isAxisDateCastAvailable(col)) {\n <label class=\"pivot-row-cast-flag\">\n <input type=\"checkbox\" [ngModel]=\"!!col.castDate\"\n (ngModelChange)=\"setColumnCastDate(col.alias, $event)\" />\n {{ 'pivot_builder.cast_date' | translate }}\n </label>\n }\n @if (isAxisDateTimeGroupAvailable(col)) {\n <p-select [options]=\"dateGroupByOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"col.dateGroupBy || ''\" (ngModelChange)=\"setColumnDateGroupBy(col.alias, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n }\n <button type=\"button\" (click)=\"removeFromColumns(col.alias)\">x</button>\n </div>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #panel>\n <div class=\"pivot-panel\">\n <h3>{{ 'pivot_builder.values' | translate }}</h3>\n <div class=\"pivot-dropzone\" (dragover)=\"allowDrop($event)\" (drop)=\"onDropToValues($event)\">\n @if (!valueColumns.length) {\n <div class=\"pivot-empty\">{{ 'pivot_builder.drag_values_here' | translate }}</div>\n }\n @for (col of valueColumns; track col.id) {\n <div class=\"pivot-chip\">\n <input class=\"pivot-value-caption\" type=\"text\" [ngModel]=\"col.caption\"\n (ngModelChange)=\"setValueCaption(col.id, $event)\" [title]=\"col.label\"\n [placeholder]=\"'pivot_builder.metric_caption' | translate\" />\n <div class=\"pivot-chip-actions\">\n <p-select [options]=\"aggregateOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"getValueAggregate(col.id)\" (ngModelChange)=\"setValueAggregate(col.id, $event)\"\n appendTo=\"body\" styleClass=\"pivot-chip-agg-select\">\n </p-select>\n <button type=\"button\" (click)=\"removeFromValues(col.id)\">x</button>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </p-splitter>\n </div>\n </p-tabpanel>\n </p-tabpanels>\n </p-tabs>\n\n <!-- ===== Output row (below tabs, always visible) ===== -->\n <div class=\"pivot-output-row\">\n @if (!showQueryResults) {\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n } @else {\n <p-splitter [panelSizes]=\"[50, 50]\" [style]=\"{ height: '100%', width: '100%' }\" styleClass=\"pivot-result-splitter\">\n <ng-template #panel>\n <div class=\"pivot-sql-editor\">\n <h3 [innerHTML]=\"'pivot_builder.generated_sql' | translate\"></h3>\n @if (generatingViewDefSql || generatingSql) {\n <div class=\"pivot-sql-busy\"><i class=\"pi pi-spin pi-spinner\"></i> {{ 'pivot_builder.generating' | translate }}</div>\n }\n <ngx-monaco-editor [options]=\"sqlEditorOptions\" [(ngModel)]=\"generatedSql\"></ngx-monaco-editor>\n </div>\n </ng-template>\n <ng-template #panel>\n <div class=\"pivot-result-panel\">\n <h3>{{ 'pivot_builder.query_results' | translate }}</h3>\n <p-table [value]=\"queryResultRows\" [scrollable]=\"true\" scrollHeight=\"flex\" styleClass=\"pivot-result-table\">\n <ng-template pTemplate=\"header\">\n <tr>\n @for (c of queryResultColumns; track c) {\n <th>{{ c }}</th>\n }\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-row>\n <tr>\n @for (c of queryResultColumns; track c) {\n <td>{{ formatQueryCellValue(row?.[c], c) }}</td>\n }\n </tr>\n </ng-template>\n </p-table>\n </div>\n </ng-template>\n </p-splitter>\n }\n </div>\n</div>\n\n<p-dialog [header]=\"viewBuilderOpenMode ? t('pivot_builder.vb.open_view_definition','Open View Definition') : ('pivot_builder.reopen_pivot' | translate)\" [(visible)]=\"reopenPivotDialogVisible\" [modal]=\"true\"\n [closable]=\"true\" [draggable]=\"false\" [resizable]=\"false\" [appendTo]=\"'body'\" [style]=\"{ width: '34rem' }\"\n (onHide)=\"cancelReopenPivotDialog()\">\n <div class=\"route-popup-form\">\n <label for=\"pivot-reopen-select\">{{ viewBuilderOpenMode ? t('pivot_builder.vb.saved_view_definitions','Saved view definitions') : ('pivot_builder.saved_pivots' | translate) }}</label>\n <p-select inputId=\"pivot-reopen-select\" [options]=\"savedPivotOptions\" optionLabel=\"label\" optionValue=\"value\"\n [(ngModel)]=\"reopenDialogSelectedPivotName\" [filter]=\"true\" [showClear]=\"true\" [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelReopenPivotDialog()\">{{ 'cancel' | translate\n }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmReopenPivotDialog()\"\n [disabled]=\"!reopenDialogSelectedPivotName\">{{ 'open' | translate }}</button>\n </div>\n </div>\n</p-dialog>", styles: [":host{display:block;height:100%;min-height:0}.pivot-builder{height:100%;min-height:0;padding:.5rem;box-sizing:border-box;display:grid;grid-template-rows:auto minmax(250px,1fr) clamp(120px,25vh,300px);gap:.5rem;overflow:auto}.pivot-toolbar{display:flex;align-items:center;gap:.6rem}.pivot-toolbar h2{margin:0;font-size:1.55rem;white-space:nowrap}.pivot-route-select{min-width:22rem;max-width:34rem;width:100%}.pivot-actions-row{height:40px;display:flex;align-items:center;gap:.75rem}.pivot-created-view-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;color:#16a34a;font-weight:600;padding:2px 8px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:4px}a.pivot-created-view-link{text-decoration:none;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}a.pivot-created-view-link:hover,a.pivot-created-view-link:focus-visible{background:#dcfce7;border-color:#86efac;outline:none}.pivot-created-view-ext{font-size:.72rem;opacity:.6}a.pivot-created-view-link:hover .pivot-created-view-ext{opacity:1}.pivot-disabled-overlay{opacity:.4;pointer-events:none;filter:grayscale(.5)}.pivot-manual-sql-label{color:#dc3545;font-weight:600}.pivot-auto-generate-label{display:inline-flex;align-items:center;gap:4px;font-size:.8rem;white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;margin-left:auto}.pivot-actions-settings{margin-left:auto;display:inline-flex;align-items:center}.pivot-settings-menu{display:flex;flex-direction:column;gap:10px;min-width:240px;padding:4px 2px}.pivot-settings-item{display:flex;align-items:center;gap:8px;font-size:.85rem;cursor:pointer;-webkit-user-select:none;user-select:none}.pivot-config-group{display:grid;grid-template-columns:minmax(200px,1fr) minmax(160px,200px);gap:.6rem;align-items:end}.pivot-config-item{display:inline;flex-direction:column;gap:.2rem}.pivot-config-item input[type=number]{width:100%;box-sizing:border-box;height:2.45rem;border:1px solid #d4d8e2;border-radius:6px;padding:.35rem .55rem}.pivot-actions{display:inline-flex;gap:.45rem;flex-wrap:wrap}.pivot-hidden-datasource{display:none}.pivot-filter-full{flex:0 0 auto;max-height:40%;max-width:100%;overflow:auto;position:relative;box-sizing:border-box;display:flex;flex-direction:column}.pivot-buckets-row{flex:1;min-height:120px;overflow:hidden}.pivot-output-row{min-height:0;overflow:hidden}.pivot-panel{height:100%;min-height:0;overflow:hidden;border:1px solid #d4d8e2;border-radius:10px;background:#fff;padding:.5rem;box-sizing:border-box;display:flex;flex-direction:column;gap:.4rem}.pivot-panel h3,.pivot-sql-editor h3,.pivot-result-panel h3{margin:0;font-size:.96rem}.pivot-columns-list{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:.3rem}.pivot-column-item{border:1px solid #d4d8e2;border-radius:8px;padding:.3rem .4rem;background:#f8faff;cursor:grab;display:flex;align-items:center;justify-content:space-between;gap:.3rem}.pivot-column-actions{display:inline-flex;gap:.2rem}.mini-btn{border:1px solid #c8d0e1;background:#fff;border-radius:6px;font-size:.72rem;padding:.15rem .32rem;cursor:pointer}.pivot-dropzone{min-height:0;flex:1 1 auto;overflow:auto;border:1px dashed #9db0d8;border-radius:8px;padding:.4rem;display:flex;flex-direction:column;gap:.3rem;background:#fbfcff}.pivot-empty{color:#7f8797;font-size:.85rem}.pivot-chip{display:flex;align-items:center;justify-content:space-between;gap:.35rem;border:1px solid #cfd7ea;border-radius:8px;padding:.25rem .4rem;background:#fff}.pivot-value-caption{flex:1 1 auto;min-width:0;border:1px solid #cfd7ea;border-radius:6px;padding:.2rem .35rem;font-size:.82rem}.pivot-chip button{border:none;background:transparent;color:#6d7688;cursor:pointer}.pivot-chip-actions{display:inline-flex;align-items:center;gap:.25rem}:host ::ng-deep .pivot-chip-agg-select{min-width:6.2rem}.pivot-sql-editor,.pivot-result-panel{height:100%;min-height:0;border:1px solid #d4d8e2;border-radius:10px;overflow:hidden;background:#fff;display:flex;flex-direction:column;position:relative}.pivot-sql-busy{position:absolute;inset:0;background:#fffc;display:flex;align-items:center;justify-content:center;gap:.5rem;z-index:5;font-size:.9rem;color:var(--primary-color, #3B82F6)}.pivot-sql-editor h3,.pivot-result-panel h3{padding:.5rem .65rem;border-bottom:1px solid #d4d8e2;background:#f5f7fb}.pivot-sql-editor ngx-monaco-editor{display:block;min-height:0;flex:1 1 auto}:host ::ng-deep .pivot-result-table,:host ::ng-deep .pivot-result-table .p-datatable-wrapper{height:100%;overflow:auto}:host ::ng-deep .pivot-result-table td,:host ::ng-deep .pivot-result-table th{white-space:nowrap}:host ::ng-deep .pivot-buckets-splitter,:host ::ng-deep .pivot-result-splitter{height:100%}:host ::ng-deep .pivot-builder>p-tabs{display:flex;flex-direction:column;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels,:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels{flex:1;min-height:0;overflow:hidden}:host ::ng-deep .pivot-builder>p-tabs>p-tabpanels>.p-tabpanel:not([hidden]),:host ::ng-deep .pivot-builder>p-tabs>.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;min-height:0;overflow:hidden;display:flex!important;flex-direction:column}:host ::ng-deep .pivot-filter-full .p-accordion,:host ::ng-deep .pivot-filter-full .p-accordionpanel,:host ::ng-deep .pivot-filter-full .p-accordioncontent,:host ::ng-deep .pivot-filter-full .p-accordionpanel-content,:host ::ng-deep .pivot-filter-full .p-accordioncontent-content{position:relative;height:auto!important;max-height:none!important;overflow:visible;max-width:100%}:host ::ng-deep .pivot-filter-full p-tablist,:host ::ng-deep .pivot-filter-full .p-tablist{position:sticky;top:0;z-index:2;background:var(--p-content-background, #fff)}:host ::ng-deep .pivot-filter-full p-tabpanels,:host ::ng-deep .pivot-filter-full .p-tabpanels,:host ::ng-deep .pivot-filter-full p-tabpanel,:host ::ng-deep .pivot-filter-full .p-tabpanel{overflow:visible;max-width:100%}.route-popup-form{display:flex;flex-direction:column;gap:.75rem}.route-popup-form label{font-size:.9rem;font-weight:600}.route-popup-actions{display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem}.route-popup-btn{border:1px solid #d4d8e2;background:#fff;color:#22314d;border-radius:8px;padding:.45rem .9rem;cursor:pointer}.route-popup-btn-primary{border-color:#2f74f2;background:#2f74f2;color:#fff}.p-tabpanels>.p-tabpanel:not([hidden]){height:100%;width:100%;display:inline-block}@media(max-width:1200px){.pivot-builder{grid-template-rows:auto minmax(0,1fr) clamp(120px,25vh,300px)}.pivot-route-select{min-width:14rem}}\n"] }]
|
|
4041
|
-
}], ctorParameters: () => [{ type: DataProviderService }, { type: MetadataProviderService }, { type: TranslationManagerService }, { type: i1$
|
|
4054
|
+
}], ctorParameters: () => [{ type: DataProviderService }, { type: MetadataProviderService }, { type: TranslationManagerService }, { type: i1$2.ActivatedRoute }], propDecorators: { nestedSource: [{
|
|
4042
4055
|
type: ViewChild,
|
|
4043
4056
|
args: ['nestedSource']
|
|
4044
4057
|
}], viewBuilderRef: [{
|
|
@@ -4047,4 +4060,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
4047
4060
|
}] } });
|
|
4048
4061
|
|
|
4049
4062
|
export { PivotBuilderComponent };
|
|
4050
|
-
//# sourceMappingURL=wuic-framework-lib-pivot-builder.component-
|
|
4063
|
+
//# sourceMappingURL=wuic-framework-lib-pivot-builder.component-ChNyMAfi.mjs.map
|
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { EventEmitter, Output, Input, Component } from '@angular/core';
|
|
3
3
|
import * as i2 from 'primeng/dialog';
|
|
4
4
|
import { DialogModule } from 'primeng/dialog';
|
|
5
|
-
import { d as ParametricDialogComponent } from './wuic-framework-lib-wuic-framework-lib-
|
|
5
|
+
import { d as ParametricDialogComponent } from './wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs';
|
|
6
6
|
|
|
7
7
|
class PromptDialogFallbackHostComponent {
|
|
8
8
|
datasource;
|
|
@@ -96,4 +96,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
96
96
|
}] } });
|
|
97
97
|
|
|
98
98
|
export { PromptDialogFallbackHostComponent };
|
|
99
|
-
//# sourceMappingURL=wuic-framework-lib-prompt-dialog-fallback-host.component-
|
|
99
|
+
//# sourceMappingURL=wuic-framework-lib-prompt-dialog-fallback-host.component-DFLR_EmK.mjs.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { ViewChild, Component } from '@angular/core';
|
|
3
|
-
import { W as WtoolboxService, M as MetadataProviderService } from './wuic-framework-lib-wuic-framework-lib-
|
|
3
|
+
import { W as WtoolboxService, M as MetadataProviderService } from './wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs';
|
|
4
4
|
import * as i3 from 'stimulsoft-designer-angular';
|
|
5
5
|
import { StimulsoftDesignerModule, StimulsoftDesignerComponent } from 'stimulsoft-designer-angular';
|
|
6
6
|
import * as i1 from '@angular/router';
|
|
@@ -191,4 +191,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
191
191
|
}] } });
|
|
192
192
|
|
|
193
193
|
export { ReportDesignerComponent };
|
|
194
|
-
//# sourceMappingURL=wuic-framework-lib-report-designer.component-
|
|
194
|
+
//# sourceMappingURL=wuic-framework-lib-report-designer.component-B_SC7VkW.mjs.map
|
|
@@ -4,7 +4,7 @@ import * as i1 from '@angular/router';
|
|
|
4
4
|
import { NavigationEnd } from '@angular/router';
|
|
5
5
|
import * as i2 from 'stimulsoft-viewer-angular';
|
|
6
6
|
import { StimulsoftViewerModule, StimulsoftViewerComponent } from 'stimulsoft-viewer-angular';
|
|
7
|
-
import { W as WtoolboxService } from './wuic-framework-lib-wuic-framework-lib-
|
|
7
|
+
import { W as WtoolboxService } from './wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs';
|
|
8
8
|
import { e as ensureWuicStimulsoftLicenseRegistered } from './wuic-framework-lib-stimulsoft-license.service-BIyxB4pO.mjs';
|
|
9
9
|
|
|
10
10
|
class ReportViewerComponent {
|
|
@@ -406,4 +406,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
406
406
|
}] } });
|
|
407
407
|
|
|
408
408
|
export { ReportViewerComponent };
|
|
409
|
-
//# sourceMappingURL=wuic-framework-lib-report-viewer.component-
|
|
409
|
+
//# sourceMappingURL=wuic-framework-lib-report-viewer.component-BTK-p8xF.mjs.map
|
|
@@ -8,7 +8,7 @@ import interactionPlugin from '@fullcalendar/interaction';
|
|
|
8
8
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
|
9
9
|
import * as i1 from '@angular/platform-browser';
|
|
10
10
|
import { Title } from '@angular/platform-browser';
|
|
11
|
-
import {
|
|
11
|
+
import { o as FilterInfo, p as FilterItem, W as WtoolboxService, d as ParametricDialogComponent, M as MetadataProviderService, D as DynamicGenericTemplateComponent, T as TranslationManagerService } from './wuic-framework-lib-wuic-framework-lib-DDokY6wY.mjs';
|
|
12
12
|
import { BehaviorSubject } from 'rxjs';
|
|
13
13
|
|
|
14
14
|
// https://fullcalendar.io/docs/initialize-globals#premium-bundle -
|
|
@@ -301,7 +301,12 @@ class SchedulerListComponent {
|
|
|
301
301
|
}
|
|
302
302
|
else {
|
|
303
303
|
if (schedOptions.titleFunction) {
|
|
304
|
-
|
|
304
|
+
// skills/typed-localized-exceptions: cached compiled fn → wrap il
|
|
305
|
+
// call-site (non la compile) cosi' ogni invocazione runtime e' protetta
|
|
306
|
+
// (titleFunction(record) viene chiamata per ogni evento renderizzato).
|
|
307
|
+
const compiledTitleFn = new Function('record', schedOptions.titleFunction);
|
|
308
|
+
const route = this.metaInfo?.tableMetadata?.md_route_name;
|
|
309
|
+
this.titleFunction = (record) => WtoolboxService.runUserCallbackSync('archetypes.scheduler.titleFunction', () => compiledTitleFn(record), [], { archetype: 'scheduler', route });
|
|
305
310
|
}
|
|
306
311
|
}
|
|
307
312
|
}
|
|
@@ -327,7 +332,7 @@ class SchedulerListComponent {
|
|
|
327
332
|
var title = this.metaInfo.tableMetadata.md_display_string;
|
|
328
333
|
this.titleService.setTitle(title);
|
|
329
334
|
const template = this.itemTemplateString || MetadataProviderService.widgetDefinition.schedulerEventTemplate;
|
|
330
|
-
const component = DynamicGenericTemplateComponent.getComponentFromTemplate(template || '');
|
|
335
|
+
const component = DynamicGenericTemplateComponent.getComponentFromTemplate(template || '', 'md_props_bag.archetypes.scheduler.itemTemplate', String(this.metaInfo?.tableMetadata?.md_route_name || ''));
|
|
331
336
|
this.itemTemplate = component;
|
|
332
337
|
if (info.resultInfo.dato) {
|
|
333
338
|
this.data = this.parseData(info.resultInfo.dato);
|
|
@@ -359,6 +364,9 @@ class SchedulerListComponent {
|
|
|
359
364
|
* @returns Struttura dati prodotta da `parseData` dopo normalizzazione/elaborazione.
|
|
360
365
|
*/
|
|
361
366
|
parseData(data) {
|
|
367
|
+
return WtoolboxService.wrapArchetypeLifecycleSync('scheduler', 'parseData', () => this._parseDataInternal(data), { route: this.metaInfo?.tableMetadata?.md_route_name }, { fallback: [] });
|
|
368
|
+
}
|
|
369
|
+
_parseDataInternal(data) {
|
|
362
370
|
var startcol = this.metaInfo.columnMetadata.find(c => c.mc_nome_colonna == this.fromField);
|
|
363
371
|
var endcol = this.metaInfo.columnMetadata.find(c => c.mc_nome_colonna == this.toField);
|
|
364
372
|
const allDay = String(startcol?.mc_ui_column_type || '').trim().toLowerCase() === 'date';
|
|
@@ -583,4 +591,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
583
591
|
}] } });
|
|
584
592
|
|
|
585
593
|
export { SchedulerListComponent };
|
|
586
|
-
//# sourceMappingURL=wuic-framework-lib-scheduler-list.component-
|
|
594
|
+
//# sourceMappingURL=wuic-framework-lib-scheduler-list.component-CIoGVf4O.mjs.map
|