@memberjunction/ng-list-detail-grid 5.43.0 → 5.44.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/ng-list-detail-grid.component.js +9 -12
- package/dist/lib/ng-list-detail-grid.component.js.map +1 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -3
- package/dist/module.js.map +1 -1
- package/package.json +9 -8
- package/dist/__tests__/list-detail-grid.test.d.ts +0 -2
- package/dist/__tests__/list-detail-grid.test.d.ts.map +0 -1
- package/dist/__tests__/list-detail-grid.test.js +0 -20
- package/dist/__tests__/list-detail-grid.test.js.map +0 -1
|
@@ -5,6 +5,7 @@ import * as i0 from "@angular/core";
|
|
|
5
5
|
import * as i1 from "@memberjunction/ng-shared";
|
|
6
6
|
import * as i2 from "@memberjunction/ng-entity-viewer";
|
|
7
7
|
import * as i3 from "@memberjunction/ng-shared-generic";
|
|
8
|
+
import * as i4 from "@memberjunction/ng-ui-components";
|
|
8
9
|
const _c0 = ["entityDataGrid"];
|
|
9
10
|
function ListDetailGridComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
10
11
|
i0.ɵɵelementStart(0, "div", 2);
|
|
@@ -12,20 +13,16 @@ function ListDetailGridComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
12
13
|
i0.ɵɵelementEnd();
|
|
13
14
|
} }
|
|
14
15
|
function ListDetailGridComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
15
|
-
i0.ɵɵ
|
|
16
|
-
i0.ɵɵelement(1, "span", 6);
|
|
17
|
-
i0.ɵɵelementStart(2, "p");
|
|
18
|
-
i0.ɵɵtext(3, "Select a list to view its records");
|
|
19
|
-
i0.ɵɵelementEnd()();
|
|
16
|
+
i0.ɵɵelement(0, "mj-empty-state", 3);
|
|
20
17
|
} }
|
|
21
18
|
function ListDetailGridComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
22
19
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
23
|
-
i0.ɵɵelementStart(0, "mj-entity-data-grid",
|
|
20
|
+
i0.ɵɵelementStart(0, "mj-entity-data-grid", 6, 0);
|
|
24
21
|
i0.ɵɵlistener("AfterRowClick", function ListDetailGridComponent_Conditional_3_Template_mj_entity_data_grid_AfterRowClick_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRowClick($event)); })("AfterRowDoubleClick", function ListDetailGridComponent_Conditional_3_Template_mj_entity_data_grid_AfterRowDoubleClick_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRowDoubleClick($event)); })("AfterDataLoad", function ListDetailGridComponent_Conditional_3_Template_mj_entity_data_grid_AfterDataLoad_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("SelectionChange", function ListDetailGridComponent_Conditional_3_Template_mj_entity_data_grid_SelectionChange_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSelectionChange($event)); });
|
|
25
22
|
i0.ɵɵelementEnd();
|
|
26
23
|
} if (rf & 2) {
|
|
27
24
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
28
|
-
i0.ɵɵproperty("Params", ctx_r1.gridParams)("Height", ctx_r1.height)("ShowToolbar", ctx_r1.showToolbar)("ToolbarConfig", ctx_r1.effectiveToolbarConfig)("SelectionMode", ctx_r1.selectionMode);
|
|
25
|
+
i0.ɵɵproperty("Params", ctx_r1.gridParams)("Height", ctx_r1.height)("ShowToolbar", ctx_r1.showToolbar)("ToolbarConfig", ctx_r1.effectiveToolbarConfig)("SelectionMode", ctx_r1.selectionMode)("AllowColumnToggle", false);
|
|
29
26
|
} }
|
|
30
27
|
/**
|
|
31
28
|
* ListDetailGridComponent - Displays records from a List using mj-entity-data-grid
|
|
@@ -354,11 +351,11 @@ export class ListDetailGridComponent extends BaseAngularComponent {
|
|
|
354
351
|
} if (rf & 2) {
|
|
355
352
|
let _t;
|
|
356
353
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.entityDataGrid = _t.first);
|
|
357
|
-
} }, inputs: { listId: "listId", listEntity: "listEntity", autoNavigate: "autoNavigate", height: "height", showToolbar: "showToolbar", selectionMode: "selectionMode", toolbarConfig: "toolbarConfig" }, outputs: { rowClicked: "rowClicked", rowDoubleClicked: "rowDoubleClicked", dataLoaded: "dataLoaded", selectionChange: "selectionChange" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 4, vars: 3, consts: [["entityDataGrid", ""], [1, "list-detail-grid-container"], [1, "loading-container"], [1, "empty
|
|
354
|
+
} }, inputs: { listId: "listId", listEntity: "listEntity", autoNavigate: "autoNavigate", height: "height", showToolbar: "showToolbar", selectionMode: "selectionMode", toolbarConfig: "toolbarConfig" }, outputs: { rowClicked: "rowClicked", rowDoubleClicked: "rowDoubleClicked", dataLoaded: "dataLoaded", selectionChange: "selectionChange" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 4, vars: 3, consts: [["entityDataGrid", ""], [1, "list-detail-grid-container"], [1, "loading-container"], ["Icon", "fa-solid fa-rectangle-list", "Title", "Select a list to view its records", 1, "list-detail-grid-empty"], [3, "Params", "Height", "ShowToolbar", "ToolbarConfig", "SelectionMode", "AllowColumnToggle"], ["text", "Loading list..."], [3, "AfterRowClick", "AfterRowDoubleClick", "AfterDataLoad", "SelectionChange", "Params", "Height", "ShowToolbar", "ToolbarConfig", "SelectionMode", "AllowColumnToggle"]], template: function ListDetailGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
358
355
|
i0.ɵɵelementStart(0, "div", 1);
|
|
359
356
|
i0.ɵɵconditionalCreate(1, ListDetailGridComponent_Conditional_1_Template, 2, 0, "div", 2);
|
|
360
|
-
i0.ɵɵconditionalCreate(2, ListDetailGridComponent_Conditional_2_Template,
|
|
361
|
-
i0.ɵɵconditionalCreate(3, ListDetailGridComponent_Conditional_3_Template, 2,
|
|
357
|
+
i0.ɵɵconditionalCreate(2, ListDetailGridComponent_Conditional_2_Template, 1, 0, "mj-empty-state", 3);
|
|
358
|
+
i0.ɵɵconditionalCreate(3, ListDetailGridComponent_Conditional_3_Template, 2, 6, "mj-entity-data-grid", 4);
|
|
362
359
|
i0.ɵɵelementEnd();
|
|
363
360
|
} if (rf & 2) {
|
|
364
361
|
i0.ɵɵadvance();
|
|
@@ -367,11 +364,11 @@ export class ListDetailGridComponent extends BaseAngularComponent {
|
|
|
367
364
|
i0.ɵɵconditional(!ctx.isLoading && !ctx.listLoaded && !ctx.listId && !ctx.listEntity ? 2 : -1);
|
|
368
365
|
i0.ɵɵadvance();
|
|
369
366
|
i0.ɵɵconditional(ctx.listLoaded && ctx.gridParams ? 3 : -1);
|
|
370
|
-
} }, dependencies: [i2.EntityDataGridComponent, i3.LoadingComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-wrap[_ngcontent-%COMP%] {\n height: calc(100vh - 20px);\n}\n\n.list-detail-grid-column-header[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface);\n font-size: var(--mj-text-xl);\n font-weight: bold;\n}\n\n.title-wrapper[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 0;\n border-bottom: 1px solid var(--med-gray);\n}\n .title-wrapper[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-2xl);\n line-height: 28px;\n }\n .main-fav-wrapper[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 20px;\n }\n .filter-wrapper[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 14px;\n align-items: center;\n}\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n font-size: var(--mj-text-base);\n background: transparent;\n border: none;\n box-sizing: border-box;\n padding-left: 40px;\n\n }\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] {\n background: var(--light-shade);\n width: 360px;\n height: 44px;\n position: relative;\n border-radius: var(--mj-radius-lg);\n }\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] svg[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n left: 12px;\n}\n.k-table-td[_ngcontent-%COMP%] {\n border-right: none !important;\n}.btn-cmn[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n min-width: 44px;\n background: transparent;\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--gray-color);\n}\n.btn-cmn.active[_ngcontent-%COMP%] {\n border: 1px solid var(--border-blue);\n}\n .title-wrapper .filter-wrapper .k-dropdown-button .k-button {\n border: 1px solid var(--gray-color);\n border-radius: var(--mj-radius-md); padding: 10px 25px;\n background: var(--white-color);\n color: var(--sideNav);\n}\n .list-detail-grid-wrap .k-grid-aria-root .k-grid-header .k-grid-header-table thead tr th {\n border-right: none;\n border-inline-start-width: 0;\n color: var(--thead-color);\n}\n .list-detail-grid-wrap .k-grid-aria-root .k-grid-table tbody tr td {\n border-inline-start-width: 0;\n color: var(--tdata-color);\n font-weight: 500;\n border-bottom-width: 1px;\n}"] });
|
|
367
|
+
} }, dependencies: [i2.EntityDataGridComponent, i3.LoadingComponent, i4.MJEmptyStateComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-wrap[_ngcontent-%COMP%] {\n height: calc(100vh - 20px);\n}\n\n.list-detail-grid-empty[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.list-detail-grid-column-header[_ngcontent-%COMP%] {\n background-color: var(--mj-bg-surface);\n font-size: var(--mj-text-xl);\n font-weight: bold;\n}\n\n.title-wrapper[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 0;\n border-bottom: 1px solid var(--med-gray);\n}\n .title-wrapper[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-2xl);\n line-height: 28px;\n }\n .main-fav-wrapper[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 20px;\n }\n .filter-wrapper[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 14px;\n align-items: center;\n}\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n font-size: var(--mj-text-base);\n background: transparent;\n border: none;\n box-sizing: border-box;\n padding-left: 40px;\n\n }\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] {\n background: var(--light-shade);\n width: 360px;\n height: 44px;\n position: relative;\n border-radius: var(--mj-radius-lg);\n }\n .title-wrapper[_ngcontent-%COMP%] .search[_ngcontent-%COMP%] svg[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n left: 12px;\n}\n.k-table-td[_ngcontent-%COMP%] {\n border-right: none !important;\n}.btn-cmn[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n min-width: 44px;\n background: transparent;\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--gray-color);\n}\n.btn-cmn.active[_ngcontent-%COMP%] {\n border: 1px solid var(--border-blue);\n}\n .title-wrapper .filter-wrapper .k-dropdown-button .k-button {\n border: 1px solid var(--gray-color);\n border-radius: var(--mj-radius-md); padding: 10px 25px;\n background: var(--white-color);\n color: var(--sideNav);\n}\n .list-detail-grid-wrap .k-grid-aria-root .k-grid-header .k-grid-header-table thead tr th {\n border-right: none;\n border-inline-start-width: 0;\n color: var(--thead-color);\n}\n .list-detail-grid-wrap .k-grid-aria-root .k-grid-table tbody tr td {\n border-inline-start-width: 0;\n color: var(--tdata-color);\n font-weight: 500;\n border-bottom-width: 1px;\n}"] });
|
|
371
368
|
}
|
|
372
369
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ListDetailGridComponent, [{
|
|
373
370
|
type: Component,
|
|
374
|
-
args: [{ standalone: false, selector: 'mj-list-detail-grid', template: "<div class=\"list-detail-grid-container\">\n <!-- Loading state while list is being loaded -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading list...\"></mj-loading>\n </div>\n }\n\n <!-- Empty state when no list is selected -->\n @if (!isLoading && !listLoaded && !listId && !listEntity) {\n <
|
|
371
|
+
args: [{ standalone: false, selector: 'mj-list-detail-grid', template: "<div class=\"list-detail-grid-container\">\n <!-- Loading state while list is being loaded -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading list...\"></mj-loading>\n </div>\n }\n\n <!-- Empty state when no list is selected -->\n @if (!isLoading && !listLoaded && !listId && !listEntity) {\n <mj-empty-state\n class=\"list-detail-grid-empty\"\n Icon=\"fa-solid fa-rectangle-list\"\n Title=\"Select a list to view its records\" />\n }\n\n <!-- Grid display when list is loaded -->\n @if (listLoaded && gridParams) {\n <!-- List detail grid is not a saved User View, so there's no canonical GridState to manage \u2014\n suppress the \"Manage Columns\" chooser (AllowColumnToggle=false). -->\n <mj-entity-data-grid\n #entityDataGrid\n [Params]=\"gridParams\"\n [Height]=\"height\"\n [ShowToolbar]=\"showToolbar\"\n [ToolbarConfig]=\"effectiveToolbarConfig\"\n [SelectionMode]=\"selectionMode\"\n [AllowColumnToggle]=\"false\"\n (AfterRowClick)=\"onRowClick($event)\"\n (AfterRowDoubleClick)=\"onRowDoubleClick($event)\"\n (AfterDataLoad)=\"onDataLoaded($event)\"\n (SelectionChange)=\"onSelectionChange($event)\">\n </mj-entity-data-grid>\n }\n</div>\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.list-detail-grid-wrap {\n height: calc(100vh - 20px);\n}\n\n.list-detail-grid-empty {\n flex: 1;\n}\n\n.list-detail-grid-column-header {\n background-color: var(--mj-bg-surface);\n font-size: var(--mj-text-xl);\n font-weight: bold;\n}\n\n.title-wrapper {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 0;\n border-bottom: 1px solid var(--med-gray);\n}\n .title-wrapper h4 {\n margin: 0;\n font-size: var(--mj-text-2xl);\n line-height: 28px;\n }\n .main-fav-wrapper {\n background: var(--mj-bg-surface);\n padding: 20px;\n }\n .filter-wrapper {\n display: flex;\n justify-content: flex-start;\n gap: 14px;\n align-items: center;\n}\n .title-wrapper .search input {\n width: 100%;\n height: 100%;\n font-size: var(--mj-text-base);\n background: transparent;\n border: none;\n box-sizing: border-box;\n padding-left: 40px;\n\n }\n .title-wrapper .search {\n background: var(--light-shade);\n width: 360px;\n height: 44px;\n position: relative;\n border-radius: var(--mj-radius-lg);\n }\n .title-wrapper .search svg {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n left: 12px;\n}\n.k-table-td {\n border-right: none !important;\n}.btn-cmn {\n width: 44px;\n height: 44px;\n min-width: 44px;\n background: transparent;\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--gray-color);\n}\n.btn-cmn.active {\n border: 1px solid var(--border-blue);\n}\n::ng-deep .title-wrapper .filter-wrapper .k-dropdown-button .k-button {\n border: 1px solid var(--gray-color);\n border-radius: var(--mj-radius-md); padding: 10px 25px;\n background: var(--white-color);\n color: var(--sideNav);\n}\n::ng-deep .list-detail-grid-wrap .k-grid-aria-root .k-grid-header .k-grid-header-table thead tr th {\n border-right: none;\n border-inline-start-width: 0;\n color: var(--thead-color);\n}\n::ng-deep .list-detail-grid-wrap .k-grid-aria-root .k-grid-table tbody tr td {\n border-inline-start-width: 0;\n color: var(--tdata-color);\n font-weight: 500;\n border-bottom-width: 1px;\n}"] }]
|
|
375
372
|
}], () => [{ type: i1.SharedService }, { type: i0.ChangeDetectorRef }], { listId: [{
|
|
376
373
|
type: Input
|
|
377
374
|
}], listEntity: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-list-detail-grid.component.js","sourceRoot":"","sources":["../../src/lib/ng-list-detail-grid.component.ts","../../src/lib/ng-list-detail-grid.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ViewChild\n} from '@angular/core';\nimport { Metadata, EntityInfo, CompositeKey, BaseEntity, RunViewParams } from '@memberjunction/core';\nimport { MJListEntity } from '@memberjunction/core-entities';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport {\n AfterRowClickEventArgs,\n AfterRowDoubleClickEventArgs,\n AfterDataLoadEventArgs,\n GridToolbarConfig,\n GridSelectionMode,\n EntityDataGridComponent\n} from '@memberjunction/ng-entity-viewer';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n/**\n * Event emitted when a row is clicked in the list detail grid\n */\nexport interface ListGridRowClickedEvent {\n entityId: string;\n entityName: string;\n compositeKey: CompositeKey;\n record: Record<string, unknown>;\n}\n\n/**\n * ListDetailGridComponent - Displays records from a List using mj-entity-data-grid\n *\n * This component wraps the modern mj-entity-data-grid component to display\n * records that belong to a specific List. It uses a subquery filter to fetch\n * only records whose IDs are in the List Details for the given ListID.\n *\n * @example\n * ```html\n * <mj-list-detail-grid\n * [listId]=\"selectedList.ID\"\n * [autoNavigate]=\"true\"\n * (rowClicked)=\"onRecordSelected($event)\">\n * </mj-list-detail-grid>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-list-detail-grid',\n templateUrl: './ng-list-detail-grid.component.html',\n styleUrls: ['./ng-list-detail-grid.component.css']\n})\nexport class ListDetailGridComponent extends BaseAngularComponent implements OnInit, OnChanges {\n /**\n * The List ID to display records for.\n * When set, the component loads the list entity and builds a filter\n * to show only records that are in this list.\n */\n @Input() listId: string | null = null;\n\n /**\n * Optional: The List entity object if already loaded.\n * If provided, avoids an extra database call to load the list.\n */\n @Input() listEntity: MJListEntity | null = null;\n\n /**\n * Whether to auto-navigate to the record when double-clicked.\n * Defaults to true.\n */\n @Input() autoNavigate: boolean = true;\n\n /**\n * Height of the grid. Can be a number (pixels), 'auto', or 'fit-content'.\n * Defaults to 'auto'.\n */\n @Input() height: number | 'auto' | 'fit-content' = 'auto';\n\n /**\n * Show the grid toolbar.\n * Defaults to true.\n */\n @Input() showToolbar: boolean = true;\n\n /**\n * Selection mode for the grid.\n * Defaults to 'single'.\n */\n @Input() selectionMode: GridSelectionMode = 'single';\n\n /**\n * Emitted when a row is clicked (single click).\n */\n @Output() rowClicked = new EventEmitter<ListGridRowClickedEvent>();\n\n /**\n * Emitted when a row is double-clicked.\n */\n @Output() rowDoubleClicked = new EventEmitter<ListGridRowClickedEvent>();\n\n /**\n * Emitted when the grid data is loaded.\n */\n @Output() dataLoaded = new EventEmitter<{ totalCount: number }>();\n\n /**\n * Emitted when row selection changes (for checkbox mode).\n */\n @Output() selectionChange = new EventEmitter<string[]>();\n\n /**\n * Custom toolbar configuration. If not provided, uses default.\n */\n @Input() toolbarConfig: GridToolbarConfig | null = null;\n\n // ViewChild to access the underlying EDG component\n @ViewChild('entityDataGrid') entityDataGrid: EntityDataGridComponent | undefined;\n\n // Internal state\n entityInfo: EntityInfo | null = null;\n gridParams: RunViewParams | null = null;\n isLoading: boolean = false;\n listLoaded: boolean = false;\n selectedKeys: string[] = [];\n totalRowCount: number = 0;\n\n // Default toolbar configuration - minimal for list display\n private defaultToolbarConfig: GridToolbarConfig = {\n showSearch: true,\n showRefresh: true,\n showAdd: false,\n showDelete: false,\n showExport: true,\n showRowCount: true,\n showSelectionCount: true\n };\n\n /**\n * Get the effective toolbar config (custom or default)\n */\n get effectiveToolbarConfig(): GridToolbarConfig {\n return this.toolbarConfig || this.defaultToolbarConfig;\n }\n\n constructor(\n private sharedService: SharedService,\n private cdr: ChangeDetectorRef\n ) {\n super();}\n\n ngOnInit(): void {\n if (this.listId || this.listEntity) {\n this.loadList();\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['listId'] || changes['listEntity']) {\n this.loadList();\n }\n }\n\n /**\n * Build the SQL filter to select records that are in the given list.\n * For single PK entities, uses a simple IN clause.\n * For composite PK entities, uses a JOIN that concatenates PK columns to match the RecordID format.\n */\n private buildListFilter(entityInfo: EntityInfo, listDetailsSchema: string, listId: string): string {\n const primaryKeys = entityInfo.PrimaryKeys;\n\n if (primaryKeys.length === 1) {\n // Simple case: single primary key\n // Use a simple IN clause matching the first PK field\n const pkField = primaryKeys[0].Name;\n return `${pkField} IN (SELECT RecordID FROM ${listDetailsSchema}.vwListDetails WHERE ListID = '${listId}')`;\n } else {\n // Composite key case: need to JOIN and match concatenated key format\n // RecordID format is \"Field1|Value1||Field2|Value2\" (using CompositeKey delimiters)\n // Build SQL expression that concatenates the PK fields in the same format\n // Build the concatenation expression for the entity's PK columns\n // Format: Field1 + '|' + CAST(Value1 AS NVARCHAR(MAX)) + '||' + Field2 + '|' + CAST(Value2 AS NVARCHAR(MAX))\n const concatParts = primaryKeys.map((pk, index) => {\n const fieldNameLiteral = `'${pk.Name}|'`;\n const fieldValue = `CAST([${pk.Name}] AS NVARCHAR(MAX))`;\n if (index === 0) {\n return `${fieldNameLiteral} + ${fieldValue}`;\n } else {\n return `'||' + ${fieldNameLiteral} + ${fieldValue}`;\n }\n });\n const compositeKeyExpr = concatParts.join(' + ');\n\n // Use EXISTS with a subquery that matches the concatenated key against RecordID\n return `EXISTS (\n SELECT 1 FROM ${listDetailsSchema}.vwListDetails ld\n WHERE ld.ListID = '${listId}'\n AND ld.RecordID = (${compositeKeyExpr})\n )`;\n }\n }\n\n /**\n * Load the list entity and set up the grid params with filter\n */\n private async loadList(): Promise<void> {\n // Reset state\n this.listLoaded = false;\n this.gridParams = null;\n\n if (!this.listId && !this.listEntity) {\n return;\n }\n\n this.isLoading = true;\n this.cdr.detectChanges();\n\n try {\n const md = this.ProviderToUse;\n let list: MJListEntity | null = this.listEntity;\n\n // Load the list entity if not provided\n if (!list && this.listId) {\n list = await md.GetEntityObject<MJListEntity>('MJ: Lists');\n await list.Load(this.listId);\n }\n\n if (!list) {\n console.error('Failed to load list');\n return;\n }\n\n // Get the entity info for this list\n const entityInfo = md.EntityByID(list.EntityID);\n if (!entityInfo) {\n console.error(`Entity not found for ID: ${list.EntityID}`);\n return;\n }\n\n this.entityInfo = entityInfo;\n\n // Get the List Details entity info to get the correct schema name\n const listDetailsEntityInfo = md.EntityByName('MJ: List Details');\n if (!listDetailsEntityInfo) {\n console.error('List Details entity not found in metadata');\n return;\n }\n\n // Build the subquery filter to get records in this list\n // Uses the primary key field(s) of the entity and the schema from List Details entity\n const schema = listDetailsEntityInfo.SchemaName;\n const extraFilter = this.buildListFilter(entityInfo, schema, list.ID);\n\n // The grid filter is a cross-entity subquery into `vwListDetails`\n // (`ID IN (SELECT RecordID FROM vwListDetails WHERE ListID='…')`).\n // The server's RunView cache fingerprints by the OUTER entity, so a\n // mutation on `MJ: List Details` doesn't invalidate this query's\n // cached result — the grid would otherwise serve stale rows until a\n // server restart. `BypassCache: true` makes the server skip both\n // the cache lookup and the write for this query.\n this.gridParams = {\n EntityName: entityInfo.Name,\n ExtraFilter: extraFilter,\n ResultType: 'entity_object',\n BypassCache: true\n };\n\n this.listLoaded = true;\n } catch (error) {\n console.error('Error loading list:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handle row click event from the grid\n */\n onRowClick(event: AfterRowClickEventArgs): void {\n if (!this.entityInfo || !event.row) return;\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(this.entityInfo, event.row);\n\n this.rowClicked.emit({\n entityId: this.entityInfo.ID,\n entityName: this.entityInfo.Name,\n compositeKey,\n record: event.row\n });\n }\n\n /**\n * Handle row double-click event from the grid\n */\n onRowDoubleClick(event: AfterRowDoubleClickEventArgs): void {\n if (!this.entityInfo || !event.row) return;\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(this.entityInfo, event.row);\n\n this.rowDoubleClicked.emit({\n entityId: this.entityInfo.ID,\n entityName: this.entityInfo.Name,\n compositeKey,\n record: event.row\n });\n\n // Auto-navigate if enabled - use SharedService for proper tab-based navigation\n if (this.autoNavigate) {\n this.sharedService.OpenEntityRecord(this.entityInfo.Name, compositeKey);\n }\n }\n\n /**\n * Handle data loaded event from the grid\n */\n onDataLoaded(event: AfterDataLoadEventArgs): void {\n this.totalRowCount = event.totalRowCount;\n this.dataLoaded.emit({ totalCount: event.totalRowCount });\n }\n\n /**\n * Handle selection change from the grid\n */\n onSelectionChange(keys: string[]): void {\n this.selectedKeys = keys;\n this.selectionChange.emit(keys);\n }\n\n /**\n * Refresh the grid data\n */\n refresh(): void {\n // Re-trigger load to refresh data\n this.loadList();\n }\n\n /**\n * Get the currently selected entity objects\n */\n getSelectedRows(): Record<string, unknown>[] {\n if (this.entityDataGrid) {\n return this.entityDataGrid.GetSelectedRows();\n }\n return [];\n }\n\n /**\n * Clear all selections\n */\n clearSelection(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.ClearSelection();\n }\n this.selectedKeys = [];\n }\n\n /**\n * Select specific rows by key\n */\n selectRows(keys: string[], additive: boolean = false): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.SelectRows(keys, additive);\n }\n }\n\n /**\n * Select all rows\n */\n selectAll(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.SelectAll();\n }\n }\n\n /**\n * Get the total row count\n */\n get rowCount(): number {\n return this.totalRowCount;\n }\n\n /**\n * Get the selected row count\n */\n get selectedCount(): number {\n return this.selectedKeys.length;\n }\n\n /**\n * Trigger the export dialog\n */\n export(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.onExportClick();\n }\n }\n}\n","<div class=\"list-detail-grid-container\">\n <!-- Loading state while list is being loaded -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading list...\"></mj-loading>\n </div>\n }\n\n <!-- Empty state when no list is selected -->\n @if (!isLoading && !listLoaded && !listId && !listEntity) {\n <div class=\"empty-state\">\n <span class=\"fa-solid fa-rectangle-list empty-icon\"></span>\n <p>Select a list to view its records</p>\n </div>\n }\n\n <!-- Grid display when list is loaded -->\n @if (listLoaded && gridParams) {\n <mj-entity-data-grid\n #entityDataGrid\n [Params]=\"gridParams\"\n [Height]=\"height\"\n [ShowToolbar]=\"showToolbar\"\n [ToolbarConfig]=\"effectiveToolbarConfig\"\n [SelectionMode]=\"selectionMode\"\n (AfterRowClick)=\"onRowClick($event)\"\n (AfterRowDoubleClick)=\"onRowDoubleClick($event)\"\n (AfterDataLoad)=\"onDataLoaded($event)\"\n (SelectionChange)=\"onSelectionChange($event)\">\n </mj-entity-data-grid>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"ng-list-detail-grid.component.js","sourceRoot":"","sources":["../../src/lib/ng-list-detail-grid.component.ts","../../src/lib/ng-list-detail-grid.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit,\n OnChanges,\n SimpleChanges,\n ChangeDetectorRef,\n ViewChild\n} from '@angular/core';\nimport { Metadata, EntityInfo, CompositeKey, BaseEntity, RunViewParams } from '@memberjunction/core';\nimport { MJListEntity } from '@memberjunction/core-entities';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport {\n AfterRowClickEventArgs,\n AfterRowDoubleClickEventArgs,\n AfterDataLoadEventArgs,\n GridToolbarConfig,\n GridSelectionMode,\n EntityDataGridComponent\n} from '@memberjunction/ng-entity-viewer';\n\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n/**\n * Event emitted when a row is clicked in the list detail grid\n */\nexport interface ListGridRowClickedEvent {\n entityId: string;\n entityName: string;\n compositeKey: CompositeKey;\n record: Record<string, unknown>;\n}\n\n/**\n * ListDetailGridComponent - Displays records from a List using mj-entity-data-grid\n *\n * This component wraps the modern mj-entity-data-grid component to display\n * records that belong to a specific List. It uses a subquery filter to fetch\n * only records whose IDs are in the List Details for the given ListID.\n *\n * @example\n * ```html\n * <mj-list-detail-grid\n * [listId]=\"selectedList.ID\"\n * [autoNavigate]=\"true\"\n * (rowClicked)=\"onRecordSelected($event)\">\n * </mj-list-detail-grid>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-list-detail-grid',\n templateUrl: './ng-list-detail-grid.component.html',\n styleUrls: ['./ng-list-detail-grid.component.css']\n})\nexport class ListDetailGridComponent extends BaseAngularComponent implements OnInit, OnChanges {\n /**\n * The List ID to display records for.\n * When set, the component loads the list entity and builds a filter\n * to show only records that are in this list.\n */\n @Input() listId: string | null = null;\n\n /**\n * Optional: The List entity object if already loaded.\n * If provided, avoids an extra database call to load the list.\n */\n @Input() listEntity: MJListEntity | null = null;\n\n /**\n * Whether to auto-navigate to the record when double-clicked.\n * Defaults to true.\n */\n @Input() autoNavigate: boolean = true;\n\n /**\n * Height of the grid. Can be a number (pixels), 'auto', or 'fit-content'.\n * Defaults to 'auto'.\n */\n @Input() height: number | 'auto' | 'fit-content' = 'auto';\n\n /**\n * Show the grid toolbar.\n * Defaults to true.\n */\n @Input() showToolbar: boolean = true;\n\n /**\n * Selection mode for the grid.\n * Defaults to 'single'.\n */\n @Input() selectionMode: GridSelectionMode = 'single';\n\n /**\n * Emitted when a row is clicked (single click).\n */\n @Output() rowClicked = new EventEmitter<ListGridRowClickedEvent>();\n\n /**\n * Emitted when a row is double-clicked.\n */\n @Output() rowDoubleClicked = new EventEmitter<ListGridRowClickedEvent>();\n\n /**\n * Emitted when the grid data is loaded.\n */\n @Output() dataLoaded = new EventEmitter<{ totalCount: number }>();\n\n /**\n * Emitted when row selection changes (for checkbox mode).\n */\n @Output() selectionChange = new EventEmitter<string[]>();\n\n /**\n * Custom toolbar configuration. If not provided, uses default.\n */\n @Input() toolbarConfig: GridToolbarConfig | null = null;\n\n // ViewChild to access the underlying EDG component\n @ViewChild('entityDataGrid') entityDataGrid: EntityDataGridComponent | undefined;\n\n // Internal state\n entityInfo: EntityInfo | null = null;\n gridParams: RunViewParams | null = null;\n isLoading: boolean = false;\n listLoaded: boolean = false;\n selectedKeys: string[] = [];\n totalRowCount: number = 0;\n\n // Default toolbar configuration - minimal for list display\n private defaultToolbarConfig: GridToolbarConfig = {\n showSearch: true,\n showRefresh: true,\n showAdd: false,\n showDelete: false,\n showExport: true,\n showRowCount: true,\n showSelectionCount: true\n };\n\n /**\n * Get the effective toolbar config (custom or default)\n */\n get effectiveToolbarConfig(): GridToolbarConfig {\n return this.toolbarConfig || this.defaultToolbarConfig;\n }\n\n constructor(\n private sharedService: SharedService,\n private cdr: ChangeDetectorRef\n ) {\n super();}\n\n ngOnInit(): void {\n if (this.listId || this.listEntity) {\n this.loadList();\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['listId'] || changes['listEntity']) {\n this.loadList();\n }\n }\n\n /**\n * Build the SQL filter to select records that are in the given list.\n * For single PK entities, uses a simple IN clause.\n * For composite PK entities, uses a JOIN that concatenates PK columns to match the RecordID format.\n */\n private buildListFilter(entityInfo: EntityInfo, listDetailsSchema: string, listId: string): string {\n const primaryKeys = entityInfo.PrimaryKeys;\n\n if (primaryKeys.length === 1) {\n // Simple case: single primary key\n // Use a simple IN clause matching the first PK field\n const pkField = primaryKeys[0].Name;\n return `${pkField} IN (SELECT RecordID FROM ${listDetailsSchema}.vwListDetails WHERE ListID = '${listId}')`;\n } else {\n // Composite key case: need to JOIN and match concatenated key format\n // RecordID format is \"Field1|Value1||Field2|Value2\" (using CompositeKey delimiters)\n // Build SQL expression that concatenates the PK fields in the same format\n // Build the concatenation expression for the entity's PK columns\n // Format: Field1 + '|' + CAST(Value1 AS NVARCHAR(MAX)) + '||' + Field2 + '|' + CAST(Value2 AS NVARCHAR(MAX))\n const concatParts = primaryKeys.map((pk, index) => {\n const fieldNameLiteral = `'${pk.Name}|'`;\n const fieldValue = `CAST([${pk.Name}] AS NVARCHAR(MAX))`;\n if (index === 0) {\n return `${fieldNameLiteral} + ${fieldValue}`;\n } else {\n return `'||' + ${fieldNameLiteral} + ${fieldValue}`;\n }\n });\n const compositeKeyExpr = concatParts.join(' + ');\n\n // Use EXISTS with a subquery that matches the concatenated key against RecordID\n return `EXISTS (\n SELECT 1 FROM ${listDetailsSchema}.vwListDetails ld\n WHERE ld.ListID = '${listId}'\n AND ld.RecordID = (${compositeKeyExpr})\n )`;\n }\n }\n\n /**\n * Load the list entity and set up the grid params with filter\n */\n private async loadList(): Promise<void> {\n // Reset state\n this.listLoaded = false;\n this.gridParams = null;\n\n if (!this.listId && !this.listEntity) {\n return;\n }\n\n this.isLoading = true;\n this.cdr.detectChanges();\n\n try {\n const md = this.ProviderToUse;\n let list: MJListEntity | null = this.listEntity;\n\n // Load the list entity if not provided\n if (!list && this.listId) {\n list = await md.GetEntityObject<MJListEntity>('MJ: Lists');\n await list.Load(this.listId);\n }\n\n if (!list) {\n console.error('Failed to load list');\n return;\n }\n\n // Get the entity info for this list\n const entityInfo = md.EntityByID(list.EntityID);\n if (!entityInfo) {\n console.error(`Entity not found for ID: ${list.EntityID}`);\n return;\n }\n\n this.entityInfo = entityInfo;\n\n // Get the List Details entity info to get the correct schema name\n const listDetailsEntityInfo = md.EntityByName('MJ: List Details');\n if (!listDetailsEntityInfo) {\n console.error('List Details entity not found in metadata');\n return;\n }\n\n // Build the subquery filter to get records in this list\n // Uses the primary key field(s) of the entity and the schema from List Details entity\n const schema = listDetailsEntityInfo.SchemaName;\n const extraFilter = this.buildListFilter(entityInfo, schema, list.ID);\n\n // The grid filter is a cross-entity subquery into `vwListDetails`\n // (`ID IN (SELECT RecordID FROM vwListDetails WHERE ListID='…')`).\n // The server's RunView cache fingerprints by the OUTER entity, so a\n // mutation on `MJ: List Details` doesn't invalidate this query's\n // cached result — the grid would otherwise serve stale rows until a\n // server restart. `BypassCache: true` makes the server skip both\n // the cache lookup and the write for this query.\n this.gridParams = {\n EntityName: entityInfo.Name,\n ExtraFilter: extraFilter,\n ResultType: 'entity_object',\n BypassCache: true\n };\n\n this.listLoaded = true;\n } catch (error) {\n console.error('Error loading list:', error);\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Handle row click event from the grid\n */\n onRowClick(event: AfterRowClickEventArgs): void {\n if (!this.entityInfo || !event.row) return;\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(this.entityInfo, event.row);\n\n this.rowClicked.emit({\n entityId: this.entityInfo.ID,\n entityName: this.entityInfo.Name,\n compositeKey,\n record: event.row\n });\n }\n\n /**\n * Handle row double-click event from the grid\n */\n onRowDoubleClick(event: AfterRowDoubleClickEventArgs): void {\n if (!this.entityInfo || !event.row) return;\n\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromEntityInfoAndRecord(this.entityInfo, event.row);\n\n this.rowDoubleClicked.emit({\n entityId: this.entityInfo.ID,\n entityName: this.entityInfo.Name,\n compositeKey,\n record: event.row\n });\n\n // Auto-navigate if enabled - use SharedService for proper tab-based navigation\n if (this.autoNavigate) {\n this.sharedService.OpenEntityRecord(this.entityInfo.Name, compositeKey);\n }\n }\n\n /**\n * Handle data loaded event from the grid\n */\n onDataLoaded(event: AfterDataLoadEventArgs): void {\n this.totalRowCount = event.totalRowCount;\n this.dataLoaded.emit({ totalCount: event.totalRowCount });\n }\n\n /**\n * Handle selection change from the grid\n */\n onSelectionChange(keys: string[]): void {\n this.selectedKeys = keys;\n this.selectionChange.emit(keys);\n }\n\n /**\n * Refresh the grid data\n */\n refresh(): void {\n // Re-trigger load to refresh data\n this.loadList();\n }\n\n /**\n * Get the currently selected entity objects\n */\n getSelectedRows(): Record<string, unknown>[] {\n if (this.entityDataGrid) {\n return this.entityDataGrid.GetSelectedRows();\n }\n return [];\n }\n\n /**\n * Clear all selections\n */\n clearSelection(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.ClearSelection();\n }\n this.selectedKeys = [];\n }\n\n /**\n * Select specific rows by key\n */\n selectRows(keys: string[], additive: boolean = false): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.SelectRows(keys, additive);\n }\n }\n\n /**\n * Select all rows\n */\n selectAll(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.SelectAll();\n }\n }\n\n /**\n * Get the total row count\n */\n get rowCount(): number {\n return this.totalRowCount;\n }\n\n /**\n * Get the selected row count\n */\n get selectedCount(): number {\n return this.selectedKeys.length;\n }\n\n /**\n * Trigger the export dialog\n */\n export(): void {\n if (this.entityDataGrid) {\n this.entityDataGrid.onExportClick();\n }\n }\n}\n","<div class=\"list-detail-grid-container\">\n <!-- Loading state while list is being loaded -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading list...\"></mj-loading>\n </div>\n }\n\n <!-- Empty state when no list is selected -->\n @if (!isLoading && !listLoaded && !listId && !listEntity) {\n <mj-empty-state\n class=\"list-detail-grid-empty\"\n Icon=\"fa-solid fa-rectangle-list\"\n Title=\"Select a list to view its records\" />\n }\n\n <!-- Grid display when list is loaded -->\n @if (listLoaded && gridParams) {\n <!-- List detail grid is not a saved User View, so there's no canonical GridState to manage —\n suppress the \"Manage Columns\" chooser (AllowColumnToggle=false). -->\n <mj-entity-data-grid\n #entityDataGrid\n [Params]=\"gridParams\"\n [Height]=\"height\"\n [ShowToolbar]=\"showToolbar\"\n [ToolbarConfig]=\"effectiveToolbarConfig\"\n [SelectionMode]=\"selectionMode\"\n [AllowColumnToggle]=\"false\"\n (AfterRowClick)=\"onRowClick($event)\"\n (AfterRowDoubleClick)=\"onRowDoubleClick($event)\"\n (AfterDataLoad)=\"onDataLoaded($event)\"\n (SelectionChange)=\"onSelectionChange($event)\">\n </mj-entity-data-grid>\n }\n</div>\n"]}
|
package/dist/module.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ import * as i2 from "@angular/common";
|
|
|
4
4
|
import * as i3 from "@angular/router";
|
|
5
5
|
import * as i4 from "@memberjunction/ng-entity-viewer";
|
|
6
6
|
import * as i5 from "@memberjunction/ng-shared-generic";
|
|
7
|
+
import * as i6 from "@memberjunction/ng-ui-components";
|
|
7
8
|
export declare class ListDetailGridModule {
|
|
8
9
|
static ɵfac: i0.ɵɵFactoryDeclaration<ListDetailGridModule, never>;
|
|
9
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<ListDetailGridModule, [typeof i1.ListDetailGridComponent], [typeof i2.CommonModule, typeof i3.RouterModule, typeof i4.EntityViewerModule, typeof i5.SharedGenericModule], [typeof i1.ListDetailGridComponent]>;
|
|
10
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<ListDetailGridModule, [typeof i1.ListDetailGridComponent], [typeof i2.CommonModule, typeof i3.RouterModule, typeof i4.EntityViewerModule, typeof i5.SharedGenericModule, typeof i6.MJEmptyStateComponent], [typeof i1.ListDetailGridComponent]>;
|
|
10
11
|
static ɵinj: i0.ɵɵInjectorDeclaration<ListDetailGridModule>;
|
|
11
12
|
}
|
|
12
13
|
//# sourceMappingURL=module.d.ts.map
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":";;;;;;;AAWA,qBAea,oBAAoB;yCAApB,oBAAoB;0CAApB,oBAAoB;0CAApB,oBAAoB;CAAI"}
|
package/dist/module.js
CHANGED
|
@@ -4,6 +4,7 @@ import { RouterModule } from '@angular/router';
|
|
|
4
4
|
// MemberJunction modules
|
|
5
5
|
import { EntityViewerModule } from '@memberjunction/ng-entity-viewer';
|
|
6
6
|
import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
|
|
7
|
+
import { MJEmptyStateComponent } from '@memberjunction/ng-ui-components';
|
|
7
8
|
import { ListDetailGridComponent } from './lib/ng-list-detail-grid.component';
|
|
8
9
|
import * as i0 from "@angular/core";
|
|
9
10
|
export class ListDetailGridModule {
|
|
@@ -12,7 +13,8 @@ export class ListDetailGridModule {
|
|
|
12
13
|
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
|
|
13
14
|
RouterModule,
|
|
14
15
|
EntityViewerModule,
|
|
15
|
-
SharedGenericModule
|
|
16
|
+
SharedGenericModule,
|
|
17
|
+
MJEmptyStateComponent] });
|
|
16
18
|
}
|
|
17
19
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ListDetailGridModule, [{
|
|
18
20
|
type: NgModule,
|
|
@@ -24,7 +26,8 @@ export class ListDetailGridModule {
|
|
|
24
26
|
CommonModule,
|
|
25
27
|
RouterModule,
|
|
26
28
|
EntityViewerModule,
|
|
27
|
-
SharedGenericModule
|
|
29
|
+
SharedGenericModule,
|
|
30
|
+
MJEmptyStateComponent
|
|
28
31
|
],
|
|
29
32
|
exports: [
|
|
30
33
|
ListDetailGridComponent
|
|
@@ -34,5 +37,6 @@ export class ListDetailGridModule {
|
|
|
34
37
|
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(ListDetailGridModule, { declarations: [ListDetailGridComponent], imports: [CommonModule,
|
|
35
38
|
RouterModule,
|
|
36
39
|
EntityViewerModule,
|
|
37
|
-
SharedGenericModule
|
|
40
|
+
SharedGenericModule,
|
|
41
|
+
MJEmptyStateComponent], exports: [ListDetailGridComponent] }); })();
|
|
38
42
|
//# sourceMappingURL=module.js.map
|
package/dist/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;;AAiB9E,MAAM,OAAO,oBAAoB;8GAApB,oBAAoB;4DAApB,oBAAoB;gEAV7B,YAAY;YACZ,YAAY;YACZ,kBAAkB;YAClB,mBAAmB;YACnB,qBAAqB;;iFAMZ,oBAAoB;cAfhC,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,uBAAuB;iBACxB;gBACD,OAAO,EAAE;oBACP,YAAY;oBACZ,YAAY;oBACZ,kBAAkB;oBAClB,mBAAmB;oBACnB,qBAAqB;iBACtB;gBACD,OAAO,EAAE;oBACP,uBAAuB;iBACxB;aACF;;wFACY,oBAAoB,mBAb7B,uBAAuB,aAGvB,YAAY;QACZ,YAAY;QACZ,kBAAkB;QAClB,mBAAmB;QACnB,qBAAqB,aAGrB,uBAAuB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RouterModule } from '@angular/router';\n\n// MemberJunction modules\nimport { EntityViewerModule } from '@memberjunction/ng-entity-viewer';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\nimport { MJEmptyStateComponent } from '@memberjunction/ng-ui-components';\n\nimport { ListDetailGridComponent } from './lib/ng-list-detail-grid.component';\n\n@NgModule({\n declarations: [\n ListDetailGridComponent\n ],\n imports: [\n CommonModule,\n RouterModule,\n EntityViewerModule,\n SharedGenericModule,\n MJEmptyStateComponent\n ],\n exports: [\n ListDetailGridComponent\n ]\n})\nexport class ListDetailGridModule { }\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-list-detail-grid",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.44.0",
|
|
4
4
|
"description": "MemberJunction: Angular Grid to display dynamic and saved List Details for any entity in MemberJunction.",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -25,13 +25,14 @@
|
|
|
25
25
|
"@angular/router": "21.1.3"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@memberjunction/
|
|
29
|
-
"@memberjunction/core
|
|
30
|
-
"@memberjunction/
|
|
31
|
-
"@memberjunction/
|
|
32
|
-
"@memberjunction/ng-
|
|
33
|
-
"@memberjunction/ng-
|
|
34
|
-
"@memberjunction/ng-shared
|
|
28
|
+
"@memberjunction/ng-ui-components": "5.44.0",
|
|
29
|
+
"@memberjunction/core": "5.44.0",
|
|
30
|
+
"@memberjunction/core-entities": "5.44.0",
|
|
31
|
+
"@memberjunction/global": "5.44.0",
|
|
32
|
+
"@memberjunction/ng-base-types": "5.44.0",
|
|
33
|
+
"@memberjunction/ng-entity-viewer": "5.44.0",
|
|
34
|
+
"@memberjunction/ng-shared": "5.44.0",
|
|
35
|
+
"@memberjunction/ng-shared-generic": "5.44.0",
|
|
35
36
|
"rxjs": "~7.8.2",
|
|
36
37
|
"tslib": "^2.8.1"
|
|
37
38
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list-detail-grid.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/list-detail-grid.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for list-detail-grid package:
|
|
3
|
-
* - Module export verification
|
|
4
|
-
*/
|
|
5
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
-
vi.mock('@angular/core', () => ({
|
|
7
|
-
Component: () => (target) => target,
|
|
8
|
-
NgModule: () => (target) => target,
|
|
9
|
-
Input: () => () => { },
|
|
10
|
-
Output: () => () => { },
|
|
11
|
-
EventEmitter: class {
|
|
12
|
-
emit() { }
|
|
13
|
-
},
|
|
14
|
-
}));
|
|
15
|
-
describe('list-detail-grid package', () => {
|
|
16
|
-
it('should be a valid module', () => {
|
|
17
|
-
expect(true).toBe(true);
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
//# sourceMappingURL=list-detail-grid.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"list-detail-grid.test.js","sourceRoot":"","sources":["../../src/__tests__/list-detail-grid.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9B,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,MAAgB,EAAE,EAAE,CAAC,MAAM;IAC7C,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,MAAgB,EAAE,EAAE,CAAC,MAAM;IAC5C,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;IACrB,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;IACtB,YAAY,EAAE;QAAQ,IAAI,KAAI,CAAC;KAAE;CAClC,CAAC,CAAC,CAAC;AAEJ,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/**\n * Tests for list-detail-grid package:\n * - Module export verification\n */\nimport { describe, it, expect, vi } from 'vitest';\n\nvi.mock('@angular/core', () => ({\n Component: () => (target: Function) => target,\n NgModule: () => (target: Function) => target,\n Input: () => () => {},\n Output: () => () => {},\n EventEmitter: class { emit() {} },\n}));\n\ndescribe('list-detail-grid package', () => {\n it('should be a valid module', () => {\n expect(true).toBe(true);\n });\n});\n"]}
|