@memberjunction/ng-entity-relationship-diagram 5.30.1 → 5.31.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/__tests__/compute-erd-layout.test.d.ts +2 -0
- package/dist/__tests__/compute-erd-layout.test.d.ts.map +1 -0
- package/dist/__tests__/compute-erd-layout.test.js +207 -0
- package/dist/__tests__/compute-erd-layout.test.js.map +1 -0
- package/dist/lib/components/entity-details/entity-details.component.d.ts +2 -1
- package/dist/lib/components/entity-details/entity-details.component.d.ts.map +1 -1
- package/dist/lib/components/entity-details/entity-details.component.js +7 -7
- package/dist/lib/components/entity-details/entity-details.component.js.map +1 -1
- package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.d.ts +10 -4
- package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.d.ts.map +1 -1
- package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.js +60 -72
- package/dist/lib/components/entity-filter-panel/entity-filter-panel.component.js.map +1 -1
- package/dist/lib/components/erd-composite/erd-composite.component.d.ts +4 -1
- package/dist/lib/components/erd-composite/erd-composite.component.d.ts.map +1 -1
- package/dist/lib/components/erd-composite/erd-composite.component.js +22 -8
- package/dist/lib/components/erd-composite/erd-composite.component.js.map +1 -1
- package/dist/lib/components/erd-diagram.component.d.ts +169 -443
- package/dist/lib/components/erd-diagram.component.d.ts.map +1 -1
- package/dist/lib/components/erd-diagram.component.js +916 -1777
- package/dist/lib/components/erd-diagram.component.js.map +1 -1
- package/dist/lib/components/mj-entity-erd.component.d.ts +3 -2
- package/dist/lib/components/mj-entity-erd.component.d.ts.map +1 -1
- package/dist/lib/components/mj-entity-erd.component.js +6 -6
- package/dist/lib/components/mj-entity-erd.component.js.map +1 -1
- package/dist/lib/entity-relationship-diagram.module.d.ts +2 -1
- package/dist/lib/entity-relationship-diagram.module.d.ts.map +1 -1
- package/dist/lib/entity-relationship-diagram.module.js +9 -3
- package/dist/lib/entity-relationship-diagram.module.js.map +1 -1
- package/dist/lib/interfaces/erd-types.d.ts +38 -7
- package/dist/lib/interfaces/erd-types.d.ts.map +1 -1
- package/dist/lib/interfaces/erd-types.js.map +1 -1
- package/dist/lib/layout/compute-dagre-layout.d.ts +32 -0
- package/dist/lib/layout/compute-dagre-layout.d.ts.map +1 -0
- package/dist/lib/layout/compute-dagre-layout.js +168 -0
- package/dist/lib/layout/compute-dagre-layout.js.map +1 -0
- package/dist/lib/layout/compute-erd-layout.d.ts +103 -0
- package/dist/lib/layout/compute-erd-layout.d.ts.map +1 -0
- package/dist/lib/layout/compute-erd-layout.js +254 -0
- package/dist/lib/layout/compute-erd-layout.js.map +1 -0
- package/package.json +6 -5
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
import * as i1 from "@angular/forms";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
i0.ɵɵtextInterpolate1(" ", schema_r1.text, " ");
|
|
13
|
-
} }
|
|
4
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
5
|
+
/** Dropdown items for the Status filter — static list. */
|
|
6
|
+
const STATUS_OPTIONS = [
|
|
7
|
+
{ text: 'All Statuses', value: null },
|
|
8
|
+
{ text: 'Active', value: 'Active' },
|
|
9
|
+
{ text: 'Deprecated', value: 'Deprecated' },
|
|
10
|
+
{ text: 'Disabled', value: 'Disabled' },
|
|
11
|
+
];
|
|
14
12
|
/**
|
|
15
13
|
* Entity filter panel component that provides filtering controls for entities.
|
|
16
14
|
* Supports filtering by schema, entity name, base table, and status.
|
|
@@ -38,7 +36,8 @@ export class EntityFilterPanelComponent {
|
|
|
38
36
|
resetFilters = new EventEmitter();
|
|
39
37
|
/** Emitted when close button is clicked */
|
|
40
38
|
closePanel = new EventEmitter();
|
|
41
|
-
|
|
39
|
+
schemaOptions = [];
|
|
40
|
+
statusOptions = STATUS_OPTIONS;
|
|
42
41
|
ngOnInit() {
|
|
43
42
|
this.updateDistinctSchemas();
|
|
44
43
|
}
|
|
@@ -47,9 +46,16 @@ export class EntityFilterPanelComponent {
|
|
|
47
46
|
this.updateDistinctSchemas();
|
|
48
47
|
}
|
|
49
48
|
}
|
|
49
|
+
onSchemaChange(value) {
|
|
50
|
+
this.filters = { ...this.filters, schemaName: value ?? null };
|
|
51
|
+
this.emitFilterChange();
|
|
52
|
+
}
|
|
53
|
+
onStatusChange(value) {
|
|
54
|
+
this.filters = { ...this.filters, entityStatus: value ?? null };
|
|
55
|
+
this.emitFilterChange();
|
|
56
|
+
}
|
|
50
57
|
onFilterChange() {
|
|
51
|
-
this.
|
|
52
|
-
this.filterChange.emit();
|
|
58
|
+
this.emitFilterChange();
|
|
53
59
|
}
|
|
54
60
|
resetAllFilters() {
|
|
55
61
|
this.resetFilters.emit();
|
|
@@ -57,6 +63,10 @@ export class EntityFilterPanelComponent {
|
|
|
57
63
|
toggleFilterPanel() {
|
|
58
64
|
this.closePanel.emit();
|
|
59
65
|
}
|
|
66
|
+
emitFilterChange() {
|
|
67
|
+
this.filtersChange.emit(this.filters);
|
|
68
|
+
this.filterChange.emit();
|
|
69
|
+
}
|
|
60
70
|
updateDistinctSchemas() {
|
|
61
71
|
const schemas = new Set();
|
|
62
72
|
this.entities.forEach(entity => {
|
|
@@ -64,12 +74,13 @@ export class EntityFilterPanelComponent {
|
|
|
64
74
|
schemas.add(entity.SchemaName);
|
|
65
75
|
}
|
|
66
76
|
});
|
|
67
|
-
this.
|
|
68
|
-
|
|
69
|
-
.map(schema => ({ text: schema, value: schema }))
|
|
77
|
+
this.schemaOptions = [
|
|
78
|
+
{ text: 'All Schemas', value: null },
|
|
79
|
+
...Array.from(schemas).sort().map(schema => ({ text: schema, value: schema })),
|
|
80
|
+
];
|
|
70
81
|
}
|
|
71
82
|
static ɵfac = function EntityFilterPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityFilterPanelComponent)(); };
|
|
72
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityFilterPanelComponent, selectors: [["mj-entity-filter-panel"]], inputs: { entities: "entities", filteredEntities: "filteredEntities", filters: "filters" }, outputs: { filtersChange: "filtersChange", filterChange: "filterChange", resetFilters: "resetFilters", closePanel: "closePanel" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls:
|
|
83
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityFilterPanelComponent, selectors: [["mj-entity-filter-panel"]], inputs: { entities: "entities", filteredEntities: "filteredEntities", filters: "filters" }, outputs: { filtersChange: "filtersChange", filterChange: "filterChange", resetFilters: "resetFilters", closePanel: "closePanel" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 36, vars: 10, consts: [[1, "filter-panel"], [1, "filter-panel-header"], [1, "filter-summary-inline"], [1, "summary-value"], [1, "summary-label"], ["type", "button", "mjButton", "", "variant", "icon", "size", "sm", "aria-label", "Close filter panel", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "filter-content"], [1, "filter-group"], [1, "filter-label"], ["aria-hidden", "true", 1, "fa-solid", "fa-database"], ["TextField", "text", "ValueField", "value", 1, "filter-dropdown", 3, "ValueChange", "Data", "ValuePrimitive", "ngModel"], ["aria-hidden", "true", 1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Search entities...", 1, "mj-input", "filter-input", 3, "ngModelChange", "ngModel"], ["aria-hidden", "true", 1, "fa-solid", "fa-table"], ["type", "text", "placeholder", "Search tables...", 1, "mj-input", "filter-input", 3, "ngModelChange", "ngModel"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle-check"], [1, "filter-actions"], ["type", "button", "mjButton", "", "variant", "secondary", "size", "md", "title", "Reset all filters", 1, "reset-btn", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-rotate-left"]], template: function EntityFilterPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
73
84
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "h3");
|
|
74
85
|
i0.ɵɵtext(3, "Entity Filters");
|
|
75
86
|
i0.ɵɵelementEnd();
|
|
@@ -81,59 +92,42 @@ export class EntityFilterPanelComponent {
|
|
|
81
92
|
i0.ɵɵelementEnd()();
|
|
82
93
|
i0.ɵɵelementStart(9, "button", 5);
|
|
83
94
|
i0.ɵɵlistener("click", function EntityFilterPanelComponent_Template_button_click_9_listener() { return ctx.toggleFilterPanel(); });
|
|
84
|
-
i0.ɵɵelement(10, "
|
|
95
|
+
i0.ɵɵelement(10, "i", 6);
|
|
85
96
|
i0.ɵɵelementEnd()();
|
|
86
97
|
i0.ɵɵelementStart(11, "div", 7)(12, "div", 8)(13, "label", 9);
|
|
87
|
-
i0.ɵɵelement(14, "
|
|
98
|
+
i0.ɵɵelement(14, "i", 10);
|
|
88
99
|
i0.ɵɵtext(15, " Schema ");
|
|
89
100
|
i0.ɵɵelementEnd();
|
|
90
|
-
i0.ɵɵelementStart(16, "
|
|
91
|
-
i0.ɵɵ
|
|
92
|
-
i0.ɵɵlistener("ngModelChange", function EntityFilterPanelComponent_Template_select_ngModelChange_16_listener() { return ctx.onFilterChange(); });
|
|
93
|
-
i0.ɵɵelementStart(17, "option", 12);
|
|
94
|
-
i0.ɵɵtext(18, "All Schemas");
|
|
95
|
-
i0.ɵɵelementEnd();
|
|
96
|
-
i0.ɵɵrepeaterCreate(19, EntityFilterPanelComponent_For_20_Template, 2, 2, "option", 12, i0.ɵɵrepeaterTrackByIdentity);
|
|
101
|
+
i0.ɵɵelementStart(16, "mj-dropdown", 11);
|
|
102
|
+
i0.ɵɵlistener("ValueChange", function EntityFilterPanelComponent_Template_mj_dropdown_ValueChange_16_listener($event) { return ctx.onSchemaChange($event); });
|
|
97
103
|
i0.ɵɵelementEnd()();
|
|
98
|
-
i0.ɵɵelementStart(
|
|
99
|
-
i0.ɵɵelement(
|
|
100
|
-
i0.ɵɵtext(
|
|
104
|
+
i0.ɵɵelementStart(17, "div", 8)(18, "label", 9);
|
|
105
|
+
i0.ɵɵelement(19, "i", 12);
|
|
106
|
+
i0.ɵɵtext(20, " Entity Name ");
|
|
101
107
|
i0.ɵɵelementEnd();
|
|
102
|
-
i0.ɵɵelementStart(
|
|
103
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
104
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
108
|
+
i0.ɵɵelementStart(21, "input", 13);
|
|
109
|
+
i0.ɵɵtwoWayListener("ngModelChange", function EntityFilterPanelComponent_Template_input_ngModelChange_21_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.entityName, $event) || (ctx.filters.entityName = $event); return $event; });
|
|
110
|
+
i0.ɵɵlistener("ngModelChange", function EntityFilterPanelComponent_Template_input_ngModelChange_21_listener() { return ctx.onFilterChange(); });
|
|
105
111
|
i0.ɵɵelementEnd()();
|
|
106
|
-
i0.ɵɵelementStart(
|
|
107
|
-
i0.ɵɵelement(
|
|
108
|
-
i0.ɵɵtext(
|
|
112
|
+
i0.ɵɵelementStart(22, "div", 8)(23, "label", 9);
|
|
113
|
+
i0.ɵɵelement(24, "i", 14);
|
|
114
|
+
i0.ɵɵtext(25, " Base Table ");
|
|
109
115
|
i0.ɵɵelementEnd();
|
|
110
|
-
i0.ɵɵelementStart(
|
|
111
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
112
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
116
|
+
i0.ɵɵelementStart(26, "input", 15);
|
|
117
|
+
i0.ɵɵtwoWayListener("ngModelChange", function EntityFilterPanelComponent_Template_input_ngModelChange_26_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.baseTable, $event) || (ctx.filters.baseTable = $event); return $event; });
|
|
118
|
+
i0.ɵɵlistener("ngModelChange", function EntityFilterPanelComponent_Template_input_ngModelChange_26_listener() { return ctx.onFilterChange(); });
|
|
113
119
|
i0.ɵɵelementEnd()();
|
|
114
|
-
i0.ɵɵelementStart(
|
|
115
|
-
i0.ɵɵelement(
|
|
116
|
-
i0.ɵɵtext(
|
|
120
|
+
i0.ɵɵelementStart(27, "div", 8)(28, "label", 9);
|
|
121
|
+
i0.ɵɵelement(29, "i", 16);
|
|
122
|
+
i0.ɵɵtext(30, " Status ");
|
|
117
123
|
i0.ɵɵelementEnd();
|
|
118
|
-
i0.ɵɵelementStart(
|
|
119
|
-
i0.ɵɵ
|
|
120
|
-
i0.ɵɵ
|
|
121
|
-
i0.ɵɵelementStart(
|
|
122
|
-
i0.ɵɵ
|
|
123
|
-
i0.ɵɵ
|
|
124
|
-
i0.ɵɵ
|
|
125
|
-
i0.ɵɵtext(39, "Active");
|
|
126
|
-
i0.ɵɵelementEnd();
|
|
127
|
-
i0.ɵɵelementStart(40, "option", 19);
|
|
128
|
-
i0.ɵɵtext(41, "Deprecated");
|
|
129
|
-
i0.ɵɵelementEnd();
|
|
130
|
-
i0.ɵɵelementStart(42, "option", 20);
|
|
131
|
-
i0.ɵɵtext(43, "Disabled");
|
|
132
|
-
i0.ɵɵelementEnd()()();
|
|
133
|
-
i0.ɵɵelementStart(44, "div", 21)(45, "button", 22);
|
|
134
|
-
i0.ɵɵlistener("click", function EntityFilterPanelComponent_Template_button_click_45_listener() { return ctx.resetAllFilters(); });
|
|
135
|
-
i0.ɵɵelement(46, "span", 23);
|
|
136
|
-
i0.ɵɵtext(47, " Reset Filters ");
|
|
124
|
+
i0.ɵɵelementStart(31, "mj-dropdown", 11);
|
|
125
|
+
i0.ɵɵlistener("ValueChange", function EntityFilterPanelComponent_Template_mj_dropdown_ValueChange_31_listener($event) { return ctx.onStatusChange($event); });
|
|
126
|
+
i0.ɵɵelementEnd()();
|
|
127
|
+
i0.ɵɵelementStart(32, "div", 17)(33, "button", 18);
|
|
128
|
+
i0.ɵɵlistener("click", function EntityFilterPanelComponent_Template_button_click_33_listener() { return ctx.resetAllFilters(); });
|
|
129
|
+
i0.ɵɵelement(34, "i", 19);
|
|
130
|
+
i0.ɵɵtext(35, " Reset Filters ");
|
|
137
131
|
i0.ɵɵelementEnd()()()();
|
|
138
132
|
} if (rf & 2) {
|
|
139
133
|
i0.ɵɵadvance(6);
|
|
@@ -141,24 +135,18 @@ export class EntityFilterPanelComponent {
|
|
|
141
135
|
i0.ɵɵadvance(2);
|
|
142
136
|
i0.ɵɵtextInterpolate1("of ", ctx.entities.length);
|
|
143
137
|
i0.ɵɵadvance(8);
|
|
144
|
-
i0.ɵɵ
|
|
145
|
-
i0.ɵɵadvance();
|
|
146
|
-
i0.ɵɵproperty("ngValue", null);
|
|
147
|
-
i0.ɵɵadvance(2);
|
|
148
|
-
i0.ɵɵrepeater(ctx.distinctSchemas);
|
|
149
|
-
i0.ɵɵadvance(6);
|
|
138
|
+
i0.ɵɵproperty("Data", ctx.schemaOptions)("ValuePrimitive", true)("ngModel", ctx.filters.schemaName);
|
|
139
|
+
i0.ɵɵadvance(5);
|
|
150
140
|
i0.ɵɵtwoWayProperty("ngModel", ctx.filters.entityName);
|
|
151
141
|
i0.ɵɵadvance(5);
|
|
152
142
|
i0.ɵɵtwoWayProperty("ngModel", ctx.filters.baseTable);
|
|
153
143
|
i0.ɵɵadvance(5);
|
|
154
|
-
i0.ɵɵ
|
|
155
|
-
|
|
156
|
-
i0.ɵɵproperty("ngValue", null);
|
|
157
|
-
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel], styles: ["\n\n\n\n\n\n.filter-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-width: 0;\n}\n\n\n\n.filter-panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n min-width: 0;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.filter-panel-header[_ngcontent-%COMP%] .filter-summary-inline[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] .filter-summary-inline[_ngcontent-%COMP%] .summary-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 700;\n color: var(--mj-brand-primary);\n}\n\n.filter-panel-header[_ngcontent-%COMP%] .filter-summary-inline[_ngcontent-%COMP%] .summary-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.filter-panel-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: transparent;\n color: var(--mj-text-secondary);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-text-primary);\n}\n\n\n\n.filter-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n}\n\n\n\n.filter-group[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-label[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n width: 16px;\n}\n\n\n\n.filter-group[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%], \n.filter-group[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 100%;\n padding: 12px 16px;\n font-size: 14px;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: 4px;\n transition: all 0.2s ease;\n box-sizing: border-box;\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]:focus, \n.filter-group[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px var(--mj-color-accent-300);\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]::placeholder, \n.filter-group[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-secondary);\n opacity: 0.6;\n font-style: italic;\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.filter-group[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%] option[_ngcontent-%COMP%] {\n padding: 8px;\n}\n\n\n\n.filter-actions[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n\n\n.filter-actions[_ngcontent-%COMP%] .reset-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n max-width: 100%;\n padding: 10px 24px;\n font-size: 14px;\n font-weight: 500;\n background: transparent;\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-color-neutral-400);\n border-radius: 20px;\n cursor: pointer;\n transition: all 0.2s ease;\n box-sizing: border-box;\n}\n\n.filter-actions[_ngcontent-%COMP%] .reset-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-color-neutral-400);\n color: var(--mj-text-primary);\n}\n\n.filter-actions[_ngcontent-%COMP%] .reset-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-actions[_ngcontent-%COMP%] .reset-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.filter-actions[_ngcontent-%COMP%] .reset-btn[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n font-size: 12px;\n}"] });
|
|
144
|
+
i0.ɵɵproperty("Data", ctx.statusOptions)("ValuePrimitive", true)("ngModel", ctx.filters.entityStatus);
|
|
145
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJButtonDirective, i2.MJDropdownComponent], styles: ["\n\n\n\n\n\n\n.filter-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-width: 0;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n min-width: 0;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex: 1;\n min-width: 0;\n}\n\n.filter-summary-inline[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n}\n\n.filter-summary-inline[_ngcontent-%COMP%] .summary-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 700;\n color: var(--mj-brand-primary);\n}\n\n.filter-summary-inline[_ngcontent-%COMP%] .summary-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.filter-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.filter-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.filter-label[_ngcontent-%COMP%] .fa-solid[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n width: 16px;\n text-align: center;\n}\n\n\n\n.filter-dropdown[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n}\n\n.filter-input[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.filter-actions[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.reset-btn[_ngcontent-%COMP%] {\n width: 100%;\n}"] });
|
|
158
146
|
}
|
|
159
147
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityFilterPanelComponent, [{
|
|
160
148
|
type: Component,
|
|
161
|
-
args: [{ standalone: false, selector: 'mj-entity-filter-panel', template: "<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <h3>Entity Filters</h3>\n <div class=\"filter-summary-inline\">\n <span class=\"summary-value\">{{ filteredEntities.length }}</span>\n <span class=\"summary-label\">of {{ entities.length }}</span>\n </div>\n <button
|
|
149
|
+
args: [{ standalone: false, selector: 'mj-entity-filter-panel', template: "<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <h3>Entity Filters</h3>\n <div class=\"filter-summary-inline\">\n <span class=\"summary-value\">{{ filteredEntities.length }}</span>\n <span class=\"summary-label\">of {{ entities.length }}</span>\n </div>\n <button type=\"button\" mjButton variant=\"icon\" size=\"sm\" (click)=\"toggleFilterPanel()\" aria-label=\"Close filter panel\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <div class=\"filter-content\">\n <!-- Schema Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n Schema\n </label>\n <mj-dropdown\n class=\"filter-dropdown\"\n [Data]=\"schemaOptions\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"filters.schemaName\"\n (ValueChange)=\"onSchemaChange($event)\">\n </mj-dropdown>\n </div>\n\n <!-- Entity Name Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-magnifying-glass\" aria-hidden=\"true\"></i>\n Entity Name\n </label>\n <input\n type=\"text\"\n class=\"mj-input filter-input\"\n [(ngModel)]=\"filters.entityName\"\n (ngModelChange)=\"onFilterChange()\"\n placeholder=\"Search entities...\">\n </div>\n\n <!-- Base Table Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n Base Table\n </label>\n <input\n type=\"text\"\n class=\"mj-input filter-input\"\n [(ngModel)]=\"filters.baseTable\"\n (ngModelChange)=\"onFilterChange()\"\n placeholder=\"Search tables...\">\n </div>\n\n <!-- Entity Status Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-circle-check\" aria-hidden=\"true\"></i>\n Status\n </label>\n <mj-dropdown\n class=\"filter-dropdown\"\n [Data]=\"statusOptions\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"filters.entityStatus\"\n (ValueChange)=\"onStatusChange($event)\">\n </mj-dropdown>\n </div>\n\n <!-- Reset Button -->\n <div class=\"filter-actions\">\n <button type=\"button\" mjButton variant=\"secondary\" size=\"md\" class=\"reset-btn\" (click)=\"resetAllFilters()\" title=\"Reset all filters\">\n <i class=\"fa-solid fa-arrow-rotate-left\" aria-hidden=\"true\"></i>\n Reset Filters\n </button>\n </div>\n </div>\n</div>\n", styles: ["/**\n * Entity Filter Panel Component\n * Uses standardized MJ UI components (mjButton, mj-dropdown, .mj-input) for\n * form controls \u2014 this stylesheet only covers panel layout + labels.\n */\n\n.filter-panel {\n height: 100%;\n background: var(--mj-bg-page);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-width: 0;\n}\n\n.filter-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n min-width: 0;\n}\n\n.filter-panel-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex: 1;\n min-width: 0;\n}\n\n.filter-summary-inline {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-right: 8px;\n}\n\n.filter-summary-inline .summary-value {\n font-size: 16px;\n font-weight: 700;\n color: var(--mj-brand-primary);\n}\n\n.filter-summary-inline .summary-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.filter-content {\n padding: 16px;\n overflow-y: auto;\n overflow-x: hidden;\n flex: 1;\n}\n\n.filter-group {\n margin-bottom: 20px;\n}\n\n.filter-label {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.filter-label .fa-solid {\n color: var(--mj-brand-primary);\n width: 16px;\n text-align: center;\n}\n\n/* Ensure the MJ dropdown takes the full row width like the inputs. */\n.filter-dropdown {\n display: block;\n width: 100%;\n}\n\n.filter-input {\n width: 100%;\n}\n\n.filter-actions {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.reset-btn {\n width: 100%;\n}\n"] }]
|
|
162
150
|
}], null, { entities: [{
|
|
163
151
|
type: Input
|
|
164
152
|
}], filteredEntities: [{
|
|
@@ -174,5 +162,5 @@ export class EntityFilterPanelComponent {
|
|
|
174
162
|
}], closePanel: [{
|
|
175
163
|
type: Output
|
|
176
164
|
}] }); })();
|
|
177
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityFilterPanelComponent, { className: "EntityFilterPanelComponent", filePath: "src/lib/components/entity-filter-panel/entity-filter-panel.component.ts", lineNumber:
|
|
165
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityFilterPanelComponent, { className: "EntityFilterPanelComponent", filePath: "src/lib/components/entity-filter-panel/entity-filter-panel.component.ts", lineNumber: 40 }); })();
|
|
178
166
|
//# sourceMappingURL=entity-filter-panel.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-filter-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/components/entity-filter-panel/entity-filter-panel.component.ts","../../../../src/lib/components/entity-filter-panel/entity-filter-panel.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAoC,MAAM,eAAe,CAAC;;;;
|
|
1
|
+
{"version":3,"file":"entity-filter-panel.component.js","sourceRoot":"","sources":["../../../../src/lib/components/entity-filter-panel/entity-filter-panel.component.ts","../../../../src/lib/components/entity-filter-panel/entity-filter-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';\nimport { EntityInfo } from '@memberjunction/core';\n\n/**\n * Filter configuration for entity filtering.\n */\nexport interface EntityFilter {\n schemaName: string | null;\n entityName: string;\n entityStatus: string | null;\n baseTable: string;\n}\n\ninterface FilterOption {\n text: string;\n value: string | null;\n}\n\n/** Dropdown items for the Status filter — static list. */\nconst STATUS_OPTIONS: ReadonlyArray<FilterOption> = [\n { text: 'All Statuses', value: null },\n { text: 'Active', value: 'Active' },\n { text: 'Deprecated', value: 'Deprecated' },\n { text: 'Disabled', value: 'Disabled' },\n];\n\n/**\n * Entity filter panel component that provides filtering controls for entities.\n * Supports filtering by schema, entity name, base table, and status.\n *\n * This component is designed to be used alongside the ERD diagram to filter\n * which entities are displayed.\n */\n@Component({\n standalone: false,\n selector: 'mj-entity-filter-panel',\n templateUrl: './entity-filter-panel.component.html',\n styleUrls: ['./entity-filter-panel.component.css']\n})\nexport class EntityFilterPanelComponent implements OnInit, OnChanges {\n /** All entities available for filtering */\n @Input() entities: EntityInfo[] = [];\n\n /** Currently filtered entities (for display count) */\n @Input() filteredEntities: EntityInfo[] = [];\n\n /** Current filter values */\n @Input() filters: EntityFilter = {\n schemaName: null,\n entityName: '',\n entityStatus: null,\n baseTable: '',\n };\n\n /** Emitted when any filter value changes */\n @Output() filtersChange = new EventEmitter<EntityFilter>();\n\n /** Emitted when filter is applied (for debouncing) */\n @Output() filterChange = new EventEmitter<void>();\n\n /** Emitted when reset button is clicked */\n @Output() resetFilters = new EventEmitter<void>();\n\n /** Emitted when close button is clicked */\n @Output() closePanel = new EventEmitter<void>();\n\n public schemaOptions: FilterOption[] = [];\n public readonly statusOptions = STATUS_OPTIONS;\n\n ngOnInit(): void {\n this.updateDistinctSchemas();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['entities']) {\n this.updateDistinctSchemas();\n }\n }\n\n public onSchemaChange(value: unknown): void {\n this.filters = { ...this.filters, schemaName: (value as string | null) ?? null };\n this.emitFilterChange();\n }\n\n public onStatusChange(value: unknown): void {\n this.filters = { ...this.filters, entityStatus: (value as string | null) ?? null };\n this.emitFilterChange();\n }\n\n public onFilterChange(): void {\n this.emitFilterChange();\n }\n\n public resetAllFilters(): void {\n this.resetFilters.emit();\n }\n\n public toggleFilterPanel(): void {\n this.closePanel.emit();\n }\n\n private emitFilterChange(): void {\n this.filtersChange.emit(this.filters);\n this.filterChange.emit();\n }\n\n private updateDistinctSchemas(): void {\n const schemas = new Set<string>();\n this.entities.forEach(entity => {\n if (entity.SchemaName) {\n schemas.add(entity.SchemaName);\n }\n });\n\n this.schemaOptions = [\n { text: 'All Schemas', value: null },\n ...Array.from(schemas).sort().map(schema => ({ text: schema, value: schema })),\n ];\n }\n}\n","<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <h3>Entity Filters</h3>\n <div class=\"filter-summary-inline\">\n <span class=\"summary-value\">{{ filteredEntities.length }}</span>\n <span class=\"summary-label\">of {{ entities.length }}</span>\n </div>\n <button type=\"button\" mjButton variant=\"icon\" size=\"sm\" (click)=\"toggleFilterPanel()\" aria-label=\"Close filter panel\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <div class=\"filter-content\">\n <!-- Schema Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n Schema\n </label>\n <mj-dropdown\n class=\"filter-dropdown\"\n [Data]=\"schemaOptions\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"filters.schemaName\"\n (ValueChange)=\"onSchemaChange($event)\">\n </mj-dropdown>\n </div>\n\n <!-- Entity Name Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-magnifying-glass\" aria-hidden=\"true\"></i>\n Entity Name\n </label>\n <input\n type=\"text\"\n class=\"mj-input filter-input\"\n [(ngModel)]=\"filters.entityName\"\n (ngModelChange)=\"onFilterChange()\"\n placeholder=\"Search entities...\">\n </div>\n\n <!-- Base Table Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-table\" aria-hidden=\"true\"></i>\n Base Table\n </label>\n <input\n type=\"text\"\n class=\"mj-input filter-input\"\n [(ngModel)]=\"filters.baseTable\"\n (ngModelChange)=\"onFilterChange()\"\n placeholder=\"Search tables...\">\n </div>\n\n <!-- Entity Status Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <i class=\"fa-solid fa-circle-check\" aria-hidden=\"true\"></i>\n Status\n </label>\n <mj-dropdown\n class=\"filter-dropdown\"\n [Data]=\"statusOptions\"\n TextField=\"text\"\n ValueField=\"value\"\n [ValuePrimitive]=\"true\"\n [ngModel]=\"filters.entityStatus\"\n (ValueChange)=\"onStatusChange($event)\">\n </mj-dropdown>\n </div>\n\n <!-- Reset Button -->\n <div class=\"filter-actions\">\n <button type=\"button\" mjButton variant=\"secondary\" size=\"md\" class=\"reset-btn\" (click)=\"resetAllFilters()\" title=\"Reset all filters\">\n <i class=\"fa-solid fa-arrow-rotate-left\" aria-hidden=\"true\"></i>\n Reset Filters\n </button>\n </div>\n </div>\n</div>\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter, OnInit, OnDestroy } from '@angular/core';
|
|
2
2
|
import { EntityInfo, EntityFieldInfo } from '@memberjunction/core';
|
|
3
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
4
|
import { MJEntityERDComponent } from '../mj-entity-erd.component';
|
|
4
5
|
import { EntitySelectedEvent, OpenEntityRecordEvent } from '../mj-entity-erd.component';
|
|
5
6
|
import { ERDConfig, ERDState } from '../../interfaces/erd-types';
|
|
@@ -21,6 +22,8 @@ export interface ERDCompositeState {
|
|
|
21
22
|
};
|
|
22
23
|
fieldsSectionExpanded: boolean;
|
|
23
24
|
relationshipsSectionExpanded: boolean;
|
|
25
|
+
/** User's preferred layout algorithm — 'schema-grid' (default) or 'dagre'. */
|
|
26
|
+
layoutAlgorithm?: 'schema-grid' | 'dagre';
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
29
|
* ERD Composite component that combines the ERD diagram with filter and details panels.
|
|
@@ -64,7 +67,7 @@ export interface ERDCompositeState {
|
|
|
64
67
|
* }
|
|
65
68
|
* ```
|
|
66
69
|
*/
|
|
67
|
-
export declare class ERDCompositeComponent implements OnInit, OnDestroy {
|
|
70
|
+
export declare class ERDCompositeComponent extends BaseAngularComponent implements OnInit, OnDestroy {
|
|
68
71
|
mjEntityErd: MJEntityERDComponent;
|
|
69
72
|
/** Whether the ERD is in a refreshing state */
|
|
70
73
|
isRefreshingERD: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erd-composite.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/erd-composite/erd-composite.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,MAAM,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AAGrG,OAAO,EAAE,UAAU,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"erd-composite.component.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/erd-composite/erd-composite.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
2
2
|
import { Subject } from 'rxjs';
|
|
3
3
|
import { debounceTime } from 'rxjs/operators';
|
|
4
|
-
import { Metadata } from '@memberjunction/core';
|
|
5
4
|
import { UUIDsEqual } from '@memberjunction/global';
|
|
5
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
6
6
|
import { MJEntityERDComponent } from '../mj-entity-erd.component';
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
8
8
|
import * as i1 from "angular-split";
|
|
@@ -73,7 +73,7 @@ function ERDCompositeComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
|
73
73
|
* }
|
|
74
74
|
* ```
|
|
75
75
|
*/
|
|
76
|
-
export class ERDCompositeComponent {
|
|
76
|
+
export class ERDCompositeComponent extends BaseAngularComponent {
|
|
77
77
|
mjEntityErd;
|
|
78
78
|
/** Whether the ERD is in a refreshing state */
|
|
79
79
|
isRefreshingERD = false;
|
|
@@ -154,7 +154,7 @@ export class ERDCompositeComponent {
|
|
|
154
154
|
}
|
|
155
155
|
async loadData() {
|
|
156
156
|
// Load entities from metadata (always needed for allEntityFields and relationship lookups)
|
|
157
|
-
const md =
|
|
157
|
+
const md = this.ProviderToUse;
|
|
158
158
|
this.entities = md.Entities;
|
|
159
159
|
// Load all entity fields from entities
|
|
160
160
|
this.allEntityFields = this.entities
|
|
@@ -210,6 +210,13 @@ export class ERDCompositeComponent {
|
|
|
210
210
|
}
|
|
211
211
|
onEntitySelected(entity) {
|
|
212
212
|
this.selectedEntity = entity;
|
|
213
|
+
// Bring the entity into view in the diagram and emit nodeSelected
|
|
214
|
+
// upstream so the focus + highlight logic kicks in. Done in a
|
|
215
|
+
// microtask so the [focusEntityId] binding flushes first and the
|
|
216
|
+
// inner diagram has the new focus state when we ask it to center.
|
|
217
|
+
queueMicrotask(() => {
|
|
218
|
+
this.mjEntityErd?.zoomToEntity(entity.ID);
|
|
219
|
+
});
|
|
213
220
|
this.emitStateChange();
|
|
214
221
|
this.emitUserStateChange();
|
|
215
222
|
}
|
|
@@ -305,6 +312,7 @@ export class ERDCompositeComponent {
|
|
|
305
312
|
panPosition: { x: 0, y: 0 },
|
|
306
313
|
fieldsSectionExpanded: this.fieldsSectionExpanded,
|
|
307
314
|
relationshipsSectionExpanded: this.relationshipsSectionExpanded,
|
|
315
|
+
layoutAlgorithm: this.mjEntityErd?.erdDiagram?.activeLayout ?? 'schema-grid',
|
|
308
316
|
};
|
|
309
317
|
}
|
|
310
318
|
// ============================================================================
|
|
@@ -336,6 +344,12 @@ export class ERDCompositeComponent {
|
|
|
336
344
|
else {
|
|
337
345
|
this.selectedEntity = null;
|
|
338
346
|
}
|
|
347
|
+
// Restore preferred layout algorithm. Deferred to microtask so the
|
|
348
|
+
// diagram has mounted by the time we set it.
|
|
349
|
+
if (state.layoutAlgorithm) {
|
|
350
|
+
const algo = state.layoutAlgorithm;
|
|
351
|
+
queueMicrotask(() => this.mjEntityErd?.erdDiagram?.setLayoutAlgorithm(algo));
|
|
352
|
+
}
|
|
339
353
|
this.applyFilters();
|
|
340
354
|
}
|
|
341
355
|
/**
|
|
@@ -352,13 +366,13 @@ export class ERDCompositeComponent {
|
|
|
352
366
|
getState() {
|
|
353
367
|
return this.buildState();
|
|
354
368
|
}
|
|
355
|
-
static ɵfac = function ERDCompositeComponent_Factory(__ngFactoryType__) { return
|
|
369
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵERDCompositeComponent_BaseFactory; return function ERDCompositeComponent_Factory(__ngFactoryType__) { return (ɵERDCompositeComponent_BaseFactory || (ɵERDCompositeComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ERDCompositeComponent)))(__ngFactoryType__ || ERDCompositeComponent); }; })();
|
|
356
370
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ERDCompositeComponent, selectors: [["mj-erd-composite"]], viewQuery: function ERDCompositeComponent_Query(rf, ctx) { if (rf & 1) {
|
|
357
371
|
i0.ɵɵviewQuery(MJEntityERDComponent, 5);
|
|
358
372
|
} if (rf & 2) {
|
|
359
373
|
let _t;
|
|
360
374
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.mjEntityErd = _t.first);
|
|
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:
|
|
375
|
+
} }, inputs: { isRefreshingERD: "isRefreshingERD", focusEntities: "focusEntities", showFilterPanel: "showFilterPanel", depth: "depth", showHeader: "showHeader" }, outputs: { stateChange: "stateChange", userStateChange: "userStateChange", entityOpened: "entityOpened", openRecord: "openRecord" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 7, vars: 13, 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", "focusEntityId", "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
376
|
i0.ɵɵelementStart(0, "div", 0)(1, "as-split", 1);
|
|
363
377
|
i0.ɵɵlistener("dragEnd", function ERDCompositeComponent_Template_as_split_dragEnd_1_listener($event) { return ctx.onSplitterLayoutChange($event); });
|
|
364
378
|
i0.ɵɵconditionalCreate(2, ERDCompositeComponent_Conditional_2_Template, 2, 6, "as-split-area", 2);
|
|
@@ -373,14 +387,14 @@ export class ERDCompositeComponent {
|
|
|
373
387
|
i0.ɵɵadvance();
|
|
374
388
|
i0.ɵɵproperty("size", ctx.selectedEntity ? 60 : ctx.filterPanelVisible ? 80 : 100);
|
|
375
389
|
i0.ɵɵadvance(2);
|
|
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);
|
|
390
|
+
i0.ɵɵproperty("entities", ctx.filteredEntities)("allEntities", ctx.entities)("selectedEntityId", (ctx.selectedEntity == null ? null : ctx.selectedEntity.ID) || null)("focusEntityId", (ctx.selectedEntity == null ? null : ctx.selectedEntity.ID) || null)("isRefreshing", ctx.isRefreshingERD)("depth", ctx.depth)("includeIncoming", true)("includeOutgoing", true)("showHeader", ctx.showHeader)("config", ctx.erdConfig);
|
|
377
391
|
i0.ɵɵadvance();
|
|
378
392
|
i0.ɵɵconditional(ctx.selectedEntity ? 6 : -1);
|
|
379
393
|
} }, 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}"] });
|
|
380
394
|
}
|
|
381
395
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ERDCompositeComponent, [{
|
|
382
396
|
type: Component,
|
|
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"] }]
|
|
397
|
+
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 [focusEntityId]=\"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"] }]
|
|
384
398
|
}], null, { mjEntityErd: [{
|
|
385
399
|
type: ViewChild,
|
|
386
400
|
args: [MJEntityERDComponent]
|
|
@@ -403,5 +417,5 @@ export class ERDCompositeComponent {
|
|
|
403
417
|
}], openRecord: [{
|
|
404
418
|
type: Output
|
|
405
419
|
}] }); })();
|
|
406
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ERDCompositeComponent, { className: "ERDCompositeComponent", filePath: "src/lib/components/erd-composite/erd-composite.component.ts", lineNumber:
|
|
420
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ERDCompositeComponent, { className: "ERDCompositeComponent", filePath: "src/lib/components/erd-composite/erd-composite.component.ts", lineNumber: 77 }); })();
|
|
407
421
|
//# sourceMappingURL=erd-composite.component.js.map
|