@memberjunction/ng-entity-relationship-diagram 5.22.0 → 5.23.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/components/erd-composite/erd-composite.component.js +36 -21
- package/dist/lib/components/erd-composite/erd-composite.component.js.map +1 -1
- package/dist/lib/entity-relationship-diagram.module.d.ts +2 -2
- package/dist/lib/entity-relationship-diagram.module.js +4 -4
- package/dist/lib/entity-relationship-diagram.module.js.map +1 -1
- package/package.json +4 -3
|
@@ -5,10 +5,32 @@ import { Metadata } from '@memberjunction/core';
|
|
|
5
5
|
import { UUIDsEqual } from '@memberjunction/global';
|
|
6
6
|
import { MJEntityERDComponent } from '../mj-entity-erd.component';
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
8
|
-
import * as i1 from "
|
|
8
|
+
import * as i1 from "angular-split";
|
|
9
9
|
import * as i2 from "../mj-entity-erd.component";
|
|
10
10
|
import * as i3 from "../entity-details/entity-details.component";
|
|
11
11
|
import * as i4 from "../entity-filter-panel/entity-filter-panel.component";
|
|
12
|
+
function ERDCompositeComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
13
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
14
|
+
i0.ɵɵelementStart(0, "as-split-area", 2)(1, "mj-entity-filter-panel", 6);
|
|
15
|
+
i0.ɵɵlistener("filtersChange", function ERDCompositeComponent_Conditional_2_Template_mj_entity_filter_panel_filtersChange_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFiltersChange($event)); })("filterChange", function ERDCompositeComponent_Conditional_2_Template_mj_entity_filter_panel_filterChange_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterChange()); })("resetFilters", function ERDCompositeComponent_Conditional_2_Template_mj_entity_filter_panel_resetFilters_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onResetFilters()); })("closePanel", function ERDCompositeComponent_Conditional_2_Template_mj_entity_filter_panel_closePanel_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onToggleFilterPanel()); });
|
|
16
|
+
i0.ɵɵelementEnd()();
|
|
17
|
+
} if (rf & 2) {
|
|
18
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
19
|
+
i0.ɵɵproperty("size", 20)("minSize", 15)("maxSize", 30);
|
|
20
|
+
i0.ɵɵadvance();
|
|
21
|
+
i0.ɵɵproperty("entities", ctx_r1.entities)("filteredEntities", ctx_r1.filteredEntities)("filters", ctx_r1.filters);
|
|
22
|
+
} }
|
|
23
|
+
function ERDCompositeComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
25
|
+
i0.ɵɵelementStart(0, "as-split-area", 2)(1, "mj-entity-details", 7);
|
|
26
|
+
i0.ɵɵlistener("openEntity", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_openEntity_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityOpened($event)); })("closePanel", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_closePanel_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityDeselected()); })("fieldsSectionToggle", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_fieldsSectionToggle_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFieldsSectionToggle()); })("relationshipsSectionToggle", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_relationshipsSectionToggle_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRelationshipsSectionToggle()); })("entitySelected", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_entitySelected_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntitySelected($event)); })("openRecord", function ERDCompositeComponent_Conditional_6_Template_mj_entity_details_openRecord_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecord($event)); });
|
|
27
|
+
i0.ɵɵelementEnd()();
|
|
28
|
+
} if (rf & 2) {
|
|
29
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
30
|
+
i0.ɵɵproperty("size", 20)("minSize", 15)("maxSize", 30);
|
|
31
|
+
i0.ɵɵadvance();
|
|
32
|
+
i0.ɵɵproperty("selectedEntity", ctx_r1.selectedEntity)("allEntityFields", ctx_r1.allEntityFields)("fieldsSectionExpanded", ctx_r1.fieldsSectionExpanded)("relationshipsSectionExpanded", ctx_r1.relationshipsSectionExpanded);
|
|
33
|
+
} }
|
|
12
34
|
/**
|
|
13
35
|
* ERD Composite component that combines the ERD diagram with filter and details panels.
|
|
14
36
|
*
|
|
@@ -336,36 +358,29 @@ export class ERDCompositeComponent {
|
|
|
336
358
|
} if (rf & 2) {
|
|
337
359
|
let _t;
|
|
338
360
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.mjEntityErd = _t.first);
|
|
339
|
-
} }, inputs: { isRefreshingERD: "isRefreshingERD", focusEntities: "focusEntities", showFilterPanel: "showFilterPanel", depth: "depth", showHeader: "showHeader" }, outputs: { stateChange: "stateChange", userStateChange: "userStateChange", entityOpened: "entityOpened", openRecord: "openRecord" }, standalone: false, decls:
|
|
340
|
-
i0.ɵɵelementStart(0, "div", 0)(1, "
|
|
341
|
-
i0.ɵɵlistener("
|
|
342
|
-
i0.ɵɵ
|
|
343
|
-
i0.ɵɵ
|
|
344
|
-
i0.ɵɵ
|
|
345
|
-
i0.ɵɵelementStart(4, "kendo-splitter-pane", 4)(5, "div", 5)(6, "mj-entity-erd", 6);
|
|
346
|
-
i0.ɵɵlistener("entitySelected", function ERDCompositeComponent_Template_mj_entity_erd_entitySelected_6_listener($event) { return ctx.onERDEntitySelected($event); })("entityDeselected", function ERDCompositeComponent_Template_mj_entity_erd_entityDeselected_6_listener() { return ctx.onEntityDeselected(); })("openRecord", function ERDCompositeComponent_Template_mj_entity_erd_openRecord_6_listener($event) { return ctx.onERDOpenRecord($event); })("stateChange", function ERDCompositeComponent_Template_mj_entity_erd_stateChange_6_listener($event) { return ctx.onERDStateChange($event); });
|
|
361
|
+
} }, inputs: { isRefreshingERD: "isRefreshingERD", focusEntities: "focusEntities", showFilterPanel: "showFilterPanel", depth: "depth", showHeader: "showHeader" }, outputs: { stateChange: "stateChange", userStateChange: "userStateChange", entityOpened: "entityOpened", openRecord: "openRecord" }, standalone: false, decls: 7, vars: 12, consts: [[1, "erd-composite"], ["direction", "horizontal", 3, "dragEnd"], [3, "size", "minSize", "maxSize"], [3, "size"], [1, "erd-pane-container"], ["headerTitle", "Entity Relationship Diagram", 3, "entitySelected", "entityDeselected", "openRecord", "stateChange", "entities", "allEntities", "selectedEntityId", "isRefreshing", "depth", "includeIncoming", "includeOutgoing", "showHeader", "config"], [3, "filtersChange", "filterChange", "resetFilters", "closePanel", "entities", "filteredEntities", "filters"], [3, "openEntity", "closePanel", "fieldsSectionToggle", "relationshipsSectionToggle", "entitySelected", "openRecord", "selectedEntity", "allEntityFields", "fieldsSectionExpanded", "relationshipsSectionExpanded"]], template: function ERDCompositeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
362
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "as-split", 1);
|
|
363
|
+
i0.ɵɵlistener("dragEnd", function ERDCompositeComponent_Template_as_split_dragEnd_1_listener($event) { return ctx.onSplitterLayoutChange($event); });
|
|
364
|
+
i0.ɵɵconditionalCreate(2, ERDCompositeComponent_Conditional_2_Template, 2, 6, "as-split-area", 2);
|
|
365
|
+
i0.ɵɵelementStart(3, "as-split-area", 3)(4, "div", 4)(5, "mj-entity-erd", 5);
|
|
366
|
+
i0.ɵɵlistener("entitySelected", function ERDCompositeComponent_Template_mj_entity_erd_entitySelected_5_listener($event) { return ctx.onERDEntitySelected($event); })("entityDeselected", function ERDCompositeComponent_Template_mj_entity_erd_entityDeselected_5_listener() { return ctx.onEntityDeselected(); })("openRecord", function ERDCompositeComponent_Template_mj_entity_erd_openRecord_5_listener($event) { return ctx.onERDOpenRecord($event); })("stateChange", function ERDCompositeComponent_Template_mj_entity_erd_stateChange_5_listener($event) { return ctx.onERDStateChange($event); });
|
|
347
367
|
i0.ɵɵelementEnd()()();
|
|
348
|
-
i0.ɵɵ
|
|
349
|
-
i0.ɵɵ
|
|
350
|
-
i0.ɵɵelementEnd()()()();
|
|
368
|
+
i0.ɵɵconditionalCreate(6, ERDCompositeComponent_Conditional_6_Template, 2, 7, "as-split-area", 2);
|
|
369
|
+
i0.ɵɵelementEnd()();
|
|
351
370
|
} if (rf & 2) {
|
|
352
371
|
i0.ɵɵadvance(2);
|
|
353
|
-
i0.ɵɵ
|
|
372
|
+
i0.ɵɵconditional(ctx.filterPanelVisible ? 2 : -1);
|
|
354
373
|
i0.ɵɵadvance();
|
|
355
|
-
i0.ɵɵproperty("
|
|
356
|
-
i0.ɵɵadvance();
|
|
357
|
-
i0.ɵɵproperty("resizable", true)("scrollable", false);
|
|
374
|
+
i0.ɵɵproperty("size", ctx.selectedEntity ? 60 : ctx.filterPanelVisible ? 80 : 100);
|
|
358
375
|
i0.ɵɵadvance(2);
|
|
359
376
|
i0.ɵɵproperty("entities", ctx.filteredEntities)("allEntities", ctx.entities)("selectedEntityId", (ctx.selectedEntity == null ? null : ctx.selectedEntity.ID) || null)("isRefreshing", ctx.isRefreshingERD)("depth", ctx.depth)("includeIncoming", true)("includeOutgoing", true)("showHeader", ctx.showHeader)("config", ctx.erdConfig);
|
|
360
377
|
i0.ɵɵadvance();
|
|
361
|
-
i0.ɵɵ
|
|
362
|
-
|
|
363
|
-
i0.ɵɵproperty("selectedEntity", ctx.selectedEntity)("allEntityFields", ctx.allEntityFields)("fieldsSectionExpanded", ctx.fieldsSectionExpanded)("relationshipsSectionExpanded", ctx.relationshipsSectionExpanded);
|
|
364
|
-
} }, dependencies: [i1.SplitterComponent, i1.SplitterPaneComponent, i2.MJEntityERDComponent, i3.EntityDetailsComponent, i4.EntityFilterPanelComponent], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-composite[_ngcontent-%COMP%] {\n overflow: hidden;\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.main-splitter[_ngcontent-%COMP%] {\n height: 100%;\n width: 100%;\n}\n\n.main-splitter[_ngcontent-%COMP%] .k-pane[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n.erd-pane-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n\n\n.floating-details-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n right: 20px;\n width: 380px;\n max-height: calc(100% - 40px);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 28px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1000;\n overflow: hidden;\n transform: translateY(-50%);\n animation: _ngcontent-%COMP%_slideInFromRight 0.3s ease-out;\n}\n\n@media (max-width: 768px) {\n .floating-details-panel[_ngcontent-%COMP%] {\n right: 10px;\n left: 10px;\n width: auto;\n max-width: none;\n border-radius: 20px;\n }\n}\n\n@media (max-height: 600px) {\n .floating-details-panel[_ngcontent-%COMP%] {\n top: 20px;\n transform: none;\n max-height: calc(100vh - 40px);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideInFromRight {\n from {\n transform: translateY(-50%) translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateY(-50%) translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.explorer-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n.explorer-header-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 8px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n\n\n.back-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 20px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-color-neutral-400);\n color: var(--mj-text-primary);\n}\n\n.back-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.back-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.explorer-container[_ngcontent-%COMP%] mj-entity-explorer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n}"] });
|
|
378
|
+
i0.ɵɵconditional(ctx.selectedEntity ? 6 : -1);
|
|
379
|
+
} }, dependencies: [i1.SplitComponent, i1.SplitAreaComponent, i2.MJEntityERDComponent, i3.EntityDetailsComponent, i4.EntityFilterPanelComponent], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-composite[_ngcontent-%COMP%] {\n overflow: hidden;\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.main-splitter[_ngcontent-%COMP%] {\n height: 100%;\n width: 100%;\n}\n\n.main-splitter[_ngcontent-%COMP%] .k-pane[_ngcontent-%COMP%] {\n overflow: hidden;\n}\n\n.erd-pane-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n\n\n.floating-details-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n right: 20px;\n width: 380px;\n max-height: calc(100% - 40px);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 28px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1000;\n overflow: hidden;\n transform: translateY(-50%);\n animation: _ngcontent-%COMP%_slideInFromRight 0.3s ease-out;\n}\n\n@media (max-width: 768px) {\n .floating-details-panel[_ngcontent-%COMP%] {\n right: 10px;\n left: 10px;\n width: auto;\n max-width: none;\n border-radius: 20px;\n }\n}\n\n@media (max-height: 600px) {\n .floating-details-panel[_ngcontent-%COMP%] {\n top: 20px;\n transform: none;\n max-height: calc(100vh - 40px);\n }\n}\n\n@keyframes _ngcontent-%COMP%_slideInFromRight {\n from {\n transform: translateY(-50%) translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateY(-50%) translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.explorer-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n.explorer-header-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 8px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n\n\n.back-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 20px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-color-neutral-400);\n color: var(--mj-text-primary);\n}\n\n.back-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.back-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.explorer-container[_ngcontent-%COMP%] mj-entity-explorer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n}"] });
|
|
365
380
|
}
|
|
366
381
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ERDCompositeComponent, [{
|
|
367
382
|
type: Component,
|
|
368
|
-
args: [{ standalone: false, selector: 'mj-erd-composite', template: "<div class=\"erd-composite\">\n <
|
|
383
|
+
args: [{ standalone: false, selector: 'mj-erd-composite', template: "<div class=\"erd-composite\">\n <as-split direction=\"horizontal\" (dragEnd)=\"onSplitterLayoutChange($event)\">\n\n <!-- Filter Panel (Left) -->\n @if (filterPanelVisible) {\n <as-split-area [size]=\"20\" [minSize]=\"15\" [maxSize]=\"30\">\n <mj-entity-filter-panel\n [entities]=\"entities\"\n [filteredEntities]=\"filteredEntities\"\n [filters]=\"filters\"\n (filtersChange)=\"onFiltersChange($event)\"\n (filterChange)=\"onFilterChange()\"\n (resetFilters)=\"onResetFilters()\"\n (closePanel)=\"onToggleFilterPanel()\">\n </mj-entity-filter-panel>\n </as-split-area>\n }\n\n <!-- ERD Diagram (Center) -->\n <as-split-area [size]=\"selectedEntity ? 60 : (filterPanelVisible ? 80 : 100)\">\n <div class=\"erd-pane-container\">\n <mj-entity-erd\n [entities]=\"filteredEntities\"\n [allEntities]=\"entities\"\n [selectedEntityId]=\"selectedEntity?.ID || null\"\n [isRefreshing]=\"isRefreshingERD\"\n [depth]=\"depth\"\n [includeIncoming]=\"true\"\n [includeOutgoing]=\"true\"\n [showHeader]=\"showHeader\"\n [config]=\"erdConfig\"\n headerTitle=\"Entity Relationship Diagram\"\n (entitySelected)=\"onERDEntitySelected($event)\"\n (entityDeselected)=\"onEntityDeselected()\"\n (openRecord)=\"onERDOpenRecord($event)\"\n (stateChange)=\"onERDStateChange($event)\">\n </mj-entity-erd>\n </div>\n </as-split-area>\n\n <!-- Entity Details Panel (Right) -->\n @if (selectedEntity) {\n <as-split-area [size]=\"20\" [minSize]=\"15\" [maxSize]=\"30\">\n <mj-entity-details\n [selectedEntity]=\"selectedEntity\"\n [allEntityFields]=\"allEntityFields\"\n [fieldsSectionExpanded]=\"fieldsSectionExpanded\"\n [relationshipsSectionExpanded]=\"relationshipsSectionExpanded\"\n (openEntity)=\"onEntityOpened($event)\"\n (closePanel)=\"onEntityDeselected()\"\n (fieldsSectionToggle)=\"onFieldsSectionToggle()\"\n (relationshipsSectionToggle)=\"onRelationshipsSectionToggle()\"\n (entitySelected)=\"onEntitySelected($event)\"\n (openRecord)=\"onOpenRecord($event)\">\n </mj-entity-details>\n </as-split-area>\n }\n </as-split>\n</div>\n", styles: ["/**\n * ERD Composite Component - MJ Design Tokens\n * MJ theming for the ERD composite wrapper\n */\n\n:host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.erd-composite {\n overflow: hidden;\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n.main-splitter {\n height: 100%;\n width: 100%;\n}\n\n.main-splitter .k-pane {\n overflow: hidden;\n}\n\n.erd-pane-container {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n/* Floating Details Panel - MD3 Styled */\n.floating-details-panel {\n position: absolute;\n top: 50%;\n right: 20px;\n width: 380px;\n max-height: calc(100% - 40px);\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 28px;\n box-shadow: var(--mj-shadow-lg);\n z-index: 1000;\n overflow: hidden;\n transform: translateY(-50%);\n animation: slideInFromRight 0.3s ease-out;\n}\n\n@media (max-width: 768px) {\n .floating-details-panel {\n right: 10px;\n left: 10px;\n width: auto;\n max-width: none;\n border-radius: 20px;\n }\n}\n\n@media (max-height: 600px) {\n .floating-details-panel {\n top: 20px;\n transform: none;\n max-height: calc(100vh - 40px);\n }\n}\n\n@keyframes slideInFromRight {\n from {\n transform: translateY(-50%) translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateY(-50%) translateX(0);\n opacity: 1;\n }\n}\n\n/* Entity Explorer Container - MD3 Styled */\n.explorer-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n.explorer-header-bar {\n display: flex;\n align-items: center;\n padding: 8px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n/* MD3 Outlined Back Button */\n.back-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: 20px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.back-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-color-neutral-400);\n color: var(--mj-text-primary);\n}\n\n.back-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.back-btn i {\n font-size: 12px;\n}\n\n.explorer-container mj-entity-explorer {\n flex: 1;\n overflow: hidden;\n}\n"] }]
|
|
369
384
|
}], null, { mjEntityErd: [{
|
|
370
385
|
type: ViewChild,
|
|
371
386
|
args: [MJEntityERDComponent]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erd-composite.component.js","sourceRoot":"","sources":["../../../../src/lib/components/erd-composite/erd-composite.component.ts","../../../../src/lib/components/erd-composite/erd-composite.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ViewChild } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\nimport { EntityInfo, EntityFieldInfo, Metadata } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJEntityERDComponent } from '../mj-entity-erd.component';\nimport { EntitySelectedEvent, OpenEntityRecordEvent } from '../mj-entity-erd.component';\nimport { ERDConfig, ERDState } from '../../interfaces/erd-types';\nimport { EntityFilter } from '../entity-filter-panel/entity-filter-panel.component';\n\n/**\n * State object for the ERD composite component.\n * Used for state persistence and restoration.\n */\nexport interface ERDCompositeState {\n filterPanelVisible: boolean;\n filterPanelWidth: number;\n filters: EntityFilter;\n selectedEntityId: string | null;\n zoomLevel: number;\n panPosition: { x: number; y: number };\n fieldsSectionExpanded: boolean;\n relationshipsSectionExpanded: boolean;\n}\n\n/**\n * ERD Composite component that combines the ERD diagram with filter and details panels.\n *\n * This is a complete, ready-to-use ERD exploration interface that includes:\n * - Left panel: Entity filter controls (schema, name, status, etc.)\n * - Center: Interactive ERD diagram\n * - Right panel: Entity details (shown when an entity is selected)\n *\n * The component handles all internal state but emits events for:\n * - State changes (for parent to persist user preferences)\n * - Open record requests (for parent to handle navigation)\n *\n * ## Usage\n *\n * ```html\n * <mj-erd-composite\n * (stateChange)=\"onStateChange($event)\"\n * (userStateChange)=\"saveUserPreferences($event)\"\n * (openRecord)=\"navigateToRecord($event)\">\n * </mj-erd-composite>\n * ```\n *\n * ## State Persistence\n *\n * The component emits `userStateChange` events (debounced 1s) when user changes\n * any settings. The parent should save this state and restore it using `loadUserState()`:\n *\n * ```typescript\n * @ViewChild(ERDCompositeComponent) erdComposite!: ERDCompositeComponent;\n *\n * ngAfterViewInit() {\n * const savedState = await this.loadSavedState();\n * if (savedState) {\n * this.erdComposite.loadUserState(savedState);\n * }\n * }\n *\n * onUserStateChange(state: ERDCompositeState) {\n * await this.saveState(state);\n * }\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-erd-composite',\n templateUrl: './erd-composite.component.html',\n styleUrls: ['./erd-composite.component.css']\n})\nexport class ERDCompositeComponent implements OnInit, OnDestroy {\n @ViewChild(MJEntityERDComponent) mjEntityErd!: MJEntityERDComponent;\n\n /** Whether the ERD is in a refreshing state */\n @Input() isRefreshingERD = false;\n\n /**\n * Optional: Focus entities to display in the ERD.\n * When provided, only these entities will be shown (useful for single-entity views).\n * When not provided, all entities from metadata are loaded.\n */\n @Input() focusEntities: EntityInfo[] | null = null;\n\n /**\n * Whether to show the filter panel on the left.\n * Set to false for focused/single-entity views.\n */\n @Input() showFilterPanel = true;\n\n /**\n * Depth of relationships to display.\n * 1 = only direct relationships, 2 = relationships of relationships, etc.\n */\n @Input() depth = 1;\n\n /**\n * Whether to show the ERD header bar.\n */\n @Input() showHeader = true;\n\n /** All entities loaded from metadata */\n public entities: EntityInfo[] = [];\n\n /** All entity fields (flattened from all entities) */\n public allEntityFields: EntityFieldInfo[] = [];\n\n /** Emitted on any state change (debounced 50ms) */\n @Output() stateChange = new EventEmitter<ERDCompositeState>();\n\n /** Emitted on user-initiated state changes (debounced 1s) for persistence */\n @Output() userStateChange = new EventEmitter<ERDCompositeState>();\n\n /** Emitted when an entity is opened (e.g., double-clicked in details panel) */\n @Output() entityOpened = new EventEmitter<EntityInfo>();\n\n /** Emitted when requesting to open an entity record (for navigation) */\n @Output() openRecord = new EventEmitter<{EntityName: string, RecordID: string}>();\n\n // Panel visibility and configuration\n public filterPanelVisible = true;\n public fieldsSectionExpanded = true;\n public relationshipsSectionExpanded = true;\n\n /** ERD configuration - skip animation for faster rendering */\n public erdConfig: ERDConfig = { skipAnimation: true };\n\n // Entity state\n public selectedEntity: EntityInfo | null = null;\n public filteredEntities: EntityInfo[] = [];\n public isDataLoaded = false;\n\n // Filters\n public filters: EntityFilter = {\n schemaName: null,\n entityName: '',\n entityStatus: null,\n baseTable: '',\n };\n\n // State management\n private stateChangeSubject = new Subject<ERDCompositeState>();\n private userStateChangeSubject = new Subject<ERDCompositeState>();\n private filterChangeSubject = new Subject<void>();\n\n async ngOnInit(): Promise<void> {\n // Initialize filter panel visibility based on input\n this.filterPanelVisible = this.showFilterPanel;\n\n this.setupStateManagement();\n await this.loadData();\n\n // Use focusEntities if provided, otherwise use all entities\n if (this.focusEntities && this.focusEntities.length > 0) {\n this.filteredEntities = [...this.focusEntities];\n } else {\n this.filteredEntities = [...this.entities];\n this.applyFilters();\n }\n\n this.isDataLoaded = true;\n\n // Notify parent that data is loaded and ready for state loading\n this.emitStateChange();\n }\n\n ngOnDestroy(): void {\n this.stateChangeSubject.complete();\n this.userStateChangeSubject.complete();\n this.filterChangeSubject.complete();\n }\n\n private async loadData(): Promise<void> {\n // Load entities from metadata (always needed for allEntityFields and relationship lookups)\n const md = new Metadata();\n this.entities = md.Entities;\n\n // Load all entity fields from entities\n this.allEntityFields = this.entities\n .map((entity) => {\n return entity.Fields;\n })\n .flat();\n }\n\n private setupStateManagement(): void {\n // State change emissions with debouncing\n this.stateChangeSubject.pipe(\n debounceTime(50)\n ).subscribe(state => {\n this.stateChange.emit(state);\n });\n\n this.userStateChangeSubject.pipe(\n debounceTime(1000)\n ).subscribe(state => {\n this.userStateChange.emit(state);\n });\n\n // Filter changes with debouncing\n this.filterChangeSubject.pipe(\n debounceTime(300)\n ).subscribe(() => {\n this.applyFilters();\n this.emitStateChange();\n this.emitUserStateChange();\n });\n }\n\n public onFilterChange(): void {\n this.filterChangeSubject.next();\n }\n\n public onFiltersChange(newFilters: EntityFilter): void {\n this.filters = { ...newFilters };\n this.onFilterChange();\n }\n\n public onResetFilters(): void {\n this.filters = {\n schemaName: null,\n entityName: '',\n entityStatus: null,\n baseTable: '',\n };\n this.onFilterChange();\n }\n\n public onToggleFilterPanel(): void {\n this.filterPanelVisible = !this.filterPanelVisible;\n\n // Trigger ERD resize when filter panel is toggled\n if (this.mjEntityErd) {\n this.mjEntityErd.triggerResize();\n }\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n public onEntityDeselected(): void {\n this.selectedEntity = null;\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n public onEntitySelected(entity: EntityInfo): void {\n this.selectedEntity = entity;\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n /**\n * Handle entity selection from the mj-entity-erd wrapper.\n * Updates internal state.\n */\n public onERDEntitySelected(event: EntitySelectedEvent): void {\n this.selectedEntity = event.entity;\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n /**\n * Handle open record from the mj-entity-erd wrapper (double-click).\n * Opens the entity record using the entity form.\n */\n public onERDOpenRecord(event: OpenEntityRecordEvent): void {\n this.openRecord.emit({ EntityName: event.EntityName, RecordID: event.RecordID });\n }\n\n /**\n * Handle state changes from the ERD component.\n */\n public onERDStateChange(_state: ERDState): void {\n // State changes are tracked for user preference persistence\n this.emitUserStateChange();\n }\n\n public onEntityOpened(entity: EntityInfo): void {\n this.entityOpened.emit(entity);\n }\n\n public onFieldsSectionToggle(): void {\n this.fieldsSectionExpanded = !this.fieldsSectionExpanded;\n this.emitUserStateChange();\n }\n\n public onRelationshipsSectionToggle(): void {\n this.relationshipsSectionExpanded = !this.relationshipsSectionExpanded;\n this.emitUserStateChange();\n }\n\n public onOpenRecord(event: {EntityName: string, RecordID: string}): void {\n this.openRecord.emit(event);\n }\n\n public onSplitterLayoutChange(_event: unknown): void {\n // Trigger ERD diagram resize when splitter layout changes\n if (this.mjEntityErd) {\n this.mjEntityErd.triggerResize();\n }\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n private applyFilters(): void {\n this.filteredEntities = this.entities.filter(entity => {\n // Schema filter\n if (this.filters.schemaName && entity.SchemaName !== this.filters.schemaName) {\n return false;\n }\n\n // Entity name filter\n if (this.filters.entityName) {\n const searchTerm = this.filters.entityName.toLowerCase();\n const entityName = (entity.Name || entity.SchemaName || '').toLowerCase();\n if (!entityName.includes(searchTerm)) {\n return false;\n }\n }\n\n // Base table filter\n if (this.filters.baseTable) {\n const searchTerm = this.filters.baseTable.toLowerCase();\n const baseTable = (entity.BaseTable || '').toLowerCase();\n if (!baseTable.includes(searchTerm)) {\n return false;\n }\n }\n\n // Status filter\n if (this.filters.entityStatus && entity.Status !== this.filters.entityStatus) {\n return false;\n }\n\n return true;\n });\n }\n\n private emitStateChange(): void {\n const state = this.buildState();\n this.stateChangeSubject.next(state);\n }\n\n private emitUserStateChange(): void {\n const state = this.buildState();\n this.userStateChangeSubject.next(state);\n }\n\n private buildState(): ERDCompositeState {\n return {\n filterPanelVisible: this.filterPanelVisible,\n filterPanelWidth: 320,\n filters: { ...this.filters },\n selectedEntityId: this.selectedEntity?.ID || null,\n zoomLevel: 1,\n panPosition: { x: 0, y: 0 },\n fieldsSectionExpanded: this.fieldsSectionExpanded,\n relationshipsSectionExpanded: this.relationshipsSectionExpanded,\n };\n }\n\n // ============================================================================\n // PUBLIC API\n // ============================================================================\n\n /**\n * Load user state from a previously saved state object.\n * Call this after the component is initialized to restore user preferences.\n */\n public loadUserState(state: Partial<ERDCompositeState>): void {\n if (state.filterPanelVisible !== undefined) {\n this.filterPanelVisible = state.filterPanelVisible;\n }\n if (state.filters) {\n this.filters = { ...state.filters };\n }\n if (state.fieldsSectionExpanded !== undefined) {\n this.fieldsSectionExpanded = state.fieldsSectionExpanded;\n }\n if (state.relationshipsSectionExpanded !== undefined) {\n this.relationshipsSectionExpanded = state.relationshipsSectionExpanded;\n }\n if (state.selectedEntityId && this.entities.length > 0) {\n const entity = this.entities.find(e => UUIDsEqual(e.ID, state.selectedEntityId));\n if (entity) {\n this.selectedEntity = entity;\n }\n } else {\n this.selectedEntity = null;\n }\n\n this.applyFilters();\n }\n\n /**\n * Refresh the ERD diagram.\n */\n public refreshERD(): void {\n if (this.mjEntityErd) {\n this.mjEntityErd.refresh();\n }\n }\n\n /**\n * Get the current state for external use.\n */\n public getState(): ERDCompositeState {\n return this.buildState();\n }\n}\n","<div class=\"erd-composite\">\n <kendo-splitter\n class=\"main-splitter\"\n orientation=\"horizontal\"\n (layoutChange)=\"onSplitterLayoutChange($event)\">\n\n <!-- Filter Panel (Left) -->\n <kendo-splitter-pane\n [size]=\"filterPanelVisible ? '320px' : '0px'\"\n [collapsible]=\"false\"\n [resizable]=\"filterPanelVisible\"\n [scrollable]=\"false\"\n [hidden]=\"!filterPanelVisible\">\n <mj-entity-filter-panel\n [entities]=\"entities\"\n [filteredEntities]=\"filteredEntities\"\n [filters]=\"filters\"\n (filtersChange)=\"onFiltersChange($event)\"\n (filterChange)=\"onFilterChange()\"\n (resetFilters)=\"onResetFilters()\"\n (closePanel)=\"onToggleFilterPanel()\">\n </mj-entity-filter-panel>\n </kendo-splitter-pane>\n\n <!-- ERD Diagram (Center) -->\n <kendo-splitter-pane\n [resizable]=\"true\"\n [scrollable]=\"false\">\n <div class=\"erd-pane-container\">\n <mj-entity-erd\n [entities]=\"filteredEntities\"\n [allEntities]=\"entities\"\n [selectedEntityId]=\"selectedEntity?.ID || null\"\n [isRefreshing]=\"isRefreshingERD\"\n [depth]=\"depth\"\n [includeIncoming]=\"true\"\n [includeOutgoing]=\"true\"\n [showHeader]=\"showHeader\"\n [config]=\"erdConfig\"\n headerTitle=\"Entity Relationship Diagram\"\n (entitySelected)=\"onERDEntitySelected($event)\"\n (entityDeselected)=\"onEntityDeselected()\"\n (openRecord)=\"onERDOpenRecord($event)\"\n (stateChange)=\"onERDStateChange($event)\">\n </mj-entity-erd>\n </div>\n </kendo-splitter-pane>\n\n <!-- Entity Details Panel (Right) -->\n <kendo-splitter-pane\n [size]=\"selectedEntity ? '320px' : '0px'\"\n [collapsible]=\"false\"\n [resizable]=\"!!selectedEntity\"\n [scrollable]=\"false\"\n [hidden]=\"!selectedEntity\">\n <mj-entity-details\n [selectedEntity]=\"selectedEntity\"\n [allEntityFields]=\"allEntityFields\"\n [fieldsSectionExpanded]=\"fieldsSectionExpanded\"\n [relationshipsSectionExpanded]=\"relationshipsSectionExpanded\"\n (openEntity)=\"onEntityOpened($event)\"\n (closePanel)=\"onEntityDeselected()\"\n (fieldsSectionToggle)=\"onFieldsSectionToggle()\"\n (relationshipsSectionToggle)=\"onRelationshipsSectionToggle()\"\n (entitySelected)=\"onEntitySelected($event)\"\n (openRecord)=\"onOpenRecord($event)\">\n </mj-entity-details>\n </kendo-splitter-pane>\n </kendo-splitter>\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"erd-composite.component.js","sourceRoot":"","sources":["../../../../src/lib/components/erd-composite/erd-composite.component.ts","../../../../src/lib/components/erd-composite/erd-composite.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ViewChild } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\nimport { EntityInfo, EntityFieldInfo, Metadata } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJEntityERDComponent } from '../mj-entity-erd.component';\nimport { EntitySelectedEvent, OpenEntityRecordEvent } from '../mj-entity-erd.component';\nimport { ERDConfig, ERDState } from '../../interfaces/erd-types';\nimport { EntityFilter } from '../entity-filter-panel/entity-filter-panel.component';\n\n/**\n * State object for the ERD composite component.\n * Used for state persistence and restoration.\n */\nexport interface ERDCompositeState {\n filterPanelVisible: boolean;\n filterPanelWidth: number;\n filters: EntityFilter;\n selectedEntityId: string | null;\n zoomLevel: number;\n panPosition: { x: number; y: number };\n fieldsSectionExpanded: boolean;\n relationshipsSectionExpanded: boolean;\n}\n\n/**\n * ERD Composite component that combines the ERD diagram with filter and details panels.\n *\n * This is a complete, ready-to-use ERD exploration interface that includes:\n * - Left panel: Entity filter controls (schema, name, status, etc.)\n * - Center: Interactive ERD diagram\n * - Right panel: Entity details (shown when an entity is selected)\n *\n * The component handles all internal state but emits events for:\n * - State changes (for parent to persist user preferences)\n * - Open record requests (for parent to handle navigation)\n *\n * ## Usage\n *\n * ```html\n * <mj-erd-composite\n * (stateChange)=\"onStateChange($event)\"\n * (userStateChange)=\"saveUserPreferences($event)\"\n * (openRecord)=\"navigateToRecord($event)\">\n * </mj-erd-composite>\n * ```\n *\n * ## State Persistence\n *\n * The component emits `userStateChange` events (debounced 1s) when user changes\n * any settings. The parent should save this state and restore it using `loadUserState()`:\n *\n * ```typescript\n * @ViewChild(ERDCompositeComponent) erdComposite!: ERDCompositeComponent;\n *\n * ngAfterViewInit() {\n * const savedState = await this.loadSavedState();\n * if (savedState) {\n * this.erdComposite.loadUserState(savedState);\n * }\n * }\n *\n * onUserStateChange(state: ERDCompositeState) {\n * await this.saveState(state);\n * }\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-erd-composite',\n templateUrl: './erd-composite.component.html',\n styleUrls: ['./erd-composite.component.css']\n})\nexport class ERDCompositeComponent implements OnInit, OnDestroy {\n @ViewChild(MJEntityERDComponent) mjEntityErd!: MJEntityERDComponent;\n\n /** Whether the ERD is in a refreshing state */\n @Input() isRefreshingERD = false;\n\n /**\n * Optional: Focus entities to display in the ERD.\n * When provided, only these entities will be shown (useful for single-entity views).\n * When not provided, all entities from metadata are loaded.\n */\n @Input() focusEntities: EntityInfo[] | null = null;\n\n /**\n * Whether to show the filter panel on the left.\n * Set to false for focused/single-entity views.\n */\n @Input() showFilterPanel = true;\n\n /**\n * Depth of relationships to display.\n * 1 = only direct relationships, 2 = relationships of relationships, etc.\n */\n @Input() depth = 1;\n\n /**\n * Whether to show the ERD header bar.\n */\n @Input() showHeader = true;\n\n /** All entities loaded from metadata */\n public entities: EntityInfo[] = [];\n\n /** All entity fields (flattened from all entities) */\n public allEntityFields: EntityFieldInfo[] = [];\n\n /** Emitted on any state change (debounced 50ms) */\n @Output() stateChange = new EventEmitter<ERDCompositeState>();\n\n /** Emitted on user-initiated state changes (debounced 1s) for persistence */\n @Output() userStateChange = new EventEmitter<ERDCompositeState>();\n\n /** Emitted when an entity is opened (e.g., double-clicked in details panel) */\n @Output() entityOpened = new EventEmitter<EntityInfo>();\n\n /** Emitted when requesting to open an entity record (for navigation) */\n @Output() openRecord = new EventEmitter<{EntityName: string, RecordID: string}>();\n\n // Panel visibility and configuration\n public filterPanelVisible = true;\n public fieldsSectionExpanded = true;\n public relationshipsSectionExpanded = true;\n\n /** ERD configuration - skip animation for faster rendering */\n public erdConfig: ERDConfig = { skipAnimation: true };\n\n // Entity state\n public selectedEntity: EntityInfo | null = null;\n public filteredEntities: EntityInfo[] = [];\n public isDataLoaded = false;\n\n // Filters\n public filters: EntityFilter = {\n schemaName: null,\n entityName: '',\n entityStatus: null,\n baseTable: '',\n };\n\n // State management\n private stateChangeSubject = new Subject<ERDCompositeState>();\n private userStateChangeSubject = new Subject<ERDCompositeState>();\n private filterChangeSubject = new Subject<void>();\n\n async ngOnInit(): Promise<void> {\n // Initialize filter panel visibility based on input\n this.filterPanelVisible = this.showFilterPanel;\n\n this.setupStateManagement();\n await this.loadData();\n\n // Use focusEntities if provided, otherwise use all entities\n if (this.focusEntities && this.focusEntities.length > 0) {\n this.filteredEntities = [...this.focusEntities];\n } else {\n this.filteredEntities = [...this.entities];\n this.applyFilters();\n }\n\n this.isDataLoaded = true;\n\n // Notify parent that data is loaded and ready for state loading\n this.emitStateChange();\n }\n\n ngOnDestroy(): void {\n this.stateChangeSubject.complete();\n this.userStateChangeSubject.complete();\n this.filterChangeSubject.complete();\n }\n\n private async loadData(): Promise<void> {\n // Load entities from metadata (always needed for allEntityFields and relationship lookups)\n const md = new Metadata();\n this.entities = md.Entities;\n\n // Load all entity fields from entities\n this.allEntityFields = this.entities\n .map((entity) => {\n return entity.Fields;\n })\n .flat();\n }\n\n private setupStateManagement(): void {\n // State change emissions with debouncing\n this.stateChangeSubject.pipe(\n debounceTime(50)\n ).subscribe(state => {\n this.stateChange.emit(state);\n });\n\n this.userStateChangeSubject.pipe(\n debounceTime(1000)\n ).subscribe(state => {\n this.userStateChange.emit(state);\n });\n\n // Filter changes with debouncing\n this.filterChangeSubject.pipe(\n debounceTime(300)\n ).subscribe(() => {\n this.applyFilters();\n this.emitStateChange();\n this.emitUserStateChange();\n });\n }\n\n public onFilterChange(): void {\n this.filterChangeSubject.next();\n }\n\n public onFiltersChange(newFilters: EntityFilter): void {\n this.filters = { ...newFilters };\n this.onFilterChange();\n }\n\n public onResetFilters(): void {\n this.filters = {\n schemaName: null,\n entityName: '',\n entityStatus: null,\n baseTable: '',\n };\n this.onFilterChange();\n }\n\n public onToggleFilterPanel(): void {\n this.filterPanelVisible = !this.filterPanelVisible;\n\n // Trigger ERD resize when filter panel is toggled\n if (this.mjEntityErd) {\n this.mjEntityErd.triggerResize();\n }\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n public onEntityDeselected(): void {\n this.selectedEntity = null;\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n public onEntitySelected(entity: EntityInfo): void {\n this.selectedEntity = entity;\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n /**\n * Handle entity selection from the mj-entity-erd wrapper.\n * Updates internal state.\n */\n public onERDEntitySelected(event: EntitySelectedEvent): void {\n this.selectedEntity = event.entity;\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n /**\n * Handle open record from the mj-entity-erd wrapper (double-click).\n * Opens the entity record using the entity form.\n */\n public onERDOpenRecord(event: OpenEntityRecordEvent): void {\n this.openRecord.emit({ EntityName: event.EntityName, RecordID: event.RecordID });\n }\n\n /**\n * Handle state changes from the ERD component.\n */\n public onERDStateChange(_state: ERDState): void {\n // State changes are tracked for user preference persistence\n this.emitUserStateChange();\n }\n\n public onEntityOpened(entity: EntityInfo): void {\n this.entityOpened.emit(entity);\n }\n\n public onFieldsSectionToggle(): void {\n this.fieldsSectionExpanded = !this.fieldsSectionExpanded;\n this.emitUserStateChange();\n }\n\n public onRelationshipsSectionToggle(): void {\n this.relationshipsSectionExpanded = !this.relationshipsSectionExpanded;\n this.emitUserStateChange();\n }\n\n public onOpenRecord(event: {EntityName: string, RecordID: string}): void {\n this.openRecord.emit(event);\n }\n\n public onSplitterLayoutChange(_event: unknown): void {\n // Trigger ERD diagram resize when splitter layout changes\n if (this.mjEntityErd) {\n this.mjEntityErd.triggerResize();\n }\n\n this.emitStateChange();\n this.emitUserStateChange();\n }\n\n private applyFilters(): void {\n this.filteredEntities = this.entities.filter(entity => {\n // Schema filter\n if (this.filters.schemaName && entity.SchemaName !== this.filters.schemaName) {\n return false;\n }\n\n // Entity name filter\n if (this.filters.entityName) {\n const searchTerm = this.filters.entityName.toLowerCase();\n const entityName = (entity.Name || entity.SchemaName || '').toLowerCase();\n if (!entityName.includes(searchTerm)) {\n return false;\n }\n }\n\n // Base table filter\n if (this.filters.baseTable) {\n const searchTerm = this.filters.baseTable.toLowerCase();\n const baseTable = (entity.BaseTable || '').toLowerCase();\n if (!baseTable.includes(searchTerm)) {\n return false;\n }\n }\n\n // Status filter\n if (this.filters.entityStatus && entity.Status !== this.filters.entityStatus) {\n return false;\n }\n\n return true;\n });\n }\n\n private emitStateChange(): void {\n const state = this.buildState();\n this.stateChangeSubject.next(state);\n }\n\n private emitUserStateChange(): void {\n const state = this.buildState();\n this.userStateChangeSubject.next(state);\n }\n\n private buildState(): ERDCompositeState {\n return {\n filterPanelVisible: this.filterPanelVisible,\n filterPanelWidth: 320,\n filters: { ...this.filters },\n selectedEntityId: this.selectedEntity?.ID || null,\n zoomLevel: 1,\n panPosition: { x: 0, y: 0 },\n fieldsSectionExpanded: this.fieldsSectionExpanded,\n relationshipsSectionExpanded: this.relationshipsSectionExpanded,\n };\n }\n\n // ============================================================================\n // PUBLIC API\n // ============================================================================\n\n /**\n * Load user state from a previously saved state object.\n * Call this after the component is initialized to restore user preferences.\n */\n public loadUserState(state: Partial<ERDCompositeState>): void {\n if (state.filterPanelVisible !== undefined) {\n this.filterPanelVisible = state.filterPanelVisible;\n }\n if (state.filters) {\n this.filters = { ...state.filters };\n }\n if (state.fieldsSectionExpanded !== undefined) {\n this.fieldsSectionExpanded = state.fieldsSectionExpanded;\n }\n if (state.relationshipsSectionExpanded !== undefined) {\n this.relationshipsSectionExpanded = state.relationshipsSectionExpanded;\n }\n if (state.selectedEntityId && this.entities.length > 0) {\n const entity = this.entities.find(e => UUIDsEqual(e.ID, state.selectedEntityId));\n if (entity) {\n this.selectedEntity = entity;\n }\n } else {\n this.selectedEntity = null;\n }\n\n this.applyFilters();\n }\n\n /**\n * Refresh the ERD diagram.\n */\n public refreshERD(): void {\n if (this.mjEntityErd) {\n this.mjEntityErd.refresh();\n }\n }\n\n /**\n * Get the current state for external use.\n */\n public getState(): ERDCompositeState {\n return this.buildState();\n }\n}\n","<div class=\"erd-composite\">\n <as-split direction=\"horizontal\" (dragEnd)=\"onSplitterLayoutChange($event)\">\n\n <!-- Filter Panel (Left) -->\n @if (filterPanelVisible) {\n <as-split-area [size]=\"20\" [minSize]=\"15\" [maxSize]=\"30\">\n <mj-entity-filter-panel\n [entities]=\"entities\"\n [filteredEntities]=\"filteredEntities\"\n [filters]=\"filters\"\n (filtersChange)=\"onFiltersChange($event)\"\n (filterChange)=\"onFilterChange()\"\n (resetFilters)=\"onResetFilters()\"\n (closePanel)=\"onToggleFilterPanel()\">\n </mj-entity-filter-panel>\n </as-split-area>\n }\n\n <!-- ERD Diagram (Center) -->\n <as-split-area [size]=\"selectedEntity ? 60 : (filterPanelVisible ? 80 : 100)\">\n <div class=\"erd-pane-container\">\n <mj-entity-erd\n [entities]=\"filteredEntities\"\n [allEntities]=\"entities\"\n [selectedEntityId]=\"selectedEntity?.ID || null\"\n [isRefreshing]=\"isRefreshingERD\"\n [depth]=\"depth\"\n [includeIncoming]=\"true\"\n [includeOutgoing]=\"true\"\n [showHeader]=\"showHeader\"\n [config]=\"erdConfig\"\n headerTitle=\"Entity Relationship Diagram\"\n (entitySelected)=\"onERDEntitySelected($event)\"\n (entityDeselected)=\"onEntityDeselected()\"\n (openRecord)=\"onERDOpenRecord($event)\"\n (stateChange)=\"onERDStateChange($event)\">\n </mj-entity-erd>\n </div>\n </as-split-area>\n\n <!-- Entity Details Panel (Right) -->\n @if (selectedEntity) {\n <as-split-area [size]=\"20\" [minSize]=\"15\" [maxSize]=\"30\">\n <mj-entity-details\n [selectedEntity]=\"selectedEntity\"\n [allEntityFields]=\"allEntityFields\"\n [fieldsSectionExpanded]=\"fieldsSectionExpanded\"\n [relationshipsSectionExpanded]=\"relationshipsSectionExpanded\"\n (openEntity)=\"onEntityOpened($event)\"\n (closePanel)=\"onEntityDeselected()\"\n (fieldsSectionToggle)=\"onFieldsSectionToggle()\"\n (relationshipsSectionToggle)=\"onRelationshipsSectionToggle()\"\n (entitySelected)=\"onEntitySelected($event)\"\n (openRecord)=\"onOpenRecord($event)\">\n </mj-entity-details>\n </as-split-area>\n }\n </as-split>\n</div>\n"]}
|
|
@@ -6,7 +6,7 @@ import * as i4 from "./components/entity-filter-panel/entity-filter-panel.compon
|
|
|
6
6
|
import * as i5 from "./components/erd-composite/erd-composite.component";
|
|
7
7
|
import * as i6 from "@angular/common";
|
|
8
8
|
import * as i7 from "@angular/forms";
|
|
9
|
-
import * as i8 from "
|
|
9
|
+
import * as i8 from "angular-split";
|
|
10
10
|
/**
|
|
11
11
|
* Module for the Entity Relationship Diagram (ERD) visualization components.
|
|
12
12
|
*
|
|
@@ -77,7 +77,7 @@ import * as i8 from "@progress/kendo-angular-layout";
|
|
|
77
77
|
*/
|
|
78
78
|
export declare class EntityRelationshipDiagramModule {
|
|
79
79
|
static ɵfac: i0.ɵɵFactoryDeclaration<EntityRelationshipDiagramModule, never>;
|
|
80
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<EntityRelationshipDiagramModule, [typeof i1.ERDDiagramComponent, typeof i2.MJEntityERDComponent, typeof i3.EntityDetailsComponent, typeof i4.EntityFilterPanelComponent, typeof i5.ERDCompositeComponent], [typeof i6.CommonModule, typeof i7.FormsModule, typeof i8.
|
|
80
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<EntityRelationshipDiagramModule, [typeof i1.ERDDiagramComponent, typeof i2.MJEntityERDComponent, typeof i3.EntityDetailsComponent, typeof i4.EntityFilterPanelComponent, typeof i5.ERDCompositeComponent], [typeof i6.CommonModule, typeof i7.FormsModule, typeof i8.AngularSplitModule], [typeof i1.ERDDiagramComponent, typeof i2.MJEntityERDComponent, typeof i3.EntityDetailsComponent, typeof i4.EntityFilterPanelComponent, typeof i5.ERDCompositeComponent]>;
|
|
81
81
|
static ɵinj: i0.ɵɵInjectorDeclaration<EntityRelationshipDiagramModule>;
|
|
82
82
|
}
|
|
83
83
|
//# sourceMappingURL=entity-relationship-diagram.module.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NgModule } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { FormsModule } from '@angular/forms';
|
|
4
|
-
import {
|
|
4
|
+
import { AngularSplitModule } from 'angular-split';
|
|
5
5
|
import { ERDDiagramComponent } from './components/erd-diagram.component';
|
|
6
6
|
import { MJEntityERDComponent } from './components/mj-entity-erd.component';
|
|
7
7
|
import { EntityDetailsComponent } from './components/entity-details/entity-details.component';
|
|
@@ -81,7 +81,7 @@ export class EntityRelationshipDiagramModule {
|
|
|
81
81
|
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: EntityRelationshipDiagramModule });
|
|
82
82
|
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
|
|
83
83
|
FormsModule,
|
|
84
|
-
|
|
84
|
+
AngularSplitModule] });
|
|
85
85
|
}
|
|
86
86
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityRelationshipDiagramModule, [{
|
|
87
87
|
type: NgModule,
|
|
@@ -96,7 +96,7 @@ export class EntityRelationshipDiagramModule {
|
|
|
96
96
|
imports: [
|
|
97
97
|
CommonModule,
|
|
98
98
|
FormsModule,
|
|
99
|
-
|
|
99
|
+
AngularSplitModule
|
|
100
100
|
],
|
|
101
101
|
exports: [
|
|
102
102
|
ERDDiagramComponent,
|
|
@@ -113,7 +113,7 @@ export class EntityRelationshipDiagramModule {
|
|
|
113
113
|
EntityFilterPanelComponent,
|
|
114
114
|
ERDCompositeComponent], imports: [CommonModule,
|
|
115
115
|
FormsModule,
|
|
116
|
-
|
|
116
|
+
AngularSplitModule], exports: [ERDDiagramComponent,
|
|
117
117
|
MJEntityERDComponent,
|
|
118
118
|
EntityDetailsComponent,
|
|
119
119
|
EntityFilterPanelComponent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-relationship-diagram.module.js","sourceRoot":"","sources":["../../src/lib/entity-relationship-diagram.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"entity-relationship-diagram.module.js","sourceRoot":"","sources":["../../src/lib/entity-relationship-diagram.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sDAAsD,CAAC;AAC9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,gEAAgE,CAAC;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;;AAE3F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAsBH,MAAM,OAAO,+BAA+B;yHAA/B,+BAA+B;4DAA/B,+BAA+B;gEAZxC,YAAY;YACZ,WAAW;YACX,kBAAkB;;iFAUT,+BAA+B;cArB3C,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,mBAAmB;oBACnB,oBAAoB;oBACpB,sBAAsB;oBACtB,0BAA0B;oBAC1B,qBAAqB;iBACtB;gBACD,OAAO,EAAE;oBACP,YAAY;oBACZ,WAAW;oBACX,kBAAkB;iBACnB;gBACD,OAAO,EAAE;oBACP,mBAAmB;oBACnB,oBAAoB;oBACpB,sBAAsB;oBACtB,0BAA0B;oBAC1B,qBAAqB;iBACtB;aACF;;wFACY,+BAA+B,mBAnBxC,mBAAmB;QACnB,oBAAoB;QACpB,sBAAsB;QACtB,0BAA0B;QAC1B,qBAAqB,aAGrB,YAAY;QACZ,WAAW;QACX,kBAAkB,aAGlB,mBAAmB;QACnB,oBAAoB;QACpB,sBAAsB;QACtB,0BAA0B;QAC1B,qBAAqB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { AngularSplitModule } from 'angular-split';\n\nimport { ERDDiagramComponent } from './components/erd-diagram.component';\nimport { MJEntityERDComponent } from './components/mj-entity-erd.component';\nimport { EntityDetailsComponent } from './components/entity-details/entity-details.component';\nimport { EntityFilterPanelComponent } from './components/entity-filter-panel/entity-filter-panel.component';\nimport { ERDCompositeComponent } from './components/erd-composite/erd-composite.component';\n\n/**\n * Module for the Entity Relationship Diagram (ERD) visualization components.\n *\n * This module provides a complete suite of components for visualizing and\n * exploring entity relationships:\n *\n * ## Components\n *\n * ### 1. ERDDiagramComponent (`<mj-erd-diagram>`)\n * A generic, reusable ERD component that visualizes entity relationships using\n * D3.js force-directed graphs. It works with any data conforming to the `ERDNode`\n * interface and is completely decoupled from MemberJunction-specific types.\n *\n * ### 2. MJEntityERDComponent (`<mj-entity-erd>`)\n * A higher-level wrapper specifically for MemberJunction. It accepts `EntityInfo[]`\n * directly and handles all the transformation to ERD format automatically.\n *\n * ### 3. EntityDetailsComponent (`<mj-entity-details>`)\n * A detail panel that shows entity information, fields, and relationships when\n * an entity is selected. Designed to work alongside the ERD diagram.\n *\n * ### 4. EntityFilterPanelComponent (`<mj-entity-filter-panel>`)\n * A filter panel for filtering entities by schema, name, status, and base table.\n *\n * ### 5. ERDCompositeComponent (`<mj-erd-composite>`)\n * A complete, ready-to-use ERD exploration interface that combines:\n * - Left panel: Entity filter controls\n * - Center: Interactive ERD diagram\n * - Right panel: Entity details (shown when an entity is selected)\n *\n * ### Choosing Which Component to Use\n *\n * | Use Case | Component |\n * |----------|-----------|\n * | Complete ERD exploration UI | `<mj-erd-composite>` |\n * | ERD diagram with MJ EntityInfo | `<mj-entity-erd>` |\n * | Custom data sources (non-MJ) | `<mj-erd-diagram>` |\n * | Entity detail panel standalone | `<mj-entity-details>` |\n * | Entity filter panel standalone | `<mj-entity-filter-panel>` |\n *\n * @example Using the composite (recommended for dashboards)\n * ```html\n * <mj-erd-composite\n * (userStateChange)=\"saveUserPreferences($event)\"\n * (openRecord)=\"navigateToRecord($event)\">\n * </mj-erd-composite>\n * ```\n *\n * @example Using the MJ wrapper\n * ```html\n * <mj-entity-erd\n * [entities]=\"[currentEntity]\"\n * [selectedEntityId]=\"currentEntity.ID\"\n * [depth]=\"1\"\n * (entitySelected)=\"onEntitySelected($event)\"\n * (openRecord)=\"onOpenRecord($event)\">\n * </mj-entity-erd>\n * ```\n *\n * @example Using the generic component\n * ```html\n * <mj-erd-diagram\n * [nodes]=\"myNodes\"\n * [selectedNodeId]=\"selectedId\"\n * (nodeSelected)=\"onNodeSelected($event)\">\n * </mj-erd-diagram>\n * ```\n */\n@NgModule({\n declarations: [\n ERDDiagramComponent,\n MJEntityERDComponent,\n EntityDetailsComponent,\n EntityFilterPanelComponent,\n ERDCompositeComponent\n ],\n imports: [\n CommonModule,\n FormsModule,\n AngularSplitModule\n ],\n exports: [\n ERDDiagramComponent,\n MJEntityERDComponent,\n EntityDetailsComponent,\n EntityFilterPanelComponent,\n ERDCompositeComponent\n ]\n})\nexport class EntityRelationshipDiagramModule {}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-entity-relationship-diagram",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.23.0",
|
|
4
4
|
"description": "MemberJunction: Entity Relationship Diagram (ERD) component for visualizing entity relationships using D3.js force-directed graphs",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -34,10 +34,11 @@
|
|
|
34
34
|
"@angular/platform-browser": "21.1.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@memberjunction/ng-ui-components": "5.23.0",
|
|
38
|
+
"angular-split": "^20.0.0",
|
|
37
39
|
"@angular/forms": "21.1.3",
|
|
38
40
|
"@dagrejs/dagre": "^1.1.8",
|
|
39
|
-
"@memberjunction/core": "5.
|
|
40
|
-
"@progress/kendo-angular-layout": "22.0.1",
|
|
41
|
+
"@memberjunction/core": "5.23.0",
|
|
41
42
|
"@types/d3": "^7.4.3",
|
|
42
43
|
"d3": "^7.9.0",
|
|
43
44
|
"rxjs": "^7.8.2",
|