@memberjunction/ng-entity-viewer 2.133.0 → 3.1.0
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/dist/lib/entity-cards/entity-cards.component.js +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +10 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +87 -35
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +89 -13
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +317 -136
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/pagination/pagination.component.js +1 -1
- package/dist/lib/pagination/pagination.component.js.map +1 -1
- package/dist/lib/pill/pill.component.js +1 -1
- package/dist/lib/pill/pill.component.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts +87 -2
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +720 -426
- package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/package.json +15 -15
|
@@ -470,7 +470,7 @@ function EntityDataGridComponent_ag_grid_angular_7_Template(rf, ctx) { if (rf &
|
|
|
470
470
|
i0.ɵɵelementEnd();
|
|
471
471
|
} if (rf & 2) {
|
|
472
472
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
473
|
-
i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("rowData", ctx_r2.rowData)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0)
|
|
473
|
+
i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("rowData", ctx_r2.rowData)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0);
|
|
474
474
|
} }
|
|
475
475
|
function EntityDataGridComponent_ag_grid_angular_8_Template(rf, ctx) { if (rf & 1) {
|
|
476
476
|
const _r31 = i0.ɵɵgetCurrentView();
|
|
@@ -479,7 +479,7 @@ function EntityDataGridComponent_ag_grid_angular_8_Template(rf, ctx) { if (rf &
|
|
|
479
479
|
i0.ɵɵelementEnd();
|
|
480
480
|
} if (rf & 2) {
|
|
481
481
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
482
|
-
i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0)("
|
|
482
|
+
i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0)("rowModelType", "infinite")("cacheBlockSize", ctx_r2.CacheBlockSize)("maxBlocksInCache", ctx_r2.MaxBlocksInCache)("infiniteInitialRowCount", 1)("cacheOverflowSize", 2);
|
|
483
483
|
} }
|
|
484
484
|
// Register AG Grid modules (required for v34+)
|
|
485
485
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
|
@@ -625,10 +625,21 @@ export class EntityDataGridComponent {
|
|
|
625
625
|
this._data = value || [];
|
|
626
626
|
this._useExternalData = this._data.length > 0;
|
|
627
627
|
if (this._useExternalData || hadData) {
|
|
628
|
-
|
|
628
|
+
// Suppress sort events during data update to prevent AG Grid from clearing
|
|
629
|
+
// our saved sort state when it processes the new row data
|
|
630
|
+
const savedSortState = [...this._sortState];
|
|
631
|
+
this.suppressSortEvents = true;
|
|
632
|
+
try {
|
|
633
|
+
this.processData();
|
|
634
|
+
}
|
|
635
|
+
finally {
|
|
636
|
+
this.suppressSortEvents = false;
|
|
637
|
+
}
|
|
629
638
|
// Reapply sort state to grid after data changes to maintain visual indicators
|
|
630
639
|
// Use microtask to ensure AG Grid has processed the new row data first
|
|
631
|
-
if (this.gridApi &&
|
|
640
|
+
if (this.gridApi && savedSortState.length > 0) {
|
|
641
|
+
// Restore sort state in case it was cleared during processData
|
|
642
|
+
this._sortState = savedSortState;
|
|
632
643
|
Promise.resolve().then(() => {
|
|
633
644
|
this.applySortStateToGrid();
|
|
634
645
|
});
|
|
@@ -1370,15 +1381,16 @@ export class EntityDataGridComponent {
|
|
|
1370
1381
|
}
|
|
1371
1382
|
ngOnDestroy() {
|
|
1372
1383
|
// Flush any pending state persistence immediately before destroying
|
|
1373
|
-
this.
|
|
1384
|
+
this.EnsurePendingChangesSaved();
|
|
1374
1385
|
this.destroy$.next();
|
|
1375
1386
|
this.destroy$.complete();
|
|
1376
1387
|
}
|
|
1377
1388
|
/**
|
|
1378
1389
|
* Immediately persists any pending state changes without waiting for debounce.
|
|
1379
1390
|
* Called on component destroy to ensure changes aren't lost.
|
|
1391
|
+
* Also exposed publicly so parent components can flush before view/entity switches.
|
|
1380
1392
|
*/
|
|
1381
|
-
|
|
1393
|
+
EnsurePendingChangesSaved() {
|
|
1382
1394
|
// Flush pending view state
|
|
1383
1395
|
if (this._pendingViewStateToPersist && this._viewEntity) {
|
|
1384
1396
|
this.persistGridStateToView(this._pendingViewStateToPersist);
|
|
@@ -1432,7 +1444,7 @@ export class EntityDataGridComponent {
|
|
|
1432
1444
|
if (this._params.ViewEntity) {
|
|
1433
1445
|
// ViewEntity was provided directly
|
|
1434
1446
|
this._viewEntity = this._params.ViewEntity;
|
|
1435
|
-
this._entityInfo = this._viewEntity
|
|
1447
|
+
this._entityInfo = this.getEntityInfoFromViewEntity(this._viewEntity);
|
|
1436
1448
|
this.applyViewEntitySettings();
|
|
1437
1449
|
}
|
|
1438
1450
|
else if (this._params.ViewID) {
|
|
@@ -1445,7 +1457,7 @@ export class EntityDataGridComponent {
|
|
|
1445
1457
|
// View not in cache - use ViewInfo (which also uses engine)
|
|
1446
1458
|
this._viewEntity = await ViewInfo.GetViewEntity(this._params.ViewID);
|
|
1447
1459
|
}
|
|
1448
|
-
this._entityInfo = this._viewEntity
|
|
1460
|
+
this._entityInfo = this.getEntityInfoFromViewEntity(this._viewEntity);
|
|
1449
1461
|
this.applyViewEntitySettings();
|
|
1450
1462
|
}
|
|
1451
1463
|
else if (this._params.ViewName) {
|
|
@@ -1458,7 +1470,7 @@ export class EntityDataGridComponent {
|
|
|
1458
1470
|
// View not in cache - use ViewInfo (which also uses engine)
|
|
1459
1471
|
this._viewEntity = await ViewInfo.GetViewEntityByName(this._params.ViewName);
|
|
1460
1472
|
}
|
|
1461
|
-
this._entityInfo = this._viewEntity
|
|
1473
|
+
this._entityInfo = this.getEntityInfoFromViewEntity(this._viewEntity);
|
|
1462
1474
|
this.applyViewEntitySettings();
|
|
1463
1475
|
}
|
|
1464
1476
|
else if (this._params.EntityName) {
|
|
@@ -1520,6 +1532,38 @@ export class EntityDataGridComponent {
|
|
|
1520
1532
|
return undefined;
|
|
1521
1533
|
}
|
|
1522
1534
|
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Gets EntityInfo from a ViewEntity with multiple fallback strategies.
|
|
1537
|
+
* Priority: 1) ViewEntityInfo property (set by Load)
|
|
1538
|
+
* 2) Entity name lookup (virtual field)
|
|
1539
|
+
* 3) EntityID lookup
|
|
1540
|
+
* Returns null if entity cannot be determined.
|
|
1541
|
+
*/
|
|
1542
|
+
getEntityInfoFromViewEntity(viewEntity) {
|
|
1543
|
+
if (!viewEntity)
|
|
1544
|
+
return null;
|
|
1545
|
+
// First try: ViewEntityInfo is the preferred source (set by UserViewEntityExtended.Load)
|
|
1546
|
+
if (viewEntity.ViewEntityInfo) {
|
|
1547
|
+
return viewEntity.ViewEntityInfo;
|
|
1548
|
+
}
|
|
1549
|
+
const md = new Metadata();
|
|
1550
|
+
// Second try: Look up by Entity name (virtual field that returns entity name)
|
|
1551
|
+
if (viewEntity.Entity) {
|
|
1552
|
+
const entityByName = md.Entities.find(e => e.Name === viewEntity.Entity);
|
|
1553
|
+
if (entityByName) {
|
|
1554
|
+
return entityByName;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
// Third try: Look up by EntityID
|
|
1558
|
+
if (viewEntity.EntityID) {
|
|
1559
|
+
const entityById = md.Entities.find(e => e.ID === viewEntity.EntityID);
|
|
1560
|
+
if (entityById) {
|
|
1561
|
+
return entityById;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
console.warn(`[EntityDataGrid] Could not determine entity for view "${viewEntity.Name}" (ID: ${viewEntity.ID})`);
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1523
1567
|
/**
|
|
1524
1568
|
* Loads user's saved grid state defaults for a dynamic view.
|
|
1525
1569
|
* Uses UserInfoEngine to retrieve settings stored with key format: "default-view-setting/{entityName}"
|
|
@@ -1628,14 +1672,13 @@ export class EntityDataGridComponent {
|
|
|
1628
1672
|
// Refresh header to apply new header styles
|
|
1629
1673
|
this.gridApi.refreshHeader();
|
|
1630
1674
|
}
|
|
1631
|
-
// Apply sort if present
|
|
1675
|
+
// Apply sort if present - support multi-column sort
|
|
1632
1676
|
if (this._gridState.sortSettings?.length && this.gridApi) {
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
}];
|
|
1677
|
+
this._sortState = this._gridState.sortSettings.map((sortSetting, index) => ({
|
|
1678
|
+
field: sortSetting.field,
|
|
1679
|
+
direction: sortSetting.dir,
|
|
1680
|
+
index: index
|
|
1681
|
+
}));
|
|
1639
1682
|
this.applySortStateToGrid();
|
|
1640
1683
|
}
|
|
1641
1684
|
}
|
|
@@ -2194,14 +2237,16 @@ export class EntityDataGridComponent {
|
|
|
2194
2237
|
this.agRowSelection = { mode: 'singleRow', enableClickSelection: true, checkboxes: false };
|
|
2195
2238
|
break;
|
|
2196
2239
|
case 'multiple':
|
|
2197
|
-
|
|
2240
|
+
// enableSelectionWithoutKeys replaces deprecated rowMultiSelectWithClick (as of AG Grid v32.2)
|
|
2241
|
+
this.agRowSelection = { mode: 'multiRow', enableClickSelection: true, checkboxes: false, enableSelectionWithoutKeys: true };
|
|
2198
2242
|
break;
|
|
2199
2243
|
case 'checkbox':
|
|
2200
2244
|
this.agRowSelection = {
|
|
2201
2245
|
mode: 'multiRow',
|
|
2202
2246
|
enableClickSelection: true,
|
|
2203
2247
|
checkboxes: true,
|
|
2204
|
-
headerCheckbox: true
|
|
2248
|
+
headerCheckbox: true,
|
|
2249
|
+
enableSelectionWithoutKeys: true
|
|
2205
2250
|
};
|
|
2206
2251
|
break;
|
|
2207
2252
|
}
|
|
@@ -2626,8 +2671,9 @@ export class EntityDataGridComponent {
|
|
|
2626
2671
|
});
|
|
2627
2672
|
}
|
|
2628
2673
|
onAgSortChanged(event) {
|
|
2629
|
-
if (this.suppressSortEvents)
|
|
2674
|
+
if (this.suppressSortEvents) {
|
|
2630
2675
|
return;
|
|
2676
|
+
}
|
|
2631
2677
|
const sortModel = event.api.getColumnState()
|
|
2632
2678
|
.filter(col => col.sort)
|
|
2633
2679
|
.map(col => ({
|
|
@@ -2662,12 +2708,8 @@ export class EntityDataGridComponent {
|
|
|
2662
2708
|
if (this._serverSideSorting && !this._useExternalData) {
|
|
2663
2709
|
this.loadData(true);
|
|
2664
2710
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
// If totalRowCount > current data length, we only have partial data and parent must handle sorting
|
|
2668
|
-
// Parent receives afterSort event and can reload with new sort order
|
|
2669
|
-
// If we have all data, AG Grid handles client-side sorting automatically
|
|
2670
|
-
}
|
|
2711
|
+
// When using external data, parent receives afterSort event and can reload with new sort order
|
|
2712
|
+
// If we have all data, AG Grid handles client-side sorting automatically
|
|
2671
2713
|
}
|
|
2672
2714
|
else {
|
|
2673
2715
|
this._sortState = [];
|
|
@@ -2842,7 +2884,8 @@ export class EntityDataGridComponent {
|
|
|
2842
2884
|
}
|
|
2843
2885
|
}
|
|
2844
2886
|
const columnSettings = [];
|
|
2845
|
-
|
|
2887
|
+
// Collect sorted columns with their sortIndex for proper ordering
|
|
2888
|
+
const sortedColumns = [];
|
|
2846
2889
|
for (let i = 0; i < columnState.length; i++) {
|
|
2847
2890
|
const col = columnState[i];
|
|
2848
2891
|
if (col.colId === '__rowNumber')
|
|
@@ -2871,20 +2914,29 @@ export class EntityDataGridComponent {
|
|
|
2871
2914
|
columnSettings.push(colConfig);
|
|
2872
2915
|
}
|
|
2873
2916
|
if (col.sort) {
|
|
2874
|
-
|
|
2917
|
+
sortedColumns.push({
|
|
2875
2918
|
field: col.colId,
|
|
2876
|
-
dir: col.sort
|
|
2919
|
+
dir: col.sort,
|
|
2920
|
+
sortIndex: col.sortIndex ?? 0
|
|
2877
2921
|
});
|
|
2878
2922
|
}
|
|
2879
2923
|
}
|
|
2924
|
+
// Sort by sortIndex to maintain correct multi-sort priority order
|
|
2925
|
+
sortedColumns.sort((a, b) => a.sortIndex - b.sortIndex);
|
|
2926
|
+
const sortSettings = sortedColumns.map(s => ({
|
|
2927
|
+
field: s.field,
|
|
2928
|
+
dir: s.dir
|
|
2929
|
+
}));
|
|
2880
2930
|
return { columnSettings, sortSettings };
|
|
2881
2931
|
}
|
|
2882
2932
|
applySortStateToGrid() {
|
|
2883
|
-
if (!this.gridApi || this._sortState.length === 0)
|
|
2933
|
+
if (!this.gridApi || this._sortState.length === 0) {
|
|
2884
2934
|
return;
|
|
2935
|
+
}
|
|
2885
2936
|
const currentColumnState = this.gridApi.getColumnState();
|
|
2886
|
-
if (!currentColumnState)
|
|
2937
|
+
if (!currentColumnState) {
|
|
2887
2938
|
return;
|
|
2939
|
+
}
|
|
2888
2940
|
this.suppressSortEvents = true;
|
|
2889
2941
|
try {
|
|
2890
2942
|
const columnState = currentColumnState.map(col => {
|
|
@@ -3496,18 +3548,18 @@ export class EntityDataGridComponent {
|
|
|
3496
3548
|
.filter(c => c.visible)
|
|
3497
3549
|
.sort((a, b) => a.order - b.order);
|
|
3498
3550
|
}
|
|
3499
|
-
static ɵfac = function EntityDataGridComponent_Factory(
|
|
3551
|
+
static ɵfac = function EntityDataGridComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityDataGridComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.ExportService)); };
|
|
3500
3552
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityDataGridComponent, selectors: [["mj-entity-data-grid"]], viewQuery: function EntityDataGridComponent_Query(rf, ctx) { if (rf & 1) {
|
|
3501
3553
|
i0.ɵɵviewQuery(_c0, 5);
|
|
3502
3554
|
} if (rf & 2) {
|
|
3503
3555
|
let _t;
|
|
3504
3556
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.gridContainer = _t.first);
|
|
3505
|
-
} }, inputs: { Params: "Params", AllowLoad: "AllowLoad", AutoRefreshOnParamsChange: "AutoRefreshOnParamsChange", PaginationMode: "PaginationMode", PageSize: "PageSize", CacheBlockSize: "CacheBlockSize", MaxBlocksInCache: "MaxBlocksInCache", Data: "Data", Columns: "Columns", GridState: "GridState", AllowColumnReorder: "AllowColumnReorder", AllowColumnResize: "AllowColumnResize", AllowColumnToggle: "AllowColumnToggle", ShowHeader: "ShowHeader", AllowSorting: "AllowSorting", AllowMultiSort: "AllowMultiSort", ServerSideSorting: "ServerSideSorting", AllowColumnFilters: "AllowColumnFilters", ShowSearch: "ShowSearch", SelectionMode: "SelectionMode", SelectedKeys: "SelectedKeys", KeyField: "KeyField", EditMode: "EditMode", AllowAdd: "AllowAdd", AllowDelete: "AllowDelete", Height: "Height", RowHeight: "RowHeight", VirtualScroll: "VirtualScroll", ShowRowNumbers: "ShowRowNumbers", Striped: "Striped", GridLines: "GridLines", VisualConfig: "VisualConfig", ShowToolbar: "ShowToolbar", ToolbarConfig: "ToolbarConfig", StateKey: "StateKey", AutoPersistState: "AutoPersistState", StatePersistDebounce: "StatePersistDebounce", RefreshDebounce: "RefreshDebounce", FilterText: "FilterText", ShowNewButton: "ShowNewButton", ShowRefreshButton: "ShowRefreshButton", ShowExportButton: "ShowExportButton", ShowDeleteButton: "ShowDeleteButton", ShowCompareButton: "ShowCompareButton", ShowMergeButton: "ShowMergeButton", ShowAddToListButton: "ShowAddToListButton", ShowDuplicateSearchButton: "ShowDuplicateSearchButton", ShowCommunicationButton: "ShowCommunicationButton", AutoNavigate: "AutoNavigate", NavigateOnDoubleClick: "NavigateOnDoubleClick", CreateRecordMode: "CreateRecordMode", NewRecordValues: "NewRecordValues", ShowEntityActionButtons: "ShowEntityActionButtons", EntityActions: "EntityActions" }, outputs: { BeforeRowSelect: "BeforeRowSelect", AfterRowSelect: "AfterRowSelect", BeforeRowDeselect: "BeforeRowDeselect", AfterRowDeselect: "AfterRowDeselect", SelectionChange: "SelectionChange", BeforeRowClick: "BeforeRowClick", AfterRowClick: "AfterRowClick", BeforeRowDoubleClick: "BeforeRowDoubleClick", AfterRowDoubleClick: "AfterRowDoubleClick", BeforeCellEdit: "BeforeCellEdit", AfterCellEditBegin: "AfterCellEditBegin", BeforeCellEditCommit: "BeforeCellEditCommit", AfterCellEditCommit: "AfterCellEditCommit", BeforeCellEditCancel: "BeforeCellEditCancel", AfterCellEditCancel: "AfterCellEditCancel", BeforeRowSave: "BeforeRowSave", AfterRowSave: "AfterRowSave", BeforeRowDelete: "BeforeRowDelete", AfterRowDelete: "AfterRowDelete", BeforeDataLoad: "BeforeDataLoad", AfterDataLoad: "AfterDataLoad", BeforeDataRefresh: "BeforeDataRefresh", AfterDataRefresh: "AfterDataRefresh", BeforeSort: "BeforeSort", AfterSort: "AfterSort", BeforeColumnReorder: "BeforeColumnReorder", AfterColumnReorder: "AfterColumnReorder", BeforeColumnResize: "BeforeColumnResize", AfterColumnResize: "AfterColumnResize", BeforeColumnVisibilityChange: "BeforeColumnVisibilityChange", AfterColumnVisibilityChange: "AfterColumnVisibilityChange", GridStateChanged: "GridStateChanged", AddRequested: "AddRequested", DeleteRequested: "DeleteRequested", ExportRequested: "ExportRequested", NewButtonClick: "NewButtonClick", RefreshButtonClick: "RefreshButtonClick", ExportButtonClick: "ExportButtonClick", DeleteButtonClick: "DeleteButtonClick", CompareButtonClick: "CompareButtonClick", MergeButtonClick: "MergeButtonClick", AddToListButtonClick: "AddToListButtonClick", DuplicateSearchButtonClick: "DuplicateSearchButtonClick", CommunicationButtonClick: "CommunicationButtonClick", NavigationRequested: "NavigationRequested", NewRecordDialogRequested: "NewRecordDialogRequested", NewRecordTabRequested: "NewRecordTabRequested", CompareRecordsRequested: "CompareRecordsRequested", MergeRecordsRequested: "MergeRecordsRequested", CommunicationRequested: "CommunicationRequested", DuplicateSearchRequested: "DuplicateSearchRequested", AddToListRequested: "AddToListRequested", LoadEntityActionsRequested: "LoadEntityActionsRequested", EntityActionRequested: "EntityActionRequested" }, decls: 10, vars: 12, consts: [["gridContainer", ""], ["class", "mj-grid-toolbar", 4, "ngIf"], [1, "mj-grid-content"], ["class", "mj-grid-loading-overlay", 4, "ngIf"], ["class", "mj-grid-error", 4, "ngIf"], ["class", "mj-grid-empty", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowMultiSelectWithClick", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowMultiSelectWithClick", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], [3, "closed", "visible", "config"], [1, "mj-grid-toolbar"], [1, "toolbar-left"], ["class", "toolbar-search", 4, "ngIf"], [4, "ngFor", "ngForOf"], [1, "toolbar-center"], ["class", "row-count", 4, "ngIf"], ["class", "selection-count", 4, "ngIf"], [1, "toolbar-right"], ["class", "toolbar-button", "title", "Create new record", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh data", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export to Excel", 3, "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete selected records", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Compare selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Merge selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add selected records to a list", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Search for duplicate records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Send message to selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add New", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete Selected", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Column Chooser", 3, "click", 4, "ngIf"], ["class", "toolbar-overflow", 3, "click", 4, "ngIf"], [1, "toolbar-search"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", 1, "search-input", 3, "input", "placeholder", "value"], ["class", "search-clear", 3, "click", 4, "ngIf"], [1, "search-clear", 3, "click"], [1, "fa-solid", "fa-times"], ["class", "toolbar-button", 3, "class", "disabled", "title", "click", 4, "ngIf"], [1, "toolbar-button", 3, "click", "disabled", "title"], [3, "class", 4, "ngIf"], [4, "ngIf"], [1, "row-count"], [1, "selection-count"], ["title", "Create new record", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "button-text"], ["title", "Refresh data", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], ["title", "Export to Excel", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-file-excel"], ["title", "Delete selected records", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "Compare selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-compare"], ["title", "Merge selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-merge"], ["title", "Add selected records to a list", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-list-check"], ["title", "Search for duplicate records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-magnifying-glass-plus"], ["title", "Send message to selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-envelope"], ["title", "Add New", 1, "toolbar-button", 3, "click"], ["title", "Refresh", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], ["title", "Delete Selected", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], ["title", "Export", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-download"], ["title", "Column Chooser", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-columns"], [1, "toolbar-overflow", 3, "click"], ["title", "More actions", 1, "toolbar-button", "overflow-trigger", 3, "click"], [1, "fa-solid", "fa-ellipsis-vertical"], ["class", "overflow-menu", 4, "ngIf"], [1, "overflow-menu"], ["class", "overflow-item", 3, "click", 4, "ngIf"], ["class", "overflow-divider", 4, "ngIf"], [1, "overflow-item", 3, "click"], [1, "overflow-divider"], [1, "overflow-section-label"], ["class", "overflow-item", 3, "disabled", "click", 4, "ngFor", "ngForOf"], [1, "overflow-item", 3, "click", "disabled"], [1, "mj-grid-loading-overlay"], ["text", "Loading..."], [1, "mj-grid-error"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "error-retry", 3, "click"], [1, "mj-grid-empty"], [1, "fa-solid", "fa-inbox"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowMultiSelectWithClick"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowMultiSelectWithClick", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize"]], template: function EntityDataGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
3557
|
+
} }, inputs: { Params: "Params", AllowLoad: "AllowLoad", AutoRefreshOnParamsChange: "AutoRefreshOnParamsChange", PaginationMode: "PaginationMode", PageSize: "PageSize", CacheBlockSize: "CacheBlockSize", MaxBlocksInCache: "MaxBlocksInCache", Data: "Data", Columns: "Columns", GridState: "GridState", AllowColumnReorder: "AllowColumnReorder", AllowColumnResize: "AllowColumnResize", AllowColumnToggle: "AllowColumnToggle", ShowHeader: "ShowHeader", AllowSorting: "AllowSorting", AllowMultiSort: "AllowMultiSort", ServerSideSorting: "ServerSideSorting", AllowColumnFilters: "AllowColumnFilters", ShowSearch: "ShowSearch", SelectionMode: "SelectionMode", SelectedKeys: "SelectedKeys", KeyField: "KeyField", EditMode: "EditMode", AllowAdd: "AllowAdd", AllowDelete: "AllowDelete", Height: "Height", RowHeight: "RowHeight", VirtualScroll: "VirtualScroll", ShowRowNumbers: "ShowRowNumbers", Striped: "Striped", GridLines: "GridLines", VisualConfig: "VisualConfig", ShowToolbar: "ShowToolbar", ToolbarConfig: "ToolbarConfig", StateKey: "StateKey", AutoPersistState: "AutoPersistState", StatePersistDebounce: "StatePersistDebounce", RefreshDebounce: "RefreshDebounce", FilterText: "FilterText", ShowNewButton: "ShowNewButton", ShowRefreshButton: "ShowRefreshButton", ShowExportButton: "ShowExportButton", ShowDeleteButton: "ShowDeleteButton", ShowCompareButton: "ShowCompareButton", ShowMergeButton: "ShowMergeButton", ShowAddToListButton: "ShowAddToListButton", ShowDuplicateSearchButton: "ShowDuplicateSearchButton", ShowCommunicationButton: "ShowCommunicationButton", AutoNavigate: "AutoNavigate", NavigateOnDoubleClick: "NavigateOnDoubleClick", CreateRecordMode: "CreateRecordMode", NewRecordValues: "NewRecordValues", ShowEntityActionButtons: "ShowEntityActionButtons", EntityActions: "EntityActions" }, outputs: { BeforeRowSelect: "BeforeRowSelect", AfterRowSelect: "AfterRowSelect", BeforeRowDeselect: "BeforeRowDeselect", AfterRowDeselect: "AfterRowDeselect", SelectionChange: "SelectionChange", BeforeRowClick: "BeforeRowClick", AfterRowClick: "AfterRowClick", BeforeRowDoubleClick: "BeforeRowDoubleClick", AfterRowDoubleClick: "AfterRowDoubleClick", BeforeCellEdit: "BeforeCellEdit", AfterCellEditBegin: "AfterCellEditBegin", BeforeCellEditCommit: "BeforeCellEditCommit", AfterCellEditCommit: "AfterCellEditCommit", BeforeCellEditCancel: "BeforeCellEditCancel", AfterCellEditCancel: "AfterCellEditCancel", BeforeRowSave: "BeforeRowSave", AfterRowSave: "AfterRowSave", BeforeRowDelete: "BeforeRowDelete", AfterRowDelete: "AfterRowDelete", BeforeDataLoad: "BeforeDataLoad", AfterDataLoad: "AfterDataLoad", BeforeDataRefresh: "BeforeDataRefresh", AfterDataRefresh: "AfterDataRefresh", BeforeSort: "BeforeSort", AfterSort: "AfterSort", BeforeColumnReorder: "BeforeColumnReorder", AfterColumnReorder: "AfterColumnReorder", BeforeColumnResize: "BeforeColumnResize", AfterColumnResize: "AfterColumnResize", BeforeColumnVisibilityChange: "BeforeColumnVisibilityChange", AfterColumnVisibilityChange: "AfterColumnVisibilityChange", GridStateChanged: "GridStateChanged", AddRequested: "AddRequested", DeleteRequested: "DeleteRequested", ExportRequested: "ExportRequested", NewButtonClick: "NewButtonClick", RefreshButtonClick: "RefreshButtonClick", ExportButtonClick: "ExportButtonClick", DeleteButtonClick: "DeleteButtonClick", CompareButtonClick: "CompareButtonClick", MergeButtonClick: "MergeButtonClick", AddToListButtonClick: "AddToListButtonClick", DuplicateSearchButtonClick: "DuplicateSearchButtonClick", CommunicationButtonClick: "CommunicationButtonClick", NavigationRequested: "NavigationRequested", NewRecordDialogRequested: "NewRecordDialogRequested", NewRecordTabRequested: "NewRecordTabRequested", CompareRecordsRequested: "CompareRecordsRequested", MergeRecordsRequested: "MergeRecordsRequested", CommunicationRequested: "CommunicationRequested", DuplicateSearchRequested: "DuplicateSearchRequested", AddToListRequested: "AddToListRequested", LoadEntityActionsRequested: "LoadEntityActionsRequested", EntityActionRequested: "EntityActionRequested" }, decls: 10, vars: 12, consts: [["gridContainer", ""], ["class", "mj-grid-toolbar", 4, "ngIf"], [1, "mj-grid-content"], ["class", "mj-grid-loading-overlay", 4, "ngIf"], ["class", "mj-grid-error", 4, "ngIf"], ["class", "mj-grid-empty", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], [3, "closed", "visible", "config"], [1, "mj-grid-toolbar"], [1, "toolbar-left"], ["class", "toolbar-search", 4, "ngIf"], [4, "ngFor", "ngForOf"], [1, "toolbar-center"], ["class", "row-count", 4, "ngIf"], ["class", "selection-count", 4, "ngIf"], [1, "toolbar-right"], ["class", "toolbar-button", "title", "Create new record", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh data", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export to Excel", 3, "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete selected records", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Compare selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Merge selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add selected records to a list", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Search for duplicate records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Send message to selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add New", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete Selected", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Column Chooser", 3, "click", 4, "ngIf"], ["class", "toolbar-overflow", 3, "click", 4, "ngIf"], [1, "toolbar-search"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", 1, "search-input", 3, "input", "placeholder", "value"], ["class", "search-clear", 3, "click", 4, "ngIf"], [1, "search-clear", 3, "click"], [1, "fa-solid", "fa-times"], ["class", "toolbar-button", 3, "class", "disabled", "title", "click", 4, "ngIf"], [1, "toolbar-button", 3, "click", "disabled", "title"], [3, "class", 4, "ngIf"], [4, "ngIf"], [1, "row-count"], [1, "selection-count"], ["title", "Create new record", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "button-text"], ["title", "Refresh data", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], ["title", "Export to Excel", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-file-excel"], ["title", "Delete selected records", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "Compare selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-compare"], ["title", "Merge selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-merge"], ["title", "Add selected records to a list", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-list-check"], ["title", "Search for duplicate records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-magnifying-glass-plus"], ["title", "Send message to selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-envelope"], ["title", "Add New", 1, "toolbar-button", 3, "click"], ["title", "Refresh", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], ["title", "Delete Selected", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], ["title", "Export", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-download"], ["title", "Column Chooser", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-columns"], [1, "toolbar-overflow", 3, "click"], ["title", "More actions", 1, "toolbar-button", "overflow-trigger", 3, "click"], [1, "fa-solid", "fa-ellipsis-vertical"], ["class", "overflow-menu", 4, "ngIf"], [1, "overflow-menu"], ["class", "overflow-item", 3, "click", 4, "ngIf"], ["class", "overflow-divider", 4, "ngIf"], [1, "overflow-item", 3, "click"], [1, "overflow-divider"], [1, "overflow-section-label"], ["class", "overflow-item", 3, "disabled", "click", 4, "ngFor", "ngForOf"], [1, "overflow-item", 3, "click", "disabled"], [1, "mj-grid-loading-overlay"], ["text", "Loading..."], [1, "mj-grid-error"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "error-retry", 3, "click"], [1, "mj-grid-empty"], [1, "fa-solid", "fa-inbox"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize"]], template: function EntityDataGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
3506
3558
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
3507
3559
|
i0.ɵɵelementStart(0, "div", null, 0);
|
|
3508
3560
|
i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_Template, 24, 20, "div", 1);
|
|
3509
3561
|
i0.ɵɵelementStart(3, "div", 2);
|
|
3510
|
-
i0.ɵɵtemplate(4, EntityDataGridComponent_div_4_Template, 2, 0, "div", 3)(5, EntityDataGridComponent_div_5_Template, 6, 1, "div", 4)(6, EntityDataGridComponent_div_6_Template, 4, 0, "div", 5)(7, EntityDataGridComponent_ag_grid_angular_7_Template, 1,
|
|
3562
|
+
i0.ɵɵtemplate(4, EntityDataGridComponent_div_4_Template, 2, 0, "div", 3)(5, EntityDataGridComponent_div_5_Template, 6, 1, "div", 4)(6, EntityDataGridComponent_div_6_Template, 4, 0, "div", 5)(7, EntityDataGridComponent_ag_grid_angular_7_Template, 1, 9, "ag-grid-angular", 6)(8, EntityDataGridComponent_ag_grid_angular_8_Template, 1, 13, "ag-grid-angular", 7);
|
|
3511
3563
|
i0.ɵɵelementEnd()();
|
|
3512
3564
|
i0.ɵɵelementStart(9, "mj-export-dialog", 8);
|
|
3513
3565
|
i0.ɵɵlistener("closed", function EntityDataGridComponent_Template_mj_export_dialog_closed_9_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onExportDialogClosed($event)); });
|
|
@@ -3529,7 +3581,7 @@ export class EntityDataGridComponent {
|
|
|
3529
3581
|
i0.ɵɵproperty("ngIf", !ctx.errorMessage && ctx.PaginationMode === "infinite");
|
|
3530
3582
|
i0.ɵɵadvance();
|
|
3531
3583
|
i0.ɵɵproperty("visible", ctx.showExportDialog)("config", ctx.exportDialogConfig);
|
|
3532
|
-
} }, dependencies: [i2.NgForOf, i2.NgIf, i3.AgGridAngular, i4.LoadingComponent, i1.ExportDialogComponent], styles: ["\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n \n\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n \n\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n \n\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n \n\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n \n\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n \n\n --grid-sort-indicator-color: #2196F3;\n\n \n\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n \n\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n \n\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n\n\n\n\n\n.mj-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-grid-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left[_ngcontent-%COMP%], \n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input[_ngcontent-%COMP%] {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n color: #666;\n}\n\n.toolbar-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%] {\n color: #d32f2f;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count[_ngcontent-%COMP%], \n.selection-count[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n\n\n\n\n.mj-grid-content[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: auto;\n}\n\n\n\n\n\n\n.mj-grid-loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n\n\n\n\n\n.mj-grid-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.error-retry[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry[_ngcontent-%COMP%]:hover {\n background: #c62828;\n}\n\n\n\n\n\n\n.mj-grid-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n\n\n\n\n\n.mj-grid-header[_ngcontent-%COMP%] {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.sort-index[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n\n\n\n\n\n.mj-grid-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%] {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%] {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing[_ngcontent-%COMP%] {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty[_ngcontent-%COMP%] {\n border-left: 3px solid #ff9800;\n}\n\n\n\n\n\n\n.mj-grid-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n\n\n.grid-lines-horizontal[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n\n\n.mj-grid-cell.align-left[_ngcontent-%COMP%] {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center[_ngcontent-%COMP%] {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right[_ngcontent-%COMP%] {\n justify-content: flex-end;\n}\n\n.cell-content[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.row-number-cell[_ngcontent-%COMP%] {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell[_ngcontent-%COMP%] {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n\n\n\n\n\n.mj-grid-virtual-spacer[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n\n\n\n\n\n@media (max-width: 768px) {\n .mj-grid-toolbar[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search[_ngcontent-%COMP%] {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-center[_ngcontent-%COMP%] {\n order: 2;\n }\n\n \n\n .toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n\n.toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n.toolbar-overflow[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.overflow-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.overflow-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label[_ngcontent-%COMP%] {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n\n\n.overflow-item.action-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196F3;\n}\n\n\n\n\n\n\n .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n\n\n\n\n\n.mj-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n .ag-theme-alpine {\n \n\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n \n\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n \n\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n\n\n .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n\n\n .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n\n\n\n\n\n\n\n.header-style-flat[_ngcontent-%COMP%] .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n\n\n.header-style-elevated[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n\n\n.header-style-gradient[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n\n\n .ag-header-cell-sorted-asc .ag-icon-asc, \n .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n\n\n\n\n\n\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n\n\n\n.hover-transitions[_ngcontent-%COMP%] .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions[_ngcontent-%COMP%] .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n\n\n\n\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n\n\n\n\n\n\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n\n\n\n\n\n\n\n .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n\n\n .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n\n\n .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n\n\n .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n\n\n .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n\n\n .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n\n\n .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row[_ngcontent-%COMP%] {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell[_ngcontent-%COMP%] {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: _ngcontent-%COMP%_skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short[_ngcontent-%COMP%] {\n width: 60px;\n}\n\n.skeleton-cell-medium[_ngcontent-%COMP%] {\n width: 120px;\n}\n\n.skeleton-cell-long[_ngcontent-%COMP%] {\n width: 180px;\n}\n\n\n\n .ag-header-select-all {\n margin-right: 0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n\n\n\n\n\n .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}"], data: { animation: [
|
|
3584
|
+
} }, dependencies: [i2.NgForOf, i2.NgIf, i3.AgGridAngular, i4.LoadingComponent, i1.ExportDialogComponent], styles: ["\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n \n\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n \n\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n \n\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n \n\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n \n\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n \n\n --grid-sort-indicator-color: #2196F3;\n\n \n\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n \n\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n \n\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n\n\n\n\n\n.mj-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-grid-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left[_ngcontent-%COMP%], \n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input[_ngcontent-%COMP%] {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n color: #666;\n}\n\n.toolbar-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%] {\n color: #d32f2f;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count[_ngcontent-%COMP%], \n.selection-count[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n\n\n\n\n.mj-grid-content[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: auto;\n}\n\n\n\n\n\n\n.mj-grid-loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n\n\n\n\n\n.mj-grid-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.error-retry[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry[_ngcontent-%COMP%]:hover {\n background: #c62828;\n}\n\n\n\n\n\n\n.mj-grid-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n\n\n\n\n\n.mj-grid-header[_ngcontent-%COMP%] {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.sort-index[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n\n\n\n\n\n.mj-grid-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%] {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%] {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing[_ngcontent-%COMP%] {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty[_ngcontent-%COMP%] {\n border-left: 3px solid #ff9800;\n}\n\n\n\n\n\n\n.mj-grid-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n\n\n.grid-lines-horizontal[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n\n\n.mj-grid-cell.align-left[_ngcontent-%COMP%] {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center[_ngcontent-%COMP%] {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right[_ngcontent-%COMP%] {\n justify-content: flex-end;\n}\n\n.cell-content[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.row-number-cell[_ngcontent-%COMP%] {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell[_ngcontent-%COMP%] {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n\n\n\n\n\n.mj-grid-virtual-spacer[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n\n\n\n\n\n@media (max-width: 768px) {\n .mj-grid-toolbar[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search[_ngcontent-%COMP%] {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-center[_ngcontent-%COMP%] {\n order: 2;\n }\n\n \n\n .toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n\n.toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n.toolbar-overflow[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.overflow-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.overflow-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label[_ngcontent-%COMP%] {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n\n\n.overflow-item.action-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196F3;\n}\n\n\n\n\n\n\n .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n\n\n\n\n\n.mj-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n .ag-theme-alpine {\n \n\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n \n\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n \n\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n\n\n .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n\n\n .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n\n\n\n\n\n\n\n.header-style-flat[_ngcontent-%COMP%] .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n\n\n.header-style-elevated[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n\n\n.header-style-gradient[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n\n\n .ag-header-cell-sorted-asc .ag-icon-asc, \n .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n\n\n\n\n\n\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n\n\n\n.hover-transitions[_ngcontent-%COMP%] .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions[_ngcontent-%COMP%] .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n\n\n\n\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n\n\n\n\n\n\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n\n\n\n\n\n\n\n .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n\n\n .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n\n\n .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n\n\n .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n\n\n .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n\n\n .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n\n\n .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row[_ngcontent-%COMP%] {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell[_ngcontent-%COMP%] {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: _ngcontent-%COMP%_skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short[_ngcontent-%COMP%] {\n width: 60px;\n}\n\n.skeleton-cell-medium[_ngcontent-%COMP%] {\n width: 120px;\n}\n\n.skeleton-cell-long[_ngcontent-%COMP%] {\n width: 180px;\n}\n\n\n\n .ag-header-select-all {\n margin-right: 0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n\n\n\n\n\n .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n[_nghost-%COMP%] .ag-sort-ascending-icon .ag-icon, \n[_nghost-%COMP%] .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}"], data: { animation: [
|
|
3533
3585
|
trigger('fadeIn', [
|
|
3534
3586
|
transition(':enter', [
|
|
3535
3587
|
style({ opacity: 0, transform: 'translateY(-8px)' }),
|
|
@@ -3553,7 +3605,7 @@ export class EntityDataGridComponent {
|
|
|
3553
3605
|
animate('100ms ease-in', style({ opacity: 0, transform: 'translateY(-8px)' }))
|
|
3554
3606
|
])
|
|
3555
3607
|
])
|
|
3556
|
-
], template: "<!-- Grid Container -->\n<div\n #gridContainer\n [class]=\"gridContainerClasses.join(' ')\"\n [style.height]=\"gridHeightStyle\">\n\n <!-- Toolbar -->\n <div *ngIf=\"ShowToolbar\" class=\"mj-grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div *ngIf=\"ShowSearch\" class=\"toolbar-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n [placeholder]=\"ToolbarConfig.searchPlaceholder || 'Search...'\"\n [value]=\"FilterText\"\n (input)=\"FilterText = $any($event.target).value\" />\n <button\n *ngIf=\"FilterText\"\n class=\"search-clear\"\n (click)=\"FilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Custom Left Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position !== 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Row Count -->\n <span *ngIf=\"ToolbarConfig.showRowCount !== false\" class=\"row-count\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'row' : 'rows' }}\n </span>\n\n <!-- Selection Count -->\n <span *ngIf=\"ToolbarConfig.showSelectionCount && SelectedKeys.length > 0\" class=\"selection-count\">\n ({{ SelectedKeys.length }} selected)\n </span>\n </div>\n\n <div class=\"toolbar-right\">\n <!-- New/Add Button (predefined) -->\n <button\n *ngIf=\"ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Create new record\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span class=\"button-text\">New</span>\n </button>\n\n <!-- Refresh Button (predefined) -->\n <button\n *ngIf=\"ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh data\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i>\n <span class=\"button-text\">Refresh</span>\n </button>\n\n <!-- Export Button (predefined) -->\n <button\n *ngIf=\"ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export to Excel\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n\n <!-- Delete Button (predefined) -->\n <button\n *ngIf=\"ShowDeleteButton && HasSelection\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete selected records\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n <span class=\"button-text\">Delete</span>\n </button>\n\n <!-- Compare Button (predefined) -->\n <button\n *ngIf=\"ShowCompareButton\"\n class=\"toolbar-button\"\n title=\"Compare selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onCompareClick()\">\n <i class=\"fa-solid fa-code-compare\"></i>\n <span class=\"button-text\">Compare</span>\n </button>\n\n <!-- Merge Button (predefined) -->\n <button\n *ngIf=\"ShowMergeButton\"\n class=\"toolbar-button\"\n title=\"Merge selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onMergeClick()\">\n <i class=\"fa-solid fa-code-merge\"></i>\n <span class=\"button-text\">Merge</span>\n </button>\n\n <!-- Add to List Button (predefined) -->\n <button\n *ngIf=\"ShowAddToListButton\"\n class=\"toolbar-button\"\n title=\"Add selected records to a list\"\n [disabled]=\"!HasSelection\"\n (click)=\"onAddToListClick()\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span class=\"button-text\">Add to List</span>\n </button>\n\n <!-- Search for Duplicates Button (predefined) -->\n <button\n *ngIf=\"ShowDuplicateSearchButton\"\n class=\"toolbar-button\"\n title=\"Search for duplicate records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onDuplicateSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n <span class=\"button-text\">Find Duplicates</span>\n </button>\n\n <!-- Communication Button (predefined) -->\n <button\n *ngIf=\"ShowCommunicationButton\"\n class=\"toolbar-button\"\n title=\"Send message to selected records\"\n [disabled]=\"!HasSelection\"\n (click)=\"onCommunicationClick()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span class=\"button-text\">Send Message</span>\n </button>\n\n <!-- Legacy ToolbarConfig buttons -->\n <!-- Add Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showAdd && AllowAdd && !ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Add New\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Refresh Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showRefresh !== false && !ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n </button>\n\n <!-- Delete Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showDelete && AllowDelete && HasSelection && !ShowDeleteButton\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete Selected\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n\n <!-- Export Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showExport && !ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n\n <!-- Column Chooser Button -->\n <button\n *ngIf=\"ToolbarConfig.showColumnChooser && AllowColumnToggle\"\n class=\"toolbar-button\"\n title=\"Column Chooser\"\n (click)=\"onColumnChooserClick()\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n\n <!-- Custom Right Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position === 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n\n <!-- Overflow Menu -->\n <div *ngIf=\"hasOverflowMenuItems\" class=\"toolbar-overflow\" (click)=\"$event.stopPropagation()\">\n <button\n class=\"toolbar-button overflow-trigger\"\n title=\"More actions\"\n (click)=\"toggleOverflowMenu()\">\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </button>\n\n <div *ngIf=\"showOverflowMenu\" class=\"overflow-menu\" [@fadeIn]>\n <!-- Export (if in overflow) -->\n <button *ngIf=\"showExportInOverflow\" class=\"overflow-item\" (click)=\"onExportClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span>Export to Excel</span>\n </button>\n\n <!-- Entity Actions -->\n <ng-container *ngIf=\"ShowEntityActionButtons && EntityActions.length > 0\">\n <div class=\"overflow-divider\"></div>\n <div class=\"overflow-section-label\">Actions</div>\n <button\n *ngFor=\"let action of EntityActions\"\n class=\"overflow-item\"\n [disabled]=\"!isEntityActionEnabled(action)\"\n (click)=\"onEntityActionClick(action); closeOverflowMenu()\">\n <i [class]=\"action.icon || 'fa-solid fa-bolt'\"></i>\n <span>{{ action.name }}</span>\n </button>\n </ng-container>\n\n <!-- Column Chooser (if in overflow) -->\n <div *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-divider\"></div>\n <button *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-item\" (click)=\"onColumnChooserClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-columns\"></i>\n <span>Manage Columns</span>\n </button>\n\n <!-- Selection-dependent actions in overflow -->\n <ng-container *ngIf=\"HasSelection && hasSelectionDependentOverflowActions\">\n <div class=\"overflow-divider\"></div>\n <button *ngIf=\"showCommunicationInOverflow\" class=\"overflow-item\" (click)=\"onCommunicationClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span>Send Message</span>\n </button>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Grid Content -->\n <div class=\"mj-grid-content\">\n <!-- Loading Overlay -->\n <div *ngIf=\"loading && rowData.length === 0\" class=\"mj-grid-loading-overlay\">\n <mj-loading text=\"Loading...\"></mj-loading>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !loading\" class=\"mj-grid-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n <button class=\"error-retry\" (click)=\"Refresh()\">Retry</button>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"!loading && !errorMessage && rowData.length === 0\" class=\"mj-grid-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No data to display</span>\n </div>\n\n <!-- AG Grid (Client-side mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'client' && (rowData.length > 0 || loading)\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [rowData]=\"rowData\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n [rowMultiSelectWithClick]=\"SelectionMode === 'multiple'\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n\n <!-- AG Grid (Infinite Scroll mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'infinite'\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n [rowMultiSelectWithClick]=\"SelectionMode === 'multiple'\"\n [rowModelType]=\"'infinite'\"\n [cacheBlockSize]=\"CacheBlockSize\"\n [maxBlocksInCache]=\"MaxBlocksInCache\"\n [infiniteInitialRowCount]=\"1\"\n [cacheOverflowSize]=\"2\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n </div>\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n</mj-export-dialog>\n", styles: ["/* ========================================\n CSS Custom Properties (Theme Variables)\n ======================================== */\n\n:host {\n /* Grid container */\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n /* Header */\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n /* Rows */\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n /* Cells */\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n /* Selection - mellow yellow to avoid conflict with blue hyperlinks */\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n /* Editing */\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n /* Sorting */\n --grid-sort-indicator-color: #2196F3;\n\n /* Toolbar */\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n /* Loading */\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n /* Empty state */\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n/* ========================================\n Grid Container\n ======================================== */\n\n.mj-grid-container {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.mj-grid-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear:hover {\n color: #666;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n.toolbar-button-danger {\n color: #d32f2f;\n}\n\n.toolbar-button-danger:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count,\n.selection-count {\n font-weight: 500;\n}\n\n/* ========================================\n Grid Content\n ======================================== */\n\n.mj-grid-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container {\n height: 100%;\n overflow: auto;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.mj-grid-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n/* ========================================\n Error State\n ======================================== */\n\n.mj-grid-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error i {\n font-size: 32px;\n}\n\n.error-retry {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry:hover {\n background: #c62828;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.mj-grid-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty i {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n/* ========================================\n Header Row\n ======================================== */\n\n.mj-grid-header {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator i {\n font-size: 12px;\n}\n\n.sort-index {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n/* ========================================\n Data Rows\n ======================================== */\n\n.mj-grid-row {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty {\n border-left: 3px solid #ff9800;\n}\n\n/* ========================================\n Data Cells\n ======================================== */\n\n.mj-grid-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell:last-child {\n border-right: none;\n}\n\n/* Grid lines modes */\n.grid-lines-horizontal .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n/* Cell alignment */\n.mj-grid-cell.align-left {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right {\n justify-content: flex-end;\n}\n\n.cell-content {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Special cells */\n.row-number-cell {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n/* ========================================\n Virtual Scrolling\n ======================================== */\n\n.mj-grid-virtual-spacer {\n flex-shrink: 0;\n}\n\n/* ========================================\n Responsive Adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .mj-grid-toolbar {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input {\n width: 100%;\n }\n\n .toolbar-center {\n order: 2;\n }\n\n /* Hide button text on mobile */\n .toolbar-button .button-text {\n display: none;\n }\n}\n\n/* ========================================\n Toolbar Button Text\n ======================================== */\n\n.toolbar-button .button-text {\n font-size: 13px;\n}\n\n/* ========================================\n Overflow Menu\n ======================================== */\n\n.toolbar-overflow {\n position: relative;\n}\n\n.overflow-trigger {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger i {\n font-size: 16px;\n}\n\n.overflow-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item i {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item span {\n flex: 1;\n}\n\n.overflow-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n/* Entity Actions submenu styling */\n.overflow-item.action-item i {\n color: #2196F3;\n}\n\n/* ========================================\n Highlight Matches\n ======================================== */\n\n::ng-deep .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n/* ========================================\n AG Grid Customizations\n ======================================== */\n\n.mj-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n::ng-deep .ag-theme-alpine {\n /* Row colors */\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n /* Selection accent colors - mellow yellow */\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n /* Ensure borders are visible */\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n/* Selected row styling - left indicator bar only, background handled by AG Grid theme */\n::ng-deep .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n/* Selection checkbox styling */\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n/* Row hover effect */\n::ng-deep .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n/* ========================================\n Visual Config: Header Styles\n ======================================== */\n\n/* Flat header (minimal) */\n.header-style-flat ::ng-deep .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n/* Elevated header (default - subtle shadow) */\n.header-style-elevated ::ng-deep .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n/* Gradient header (more prominent) */\n.header-style-gradient ::ng-deep .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n/* Bold header (high contrast) */\n.header-style-bold ::ng-deep .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold ::ng-deep .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold ::ng-deep .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold ::ng-deep .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n/* Header sort icons enhancement */\n::ng-deep .ag-header-cell-sorted-asc .ag-icon-asc,\n::ng-deep .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n/* ========================================\n Visual Config: Zebra Striping\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* ========================================\n Visual Config: Hover Transitions\n ======================================== */\n\n.hover-transitions ::ng-deep .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions ::ng-deep .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n/* ========================================\n Visual Config: Cell Padding\n ======================================== */\n\n.cell-padding-compact ::ng-deep .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact ::ng-deep .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal ::ng-deep .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal ::ng-deep .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n/* ========================================\n Visual Config: Checkbox Styles\n ======================================== */\n\n/* Rounded checkbox */\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n/* Filled checkbox */\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n/* ========================================\n Cell Content Formatting\n ======================================== */\n\n/* Right-aligned cells (numbers) */\n::ng-deep .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n::ng-deep .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n/* Empty cell placeholder */\n::ng-deep .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n/* Boolean icons */\n::ng-deep .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n::ng-deep .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n/* Clickable links */\n::ng-deep .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n::ng-deep .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n/* Email cells */\n::ng-deep .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n/* URL cells */\n::ng-deep .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n/* Phone cells */\n::ng-deep .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n/* ========================================\n Skeleton Loading Animation\n ======================================== */\n\n@keyframes skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short {\n width: 60px;\n}\n\n.skeleton-cell-medium {\n width: 120px;\n}\n\n.skeleton-cell-long {\n width: 180px;\n}\n\n/* Selection checkbox column header */\n::ng-deep .ag-header-select-all {\n margin-right: 0;\n}\n\n/* ========================================\n Row Border Enhancement\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n::ng-deep .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n/* ========================================\n Focus States\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n/* ========================================\n Pinned Column Styling\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n::ng-deep .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n/* ========================================\n Header Cell Enhancements\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n/* Sort icon animation */\n::ng-deep .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n"] }]
|
|
3608
|
+
], template: "<!-- Grid Container -->\n<div\n #gridContainer\n [class]=\"gridContainerClasses.join(' ')\"\n [style.height]=\"gridHeightStyle\">\n\n <!-- Toolbar -->\n <div *ngIf=\"ShowToolbar\" class=\"mj-grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div *ngIf=\"ShowSearch\" class=\"toolbar-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n [placeholder]=\"ToolbarConfig.searchPlaceholder || 'Search...'\"\n [value]=\"FilterText\"\n (input)=\"FilterText = $any($event.target).value\" />\n <button\n *ngIf=\"FilterText\"\n class=\"search-clear\"\n (click)=\"FilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Custom Left Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position !== 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Row Count -->\n <span *ngIf=\"ToolbarConfig.showRowCount !== false\" class=\"row-count\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'row' : 'rows' }}\n </span>\n\n <!-- Selection Count -->\n <span *ngIf=\"ToolbarConfig.showSelectionCount && SelectedKeys.length > 0\" class=\"selection-count\">\n ({{ SelectedKeys.length }} selected)\n </span>\n </div>\n\n <div class=\"toolbar-right\">\n <!-- New/Add Button (predefined) -->\n <button\n *ngIf=\"ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Create new record\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span class=\"button-text\">New</span>\n </button>\n\n <!-- Refresh Button (predefined) -->\n <button\n *ngIf=\"ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh data\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i>\n <span class=\"button-text\">Refresh</span>\n </button>\n\n <!-- Export Button (predefined) -->\n <button\n *ngIf=\"ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export to Excel\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n\n <!-- Delete Button (predefined) -->\n <button\n *ngIf=\"ShowDeleteButton && HasSelection\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete selected records\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n <span class=\"button-text\">Delete</span>\n </button>\n\n <!-- Compare Button (predefined) -->\n <button\n *ngIf=\"ShowCompareButton\"\n class=\"toolbar-button\"\n title=\"Compare selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onCompareClick()\">\n <i class=\"fa-solid fa-code-compare\"></i>\n <span class=\"button-text\">Compare</span>\n </button>\n\n <!-- Merge Button (predefined) -->\n <button\n *ngIf=\"ShowMergeButton\"\n class=\"toolbar-button\"\n title=\"Merge selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onMergeClick()\">\n <i class=\"fa-solid fa-code-merge\"></i>\n <span class=\"button-text\">Merge</span>\n </button>\n\n <!-- Add to List Button (predefined) -->\n <button\n *ngIf=\"ShowAddToListButton\"\n class=\"toolbar-button\"\n title=\"Add selected records to a list\"\n [disabled]=\"!HasSelection\"\n (click)=\"onAddToListClick()\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span class=\"button-text\">Add to List</span>\n </button>\n\n <!-- Search for Duplicates Button (predefined) -->\n <button\n *ngIf=\"ShowDuplicateSearchButton\"\n class=\"toolbar-button\"\n title=\"Search for duplicate records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onDuplicateSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n <span class=\"button-text\">Find Duplicates</span>\n </button>\n\n <!-- Communication Button (predefined) -->\n <button\n *ngIf=\"ShowCommunicationButton\"\n class=\"toolbar-button\"\n title=\"Send message to selected records\"\n [disabled]=\"!HasSelection\"\n (click)=\"onCommunicationClick()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span class=\"button-text\">Send Message</span>\n </button>\n\n <!-- Legacy ToolbarConfig buttons -->\n <!-- Add Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showAdd && AllowAdd && !ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Add New\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Refresh Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showRefresh !== false && !ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n </button>\n\n <!-- Delete Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showDelete && AllowDelete && HasSelection && !ShowDeleteButton\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete Selected\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n\n <!-- Export Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showExport && !ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n\n <!-- Column Chooser Button -->\n <button\n *ngIf=\"ToolbarConfig.showColumnChooser && AllowColumnToggle\"\n class=\"toolbar-button\"\n title=\"Column Chooser\"\n (click)=\"onColumnChooserClick()\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n\n <!-- Custom Right Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position === 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n\n <!-- Overflow Menu -->\n <div *ngIf=\"hasOverflowMenuItems\" class=\"toolbar-overflow\" (click)=\"$event.stopPropagation()\">\n <button\n class=\"toolbar-button overflow-trigger\"\n title=\"More actions\"\n (click)=\"toggleOverflowMenu()\">\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </button>\n\n <div *ngIf=\"showOverflowMenu\" class=\"overflow-menu\" [@fadeIn]>\n <!-- Export (if in overflow) -->\n <button *ngIf=\"showExportInOverflow\" class=\"overflow-item\" (click)=\"onExportClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span>Export to Excel</span>\n </button>\n\n <!-- Entity Actions -->\n <ng-container *ngIf=\"ShowEntityActionButtons && EntityActions.length > 0\">\n <div class=\"overflow-divider\"></div>\n <div class=\"overflow-section-label\">Actions</div>\n <button\n *ngFor=\"let action of EntityActions\"\n class=\"overflow-item\"\n [disabled]=\"!isEntityActionEnabled(action)\"\n (click)=\"onEntityActionClick(action); closeOverflowMenu()\">\n <i [class]=\"action.icon || 'fa-solid fa-bolt'\"></i>\n <span>{{ action.name }}</span>\n </button>\n </ng-container>\n\n <!-- Column Chooser (if in overflow) -->\n <div *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-divider\"></div>\n <button *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-item\" (click)=\"onColumnChooserClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-columns\"></i>\n <span>Manage Columns</span>\n </button>\n\n <!-- Selection-dependent actions in overflow -->\n <ng-container *ngIf=\"HasSelection && hasSelectionDependentOverflowActions\">\n <div class=\"overflow-divider\"></div>\n <button *ngIf=\"showCommunicationInOverflow\" class=\"overflow-item\" (click)=\"onCommunicationClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span>Send Message</span>\n </button>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Grid Content -->\n <div class=\"mj-grid-content\">\n <!-- Loading Overlay -->\n <div *ngIf=\"loading && rowData.length === 0\" class=\"mj-grid-loading-overlay\">\n <mj-loading text=\"Loading...\"></mj-loading>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !loading\" class=\"mj-grid-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n <button class=\"error-retry\" (click)=\"Refresh()\">Retry</button>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"!loading && !errorMessage && rowData.length === 0\" class=\"mj-grid-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No data to display</span>\n </div>\n\n <!-- AG Grid (Client-side mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'client' && (rowData.length > 0 || loading)\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [rowData]=\"rowData\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n\n <!-- AG Grid (Infinite Scroll mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'infinite'\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n [rowModelType]=\"'infinite'\"\n [cacheBlockSize]=\"CacheBlockSize\"\n [maxBlocksInCache]=\"MaxBlocksInCache\"\n [infiniteInitialRowCount]=\"1\"\n [cacheOverflowSize]=\"2\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n </div>\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n</mj-export-dialog>\n", styles: ["/* ========================================\n CSS Custom Properties (Theme Variables)\n ======================================== */\n\n:host {\n /* Grid container */\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n /* Header */\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n /* Rows */\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n /* Cells */\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n /* Selection - mellow yellow to avoid conflict with blue hyperlinks */\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n /* Editing */\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n /* Sorting */\n --grid-sort-indicator-color: #2196F3;\n\n /* Toolbar */\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n /* Loading */\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n /* Empty state */\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n/* ========================================\n Grid Container\n ======================================== */\n\n.mj-grid-container {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.mj-grid-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear:hover {\n color: #666;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n.toolbar-button-danger {\n color: #d32f2f;\n}\n\n.toolbar-button-danger:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count,\n.selection-count {\n font-weight: 500;\n}\n\n/* ========================================\n Grid Content\n ======================================== */\n\n.mj-grid-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container {\n height: 100%;\n overflow: auto;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.mj-grid-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n/* ========================================\n Error State\n ======================================== */\n\n.mj-grid-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error i {\n font-size: 32px;\n}\n\n.error-retry {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry:hover {\n background: #c62828;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.mj-grid-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty i {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n/* ========================================\n Header Row\n ======================================== */\n\n.mj-grid-header {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator i {\n font-size: 12px;\n}\n\n.sort-index {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n/* ========================================\n Data Rows\n ======================================== */\n\n.mj-grid-row {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty {\n border-left: 3px solid #ff9800;\n}\n\n/* ========================================\n Data Cells\n ======================================== */\n\n.mj-grid-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell:last-child {\n border-right: none;\n}\n\n/* Grid lines modes */\n.grid-lines-horizontal .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n/* Cell alignment */\n.mj-grid-cell.align-left {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right {\n justify-content: flex-end;\n}\n\n.cell-content {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Special cells */\n.row-number-cell {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n/* ========================================\n Virtual Scrolling\n ======================================== */\n\n.mj-grid-virtual-spacer {\n flex-shrink: 0;\n}\n\n/* ========================================\n Responsive Adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .mj-grid-toolbar {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input {\n width: 100%;\n }\n\n .toolbar-center {\n order: 2;\n }\n\n /* Hide button text on mobile */\n .toolbar-button .button-text {\n display: none;\n }\n}\n\n/* ========================================\n Toolbar Button Text\n ======================================== */\n\n.toolbar-button .button-text {\n font-size: 13px;\n}\n\n/* ========================================\n Overflow Menu\n ======================================== */\n\n.toolbar-overflow {\n position: relative;\n}\n\n.overflow-trigger {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger i {\n font-size: 16px;\n}\n\n.overflow-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item i {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item span {\n flex: 1;\n}\n\n.overflow-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n/* Entity Actions submenu styling */\n.overflow-item.action-item i {\n color: #2196F3;\n}\n\n/* ========================================\n Highlight Matches\n ======================================== */\n\n::ng-deep .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n/* ========================================\n AG Grid Customizations\n ======================================== */\n\n.mj-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n::ng-deep .ag-theme-alpine {\n /* Row colors */\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n /* Selection accent colors - mellow yellow */\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n /* Ensure borders are visible */\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n/* Selected row styling - left indicator bar only, background handled by AG Grid theme */\n::ng-deep .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n/* Selection checkbox styling */\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n/* Row hover effect */\n::ng-deep .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n/* ========================================\n Visual Config: Header Styles\n ======================================== */\n\n/* Flat header (minimal) */\n.header-style-flat ::ng-deep .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n/* Elevated header (default - subtle shadow) */\n.header-style-elevated ::ng-deep .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n/* Gradient header (more prominent) */\n.header-style-gradient ::ng-deep .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n/* Bold header (high contrast) */\n.header-style-bold ::ng-deep .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold ::ng-deep .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold ::ng-deep .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold ::ng-deep .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n/* Header sort icons enhancement */\n::ng-deep .ag-header-cell-sorted-asc .ag-icon-asc,\n::ng-deep .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n/* ========================================\n Visual Config: Zebra Striping\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* ========================================\n Visual Config: Hover Transitions\n ======================================== */\n\n.hover-transitions ::ng-deep .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions ::ng-deep .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n/* ========================================\n Visual Config: Cell Padding\n ======================================== */\n\n.cell-padding-compact ::ng-deep .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact ::ng-deep .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal ::ng-deep .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal ::ng-deep .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n/* ========================================\n Visual Config: Checkbox Styles\n ======================================== */\n\n/* Rounded checkbox */\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n/* Filled checkbox */\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n/* ========================================\n Cell Content Formatting\n ======================================== */\n\n/* Right-aligned cells (numbers) */\n::ng-deep .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n::ng-deep .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n/* Empty cell placeholder */\n::ng-deep .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n/* Boolean icons */\n::ng-deep .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n::ng-deep .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n/* Clickable links */\n::ng-deep .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n::ng-deep .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n/* Email cells */\n::ng-deep .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n/* URL cells */\n::ng-deep .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n/* Phone cells */\n::ng-deep .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n/* ========================================\n Skeleton Loading Animation\n ======================================== */\n\n@keyframes skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short {\n width: 60px;\n}\n\n.skeleton-cell-medium {\n width: 120px;\n}\n\n.skeleton-cell-long {\n width: 180px;\n}\n\n/* Selection checkbox column header */\n::ng-deep .ag-header-select-all {\n margin-right: 0;\n}\n\n/* ========================================\n Row Border Enhancement\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n::ng-deep .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n/* ========================================\n Focus States\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n/* ========================================\n Pinned Column Styling\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n::ng-deep .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n/* ========================================\n Header Cell Enhancements\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n/* Sort icon animation */\n::ng-deep .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n/* ========================================\n Enhanced Multi-Sort Indicators\n These styles use :host to ensure they're scoped to this component\n and !important to override AG Grid's built-in styles\n ======================================== */\n\n/* Highlight sorted column headers with eye-catching background */\n/* Ascending = blue tint */\n:host ::ng-deep .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Descending = pink tint */\n:host ::ng-deep .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Bottom border accent for sorted columns - ascending = blue */\n:host ::ng-deep .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n/* Bottom border accent for sorted columns - descending = pink */\n:host ::ng-deep .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n/* Sorted column header text - ascending = blue, bold */\n:host ::ng-deep .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n/* Sorted column header text - descending = pink, bold */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n/* Sort icons - larger and more prominent */\n/* Ascending = blue */\n:host ::ng-deep .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n/* Descending = pink/magenta */\n:host ::ng-deep .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n:host ::ng-deep .ag-sort-ascending-icon .ag-icon,\n:host ::ng-deep .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n/* Sort order number (1, 2, 3) - show as plain number, no bubble */\n/* This avoids AG Grid bug where .ag-sort-order is always present but empty when unsorted */\n/* The number is only visible when AG Grid populates it (i.e., when column is sorted) */\n/* Default blue for ascending */\n:host ::ng-deep .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n/* Sort order number - pink for descending */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n/* Hover state for sortable headers */\n:host ::ng-deep .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n:host ::ng-deep .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}\n"] }]
|
|
3557
3609
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1.ExportService }], { Params: [{
|
|
3558
3610
|
type: Input
|
|
3559
3611
|
}], AllowLoad: [{
|