@cauca-911/datagrid 21.3.0 → 21.3.1
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { ViewChild, HostBinding, Input, Optional, ViewEncapsulation, Component, EventEmitter, input, Output, Injectable, InjectionToken, signal, ContentChild, ContentChildren, Inject, ChangeDetectionStrategy, QueryList, inject, output, TemplateRef, forwardRef, computed, model } from '@angular/core';
|
|
2
|
+
import { ViewChild, HostBinding, Input, Optional, ViewEncapsulation, Component, EventEmitter, input, Output, Injectable, InjectionToken, signal, ContentChild, ContentChildren, Inject, ChangeDetectionStrategy, QueryList, inject, output, TemplateRef, DestroyRef, makeEnvironmentProviders, provideAppInitializer, forwardRef, computed, model } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/material/table';
|
|
4
4
|
import { MatColumnDef, MatCellDef, MatHeaderCellDef, MatFooterCellDef, MatTable, MatHeaderRowDef, MatFooterRowDef, MatNoDataRow, MatRowDef, MatTableDataSource, MatHeaderCell, MatFooterCell, MatRow, MatHeaderRow, MatFooterRow, MatCell } from '@angular/material/table';
|
|
5
5
|
import { CDK_DRAG_CONFIG, moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
|
@@ -16,7 +16,7 @@ import { MatInputModule } from '@angular/material/input';
|
|
|
16
16
|
import { IconButtonComponent, RaisedButtonComponent, BasicButtonComponent, StrokedButtonComponent, MenuItemComponent, StatusMessageComponent, IconComponent, Iso8601TimeSpanPipe } from '@cauca-911/material';
|
|
17
17
|
import * as i1$3 from '@ngx-translate/core';
|
|
18
18
|
import { TranslatePipe } from '@ngx-translate/core';
|
|
19
|
-
import { Subject, debounceTime, takeUntil, BehaviorSubject, of, distinctUntilChanged } from 'rxjs';
|
|
19
|
+
import { Subject, debounceTime, takeUntil, BehaviorSubject, of, distinctUntilChanged, filter } from 'rxjs';
|
|
20
20
|
import { MatSort, MatSortHeader } from '@angular/material/sort';
|
|
21
21
|
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
|
22
22
|
import * as i1$4 from '@angular/material/card';
|
|
@@ -28,10 +28,11 @@ import { MatMenuModule } from '@angular/material/menu';
|
|
|
28
28
|
import { NgTemplateOutlet, NgStyle, NgClass, DatePipe } from '@angular/common';
|
|
29
29
|
import * as i1$5 from '@angular/material/progress-spinner';
|
|
30
30
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
31
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
32
|
+
import { Router, ActivatedRoute, NavigationEnd, RouterLink } from '@angular/router';
|
|
31
33
|
import { ODataDataSource } from 'odata-data-source';
|
|
32
34
|
import * as i1$6 from '@angular/common/http';
|
|
33
35
|
import { MatTooltip } from '@angular/material/tooltip';
|
|
34
|
-
import { RouterLink } from '@angular/router';
|
|
35
36
|
import dayjs from 'dayjs';
|
|
36
37
|
|
|
37
38
|
class DataGridRowDropEvent {
|
|
@@ -821,21 +822,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
821
822
|
}]
|
|
822
823
|
}], ctorParameters: () => [{ type: i1$6.HttpClient }] });
|
|
823
824
|
|
|
825
|
+
const PARAM_BASE_NAMES = {
|
|
826
|
+
filter: 'filter',
|
|
827
|
+
sort: 'sort',
|
|
828
|
+
direction: 'dir',
|
|
829
|
+
pageIndex: 'page',
|
|
830
|
+
pageSize: 'size',
|
|
831
|
+
};
|
|
832
|
+
/**
|
|
833
|
+
* Builds the query param name for a given base name and optional grid state key.
|
|
834
|
+
* With a key, the scheme is `<key><CapitalizedBaseName>` (e.g. key "alerts" + base "filter" -> "alertsFilter").
|
|
835
|
+
* Without a key, the plain base name is used (e.g. "filter").
|
|
836
|
+
*/
|
|
837
|
+
function paramName(baseName, key) {
|
|
838
|
+
if (!key) {
|
|
839
|
+
return baseName;
|
|
840
|
+
}
|
|
841
|
+
return `${key}${baseName.charAt(0).toUpperCase()}${baseName.slice(1)}`;
|
|
842
|
+
}
|
|
843
|
+
function toQueryParams(state, key = '') {
|
|
844
|
+
const params = {};
|
|
845
|
+
if (state.filter) {
|
|
846
|
+
params[paramName(PARAM_BASE_NAMES.filter, key)] = state.filter;
|
|
847
|
+
}
|
|
848
|
+
if (state.sort) {
|
|
849
|
+
params[paramName(PARAM_BASE_NAMES.sort, key)] = state.sort;
|
|
850
|
+
}
|
|
851
|
+
if (state.direction) {
|
|
852
|
+
params[paramName(PARAM_BASE_NAMES.direction, key)] = state.direction;
|
|
853
|
+
}
|
|
854
|
+
if (state.pageIndex) {
|
|
855
|
+
params[paramName(PARAM_BASE_NAMES.pageIndex, key)] = state.pageIndex;
|
|
856
|
+
}
|
|
857
|
+
if (state.pageSize) {
|
|
858
|
+
params[paramName(PARAM_BASE_NAMES.pageSize, key)] = state.pageSize;
|
|
859
|
+
}
|
|
860
|
+
return params;
|
|
861
|
+
}
|
|
862
|
+
function fromQueryParams(map, key = '') {
|
|
863
|
+
const state = {};
|
|
864
|
+
const filter = map.get(paramName(PARAM_BASE_NAMES.filter, key));
|
|
865
|
+
if (filter) {
|
|
866
|
+
state.filter = filter;
|
|
867
|
+
}
|
|
868
|
+
const sort = map.get(paramName(PARAM_BASE_NAMES.sort, key));
|
|
869
|
+
if (sort) {
|
|
870
|
+
state.sort = sort;
|
|
871
|
+
}
|
|
872
|
+
const direction = map.get(paramName(PARAM_BASE_NAMES.direction, key));
|
|
873
|
+
if (direction === 'asc' || direction === 'desc') {
|
|
874
|
+
state.direction = direction;
|
|
875
|
+
}
|
|
876
|
+
const pageIndex = parsePositiveInteger(map.get(paramName(PARAM_BASE_NAMES.pageIndex, key)));
|
|
877
|
+
if (pageIndex !== undefined) {
|
|
878
|
+
state.pageIndex = pageIndex;
|
|
879
|
+
}
|
|
880
|
+
const pageSize = parsePositiveInteger(map.get(paramName(PARAM_BASE_NAMES.pageSize, key)));
|
|
881
|
+
if (pageSize !== undefined) {
|
|
882
|
+
state.pageSize = pageSize;
|
|
883
|
+
}
|
|
884
|
+
return state;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Returns a Params object with every grid-state param name mapped to `null` for the given key.
|
|
888
|
+
* Combined with `queryParamsHandling: 'merge'`, this lets the grid explicitly clear stale
|
|
889
|
+
* params (e.g. a previously-set filter) instead of leaving them stuck in the URL.
|
|
890
|
+
*/
|
|
891
|
+
function emptyQueryParams(key = '') {
|
|
892
|
+
const params = {};
|
|
893
|
+
Object.values(PARAM_BASE_NAMES).forEach((baseName) => {
|
|
894
|
+
params[paramName(baseName, key)] = null;
|
|
895
|
+
});
|
|
896
|
+
return params;
|
|
897
|
+
}
|
|
898
|
+
function paramsEqual(a, b) {
|
|
899
|
+
const aKeys = Object.keys(a).filter((paramKey) => a[paramKey] !== null && a[paramKey] !== undefined);
|
|
900
|
+
const bKeys = Object.keys(b).filter((paramKey) => b[paramKey] !== null && b[paramKey] !== undefined);
|
|
901
|
+
if (aKeys.length !== bKeys.length) {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
return aKeys.every((paramKey) => String(a[paramKey]) === String(b[paramKey]));
|
|
905
|
+
}
|
|
906
|
+
function parsePositiveInteger(value) {
|
|
907
|
+
if (!value) {
|
|
908
|
+
return undefined;
|
|
909
|
+
}
|
|
910
|
+
const parsed = Number(value);
|
|
911
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
912
|
+
return undefined;
|
|
913
|
+
}
|
|
914
|
+
return parsed;
|
|
915
|
+
}
|
|
916
|
+
|
|
824
917
|
class OdataGridComponent extends BaseDataGridComponent {
|
|
825
918
|
constructor(translateService, listing) {
|
|
826
919
|
super(translateService, inject(PREFERENCE_SERVICE_TOKEN));
|
|
827
920
|
this.listing = listing;
|
|
828
921
|
this.showTableHeader = input(true, ...(ngDevMode ? [{ debugName: "showTableHeader" }] : []));
|
|
922
|
+
/** Master switch: when true, the grid's filter/sort/page are synced with the URL query params and restored when returning from a detail page. Off by default. */
|
|
923
|
+
this.persistState = input(false, ...(ngDevMode ? [{ debugName: "persistState" }] : []));
|
|
924
|
+
/** Optional prefix for the persisted query params, so two independent grids on the same route don't collide (e.g. "alerts" -> "alertsFilter"). */
|
|
925
|
+
this.stateKey = input('', ...(ngDevMode ? [{ debugName: "stateKey" }] : []));
|
|
829
926
|
this.showHeader = true;
|
|
830
927
|
this.idField = 'id';
|
|
831
928
|
this.itemClick = new EventEmitter();
|
|
832
929
|
this.refreshRequested = new EventEmitter();
|
|
833
930
|
this.showRefreshButton = false;
|
|
834
931
|
this.baseUrl = inject(CaucaCoreService).getConfig().apiUrl;
|
|
932
|
+
this.router = inject(Router, { optional: true });
|
|
933
|
+
this.route = inject(ActivatedRoute, { optional: true });
|
|
934
|
+
this.destroyRef = inject(DestroyRef);
|
|
935
|
+
this.lastWrittenParams = {};
|
|
835
936
|
}
|
|
836
937
|
ngOnDestroy() {
|
|
837
938
|
this.listing.destroy();
|
|
838
939
|
}
|
|
940
|
+
ngAfterViewInit() {
|
|
941
|
+
if (!this.canPersistState() || !this.header) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (this.pendingRestoredFilter !== undefined) {
|
|
945
|
+
this.header.filterControl.setValue(this.pendingRestoredFilter, { emitEvent: false });
|
|
946
|
+
this.header.showClearButton = !!this.pendingRestoredFilter;
|
|
947
|
+
}
|
|
948
|
+
this.header.filterChange
|
|
949
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
950
|
+
.subscribe(() => this.writeCurrentUrlState());
|
|
951
|
+
}
|
|
839
952
|
refreshData() {
|
|
840
953
|
this.listing.refresh();
|
|
841
954
|
this.refreshRequested.emit();
|
|
@@ -856,18 +969,25 @@ class OdataGridComponent extends BaseDataGridComponent {
|
|
|
856
969
|
}
|
|
857
970
|
refreshFilter() {
|
|
858
971
|
if (this.filterPredicate) {
|
|
859
|
-
this.listing.updateFilters(this.filterPredicate(toLowerCaseAndWithoutDiacritics(this.header
|
|
972
|
+
this.listing.updateFilters(this.filterPredicate(toLowerCaseAndWithoutDiacritics(this.header?.filterControl?.value)));
|
|
860
973
|
}
|
|
861
974
|
}
|
|
862
975
|
setUpFilterPredicate() {
|
|
976
|
+
let filters = this.filterPredicate?.('') ?? [];
|
|
977
|
+
if (this.canPersistState()) {
|
|
978
|
+
filters = this.restoreStateBeforeInitialLoad() ?? filters;
|
|
979
|
+
}
|
|
863
980
|
this.listing.initialize({
|
|
864
981
|
baseUrl: this.baseUrl,
|
|
865
982
|
resourceName: this.resourceName,
|
|
866
983
|
paginator: this.paginator,
|
|
867
984
|
sort: this.sort,
|
|
868
985
|
initialSort: this.baseSort,
|
|
869
|
-
filters
|
|
986
|
+
filters,
|
|
870
987
|
});
|
|
988
|
+
if (this.canPersistState()) {
|
|
989
|
+
this.setUpUrlStatePersistence();
|
|
990
|
+
}
|
|
871
991
|
}
|
|
872
992
|
setUpSort(sort) {
|
|
873
993
|
this.sort = sort;
|
|
@@ -900,8 +1020,89 @@ class OdataGridComponent extends BaseDataGridComponent {
|
|
|
900
1020
|
}
|
|
901
1021
|
this.allDisplayedColumns.set([...columns]);
|
|
902
1022
|
}
|
|
1023
|
+
canPersistState() {
|
|
1024
|
+
return this.persistState() && !!this.router && !!this.route;
|
|
1025
|
+
}
|
|
1026
|
+
restoreStateBeforeInitialLoad() {
|
|
1027
|
+
this.defaultPageSize = this.paginator?.pageSize;
|
|
1028
|
+
const restoredState = fromQueryParams(this.route.snapshot.queryParamMap, this.stateKey());
|
|
1029
|
+
this.applySortAndPage(restoredState);
|
|
1030
|
+
this.pendingRestoredFilter = restoredState.filter;
|
|
1031
|
+
if (restoredState.filter === undefined || !this.filterPredicate) {
|
|
1032
|
+
return undefined;
|
|
1033
|
+
}
|
|
1034
|
+
return this.filterPredicate(toLowerCaseAndWithoutDiacritics(restoredState.filter));
|
|
1035
|
+
}
|
|
1036
|
+
setUpUrlStatePersistence() {
|
|
1037
|
+
this.lastWrittenParams = toQueryParams(fromQueryParams(this.route.snapshot.queryParamMap, this.stateKey()), this.stateKey());
|
|
1038
|
+
this.sort?.sortChange
|
|
1039
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1040
|
+
.subscribe(() => this.writeCurrentUrlState());
|
|
1041
|
+
this.paginator?.page
|
|
1042
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1043
|
+
.subscribe(() => this.writeCurrentUrlState());
|
|
1044
|
+
this.route.queryParamMap
|
|
1045
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
1046
|
+
.subscribe((paramMap) => this.reactToExternalUrlStateChange(paramMap));
|
|
1047
|
+
}
|
|
1048
|
+
applySortAndPage(state) {
|
|
1049
|
+
if (state.sort && this.sort) {
|
|
1050
|
+
this.sort.active = state.sort;
|
|
1051
|
+
this.sort.direction = state.direction ?? '';
|
|
1052
|
+
}
|
|
1053
|
+
if (this.paginator) {
|
|
1054
|
+
if (state.pageIndex !== undefined) {
|
|
1055
|
+
this.paginator.pageIndex = state.pageIndex;
|
|
1056
|
+
}
|
|
1057
|
+
if (state.pageSize !== undefined) {
|
|
1058
|
+
this.paginator.pageSize = state.pageSize;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
currentUrlState() {
|
|
1063
|
+
const pageSize = this.paginator?.pageSize;
|
|
1064
|
+
return {
|
|
1065
|
+
filter: this.header?.filterControl.value || undefined,
|
|
1066
|
+
sort: this.sort?.active || undefined,
|
|
1067
|
+
direction: this.sort?.direction || undefined,
|
|
1068
|
+
pageIndex: this.paginator?.pageIndex,
|
|
1069
|
+
pageSize: pageSize !== undefined && pageSize !== this.defaultPageSize ? pageSize : undefined,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
writeCurrentUrlState() {
|
|
1073
|
+
const params = toQueryParams(this.currentUrlState(), this.stateKey());
|
|
1074
|
+
if (paramsEqual(params, this.lastWrittenParams)) {
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
this.lastWrittenParams = params;
|
|
1078
|
+
this.router.navigate([], {
|
|
1079
|
+
relativeTo: this.route,
|
|
1080
|
+
queryParams: { ...emptyQueryParams(this.stateKey()), ...params },
|
|
1081
|
+
queryParamsHandling: 'merge',
|
|
1082
|
+
replaceUrl: true,
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
reactToExternalUrlStateChange(paramMap) {
|
|
1086
|
+
const state = fromQueryParams(paramMap, this.stateKey());
|
|
1087
|
+
const params = toQueryParams(state, this.stateKey());
|
|
1088
|
+
if (paramsEqual(params, this.lastWrittenParams)) {
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
this.lastWrittenParams = params;
|
|
1092
|
+
this.applySortAndPage(state);
|
|
1093
|
+
if (this.header) {
|
|
1094
|
+
this.header.filterControl.setValue(state.filter ?? '', { emitEvent: false });
|
|
1095
|
+
this.header.showClearButton = !!state.filter;
|
|
1096
|
+
}
|
|
1097
|
+
if (this.filterPredicate) {
|
|
1098
|
+
this.refreshFilter();
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
this.listing.forceReloadFilter();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
903
1104
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: OdataGridComponent, deps: [{ token: i1$3.TranslateService }, { token: OdataListingService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
904
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: OdataGridComponent, isStandalone: true, selector: "cauca-odata-grid", inputs: { showTableHeader: { classPropertyName: "showTableHeader", publicName: "showTableHeader", isSignal: true, isRequired: false, transformFunction: null }, baseSort: { classPropertyName: "baseSort", publicName: "baseSort", isSignal: false, isRequired: false, transformFunction: null }, filterPredicate: { classPropertyName: "filterPredicate", publicName: "filterPredicate", isSignal: false, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: false, isRequired: false, transformFunction: null }, selectedRowId: { classPropertyName: "selectedRowId", publicName: "selectedRowId", isSignal: false, isRequired: false, transformFunction: null }, idField: { classPropertyName: "idField", publicName: "idField", isSignal: false, isRequired: false, transformFunction: null }, showRefreshButton: { classPropertyName: "showRefreshButton", publicName: "showRefreshButton", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", refreshRequested: "refreshRequested" }, providers: [OdataListingService], queries: [{ propertyName: "rowDetailTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (showHeader) {\n <cauca-data-grid-header\n [disableAddButton]=\"disableAddButton()\"\n [showRefreshButton]=\"showRefreshButton\" (refreshRequest)=\"refreshData()\"\n [showAddButton]=\"showAddButton\"\n [addButtonLabel]=\"addButtonLabel || defaultAddButtonLabel\"\n (addButtonClick)=\"addButtonClick.emit($event)\" (filterChange)=\"applyFilter($event)\">\n <ng-content select=\"[filterRow]\" ngProjectAs=\"[filterRow]\" />\n </cauca-data-grid-header>\n}\n\n<ng-content select=\"[customHeader]\" ngProjectAs=\"[customHeader]\" />\n\n@if (showTableOptions) {\n <cauca-data-grid-table-options [showColumnViewer]=\"showColumnViewer\" [gridName]=\"resourceName\" (densityChanged)=\"onDensityChanged($event)\" (columnsChanged)=\"onColumnsChanged($event)\" [allColumns]=\"regularColumns\">\n <ng-content select=\"[customFilter]\" ngProjectAs=\"[customFilter]\" />\n </cauca-data-grid-table-options>\n}\n\n<div class=\"relative\">\n <table mat-table [dataSource]=\"listing.dataSource\" aria-describedby=\"Data Grid\" multiTemplateDataRows>\n @if (showExpandButton()) {\n <ng-container matColumnDef=\"expand\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let row\">\n <div class=\"align-commands\">\n <cauca-icon-button (buttonClick)=\"onExpand(row)\" color=\"primary\" class=\"button-icon\" [icon]=\"row === expandedElement() ? 'keyboard_arrow_up' : 'keyboard_arrow_down'\" />\n </div>\n </td>\n </ng-container>\n }\n\n <ng-content></ng-content>\n @if(showTableHeader()) {\n <tr mat-header-row *matHeaderRowDef=\"allDisplayedColumns(); sticky: true\"></tr>\n }\n\n <tr mat-row *matRowDef=\"let row; columns: allDisplayedColumns()\"\n [class.showClick]=\"itemClick.observers.length > 0\"\n [class.compact]=\"preference.gridDensity === density.Compact\"\n [class.standard]=\"preference.gridDensity === density.Standard\"\n [class.comfortable]=\"preference.gridDensity === density.Comfortable\"\n [class.selected]=\"selectedRowId === row[idField]\"\n (click)=\"itemClick.emit(row)\"\n onkeypress=\"itemClick.emit(row)\">\n </tr>\n\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"allDisplayedColumns().length\">\n <div class=\"grid-element-detail-wrapper\" [class.grid-element-detail-wrapper-expanded]=\"row === expandedElement()\">\n <div class=\"grid-element-detail\">\n @if (row === expandedElement()) {\n <template [ngTemplateOutlet]=\"rowDetailTemplate\" [ngTemplateOutletContext]=\"{ row: expandedElement() }\"></template>\n }\n </div>\n </div>\n </td>\n </ng-container>\n\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"grid-detail-row\"></tr>\n\n <ng-container *matNoDataRow>\n @if(listing.loading() === false) {\n <ng-container>\n <tr class=\"mat-row\">\n @if (listing.error() === false) {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"noData\" />\n </th>\n } @else {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"error\" />\n </th>\n }\n </tr>\n </ng-container>\n }\n </ng-container>\n </table>\n\n <cauca-data-grid-progress-spiner [useBackground]=\"false\" [isLoading]=\"listing.loading()\" />\n\n</div>\n\n<mat-paginator [hidePageSize]=\"hidePageSize()\" [pageSizeOptions]=\"[5, 10, 25, 50]\" [pageSize]=\"10\" />\n", styles: ["table{width:100%;table-layout:fixed;--mat-table-header-container-height: 52px;--mat-table-footer-container-height: 48px;--mat-table-row-item-container-height: 48px;--mat-table-header-container-height: 56px}.relative{position:relative}.mat-column-expand{width:72px}cauca-data-grid-progress-spiner{left:50%;top:50%;transform:translate(-50%,-50%);position:absolute;z-index:101}tr.mat-mdc-row{transition:background-color .2s ease-out .1s}tr.mat-mdc-row:hover{background:#f5f5f5}tr.mat-mdc-row.selected{background:#249edb14}tr.mat-mdc-row.selected:hover{background:#249edb1a}cauca-data-grid-header{margin:16px}.compact{line-height:48px!important}.standard{line-height:56px!important}.comfortable{line-height:62px!important}.showClick{cursor:pointer}tr.grid-detail-row{height:0}.grid-element-row td{border-bottom-width:0;background-color:#fafafa}.mat-column-expandedDetail{background-color:#fafafa}.grid-element-detail-wrapper{overflow:hidden;display:grid;grid-template-rows:0fr;grid-template-columns:100%;transition:grid-template-rows 225ms cubic-bezier(.4,0,.2,1)}.grid-element-detail-wrapper-expanded{grid-template-rows:1fr}.grid-element-detail{display:flex;min-height:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type:
|
|
1105
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: OdataGridComponent, isStandalone: true, selector: "cauca-odata-grid", inputs: { showTableHeader: { classPropertyName: "showTableHeader", publicName: "showTableHeader", isSignal: true, isRequired: false, transformFunction: null }, persistState: { classPropertyName: "persistState", publicName: "persistState", isSignal: true, isRequired: false, transformFunction: null }, stateKey: { classPropertyName: "stateKey", publicName: "stateKey", isSignal: true, isRequired: false, transformFunction: null }, baseSort: { classPropertyName: "baseSort", publicName: "baseSort", isSignal: false, isRequired: false, transformFunction: null }, filterPredicate: { classPropertyName: "filterPredicate", publicName: "filterPredicate", isSignal: false, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: false, isRequired: false, transformFunction: null }, selectedRowId: { classPropertyName: "selectedRowId", publicName: "selectedRowId", isSignal: false, isRequired: false, transformFunction: null }, idField: { classPropertyName: "idField", publicName: "idField", isSignal: false, isRequired: false, transformFunction: null }, showRefreshButton: { classPropertyName: "showRefreshButton", publicName: "showRefreshButton", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", refreshRequested: "refreshRequested" }, providers: [OdataListingService], queries: [{ propertyName: "rowDetailTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (showHeader) {\n <cauca-data-grid-header\n [disableAddButton]=\"disableAddButton()\"\n [showRefreshButton]=\"showRefreshButton\" (refreshRequest)=\"refreshData()\"\n [showAddButton]=\"showAddButton\"\n [addButtonLabel]=\"addButtonLabel || defaultAddButtonLabel\"\n (addButtonClick)=\"addButtonClick.emit($event)\" (filterChange)=\"applyFilter($event)\">\n <ng-content select=\"[filterRow]\" ngProjectAs=\"[filterRow]\" />\n </cauca-data-grid-header>\n}\n\n<ng-content select=\"[customHeader]\" ngProjectAs=\"[customHeader]\" />\n\n@if (showTableOptions) {\n <cauca-data-grid-table-options [showColumnViewer]=\"showColumnViewer\" [gridName]=\"resourceName\" (densityChanged)=\"onDensityChanged($event)\" (columnsChanged)=\"onColumnsChanged($event)\" [allColumns]=\"regularColumns\">\n <ng-content select=\"[customFilter]\" ngProjectAs=\"[customFilter]\" />\n </cauca-data-grid-table-options>\n}\n\n<div class=\"relative\">\n <table mat-table [dataSource]=\"listing.dataSource\" aria-describedby=\"Data Grid\" multiTemplateDataRows>\n @if (showExpandButton()) {\n <ng-container matColumnDef=\"expand\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let row\">\n <div class=\"align-commands\">\n <cauca-icon-button (buttonClick)=\"onExpand(row)\" color=\"primary\" class=\"button-icon\" [icon]=\"row === expandedElement() ? 'keyboard_arrow_up' : 'keyboard_arrow_down'\" />\n </div>\n </td>\n </ng-container>\n }\n\n <ng-content></ng-content>\n @if(showTableHeader()) {\n <tr mat-header-row *matHeaderRowDef=\"allDisplayedColumns(); sticky: true\"></tr>\n }\n\n <tr mat-row *matRowDef=\"let row; columns: allDisplayedColumns()\"\n [class.showClick]=\"itemClick.observers.length > 0\"\n [class.compact]=\"preference.gridDensity === density.Compact\"\n [class.standard]=\"preference.gridDensity === density.Standard\"\n [class.comfortable]=\"preference.gridDensity === density.Comfortable\"\n [class.selected]=\"selectedRowId === row[idField]\"\n (click)=\"itemClick.emit(row)\"\n onkeypress=\"itemClick.emit(row)\">\n </tr>\n\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"allDisplayedColumns().length\">\n <div class=\"grid-element-detail-wrapper\" [class.grid-element-detail-wrapper-expanded]=\"row === expandedElement()\">\n <div class=\"grid-element-detail\">\n @if (row === expandedElement()) {\n <template [ngTemplateOutlet]=\"rowDetailTemplate\" [ngTemplateOutletContext]=\"{ row: expandedElement() }\"></template>\n }\n </div>\n </div>\n </td>\n </ng-container>\n\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"grid-detail-row\"></tr>\n\n <ng-container *matNoDataRow>\n @if(listing.loading() === false) {\n <ng-container>\n <tr class=\"mat-row\">\n @if (listing.error() === false) {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"noData\" />\n </th>\n } @else {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"error\" />\n </th>\n }\n </tr>\n </ng-container>\n }\n </ng-container>\n </table>\n\n <cauca-data-grid-progress-spiner [useBackground]=\"false\" [isLoading]=\"listing.loading()\" />\n\n</div>\n\n<mat-paginator [hidePageSize]=\"hidePageSize()\" [pageSizeOptions]=\"[5, 10, 25, 50]\" [pageSize]=\"10\" />\n", styles: ["table{width:100%;table-layout:fixed;--mat-table-header-container-height: 52px;--mat-table-footer-container-height: 48px;--mat-table-row-item-container-height: 48px;--mat-table-header-container-height: 56px}.relative{position:relative}.mat-column-expand{width:72px}cauca-data-grid-progress-spiner{left:50%;top:50%;transform:translate(-50%,-50%);position:absolute;z-index:101}tr.mat-mdc-row{transition:background-color .2s ease-out .1s}tr.mat-mdc-row:hover{background:#f5f5f5}tr.mat-mdc-row.selected{background:#249edb14}tr.mat-mdc-row.selected:hover{background:#249edb1a}cauca-data-grid-header{margin:16px}.compact{line-height:48px!important}.standard{line-height:56px!important}.comfortable{line-height:62px!important}.showClick{cursor:pointer}tr.grid-detail-row{height:0}.grid-element-row td{border-bottom-width:0;background-color:#fafafa}.mat-column-expandedDetail{background-color:#fafafa}.grid-element-detail-wrapper{overflow:hidden;display:grid;grid-template-rows:0fr;grid-template-columns:100%;transition:grid-template-rows 225ms cubic-bezier(.4,0,.2,1)}.grid-element-detail-wrapper-expanded{grid-template-rows:1fr}.grid-element-detail{display:flex;min-height:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type:
|
|
905
1106
|
// Material table structure:
|
|
906
1107
|
MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: MatCellDef, selector: "[matCellDef]" }, { kind: "component", type: MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "directive", type: MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "component", type: MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "component", type:
|
|
907
1108
|
// Material extras
|
|
@@ -927,7 +1128,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
927
1128
|
DataGridProgressSpinerComponent,
|
|
928
1129
|
StatusMessageComponent,
|
|
929
1130
|
], template: "@if (showHeader) {\n <cauca-data-grid-header\n [disableAddButton]=\"disableAddButton()\"\n [showRefreshButton]=\"showRefreshButton\" (refreshRequest)=\"refreshData()\"\n [showAddButton]=\"showAddButton\"\n [addButtonLabel]=\"addButtonLabel || defaultAddButtonLabel\"\n (addButtonClick)=\"addButtonClick.emit($event)\" (filterChange)=\"applyFilter($event)\">\n <ng-content select=\"[filterRow]\" ngProjectAs=\"[filterRow]\" />\n </cauca-data-grid-header>\n}\n\n<ng-content select=\"[customHeader]\" ngProjectAs=\"[customHeader]\" />\n\n@if (showTableOptions) {\n <cauca-data-grid-table-options [showColumnViewer]=\"showColumnViewer\" [gridName]=\"resourceName\" (densityChanged)=\"onDensityChanged($event)\" (columnsChanged)=\"onColumnsChanged($event)\" [allColumns]=\"regularColumns\">\n <ng-content select=\"[customFilter]\" ngProjectAs=\"[customFilter]\" />\n </cauca-data-grid-table-options>\n}\n\n<div class=\"relative\">\n <table mat-table [dataSource]=\"listing.dataSource\" aria-describedby=\"Data Grid\" multiTemplateDataRows>\n @if (showExpandButton()) {\n <ng-container matColumnDef=\"expand\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let row\">\n <div class=\"align-commands\">\n <cauca-icon-button (buttonClick)=\"onExpand(row)\" color=\"primary\" class=\"button-icon\" [icon]=\"row === expandedElement() ? 'keyboard_arrow_up' : 'keyboard_arrow_down'\" />\n </div>\n </td>\n </ng-container>\n }\n\n <ng-content></ng-content>\n @if(showTableHeader()) {\n <tr mat-header-row *matHeaderRowDef=\"allDisplayedColumns(); sticky: true\"></tr>\n }\n\n <tr mat-row *matRowDef=\"let row; columns: allDisplayedColumns()\"\n [class.showClick]=\"itemClick.observers.length > 0\"\n [class.compact]=\"preference.gridDensity === density.Compact\"\n [class.standard]=\"preference.gridDensity === density.Standard\"\n [class.comfortable]=\"preference.gridDensity === density.Comfortable\"\n [class.selected]=\"selectedRowId === row[idField]\"\n (click)=\"itemClick.emit(row)\"\n onkeypress=\"itemClick.emit(row)\">\n </tr>\n\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let row\" [attr.colspan]=\"allDisplayedColumns().length\">\n <div class=\"grid-element-detail-wrapper\" [class.grid-element-detail-wrapper-expanded]=\"row === expandedElement()\">\n <div class=\"grid-element-detail\">\n @if (row === expandedElement()) {\n <template [ngTemplateOutlet]=\"rowDetailTemplate\" [ngTemplateOutletContext]=\"{ row: expandedElement() }\"></template>\n }\n </div>\n </div>\n </td>\n </ng-container>\n\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"grid-detail-row\"></tr>\n\n <ng-container *matNoDataRow>\n @if(listing.loading() === false) {\n <ng-container>\n <tr class=\"mat-row\">\n @if (listing.error() === false) {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"noData\" />\n </th>\n } @else {\n <th class=\"mat-cell data-grid-message\"\n [attr.colspan]=\"allDisplayedColumns().length\">\n <cauca-status-message type=\"error\" />\n </th>\n }\n </tr>\n </ng-container>\n }\n </ng-container>\n </table>\n\n <cauca-data-grid-progress-spiner [useBackground]=\"false\" [isLoading]=\"listing.loading()\" />\n\n</div>\n\n<mat-paginator [hidePageSize]=\"hidePageSize()\" [pageSizeOptions]=\"[5, 10, 25, 50]\" [pageSize]=\"10\" />\n", styles: ["table{width:100%;table-layout:fixed;--mat-table-header-container-height: 52px;--mat-table-footer-container-height: 48px;--mat-table-row-item-container-height: 48px;--mat-table-header-container-height: 56px}.relative{position:relative}.mat-column-expand{width:72px}cauca-data-grid-progress-spiner{left:50%;top:50%;transform:translate(-50%,-50%);position:absolute;z-index:101}tr.mat-mdc-row{transition:background-color .2s ease-out .1s}tr.mat-mdc-row:hover{background:#f5f5f5}tr.mat-mdc-row.selected{background:#249edb14}tr.mat-mdc-row.selected:hover{background:#249edb1a}cauca-data-grid-header{margin:16px}.compact{line-height:48px!important}.standard{line-height:56px!important}.comfortable{line-height:62px!important}.showClick{cursor:pointer}tr.grid-detail-row{height:0}.grid-element-row td{border-bottom-width:0;background-color:#fafafa}.mat-column-expandedDetail{background-color:#fafafa}.grid-element-detail-wrapper{overflow:hidden;display:grid;grid-template-rows:0fr;grid-template-columns:100%;transition:grid-template-rows 225ms cubic-bezier(.4,0,.2,1)}.grid-element-detail-wrapper-expanded{grid-template-rows:1fr}.grid-element-detail{display:flex;min-height:0}\n"] }]
|
|
930
|
-
}], ctorParameters: () => [{ type: i1$3.TranslateService }, { type: OdataListingService }], propDecorators: { showTableHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTableHeader", required: false }] }], baseSort: [{
|
|
1131
|
+
}], ctorParameters: () => [{ type: i1$3.TranslateService }, { type: OdataListingService }], propDecorators: { showTableHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTableHeader", required: false }] }], persistState: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistState", required: false }] }], stateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], baseSort: [{
|
|
931
1132
|
type: Input
|
|
932
1133
|
}], filterPredicate: [{
|
|
933
1134
|
type: Input
|
|
@@ -951,6 +1152,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
951
1152
|
args: [MatPaginator, { static: true }]
|
|
952
1153
|
}] } });
|
|
953
1154
|
|
|
1155
|
+
/**
|
|
1156
|
+
* Re-injects a list page's remembered grid query params (filter/sort/page, written by
|
|
1157
|
+
* `OdataGridComponent` when `persistState` is enabled) when the user navigates back to that
|
|
1158
|
+
* list page from one of its own descendant (detail) routes. Any other way of reaching the
|
|
1159
|
+
* list page (menu, bookmark, direct link, refresh) leaves it clean, because the previous URL
|
|
1160
|
+
* won't be a descendant of the list path.
|
|
1161
|
+
*/
|
|
1162
|
+
class GridStateRestorationService {
|
|
1163
|
+
constructor() {
|
|
1164
|
+
this.router = inject(Router);
|
|
1165
|
+
this.rememberedParamsByPath = new Map();
|
|
1166
|
+
this.previousPath = null;
|
|
1167
|
+
this.router.events
|
|
1168
|
+
.pipe(filter((event) => event instanceof NavigationEnd))
|
|
1169
|
+
.subscribe((event) => this.onNavigationEnd(event));
|
|
1170
|
+
}
|
|
1171
|
+
onNavigationEnd(event) {
|
|
1172
|
+
const currentPath = this.pathOnly(event.urlAfterRedirects);
|
|
1173
|
+
const currentParams = this.parseParams(event.urlAfterRedirects);
|
|
1174
|
+
const previousPath = this.previousPath;
|
|
1175
|
+
this.previousPath = currentPath;
|
|
1176
|
+
if (Object.keys(currentParams).length > 0) {
|
|
1177
|
+
this.rememberedParamsByPath.set(currentPath, currentParams);
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
if (this.restoreIfReturningFromDescendant(currentPath, previousPath)) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
this.rememberedParamsByPath.delete(currentPath);
|
|
1184
|
+
}
|
|
1185
|
+
restoreIfReturningFromDescendant(currentPath, previousPath) {
|
|
1186
|
+
if (!previousPath || !previousPath.startsWith(`${currentPath}/`)) {
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
const remembered = this.rememberedParamsByPath.get(currentPath);
|
|
1190
|
+
if (!remembered) {
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
this.router.navigate([currentPath], { queryParams: remembered, replaceUrl: true });
|
|
1194
|
+
return true;
|
|
1195
|
+
}
|
|
1196
|
+
pathOnly(url) {
|
|
1197
|
+
return url.split('?')[0].split('#')[0];
|
|
1198
|
+
}
|
|
1199
|
+
parseParams(url) {
|
|
1200
|
+
const queryString = url.split('?')[1]?.split('#')[0];
|
|
1201
|
+
if (!queryString) {
|
|
1202
|
+
return {};
|
|
1203
|
+
}
|
|
1204
|
+
const params = {};
|
|
1205
|
+
new URLSearchParams(queryString).forEach((value, key) => {
|
|
1206
|
+
params[key] = value;
|
|
1207
|
+
});
|
|
1208
|
+
return params;
|
|
1209
|
+
}
|
|
1210
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: GridStateRestorationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1211
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: GridStateRestorationService, providedIn: 'root' }); }
|
|
1212
|
+
}
|
|
1213
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: GridStateRestorationService, decorators: [{
|
|
1214
|
+
type: Injectable,
|
|
1215
|
+
args: [{
|
|
1216
|
+
providedIn: 'root',
|
|
1217
|
+
}]
|
|
1218
|
+
}], ctorParameters: () => [] });
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Activates the grid list-state restoration feature for the whole application. Add this once
|
|
1222
|
+
* in the app's root providers; it has no effect on pages whose grids don't opt in via
|
|
1223
|
+
* `[persistState]="true"`.
|
|
1224
|
+
*/
|
|
1225
|
+
function provideGridStateRestoration() {
|
|
1226
|
+
return makeEnvironmentProviders([
|
|
1227
|
+
provideAppInitializer(() => {
|
|
1228
|
+
inject(GridStateRestorationService);
|
|
1229
|
+
}),
|
|
1230
|
+
]);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
954
1233
|
class ColorDataGridColumnComponent extends BaseGridColumnComponent {
|
|
955
1234
|
constructor(odata, grid) {
|
|
956
1235
|
super((grid ?? odata)?.table);
|
|
@@ -1429,5 +1708,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1429
1708
|
* Generated bundle index. Do not edit.
|
|
1430
1709
|
*/
|
|
1431
1710
|
|
|
1432
|
-
export { BaseGridColumnComponent, ColorDataGridColumnComponent, DataGridCheckColumnComponent, DataGridColumnComponent, DataGridCommandIconColumnComponent, DataGridCommandsColumnComponent, DataGridComponent, DataGridHeaderComponent, DataGridIconColumnComponent, DataGridMenuColumnComponent, DataGridRowDropEvent, DateGridColumnComponent, Density, GridConfiguration, OdataGridComponent, OdataListingService, PREFERENCE_SERVICE_TOKEN, Preference, SortableDataGridCheckColumnComponent, SortableDataGridColumnComponent, TimeSpanDataGridColumnComponent, TranslationGridColumnComponent, provideCaucaGrid };
|
|
1711
|
+
export { BaseGridColumnComponent, ColorDataGridColumnComponent, DataGridCheckColumnComponent, DataGridColumnComponent, DataGridCommandIconColumnComponent, DataGridCommandsColumnComponent, DataGridComponent, DataGridHeaderComponent, DataGridIconColumnComponent, DataGridMenuColumnComponent, DataGridRowDropEvent, DateGridColumnComponent, Density, GridConfiguration, GridStateRestorationService, OdataGridComponent, OdataListingService, PREFERENCE_SERVICE_TOKEN, Preference, SortableDataGridCheckColumnComponent, SortableDataGridColumnComponent, TimeSpanDataGridColumnComponent, TranslationGridColumnComponent, emptyQueryParams, fromQueryParams, paramsEqual, provideCaucaGrid, provideGridStateRestoration, toQueryParams };
|
|
1433
1712
|
//# sourceMappingURL=cauca-911-datagrid.mjs.map
|