@memberjunction/ng-entity-viewer 5.42.0 → 5.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +5 -0
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
- package/dist/lib/aggregate-panel/aggregate-panel.component.js +45 -47
- package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +7 -10
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +42 -2
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +256 -141
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-data-grid/models/grid-types.d.ts +8 -1
- package/dist/lib/entity-data-grid/models/grid-types.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/models/grid-types.js.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +0 -4
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +166 -207
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +109 -5
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +287 -42
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.js +21 -44
- package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
- package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js +19 -20
- package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +268 -301
- package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
- package/dist/lib/view-selector/view-selector.component.d.ts +26 -1
- package/dist/lib/view-selector/view-selector.component.d.ts.map +1 -1
- package/dist/lib/view-selector/view-selector.component.js +118 -76
- package/dist/lib/view-selector/view-selector.component.js.map +1 -1
- package/dist/lib/view-types/descriptors/grid-view-type.d.ts +7 -0
- package/dist/lib/view-types/descriptors/grid-view-type.d.ts.map +1 -1
- package/dist/lib/view-types/descriptors/grid-view-type.js +7 -0
- package/dist/lib/view-types/descriptors/grid-view-type.js.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +24 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js +39 -4
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.js +11 -14
- package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.js +12 -14
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/view-type.contracts.d.ts +44 -0
- package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -1
- package/dist/lib/view-types/view-type.contracts.js +6 -0
- package/dist/lib/view-types/view-type.contracts.js.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts +32 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.js +68 -7
- package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +20 -4
- package/dist/module.js.map +1 -1
- package/package.json +18 -15
- package/dist/__tests__/entity-cards-selection.test.d.ts +0 -2
- package/dist/__tests__/entity-cards-selection.test.d.ts.map +0 -1
- package/dist/__tests__/entity-cards-selection.test.js +0 -149
- package/dist/__tests__/entity-cards-selection.test.js.map +0 -1
- package/dist/__tests__/entity-cards-viewmodel.test.d.ts +0 -2
- package/dist/__tests__/entity-cards-viewmodel.test.d.ts.map +0 -1
- package/dist/__tests__/entity-cards-viewmodel.test.js +0 -208
- package/dist/__tests__/entity-cards-viewmodel.test.js.map +0 -1
- package/dist/__tests__/highlight.test.d.ts +0 -2
- package/dist/__tests__/highlight.test.d.ts.map +0 -1
- package/dist/__tests__/highlight.test.js +0 -67
- package/dist/__tests__/highlight.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/__tests__/view-types.test.d.ts +0 -2
- package/dist/__tests__/view-types.test.d.ts.map +0 -1
- package/dist/__tests__/view-types.test.js +0 -102
- package/dist/__tests__/view-types.test.js.map +0 -1
|
@@ -17,48 +17,25 @@ function RecycleBinComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
|
17
17
|
i0.ɵɵtextInterpolate(ctx_r0.HeaderSubtitle);
|
|
18
18
|
} }
|
|
19
19
|
function RecycleBinComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
20
|
-
i0.ɵɵ
|
|
21
|
-
i0.ɵɵelement(1, "i", 14);
|
|
22
|
-
i0.ɵɵelementStart(2, "h3");
|
|
23
|
-
i0.ɵɵtext(3, "Access denied");
|
|
24
|
-
i0.ɵɵelementEnd();
|
|
25
|
-
i0.ɵɵelementStart(4, "p");
|
|
26
|
-
i0.ɵɵtext(5);
|
|
27
|
-
i0.ɵɵelementEnd()();
|
|
20
|
+
i0.ɵɵelement(0, "mj-empty-state", 8);
|
|
28
21
|
} if (rf & 2) {
|
|
29
22
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
30
|
-
i0.ɵɵ
|
|
31
|
-
i0.ɵɵtextInterpolate(ctx_r0.LoadError);
|
|
23
|
+
i0.ɵɵproperty("Message", ctx_r0.LoadError);
|
|
32
24
|
} }
|
|
33
25
|
function RecycleBinComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
34
26
|
i0.ɵɵelement(0, "mj-loading", 9);
|
|
35
27
|
} }
|
|
36
28
|
function RecycleBinComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
37
|
-
i0.ɵɵ
|
|
38
|
-
i0.ɵɵelement(1, "i", 15);
|
|
39
|
-
i0.ɵɵelementStart(2, "h3");
|
|
40
|
-
i0.ɵɵtext(3, "Could not load deleted records");
|
|
41
|
-
i0.ɵɵelementEnd();
|
|
42
|
-
i0.ɵɵelementStart(4, "p");
|
|
43
|
-
i0.ɵɵtext(5);
|
|
44
|
-
i0.ɵɵelementEnd()();
|
|
29
|
+
i0.ɵɵelement(0, "mj-empty-state", 10);
|
|
45
30
|
} if (rf & 2) {
|
|
46
31
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
47
|
-
i0.ɵɵ
|
|
48
|
-
i0.ɵɵtextInterpolate(ctx_r0.LoadError);
|
|
32
|
+
i0.ɵɵproperty("Message", ctx_r0.LoadError);
|
|
49
33
|
} }
|
|
50
34
|
function RecycleBinComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
51
|
-
i0.ɵɵ
|
|
52
|
-
i0.ɵɵelement(1, "i", 16);
|
|
53
|
-
i0.ɵɵelementStart(2, "h3");
|
|
54
|
-
i0.ɵɵtext(3, "Recycle Bin is empty");
|
|
55
|
-
i0.ɵɵelementEnd();
|
|
56
|
-
i0.ɵɵelementStart(4, "p");
|
|
57
|
-
i0.ɵɵtext(5, "No records have been deleted from this entity, or change tracking isn't enabled here.");
|
|
58
|
-
i0.ɵɵelementEnd()();
|
|
35
|
+
i0.ɵɵelement(0, "mj-empty-state", 11);
|
|
59
36
|
} }
|
|
60
37
|
function RecycleBinComponent_Conditional_13_For_2_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
61
|
-
i0.ɵɵelementStart(0, "span",
|
|
38
|
+
i0.ɵɵelementStart(0, "span", 23)(1, "strong");
|
|
62
39
|
i0.ɵɵtext(2);
|
|
63
40
|
i0.ɵɵelementEnd();
|
|
64
41
|
i0.ɵɵtext(3);
|
|
@@ -71,8 +48,8 @@ function RecycleBinComponent_Conditional_13_For_2_Conditional_4_For_2_Template(r
|
|
|
71
48
|
i0.ɵɵtextInterpolate1(" ", sf_r3.Value, " ");
|
|
72
49
|
} }
|
|
73
50
|
function RecycleBinComponent_Conditional_13_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
74
|
-
i0.ɵɵelementStart(0, "div",
|
|
75
|
-
i0.ɵɵrepeaterCreate(1, RecycleBinComponent_Conditional_13_For_2_Conditional_4_For_2_Template, 4, 2, "span",
|
|
51
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
52
|
+
i0.ɵɵrepeaterCreate(1, RecycleBinComponent_Conditional_13_For_2_Conditional_4_For_2_Template, 4, 2, "span", 23, _forTrack1);
|
|
76
53
|
i0.ɵɵelementEnd();
|
|
77
54
|
} if (rf & 2) {
|
|
78
55
|
const entry_r4 = i0.ɵɵnextContext().$implicit;
|
|
@@ -88,18 +65,18 @@ function RecycleBinComponent_Conditional_13_For_2_Conditional_8_Template(rf, ctx
|
|
|
88
65
|
} }
|
|
89
66
|
function RecycleBinComponent_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
90
67
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
91
|
-
i0.ɵɵelementStart(0, "div",
|
|
68
|
+
i0.ɵɵelementStart(0, "div", 14)(1, "div", 15)(2, "div", 16);
|
|
92
69
|
i0.ɵɵtext(3);
|
|
93
70
|
i0.ɵɵelementEnd();
|
|
94
|
-
i0.ɵɵconditionalCreate(4, RecycleBinComponent_Conditional_13_For_2_Conditional_4_Template, 3, 0, "div",
|
|
95
|
-
i0.ɵɵelementStart(5, "div",
|
|
96
|
-
i0.ɵɵelement(6, "i",
|
|
71
|
+
i0.ɵɵconditionalCreate(4, RecycleBinComponent_Conditional_13_For_2_Conditional_4_Template, 3, 0, "div", 17);
|
|
72
|
+
i0.ɵɵelementStart(5, "div", 18);
|
|
73
|
+
i0.ɵɵelement(6, "i", 19);
|
|
97
74
|
i0.ɵɵtext(7);
|
|
98
75
|
i0.ɵɵconditionalCreate(8, RecycleBinComponent_Conditional_13_For_2_Conditional_8_Template, 1, 1);
|
|
99
76
|
i0.ɵɵelementEnd()();
|
|
100
|
-
i0.ɵɵelementStart(9, "div",
|
|
77
|
+
i0.ɵɵelementStart(9, "div", 20)(10, "button", 21);
|
|
101
78
|
i0.ɵɵlistener("click", function RecycleBinComponent_Conditional_13_For_2_Template_button_click_10_listener() { const entry_r4 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnRestoreClicked(entry_r4)); });
|
|
102
|
-
i0.ɵɵelement(11, "i",
|
|
79
|
+
i0.ɵɵelement(11, "i", 22);
|
|
103
80
|
i0.ɵɵtext(12, " Restore ");
|
|
104
81
|
i0.ɵɵelementEnd()()();
|
|
105
82
|
} if (rf & 2) {
|
|
@@ -118,7 +95,7 @@ function RecycleBinComponent_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1
|
|
|
118
95
|
} }
|
|
119
96
|
function RecycleBinComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
120
97
|
i0.ɵɵelementStart(0, "div", 12);
|
|
121
|
-
i0.ɵɵrepeaterCreate(1, RecycleBinComponent_Conditional_13_For_2_Template, 13, 6, "div",
|
|
98
|
+
i0.ɵɵrepeaterCreate(1, RecycleBinComponent_Conditional_13_For_2_Template, 13, 6, "div", 14, _forTrack0);
|
|
122
99
|
i0.ɵɵelementEnd();
|
|
123
100
|
} if (rf & 2) {
|
|
124
101
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -615,7 +592,7 @@ export class RecycleBinComponent extends BaseAngularComponent {
|
|
|
615
592
|
return user;
|
|
616
593
|
}
|
|
617
594
|
static ɵfac = function RecycleBinComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || RecycleBinComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
618
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RecycleBinComponent, selectors: [["mj-recycle-bin"]], inputs: { Visible: "Visible", EntityName: "EntityName", ContextUser: "ContextUser", MaxRecords: "MaxRecords" }, outputs: { Closed: "Closed", BeforeRecycleBinOpen: "BeforeRecycleBinOpen", AfterRecycleBinOpen: "AfterRecycleBinOpen", BeforeRecordRestore: "BeforeRecordRestore", AfterRecordRestore: "AfterRecordRestore", BeforeRestoreCommit: "BeforeRestoreCommit", AfterRestoreCommit: "AfterRestoreCommit" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 15, vars: 16, consts: [[3, "Closed", "Mode", "Title", "Visible", "Resizable", "MinWidthPx", "MaxWidthRatio"], [1, "rb-container"], [1, "rb-header"], [1, "rb-header-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash-can-arrow-up"], [1, "rb-header-text"], [1, "rb-header-title"], [1, "rb-header-subtitle"], [
|
|
595
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RecycleBinComponent, selectors: [["mj-recycle-bin"]], inputs: { Visible: "Visible", EntityName: "EntityName", ContextUser: "ContextUser", MaxRecords: "MaxRecords" }, outputs: { Closed: "Closed", BeforeRecycleBinOpen: "BeforeRecycleBinOpen", AfterRecycleBinOpen: "AfterRecycleBinOpen", BeforeRecordRestore: "BeforeRecordRestore", AfterRecordRestore: "AfterRecordRestore", BeforeRestoreCommit: "BeforeRestoreCommit", AfterRestoreCommit: "AfterRestoreCommit" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 15, vars: 16, consts: [[3, "Closed", "Mode", "Title", "Visible", "Resizable", "MinWidthPx", "MaxWidthRatio"], [1, "rb-container"], [1, "rb-header"], [1, "rb-header-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash-can-arrow-up"], [1, "rb-header-text"], [1, "rb-header-title"], [1, "rb-header-subtitle"], ["Variant", "warning", "Icon", "fa-solid fa-lock", "Title", "Access denied", 3, "Message"], ["text", "Loading deleted records...", "size", "medium"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Could not load deleted records", 3, "Message"], ["Icon", "fa-solid fa-trash-can", "Title", "Recycle Bin is empty", "Message", "No records have been deleted from this entity, or change tracking isn't enabled here."], [1, "rb-list"], [3, "RestoreConfirmed", "RestoreCancelled", "Visible", "Mode", "RecordChange", "EntityName"], [1, "rb-card"], [1, "rb-card-info"], [1, "rb-card-name"], [1, "rb-card-fields"], [1, "rb-card-meta"], ["aria-hidden", "true", 1, "fa-solid", "fa-trash"], [1, "rb-card-actions"], ["type", "button", 1, "rb-btn", "rb-btn-restore", 3, "click", "disabled", "title"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-left"], [1, "rb-card-field"]], template: function RecycleBinComponent_Template(rf, ctx) { if (rf & 1) {
|
|
619
596
|
i0.ɵɵelementStart(0, "mj-slide-panel", 0);
|
|
620
597
|
i0.ɵɵlistener("Closed", function RecycleBinComponent_Template_mj_slide_panel_Closed_0_listener() { return ctx.OnClose(); });
|
|
621
598
|
i0.ɵɵelementStart(1, "div", 1)(2, "div", 2)(3, "div", 3);
|
|
@@ -626,10 +603,10 @@ export class RecycleBinComponent extends BaseAngularComponent {
|
|
|
626
603
|
i0.ɵɵelementEnd();
|
|
627
604
|
i0.ɵɵconditionalCreate(8, RecycleBinComponent_Conditional_8_Template, 2, 1, "div", 7);
|
|
628
605
|
i0.ɵɵelementEnd()();
|
|
629
|
-
i0.ɵɵconditionalCreate(9, RecycleBinComponent_Conditional_9_Template,
|
|
606
|
+
i0.ɵɵconditionalCreate(9, RecycleBinComponent_Conditional_9_Template, 1, 1, "mj-empty-state", 8);
|
|
630
607
|
i0.ɵɵconditionalCreate(10, RecycleBinComponent_Conditional_10_Template, 1, 0, "mj-loading", 9);
|
|
631
|
-
i0.ɵɵconditionalCreate(11, RecycleBinComponent_Conditional_11_Template,
|
|
632
|
-
i0.ɵɵconditionalCreate(12, RecycleBinComponent_Conditional_12_Template,
|
|
608
|
+
i0.ɵɵconditionalCreate(11, RecycleBinComponent_Conditional_11_Template, 1, 1, "mj-empty-state", 10);
|
|
609
|
+
i0.ɵɵconditionalCreate(12, RecycleBinComponent_Conditional_12_Template, 1, 0, "mj-empty-state", 11);
|
|
633
610
|
i0.ɵɵconditionalCreate(13, RecycleBinComponent_Conditional_13_Template, 3, 0, "div", 12);
|
|
634
611
|
i0.ɵɵelementEnd();
|
|
635
612
|
i0.ɵɵelementStart(14, "mj-restore-preview-panel", 13);
|
|
@@ -651,11 +628,11 @@ export class RecycleBinComponent extends BaseAngularComponent {
|
|
|
651
628
|
i0.ɵɵconditional(!ctx.IsLoading && !ctx.LoadError && ctx.Entries.length > 0 ? 13 : -1);
|
|
652
629
|
i0.ɵɵadvance();
|
|
653
630
|
i0.ɵɵproperty("Visible", ctx.PreviewVisible)("Mode", "undelete")("RecordChange", (ctx.SelectedEntry == null ? null : ctx.SelectedEntry.RecordChange) ?? null)("EntityName", ctx.EntityName);
|
|
654
|
-
} }, dependencies: [i1.LoadingComponent, i2.RestorePreviewPanelComponent, i3.MjSlidePanelComponent], styles: ["/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Recycle Bin\n * Slide-in panel that lists hard-deleted records and offers re-create.\n * All colors use --mj-* design tokens.\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.rb-container {\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n/* \u2500\u2500\u2500 Header \u2500\u2500\u2500 */\n\n.rb-header {\n display: flex;\n align-items: flex-start;\n gap: 14px;\n padding: 8px 0 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.rb-header-icon {\n width: 40px;\n height: 40px;\n border-radius: 9px;\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 17px;\n}\n\n.rb-header-text { flex: 1; min-width: 0; }\n\n.rb-header-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.rb-header-subtitle {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n/* \u2500\u2500\u2500
|
|
631
|
+
} }, dependencies: [i1.LoadingComponent, i2.RestorePreviewPanelComponent, i3.MjSlidePanelComponent, i3.MJEmptyStateComponent], styles: ["/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Recycle Bin\n * Slide-in panel that lists hard-deleted records and offers re-create.\n * All colors use --mj-* design tokens.\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.rb-container {\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n/* \u2500\u2500\u2500 Header \u2500\u2500\u2500 */\n\n.rb-header {\n display: flex;\n align-items: flex-start;\n gap: 14px;\n padding: 8px 0 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.rb-header-icon {\n width: 40px;\n height: 40px;\n border-radius: 9px;\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 17px;\n}\n\n.rb-header-text { flex: 1; min-width: 0; }\n\n.rb-header-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.rb-header-subtitle {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n/* \u2500\u2500\u2500 List \u2500\u2500\u2500 */\n\n.rb-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500 Card \u2500\u2500\u2500 */\n\n.rb-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 14px;\n align-items: center;\n transition: border-color 0.15s;\n}\n\n.rb-card:hover {\n border-color: var(--mj-border-strong);\n}\n\n.rb-card-info { min-width: 0; }\n\n.rb-card-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n margin-bottom: 5px;\n word-break: break-word;\n}\n\n.rb-card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-bottom: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.rb-card-field strong {\n color: var(--mj-text-secondary);\n font-weight: 500;\n margin-right: 3px;\n}\n\n.rb-card-meta {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.rb-card-meta i {\n color: var(--mj-text-disabled);\n}\n\n/* \u2500\u2500\u2500 Card actions \u2500\u2500\u2500 */\n\n.rb-card-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n flex-shrink: 0;\n}\n\n.rb-btn {\n padding: 7px 14px;\n border-radius: 7px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n transition: background-color 0.1s, color 0.1s, border-color 0.1s;\n}\n\n.rb-btn-restore {\n color: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.rb-btn-restore:hover:not(:disabled) {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse, #fff);\n}\n\n.rb-btn-restore:disabled {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n cursor: not-allowed;\n}\n"], encapsulation: 2, changeDetection: 0 });
|
|
655
632
|
}
|
|
656
633
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RecycleBinComponent, [{
|
|
657
634
|
type: Component,
|
|
658
|
-
args: [{ standalone: false, selector: 'mj-recycle-bin', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Recycle Bin \u00B7 ' + (EntityName || '')\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"480\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n <div class=\"rb-container\">\n\n <!-- Header -->\n <div class=\"rb-header\">\n <div class=\"rb-header-icon\">\n <i class=\"fa-solid fa-trash-can-arrow-up\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rb-header-text\">\n <div class=\"rb-header-title\">Recycle Bin</div>\n @if (EntityName) {\n <div class=\"rb-header-subtitle\">{{ HeaderSubtitle }}</div>\n }\n </div>\n </div>\n\n <!-- No-permission state -->\n @if (!IsLoading && LoadError && !HasAccess) {\n <
|
|
635
|
+
args: [{ standalone: false, selector: 'mj-recycle-bin', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Recycle Bin \u00B7 ' + (EntityName || '')\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"480\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n <div class=\"rb-container\">\n\n <!-- Header -->\n <div class=\"rb-header\">\n <div class=\"rb-header-icon\">\n <i class=\"fa-solid fa-trash-can-arrow-up\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rb-header-text\">\n <div class=\"rb-header-title\">Recycle Bin</div>\n @if (EntityName) {\n <div class=\"rb-header-subtitle\">{{ HeaderSubtitle }}</div>\n }\n </div>\n </div>\n\n <!-- No-permission state -->\n @if (!IsLoading && LoadError && !HasAccess) {\n <mj-empty-state\n Variant=\"warning\"\n Icon=\"fa-solid fa-lock\"\n Title=\"Access denied\"\n [Message]=\"LoadError\" />\n }\n\n <!-- Loading -->\n @if (IsLoading) {\n <mj-loading text=\"Loading deleted records...\" size=\"medium\"></mj-loading>\n }\n\n <!-- Generic error -->\n @if (!IsLoading && LoadError && HasAccess) {\n <mj-empty-state\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Could not load deleted records\"\n [Message]=\"LoadError\" />\n }\n\n <!-- Empty state -->\n @if (!IsLoading && !LoadError && HasAccess && Entries.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-trash-can\"\n Title=\"Recycle Bin is empty\"\n Message=\"No records have been deleted from this entity, or change tracking isn't enabled here.\" />\n }\n\n <!-- Entries -->\n @if (!IsLoading && !LoadError && Entries.length > 0) {\n <div class=\"rb-list\">\n @for (entry of Entries; track entry.RecordChange.ID) {\n <div class=\"rb-card\">\n <div class=\"rb-card-info\">\n <div class=\"rb-card-name\">{{ entry.DisplaySummary }}</div>\n @if (entry.SupportingFields.length > 0) {\n <div class=\"rb-card-fields\">\n @for (sf of entry.SupportingFields; track sf.Name) {\n <span class=\"rb-card-field\">\n <strong>{{ sf.DisplayName }}:</strong> {{ sf.Value }}\n </span>\n }\n </div>\n }\n <div class=\"rb-card-meta\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n Deleted {{ formatTimestamp(entry.RecordChange.ChangedAt) }}\n @if (entry.RecordChange.User) {\n by {{ getUserDisplay(entry.RecordChange.User) }}\n }\n </div>\n </div>\n <div class=\"rb-card-actions\">\n <button class=\"rb-btn rb-btn-restore\"\n [disabled]=\"!CanCreate\"\n [title]=\"CanCreate ? 'Re-create this record from its snapshot' : 'You do not have Create permission for this entity'\"\n (click)=\"OnRestoreClicked(entry)\"\n type=\"button\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n Restore\n </button>\n </div>\n </div>\n }\n </div>\n }\n\n </div>\n\n <!-- Restore preview slide-in (reused from ng-record-changes) -->\n <mj-restore-preview-panel\n [Visible]=\"PreviewVisible\"\n [Mode]=\"'undelete'\"\n [RecordChange]=\"SelectedEntry?.RecordChange ?? null\"\n [EntityName]=\"EntityName\"\n (RestoreConfirmed)=\"OnPreviewConfirmed($event)\"\n (RestoreCancelled)=\"OnPreviewCancelled()\">\n </mj-restore-preview-panel>\n\n</mj-slide-panel>\n", styles: ["/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Recycle Bin\n * Slide-in panel that lists hard-deleted records and offers re-create.\n * All colors use --mj-* design tokens.\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.rb-container {\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n/* \u2500\u2500\u2500 Header \u2500\u2500\u2500 */\n\n.rb-header {\n display: flex;\n align-items: flex-start;\n gap: 14px;\n padding: 8px 0 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.rb-header-icon {\n width: 40px;\n height: 40px;\n border-radius: 9px;\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 17px;\n}\n\n.rb-header-text { flex: 1; min-width: 0; }\n\n.rb-header-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.rb-header-subtitle {\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n/* \u2500\u2500\u2500 List \u2500\u2500\u2500 */\n\n.rb-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500 Card \u2500\u2500\u2500 */\n\n.rb-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 14px;\n align-items: center;\n transition: border-color 0.15s;\n}\n\n.rb-card:hover {\n border-color: var(--mj-border-strong);\n}\n\n.rb-card-info { min-width: 0; }\n\n.rb-card-name {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n margin-bottom: 5px;\n word-break: break-word;\n}\n\n.rb-card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-bottom: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.rb-card-field strong {\n color: var(--mj-text-secondary);\n font-weight: 500;\n margin-right: 3px;\n}\n\n.rb-card-meta {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.rb-card-meta i {\n color: var(--mj-text-disabled);\n}\n\n/* \u2500\u2500\u2500 Card actions \u2500\u2500\u2500 */\n\n.rb-card-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n flex-shrink: 0;\n}\n\n.rb-btn {\n padding: 7px 14px;\n border-radius: 7px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: inherit;\n background: var(--mj-bg-surface);\n transition: background-color 0.1s, color 0.1s, border-color 0.1s;\n}\n\n.rb-btn-restore {\n color: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.rb-btn-restore:hover:not(:disabled) {\n background: var(--mj-status-success);\n color: var(--mj-text-inverse, #fff);\n}\n\n.rb-btn-restore:disabled {\n color: var(--mj-text-disabled);\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n cursor: not-allowed;\n}\n"] }]
|
|
659
636
|
}], () => [{ type: i0.ChangeDetectorRef }], { Visible: [{
|
|
660
637
|
type: Input
|
|
661
638
|
}], EntityName: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recycle-bin.component.js","sourceRoot":"","sources":["../../../src/lib/recycle-bin/recycle-bin.component.ts","../../../src/lib/recycle-bin/recycle-bin.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n EventEmitter,\n Input,\n OnInit,\n Output,\n ViewEncapsulation,\n} from '@angular/core';\nimport {\n EntityFieldInfo,\n EntityInfo,\n Metadata,\n RunView,\n UserInfo,\n} from '@memberjunction/core';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RestoreCommitEvent } from '@memberjunction/ng-record-changes';\nimport {\n AfterRecordRestoreEventArgs,\n AfterRecycleBinOpenEventArgs,\n AfterRestoreCommitEventArgs,\n BeforeRecordRestoreEventArgs,\n BeforeRecycleBinOpenEventArgs,\n BeforeRestoreCommitEventArgs,\n RecycleBinEntry,\n} from './events/recycle-bin-events';\n\n/**\n * Slide-in panel that lists all hard-deleted records for a single entity\n * and lets a user with `Delete` permission re-create any of them from its\n * historical RecordChange snapshot.\n *\n * ### When to use\n *\n * Surface this component from any entity-viewing context where the user\n * might need to restore a hard-deleted record. The {@link EntityViewerComponent},\n * {@link EntityDataGridComponent}, and {@link EntityCardsComponent}\n * already expose a `ShowRecycleBin` input (default `true`) that renders a\n * chip in their toolbar — you only need to use this component directly if\n * you're building a custom viewer.\n *\n * ### Permissions\n *\n * The chip / panel is gated on `entity.UserPermissions.CanDelete` —\n * rationale: there is no native \"undelete\" permission in MemberJunction,\n * but if a user has the higher-trust permission to *delete* records of an\n * entity, restoring deleted ones is well within scope. The actual\n * re-create action additionally requires `CanCreate`; without it the\n * Restore button on each card disables with a tooltip.\n *\n * ### Soft deletes vs hard deletes\n *\n * This component only surfaces *hard*-deleted records. Soft-deletes (e.g.,\n * `IsDeleted` flags, `Status='Inactive'`, etc.) leave the record visible\n * in normal entity views, so the standard Record Changes panel + restore\n * preview already handles them — no Recycle Bin needed.\n *\n * ### Cancelable Before/After event surface\n *\n * Every meaningful action emits a paired `before*` / `after*` event. The\n * `before*` event carries `cancel: boolean` so consumers can intercept\n * — useful for custom approval workflows, audit logging, or to take over\n * the actual restore execution entirely. See {@link BeforeRecordRestoreEventArgs}\n * and friends.\n *\n * @example Basic usage (rare — usually embedded by entity-viewer)\n * <mj-recycle-bin\n * [Visible]=\"showBin\"\n * [EntityName]=\"'Customers'\"\n * (Closed)=\"showBin = false\"\n * (BeforeRecordRestore)=\"auditRestore($event)\"\n * (AfterRestoreCommit)=\"onRestored($event)\">\n * </mj-recycle-bin>\n *\n * @example Intercepting a restore\n * onBeforeRecordRestore(e: BeforeRecordRestoreEventArgs) {\n * if (!myCustomApproval(e.entry)) {\n * e.cancel = true;\n * e.cancelReason = 'Awaiting compliance approval';\n * }\n * }\n */\n@Component({\n standalone: false,\n selector: 'mj-recycle-bin',\n templateUrl: './recycle-bin.component.html',\n styleUrls: ['./recycle-bin.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RecycleBinComponent extends BaseAngularComponent implements OnInit {\n // ─── Inputs ─────────────────────────────────────────────────────\n\n /**\n * Controls panel visibility. Set to true to slide in (and trigger an\n * initial load); false to slide out.\n */\n private _visible = false;\n @Input()\n set Visible(value: boolean) {\n const wasVisible = this._visible;\n this._visible = value;\n if (value && !wasVisible && this.isInitialized) {\n this.LoadDeletedRecords();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n /**\n * The name of the entity whose deleted records will be listed. Required.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Optional context user. When omitted, falls back to\n * {@link this.ProviderToUse.CurrentUser} per standard MJ conventions.\n */\n @Input() ContextUser: UserInfo | null = null;\n\n /**\n * Maximum number of deleted-record cards to load. Defaults to 200 — this\n * is a UI affordance, not a hard limit; consumers needing pagination\n * should listen to {@link AfterRecycleBinOpen} and surface their own UI\n * if `deletedRecordCount === MaxRecords`.\n */\n @Input() MaxRecords = 200;\n\n // ─── Outputs ────────────────────────────────────────────────────\n\n /** Fires when the user closes the panel. */\n @Output() Closed = new EventEmitter<void>();\n\n /**\n * Cancelable. Fires when {@link Visible} flips to true and the bin is\n * about to query for deleted records. Setting `cancel = true` aborts\n * the query (and the panel will show the empty state).\n */\n @Output() BeforeRecycleBinOpen = new EventEmitter<BeforeRecycleBinOpenEventArgs>();\n\n /** Fires after the deleted-record query completes. */\n @Output() AfterRecycleBinOpen = new EventEmitter<AfterRecycleBinOpenEventArgs>();\n\n /**\n * Cancelable. Fires when the user clicks Restore on a deleted-record\n * card, before the preview panel opens. Setting `cancel = true` skips\n * the preview entirely — useful for consumers that want to take over\n * the restore flow themselves.\n */\n @Output() BeforeRecordRestore = new EventEmitter<BeforeRecordRestoreEventArgs>();\n\n /**\n * Fires after the user closes the restore preview, with `success`\n * indicating whether the actual insert worked.\n */\n @Output() AfterRecordRestore = new EventEmitter<AfterRecordRestoreEventArgs>();\n\n /**\n * Cancelable. Fires after the user clicks Restore in the preview but\n * before the entity is inserted. Setting `cancel = true` aborts the\n * insert.\n */\n @Output() BeforeRestoreCommit = new EventEmitter<BeforeRestoreCommitEventArgs>();\n\n /** Fires after the insert completes (success or failure). */\n @Output() AfterRestoreCommit = new EventEmitter<AfterRestoreCommitEventArgs>();\n\n // ─── Public template state ──────────────────────────────────────\n\n public IsLoading = false;\n public LoadError: string | null = null;\n public Entries: RecycleBinEntry[] = [];\n\n /** The currently selected entry whose preview is open. */\n public SelectedEntry: RecycleBinEntry | null = null;\n public PreviewVisible = false;\n\n /** Permission flags (computed once when EntityName is set). */\n public CanDelete = false;\n public CanCreate = false;\n\n private isInitialized = false;\n private resolvedEntityInfo: EntityInfo | null = null;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isInitialized = true;\n if (this.Visible) this.LoadDeletedRecords();\n }\n\n // ─── Derived state ──────────────────────────────────────────────\n\n public get HeaderSubtitle(): string {\n if (!this.EntityName) return '';\n const n = this.Entries.length;\n return `${n} record${n === 1 ? '' : 's'} have been deleted from ${this.EntityName}.`;\n }\n\n /**\n * The user has Delete permission and may browse the bin. The Restore\n * button on each card additionally requires {@link CanCreate}.\n */\n public get HasAccess(): boolean {\n return this.CanDelete;\n }\n\n // ─── Public actions ─────────────────────────────────────────────\n\n /**\n * Manually trigger a re-load — useful for consumers who want to refresh\n * after some external event (e.g., a delete happened and they want the\n * bin to re-populate immediately).\n */\n public async LoadDeletedRecords(): Promise<void> {\n if (!this.EntityName) {\n this.LoadError = 'EntityName is required';\n return;\n }\n\n // Resolve metadata + permissions\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(\n e => e.Name.trim().toLowerCase() === this.EntityName!.trim().toLowerCase(),\n );\n if (!entityInfo) {\n this.LoadError = `Entity '${this.EntityName}' not found`;\n this.cdr.markForCheck();\n return;\n }\n this.resolvedEntityInfo = entityInfo;\n const effectiveUser = this.ContextUser ?? md.CurrentUser;\n if (effectiveUser) {\n const perms = entityInfo.GetUserPermisions(effectiveUser);\n this.CanDelete = perms?.CanDelete ?? false;\n this.CanCreate = perms?.CanCreate ?? false;\n } else {\n this.CanDelete = false;\n this.CanCreate = false;\n }\n\n if (!this.CanDelete) {\n this.Entries = [];\n this.LoadError = 'You do not have Delete permission for this entity.';\n this.cdr.markForCheck();\n return;\n }\n\n // Fire BeforeRecycleBinOpen — consumer may cancel\n const beforeArgs: BeforeRecycleBinOpenEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName,\n cancel: false,\n _kind: 'beforeRecycleBinOpen',\n };\n this.BeforeRecycleBinOpen.emit(beforeArgs);\n if (beforeArgs.cancel) {\n this.LoadError = beforeArgs.cancelReason ?? 'Cancelled by host';\n this.cdr.markForCheck();\n return;\n }\n\n this.IsLoading = true;\n this.LoadError = null;\n this.Entries = [];\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n // Get the most recent Delete change per RecordID. We over-fetch and\n // dedupe in JS — the data is small and SQL grouping with the latest\n // change per ID is awkward across dialects.\n const result = await rv.RunView<MJRecordChangeEntity>(\n {\n EntityName: 'MJ: Record Changes',\n ExtraFilter: `EntityID='${entityInfo.ID}' AND Type='Delete'`,\n OrderBy: 'ChangedAt DESC',\n MaxRows: this.MaxRecords * 2, // dedupe headroom\n ResultType: 'entity_object',\n },\n this.ContextUser ?? undefined,\n );\n\n if (!result.Success) {\n this.LoadError = result.ErrorMessage || 'Failed to load deleted records';\n } else {\n this.Entries = this.dedupeAndBuildEntries(result.Results, entityInfo);\n }\n } catch (e) {\n this.LoadError = e instanceof Error ? e.message : 'Unknown error';\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n\n // Fire AfterRecycleBinOpen\n this.AfterRecycleBinOpen.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName,\n deletedRecordCount: this.Entries.length,\n _kind: 'afterRecycleBinOpen',\n });\n }\n\n /**\n * User clicked Restore on a card — open the preview panel (unless a\n * BeforeRecordRestore handler cancelled).\n */\n public OnRestoreClicked(entry: RecycleBinEntry): void {\n if (!this.CanCreate) return; // gated in template too\n\n const beforeArgs: BeforeRecordRestoreEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n cancel: false,\n _kind: 'beforeRecordRestore',\n };\n this.BeforeRecordRestore.emit(beforeArgs);\n if (beforeArgs.cancel) return;\n\n this.SelectedEntry = entry;\n this.PreviewVisible = true;\n this.cdr.markForCheck();\n }\n\n /**\n * Preview panel emitted RestoreConfirmed — perform the insert and emit\n * the matching after* events.\n */\n public async OnPreviewConfirmed(commit: RestoreCommitEvent): Promise<void> {\n if (!this.SelectedEntry || !this.resolvedEntityInfo) return;\n const entry = this.SelectedEntry;\n\n const beforeArgs: BeforeRestoreCommitEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n fieldValues: commit.FieldValues,\n reason: commit.Reason,\n cancel: false,\n _kind: 'beforeRestoreCommit',\n };\n this.BeforeRestoreCommit.emit(beforeArgs);\n if (beforeArgs.cancel) {\n this.PreviewVisible = false;\n this.cdr.markForCheck();\n return;\n }\n\n let success = false;\n let errorMessage: string | undefined;\n let newRecordID: string | undefined;\n\n try {\n const md = this.ProviderToUse;\n const entity = await md.GetEntityObject(this.resolvedEntityInfo.Name, this.ContextUser ?? undefined);\n\n // Apply the snapshot fields, including the original primary key\n // (preserves any FK references that still point at this ID).\n for (const fv of commit.FieldValues) {\n entity.Set(fv.FieldName, fv.Value);\n }\n // Also re-apply the original primary key from the snapshot so dangling\n // FK references continue to work. Set() on a fresh entity treats this\n // as the new record's PK.\n try {\n const snapshotData = JSON.parse(entry.RecordChange.FullRecordJSON || '{}');\n for (const pk of this.resolvedEntityInfo.PrimaryKeys) {\n if (snapshotData[pk.Name] != null) {\n entity.Set(pk.Name, snapshotData[pk.Name]);\n }\n }\n } catch {\n // PK preservation is best-effort\n }\n\n entity.SetRestoreContext(commit.SourceChangeID, commit.Reason);\n\n try {\n success = await entity.Save();\n if (success) {\n newRecordID = entity.PrimaryKey.ToString();\n } else {\n errorMessage = entity.LatestResult?.CompleteMessage ?? 'Save returned false';\n }\n } finally {\n entity.ClearRestoreContext();\n }\n } catch (e) {\n success = false;\n errorMessage = e instanceof Error ? e.message : 'Unknown error';\n }\n\n this.AfterRestoreCommit.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n success,\n newRecordID,\n errorMessage,\n _kind: 'afterRestoreCommit',\n });\n\n this.AfterRecordRestore.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n success,\n errorMessage,\n _kind: 'afterRecordRestore',\n });\n\n if (success) {\n // Remove the restored entry from the list and close preview\n this.Entries = this.Entries.filter(e => e !== entry);\n }\n this.PreviewVisible = false;\n this.SelectedEntry = null;\n this.cdr.markForCheck();\n }\n\n public OnPreviewCancelled(): void {\n this.PreviewVisible = false;\n this.SelectedEntry = null;\n this.cdr.markForCheck();\n }\n\n public OnClose(): void {\n this._visible = false;\n this.cdr.markForCheck();\n this.Closed.emit();\n }\n\n // ─── Internal: build entries from raw RecordChange rows ─────────\n\n /**\n * Dedupes the raw delete-change rows: keeps only the most recent Delete\n * per RecordID (since a record could in principle have been recreated\n * and re-deleted). Builds the display fields heuristically by reading\n * the snapshot JSON.\n */\n private dedupeAndBuildEntries(\n rows: MJRecordChangeEntity[],\n entityInfo: EntityInfo,\n ): RecycleBinEntry[] {\n const seen = new Set<string>();\n const entries: RecycleBinEntry[] = [];\n\n for (const row of rows) {\n if (entries.length >= this.MaxRecords) break;\n if (seen.has(row.RecordID)) continue;\n seen.add(row.RecordID);\n\n const snapshot = this.parseSnapshot(row.FullRecordJSON);\n if (!snapshot) continue;\n\n const entry: RecycleBinEntry = {\n RecordChange: row,\n RecordID: row.RecordID,\n DisplaySummary: this.buildDisplaySummary(snapshot, entityInfo),\n SupportingFields: this.buildSupportingFields(snapshot, entityInfo),\n };\n entries.push(entry);\n }\n\n return entries;\n }\n\n /**\n * Builds the headline of the card. Prefers the entity's name field, then\n * any non-PK string field, then the RecordID itself as a last resort.\n */\n private buildDisplaySummary(snapshot: Record<string, unknown>, entityInfo: EntityInfo): string {\n const nameField = entityInfo.NameField;\n if (nameField && snapshot[nameField.Name] != null && snapshot[nameField.Name] !== '') {\n return String(snapshot[nameField.Name]);\n }\n // Fallback: first non-PK, non-empty string field\n for (const f of entityInfo.Fields) {\n if (f.IsPrimaryKey) continue;\n const v = snapshot[f.Name];\n if (typeof v === 'string' && v.trim().length > 0) return v;\n }\n return `Record ${snapshot[entityInfo.PrimaryKeys[0]?.Name] ?? ''}`;\n }\n\n /**\n * Picks up to 3 \"interesting\" fields from the snapshot to render as\n * supporting metadata under the headline. Heuristic: prefer fields that\n * are non-empty, non-PK, non-system, and have a display name.\n */\n private buildSupportingFields(\n snapshot: Record<string, unknown>,\n entityInfo: EntityInfo,\n ): Array<{ Name: string; DisplayName: string; Value: string }> {\n const out: Array<{ Name: string; DisplayName: string; Value: string }> = [];\n const nameFieldName = entityInfo.NameField?.Name;\n\n for (const f of entityInfo.Fields) {\n if (out.length >= 3) break;\n if (f.IsPrimaryKey) continue;\n if (f.Name.startsWith('__mj_')) continue;\n if (f.Name === nameFieldName) continue;\n\n const v = snapshot[f.Name];\n if (v == null || v === '') continue;\n\n out.push({\n Name: f.Name,\n DisplayName: f.DisplayNameOrName,\n Value: this.formatFieldValue(v, f),\n });\n }\n return out;\n }\n\n private formatFieldValue(value: unknown, _field: EntityFieldInfo): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n }\n\n private parseSnapshot(json: string | null | undefined): Record<string, unknown> | null {\n if (!json) return null;\n try {\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n }\n\n // ─── Display helpers (template) ─────────────────────────────────\n\n public formatTimestamp(date: Date | string | null): string {\n if (!date) return '';\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n\n public getUserDisplay(user: string | null): string {\n if (!user) return 'Unknown';\n if (user.includes('@')) return user.split('@')[0];\n return user;\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Recycle Bin · ' + (EntityName || '')\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"480\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n <div class=\"rb-container\">\n\n <!-- Header -->\n <div class=\"rb-header\">\n <div class=\"rb-header-icon\">\n <i class=\"fa-solid fa-trash-can-arrow-up\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rb-header-text\">\n <div class=\"rb-header-title\">Recycle Bin</div>\n @if (EntityName) {\n <div class=\"rb-header-subtitle\">{{ HeaderSubtitle }}</div>\n }\n </div>\n </div>\n\n <!-- No-permission state -->\n @if (!IsLoading && LoadError && !HasAccess) {\n <div class=\"rb-state rb-state-denied\">\n <i class=\"fa-solid fa-lock\" aria-hidden=\"true\"></i>\n <h3>Access denied</h3>\n <p>{{ LoadError }}</p>\n </div>\n }\n\n <!-- Loading -->\n @if (IsLoading) {\n <mj-loading text=\"Loading deleted records...\" size=\"medium\"></mj-loading>\n }\n\n <!-- Generic error -->\n @if (!IsLoading && LoadError && HasAccess) {\n <div class=\"rb-state rb-state-error\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <h3>Could not load deleted records</h3>\n <p>{{ LoadError }}</p>\n </div>\n }\n\n <!-- Empty state -->\n @if (!IsLoading && !LoadError && HasAccess && Entries.length === 0) {\n <div class=\"rb-state rb-state-empty\">\n <i class=\"fa-solid fa-trash-can\" aria-hidden=\"true\"></i>\n <h3>Recycle Bin is empty</h3>\n <p>No records have been deleted from this entity, or change tracking\n isn't enabled here.</p>\n </div>\n }\n\n <!-- Entries -->\n @if (!IsLoading && !LoadError && Entries.length > 0) {\n <div class=\"rb-list\">\n @for (entry of Entries; track entry.RecordChange.ID) {\n <div class=\"rb-card\">\n <div class=\"rb-card-info\">\n <div class=\"rb-card-name\">{{ entry.DisplaySummary }}</div>\n @if (entry.SupportingFields.length > 0) {\n <div class=\"rb-card-fields\">\n @for (sf of entry.SupportingFields; track sf.Name) {\n <span class=\"rb-card-field\">\n <strong>{{ sf.DisplayName }}:</strong> {{ sf.Value }}\n </span>\n }\n </div>\n }\n <div class=\"rb-card-meta\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n Deleted {{ formatTimestamp(entry.RecordChange.ChangedAt) }}\n @if (entry.RecordChange.User) {\n by {{ getUserDisplay(entry.RecordChange.User) }}\n }\n </div>\n </div>\n <div class=\"rb-card-actions\">\n <button class=\"rb-btn rb-btn-restore\"\n [disabled]=\"!CanCreate\"\n [title]=\"CanCreate ? 'Re-create this record from its snapshot' : 'You do not have Create permission for this entity'\"\n (click)=\"OnRestoreClicked(entry)\"\n type=\"button\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n Restore\n </button>\n </div>\n </div>\n }\n </div>\n }\n\n </div>\n\n <!-- Restore preview slide-in (reused from ng-record-changes) -->\n <mj-restore-preview-panel\n [Visible]=\"PreviewVisible\"\n [Mode]=\"'undelete'\"\n [RecordChange]=\"SelectedEntry?.RecordChange ?? null\"\n [EntityName]=\"EntityName\"\n (RestoreConfirmed)=\"OnPreviewConfirmed($event)\"\n (RestoreCancelled)=\"OnPreviewCancelled()\">\n </mj-restore-preview-panel>\n\n</mj-slide-panel>\n"]}
|
|
1
|
+
{"version":3,"file":"recycle-bin.component.js","sourceRoot":"","sources":["../../../src/lib/recycle-bin/recycle-bin.component.ts","../../../src/lib/recycle-bin/recycle-bin.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n EventEmitter,\n Input,\n OnInit,\n Output,\n ViewEncapsulation,\n} from '@angular/core';\nimport {\n EntityFieldInfo,\n EntityInfo,\n Metadata,\n RunView,\n UserInfo,\n} from '@memberjunction/core';\nimport { MJRecordChangeEntity } from '@memberjunction/core-entities';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { RestoreCommitEvent } from '@memberjunction/ng-record-changes';\nimport {\n AfterRecordRestoreEventArgs,\n AfterRecycleBinOpenEventArgs,\n AfterRestoreCommitEventArgs,\n BeforeRecordRestoreEventArgs,\n BeforeRecycleBinOpenEventArgs,\n BeforeRestoreCommitEventArgs,\n RecycleBinEntry,\n} from './events/recycle-bin-events';\n\n/**\n * Slide-in panel that lists all hard-deleted records for a single entity\n * and lets a user with `Delete` permission re-create any of them from its\n * historical RecordChange snapshot.\n *\n * ### When to use\n *\n * Surface this component from any entity-viewing context where the user\n * might need to restore a hard-deleted record. The {@link EntityViewerComponent},\n * {@link EntityDataGridComponent}, and {@link EntityCardsComponent}\n * already expose a `ShowRecycleBin` input (default `true`) that renders a\n * chip in their toolbar — you only need to use this component directly if\n * you're building a custom viewer.\n *\n * ### Permissions\n *\n * The chip / panel is gated on `entity.UserPermissions.CanDelete` —\n * rationale: there is no native \"undelete\" permission in MemberJunction,\n * but if a user has the higher-trust permission to *delete* records of an\n * entity, restoring deleted ones is well within scope. The actual\n * re-create action additionally requires `CanCreate`; without it the\n * Restore button on each card disables with a tooltip.\n *\n * ### Soft deletes vs hard deletes\n *\n * This component only surfaces *hard*-deleted records. Soft-deletes (e.g.,\n * `IsDeleted` flags, `Status='Inactive'`, etc.) leave the record visible\n * in normal entity views, so the standard Record Changes panel + restore\n * preview already handles them — no Recycle Bin needed.\n *\n * ### Cancelable Before/After event surface\n *\n * Every meaningful action emits a paired `before*` / `after*` event. The\n * `before*` event carries `cancel: boolean` so consumers can intercept\n * — useful for custom approval workflows, audit logging, or to take over\n * the actual restore execution entirely. See {@link BeforeRecordRestoreEventArgs}\n * and friends.\n *\n * @example Basic usage (rare — usually embedded by entity-viewer)\n * <mj-recycle-bin\n * [Visible]=\"showBin\"\n * [EntityName]=\"'Customers'\"\n * (Closed)=\"showBin = false\"\n * (BeforeRecordRestore)=\"auditRestore($event)\"\n * (AfterRestoreCommit)=\"onRestored($event)\">\n * </mj-recycle-bin>\n *\n * @example Intercepting a restore\n * onBeforeRecordRestore(e: BeforeRecordRestoreEventArgs) {\n * if (!myCustomApproval(e.entry)) {\n * e.cancel = true;\n * e.cancelReason = 'Awaiting compliance approval';\n * }\n * }\n */\n@Component({\n standalone: false,\n selector: 'mj-recycle-bin',\n templateUrl: './recycle-bin.component.html',\n styleUrls: ['./recycle-bin.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class RecycleBinComponent extends BaseAngularComponent implements OnInit {\n // ─── Inputs ─────────────────────────────────────────────────────\n\n /**\n * Controls panel visibility. Set to true to slide in (and trigger an\n * initial load); false to slide out.\n */\n private _visible = false;\n @Input()\n set Visible(value: boolean) {\n const wasVisible = this._visible;\n this._visible = value;\n if (value && !wasVisible && this.isInitialized) {\n this.LoadDeletedRecords();\n }\n }\n get Visible(): boolean {\n return this._visible;\n }\n\n /**\n * The name of the entity whose deleted records will be listed. Required.\n */\n @Input() EntityName: string | null = null;\n\n /**\n * Optional context user. When omitted, falls back to\n * {@link this.ProviderToUse.CurrentUser} per standard MJ conventions.\n */\n @Input() ContextUser: UserInfo | null = null;\n\n /**\n * Maximum number of deleted-record cards to load. Defaults to 200 — this\n * is a UI affordance, not a hard limit; consumers needing pagination\n * should listen to {@link AfterRecycleBinOpen} and surface their own UI\n * if `deletedRecordCount === MaxRecords`.\n */\n @Input() MaxRecords = 200;\n\n // ─── Outputs ────────────────────────────────────────────────────\n\n /** Fires when the user closes the panel. */\n @Output() Closed = new EventEmitter<void>();\n\n /**\n * Cancelable. Fires when {@link Visible} flips to true and the bin is\n * about to query for deleted records. Setting `cancel = true` aborts\n * the query (and the panel will show the empty state).\n */\n @Output() BeforeRecycleBinOpen = new EventEmitter<BeforeRecycleBinOpenEventArgs>();\n\n /** Fires after the deleted-record query completes. */\n @Output() AfterRecycleBinOpen = new EventEmitter<AfterRecycleBinOpenEventArgs>();\n\n /**\n * Cancelable. Fires when the user clicks Restore on a deleted-record\n * card, before the preview panel opens. Setting `cancel = true` skips\n * the preview entirely — useful for consumers that want to take over\n * the restore flow themselves.\n */\n @Output() BeforeRecordRestore = new EventEmitter<BeforeRecordRestoreEventArgs>();\n\n /**\n * Fires after the user closes the restore preview, with `success`\n * indicating whether the actual insert worked.\n */\n @Output() AfterRecordRestore = new EventEmitter<AfterRecordRestoreEventArgs>();\n\n /**\n * Cancelable. Fires after the user clicks Restore in the preview but\n * before the entity is inserted. Setting `cancel = true` aborts the\n * insert.\n */\n @Output() BeforeRestoreCommit = new EventEmitter<BeforeRestoreCommitEventArgs>();\n\n /** Fires after the insert completes (success or failure). */\n @Output() AfterRestoreCommit = new EventEmitter<AfterRestoreCommitEventArgs>();\n\n // ─── Public template state ──────────────────────────────────────\n\n public IsLoading = false;\n public LoadError: string | null = null;\n public Entries: RecycleBinEntry[] = [];\n\n /** The currently selected entry whose preview is open. */\n public SelectedEntry: RecycleBinEntry | null = null;\n public PreviewVisible = false;\n\n /** Permission flags (computed once when EntityName is set). */\n public CanDelete = false;\n public CanCreate = false;\n\n private isInitialized = false;\n private resolvedEntityInfo: EntityInfo | null = null;\n\n constructor(private cdr: ChangeDetectorRef) {\n super();}\n\n ngOnInit(): void {\n this.isInitialized = true;\n if (this.Visible) this.LoadDeletedRecords();\n }\n\n // ─── Derived state ──────────────────────────────────────────────\n\n public get HeaderSubtitle(): string {\n if (!this.EntityName) return '';\n const n = this.Entries.length;\n return `${n} record${n === 1 ? '' : 's'} have been deleted from ${this.EntityName}.`;\n }\n\n /**\n * The user has Delete permission and may browse the bin. The Restore\n * button on each card additionally requires {@link CanCreate}.\n */\n public get HasAccess(): boolean {\n return this.CanDelete;\n }\n\n // ─── Public actions ─────────────────────────────────────────────\n\n /**\n * Manually trigger a re-load — useful for consumers who want to refresh\n * after some external event (e.g., a delete happened and they want the\n * bin to re-populate immediately).\n */\n public async LoadDeletedRecords(): Promise<void> {\n if (!this.EntityName) {\n this.LoadError = 'EntityName is required';\n return;\n }\n\n // Resolve metadata + permissions\n const md = this.ProviderToUse;\n const entityInfo = md.Entities.find(\n e => e.Name.trim().toLowerCase() === this.EntityName!.trim().toLowerCase(),\n );\n if (!entityInfo) {\n this.LoadError = `Entity '${this.EntityName}' not found`;\n this.cdr.markForCheck();\n return;\n }\n this.resolvedEntityInfo = entityInfo;\n const effectiveUser = this.ContextUser ?? md.CurrentUser;\n if (effectiveUser) {\n const perms = entityInfo.GetUserPermisions(effectiveUser);\n this.CanDelete = perms?.CanDelete ?? false;\n this.CanCreate = perms?.CanCreate ?? false;\n } else {\n this.CanDelete = false;\n this.CanCreate = false;\n }\n\n if (!this.CanDelete) {\n this.Entries = [];\n this.LoadError = 'You do not have Delete permission for this entity.';\n this.cdr.markForCheck();\n return;\n }\n\n // Fire BeforeRecycleBinOpen — consumer may cancel\n const beforeArgs: BeforeRecycleBinOpenEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName,\n cancel: false,\n _kind: 'beforeRecycleBinOpen',\n };\n this.BeforeRecycleBinOpen.emit(beforeArgs);\n if (beforeArgs.cancel) {\n this.LoadError = beforeArgs.cancelReason ?? 'Cancelled by host';\n this.cdr.markForCheck();\n return;\n }\n\n this.IsLoading = true;\n this.LoadError = null;\n this.Entries = [];\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n // Get the most recent Delete change per RecordID. We over-fetch and\n // dedupe in JS — the data is small and SQL grouping with the latest\n // change per ID is awkward across dialects.\n const result = await rv.RunView<MJRecordChangeEntity>(\n {\n EntityName: 'MJ: Record Changes',\n ExtraFilter: `EntityID='${entityInfo.ID}' AND Type='Delete'`,\n OrderBy: 'ChangedAt DESC',\n MaxRows: this.MaxRecords * 2, // dedupe headroom\n ResultType: 'entity_object',\n },\n this.ContextUser ?? undefined,\n );\n\n if (!result.Success) {\n this.LoadError = result.ErrorMessage || 'Failed to load deleted records';\n } else {\n this.Entries = this.dedupeAndBuildEntries(result.Results, entityInfo);\n }\n } catch (e) {\n this.LoadError = e instanceof Error ? e.message : 'Unknown error';\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n\n // Fire AfterRecycleBinOpen\n this.AfterRecycleBinOpen.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName,\n deletedRecordCount: this.Entries.length,\n _kind: 'afterRecycleBinOpen',\n });\n }\n\n /**\n * User clicked Restore on a card — open the preview panel (unless a\n * BeforeRecordRestore handler cancelled).\n */\n public OnRestoreClicked(entry: RecycleBinEntry): void {\n if (!this.CanCreate) return; // gated in template too\n\n const beforeArgs: BeforeRecordRestoreEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n cancel: false,\n _kind: 'beforeRecordRestore',\n };\n this.BeforeRecordRestore.emit(beforeArgs);\n if (beforeArgs.cancel) return;\n\n this.SelectedEntry = entry;\n this.PreviewVisible = true;\n this.cdr.markForCheck();\n }\n\n /**\n * Preview panel emitted RestoreConfirmed — perform the insert and emit\n * the matching after* events.\n */\n public async OnPreviewConfirmed(commit: RestoreCommitEvent): Promise<void> {\n if (!this.SelectedEntry || !this.resolvedEntityInfo) return;\n const entry = this.SelectedEntry;\n\n const beforeArgs: BeforeRestoreCommitEventArgs = {\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n fieldValues: commit.FieldValues,\n reason: commit.Reason,\n cancel: false,\n _kind: 'beforeRestoreCommit',\n };\n this.BeforeRestoreCommit.emit(beforeArgs);\n if (beforeArgs.cancel) {\n this.PreviewVisible = false;\n this.cdr.markForCheck();\n return;\n }\n\n let success = false;\n let errorMessage: string | undefined;\n let newRecordID: string | undefined;\n\n try {\n const md = this.ProviderToUse;\n const entity = await md.GetEntityObject(this.resolvedEntityInfo.Name, this.ContextUser ?? undefined);\n\n // Apply the snapshot fields, including the original primary key\n // (preserves any FK references that still point at this ID).\n for (const fv of commit.FieldValues) {\n entity.Set(fv.FieldName, fv.Value);\n }\n // Also re-apply the original primary key from the snapshot so dangling\n // FK references continue to work. Set() on a fresh entity treats this\n // as the new record's PK.\n try {\n const snapshotData = JSON.parse(entry.RecordChange.FullRecordJSON || '{}');\n for (const pk of this.resolvedEntityInfo.PrimaryKeys) {\n if (snapshotData[pk.Name] != null) {\n entity.Set(pk.Name, snapshotData[pk.Name]);\n }\n }\n } catch {\n // PK preservation is best-effort\n }\n\n entity.SetRestoreContext(commit.SourceChangeID, commit.Reason);\n\n try {\n success = await entity.Save();\n if (success) {\n newRecordID = entity.PrimaryKey.ToString();\n } else {\n errorMessage = entity.LatestResult?.CompleteMessage ?? 'Save returned false';\n }\n } finally {\n entity.ClearRestoreContext();\n }\n } catch (e) {\n success = false;\n errorMessage = e instanceof Error ? e.message : 'Unknown error';\n }\n\n this.AfterRestoreCommit.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n success,\n newRecordID,\n errorMessage,\n _kind: 'afterRestoreCommit',\n });\n\n this.AfterRecordRestore.emit({\n bin: this,\n timestamp: new Date(),\n entityName: this.EntityName ?? '',\n entry,\n success,\n errorMessage,\n _kind: 'afterRecordRestore',\n });\n\n if (success) {\n // Remove the restored entry from the list and close preview\n this.Entries = this.Entries.filter(e => e !== entry);\n }\n this.PreviewVisible = false;\n this.SelectedEntry = null;\n this.cdr.markForCheck();\n }\n\n public OnPreviewCancelled(): void {\n this.PreviewVisible = false;\n this.SelectedEntry = null;\n this.cdr.markForCheck();\n }\n\n public OnClose(): void {\n this._visible = false;\n this.cdr.markForCheck();\n this.Closed.emit();\n }\n\n // ─── Internal: build entries from raw RecordChange rows ─────────\n\n /**\n * Dedupes the raw delete-change rows: keeps only the most recent Delete\n * per RecordID (since a record could in principle have been recreated\n * and re-deleted). Builds the display fields heuristically by reading\n * the snapshot JSON.\n */\n private dedupeAndBuildEntries(\n rows: MJRecordChangeEntity[],\n entityInfo: EntityInfo,\n ): RecycleBinEntry[] {\n const seen = new Set<string>();\n const entries: RecycleBinEntry[] = [];\n\n for (const row of rows) {\n if (entries.length >= this.MaxRecords) break;\n if (seen.has(row.RecordID)) continue;\n seen.add(row.RecordID);\n\n const snapshot = this.parseSnapshot(row.FullRecordJSON);\n if (!snapshot) continue;\n\n const entry: RecycleBinEntry = {\n RecordChange: row,\n RecordID: row.RecordID,\n DisplaySummary: this.buildDisplaySummary(snapshot, entityInfo),\n SupportingFields: this.buildSupportingFields(snapshot, entityInfo),\n };\n entries.push(entry);\n }\n\n return entries;\n }\n\n /**\n * Builds the headline of the card. Prefers the entity's name field, then\n * any non-PK string field, then the RecordID itself as a last resort.\n */\n private buildDisplaySummary(snapshot: Record<string, unknown>, entityInfo: EntityInfo): string {\n const nameField = entityInfo.NameField;\n if (nameField && snapshot[nameField.Name] != null && snapshot[nameField.Name] !== '') {\n return String(snapshot[nameField.Name]);\n }\n // Fallback: first non-PK, non-empty string field\n for (const f of entityInfo.Fields) {\n if (f.IsPrimaryKey) continue;\n const v = snapshot[f.Name];\n if (typeof v === 'string' && v.trim().length > 0) return v;\n }\n return `Record ${snapshot[entityInfo.PrimaryKeys[0]?.Name] ?? ''}`;\n }\n\n /**\n * Picks up to 3 \"interesting\" fields from the snapshot to render as\n * supporting metadata under the headline. Heuristic: prefer fields that\n * are non-empty, non-PK, non-system, and have a display name.\n */\n private buildSupportingFields(\n snapshot: Record<string, unknown>,\n entityInfo: EntityInfo,\n ): Array<{ Name: string; DisplayName: string; Value: string }> {\n const out: Array<{ Name: string; DisplayName: string; Value: string }> = [];\n const nameFieldName = entityInfo.NameField?.Name;\n\n for (const f of entityInfo.Fields) {\n if (out.length >= 3) break;\n if (f.IsPrimaryKey) continue;\n if (f.Name.startsWith('__mj_')) continue;\n if (f.Name === nameFieldName) continue;\n\n const v = snapshot[f.Name];\n if (v == null || v === '') continue;\n\n out.push({\n Name: f.Name,\n DisplayName: f.DisplayNameOrName,\n Value: this.formatFieldValue(v, f),\n });\n }\n return out;\n }\n\n private formatFieldValue(value: unknown, _field: EntityFieldInfo): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n }\n\n private parseSnapshot(json: string | null | undefined): Record<string, unknown> | null {\n if (!json) return null;\n try {\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n }\n\n // ─── Display helpers (template) ─────────────────────────────────\n\n public formatTimestamp(date: Date | string | null): string {\n if (!date) return '';\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n }).format(new Date(date));\n }\n\n public getUserDisplay(user: string | null): string {\n if (!user) return 'Unknown';\n if (user.includes('@')) return user.split('@')[0];\n return user;\n }\n}\n","<mj-slide-panel\n [Mode]=\"'slide'\"\n [Title]=\"'Recycle Bin · ' + (EntityName || '')\"\n [Visible]=\"Visible\"\n [Resizable]=\"true\"\n [MinWidthPx]=\"480\"\n [MaxWidthRatio]=\"0.6\"\n (Closed)=\"OnClose()\">\n\n <div class=\"rb-container\">\n\n <!-- Header -->\n <div class=\"rb-header\">\n <div class=\"rb-header-icon\">\n <i class=\"fa-solid fa-trash-can-arrow-up\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"rb-header-text\">\n <div class=\"rb-header-title\">Recycle Bin</div>\n @if (EntityName) {\n <div class=\"rb-header-subtitle\">{{ HeaderSubtitle }}</div>\n }\n </div>\n </div>\n\n <!-- No-permission state -->\n @if (!IsLoading && LoadError && !HasAccess) {\n <mj-empty-state\n Variant=\"warning\"\n Icon=\"fa-solid fa-lock\"\n Title=\"Access denied\"\n [Message]=\"LoadError\" />\n }\n\n <!-- Loading -->\n @if (IsLoading) {\n <mj-loading text=\"Loading deleted records...\" size=\"medium\"></mj-loading>\n }\n\n <!-- Generic error -->\n @if (!IsLoading && LoadError && HasAccess) {\n <mj-empty-state\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Could not load deleted records\"\n [Message]=\"LoadError\" />\n }\n\n <!-- Empty state -->\n @if (!IsLoading && !LoadError && HasAccess && Entries.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-trash-can\"\n Title=\"Recycle Bin is empty\"\n Message=\"No records have been deleted from this entity, or change tracking isn't enabled here.\" />\n }\n\n <!-- Entries -->\n @if (!IsLoading && !LoadError && Entries.length > 0) {\n <div class=\"rb-list\">\n @for (entry of Entries; track entry.RecordChange.ID) {\n <div class=\"rb-card\">\n <div class=\"rb-card-info\">\n <div class=\"rb-card-name\">{{ entry.DisplaySummary }}</div>\n @if (entry.SupportingFields.length > 0) {\n <div class=\"rb-card-fields\">\n @for (sf of entry.SupportingFields; track sf.Name) {\n <span class=\"rb-card-field\">\n <strong>{{ sf.DisplayName }}:</strong> {{ sf.Value }}\n </span>\n }\n </div>\n }\n <div class=\"rb-card-meta\">\n <i class=\"fa-solid fa-trash\" aria-hidden=\"true\"></i>\n Deleted {{ formatTimestamp(entry.RecordChange.ChangedAt) }}\n @if (entry.RecordChange.User) {\n by {{ getUserDisplay(entry.RecordChange.User) }}\n }\n </div>\n </div>\n <div class=\"rb-card-actions\">\n <button class=\"rb-btn rb-btn-restore\"\n [disabled]=\"!CanCreate\"\n [title]=\"CanCreate ? 'Re-create this record from its snapshot' : 'You do not have Create permission for this entity'\"\n (click)=\"OnRestoreClicked(entry)\"\n type=\"button\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n Restore\n </button>\n </div>\n </div>\n }\n </div>\n }\n\n </div>\n\n <!-- Restore preview slide-in (reused from ng-record-changes) -->\n <mj-restore-preview-panel\n [Visible]=\"PreviewVisible\"\n [Mode]=\"'undelete'\"\n [RecordChange]=\"SelectedEntry?.RecordChange ?? null\"\n [EntityName]=\"EntityName\"\n (RestoreConfirmed)=\"OnPreviewConfirmed($event)\"\n (RestoreCancelled)=\"OnPreviewCancelled()\">\n </mj-restore-preview-panel>\n\n</mj-slide-panel>\n"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
|
+
import * as i1 from "@memberjunction/ng-ui-components";
|
|
3
4
|
function SharedViewWarningDialogComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
4
5
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
5
|
-
i0.ɵɵelementStart(0, "div",
|
|
6
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
6
7
|
i0.ɵɵlistener("click", function SharedViewWarningDialogComponent_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnCancel()); });
|
|
7
8
|
i0.ɵɵelementEnd();
|
|
8
9
|
} }
|
|
@@ -40,7 +41,7 @@ export class SharedViewWarningDialogComponent {
|
|
|
40
41
|
this.Cancel.emit();
|
|
41
42
|
}
|
|
42
43
|
static ɵfac = function SharedViewWarningDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SharedViewWarningDialogComponent)(); };
|
|
43
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SharedViewWarningDialogComponent, selectors: [["mj-shared-view-warning-dialog"]], inputs: { IsOpen: "IsOpen", ViewName: "ViewName" }, outputs: { Action: "Action", Cancel: "Cancel" }, standalone: false, decls:
|
|
44
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SharedViewWarningDialogComponent, selectors: [["mj-shared-view-warning-dialog"]], inputs: { IsOpen: "IsOpen", ViewName: "ViewName" }, outputs: { Action: "Action", Cancel: "Cancel" }, standalone: false, decls: 25, vars: 4, consts: [[1, "dialog-backdrop"], [1, "dialog-panel"], [1, "dialog-header"], [1, "icon-circle", "warning"], [1, "fa-solid", "fa-users"], [1, "header-title"], ["title", "Close", "aria-label", "Close dialog", 1, "close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "dialog-body"], [1, "message"], ["Variant", "warning", "Size", "sm", 1, "shared-view-alert-pos"], [1, "dialog-footer"], [1, "btn", "btn-primary", 3, "click"], [1, "fa-solid", "fa-save"], [1, "btn", "btn-secondary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "btn", "btn-ghost", 3, "click"], [1, "dialog-backdrop", 3, "click"]], template: function SharedViewWarningDialogComponent_Template(rf, ctx) { if (rf & 1) {
|
|
44
45
|
i0.ɵɵconditionalCreate(0, SharedViewWarningDialogComponent_Conditional_0_Template, 1, 0, "div", 0);
|
|
45
46
|
i0.ɵɵelementStart(1, "div", 1)(2, "div", 2)(3, "div", 3);
|
|
46
47
|
i0.ɵɵelement(4, "i", 4);
|
|
@@ -57,24 +58,22 @@ export class SharedViewWarningDialogComponent {
|
|
|
57
58
|
i0.ɵɵelementEnd();
|
|
58
59
|
i0.ɵɵtext(13, " is shared with other users. Changes you save will affect everyone who uses this view. ");
|
|
59
60
|
i0.ɵɵelementEnd();
|
|
60
|
-
i0.ɵɵelementStart(14, "
|
|
61
|
-
i0.ɵɵ
|
|
62
|
-
i0.ɵɵ
|
|
63
|
-
i0.ɵɵ
|
|
64
|
-
i0.ɵɵ
|
|
65
|
-
i0.ɵɵ
|
|
66
|
-
i0.ɵɵ
|
|
67
|
-
i0.ɵɵelement(20, "i", 14);
|
|
68
|
-
i0.ɵɵtext(21, " Update Shared View ");
|
|
61
|
+
i0.ɵɵelementStart(14, "mj-alert", 10);
|
|
62
|
+
i0.ɵɵtext(15, "Other users may be relying on this view's current configuration.");
|
|
63
|
+
i0.ɵɵelementEnd()();
|
|
64
|
+
i0.ɵɵelementStart(16, "div", 11)(17, "button", 12);
|
|
65
|
+
i0.ɵɵlistener("click", function SharedViewWarningDialogComponent_Template_button_click_17_listener() { return ctx.OnUpdateShared(); });
|
|
66
|
+
i0.ɵɵelement(18, "i", 13);
|
|
67
|
+
i0.ɵɵtext(19, " Update Shared View ");
|
|
69
68
|
i0.ɵɵelementEnd();
|
|
70
|
-
i0.ɵɵelementStart(
|
|
71
|
-
i0.ɵɵlistener("click", function
|
|
72
|
-
i0.ɵɵelement(
|
|
73
|
-
i0.ɵɵtext(
|
|
69
|
+
i0.ɵɵelementStart(20, "button", 14);
|
|
70
|
+
i0.ɵɵlistener("click", function SharedViewWarningDialogComponent_Template_button_click_20_listener() { return ctx.OnSaveAsCopy(); });
|
|
71
|
+
i0.ɵɵelement(21, "i", 15);
|
|
72
|
+
i0.ɵɵtext(22, " Save As My Copy ");
|
|
74
73
|
i0.ɵɵelementEnd();
|
|
75
|
-
i0.ɵɵelementStart(
|
|
76
|
-
i0.ɵɵlistener("click", function
|
|
77
|
-
i0.ɵɵtext(
|
|
74
|
+
i0.ɵɵelementStart(23, "button", 16);
|
|
75
|
+
i0.ɵɵlistener("click", function SharedViewWarningDialogComponent_Template_button_click_23_listener() { return ctx.OnCancel(); });
|
|
76
|
+
i0.ɵɵtext(24, " Cancel ");
|
|
78
77
|
i0.ɵɵelementEnd()()();
|
|
79
78
|
} if (rf & 2) {
|
|
80
79
|
i0.ɵɵconditional(ctx.IsOpen ? 0 : -1);
|
|
@@ -82,11 +81,11 @@ export class SharedViewWarningDialogComponent {
|
|
|
82
81
|
i0.ɵɵclassProp("open", ctx.IsOpen);
|
|
83
82
|
i0.ɵɵadvance(11);
|
|
84
83
|
i0.ɵɵtextInterpolate1("\"", ctx.ViewName, "\"");
|
|
85
|
-
} }, styles: ["\n\n.dialog-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: 2000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.dialog-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n width: 440px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);\n z-index: 2001;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.dialog-panel.open[_ngcontent-%COMP%] {\n opacity: 1;\n pointer-events: auto;\n transform: translate(-50%, -50%) scale(1);\n}\n\n\n\n.dialog-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px 24px 0;\n}\n\n.icon-circle[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.icon-circle.warning[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning);\n}\n\n.header-title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.close-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: auto;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n\n.dialog-body[_ngcontent-%COMP%] {\n padding: 20px 24px;\n}\n\n.message[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-muted);\n line-height: 1.6;\n margin: 0 0 16px 0;\n}\n\n.message[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n}\n\n\n\n
|
|
84
|
+
} }, dependencies: [i1.MJAlertComponent], styles: ["\n\n.dialog-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: 2000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n\n\n.dialog-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n width: 440px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);\n z-index: 2001;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.dialog-panel.open[_ngcontent-%COMP%] {\n opacity: 1;\n pointer-events: auto;\n transform: translate(-50%, -50%) scale(1);\n}\n\n\n\n.dialog-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px 24px 0;\n}\n\n.icon-circle[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.icon-circle.warning[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning);\n}\n\n.header-title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.close-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: auto;\n}\n\n.close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n\n\n.dialog-body[_ngcontent-%COMP%] {\n padding: 20px 24px;\n}\n\n.message[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-text-muted);\n line-height: 1.6;\n margin: 0 0 16px 0;\n}\n\n.message[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n}\n\n\n\n\n.shared-view-alert-pos[_ngcontent-%COMP%] { margin: 0; }\n\n\n\n.dialog-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 24px 20px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n\n\n.btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 9px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover {\n background: var(--mj-color-info-600);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border: 1px solid var(--mj-border-strong);\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-text-disabled);\n}\n\n.btn-ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--mj-text-muted);\n margin-left: auto;\n}\n\n.btn-ghost[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}"] });
|
|
86
85
|
}
|
|
87
86
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SharedViewWarningDialogComponent, [{
|
|
88
87
|
type: Component,
|
|
89
|
-
args: [{ standalone: false, selector: 'mj-shared-view-warning-dialog', template: "<!-- Dialog Backdrop -->\n@if (IsOpen) {\n <div class=\"dialog-backdrop\" (click)=\"OnCancel()\"></div>\n}\n\n<!-- Dialog Panel -->\n<div class=\"dialog-panel\" [class.open]=\"IsOpen\">\n <!-- Header -->\n <div class=\"dialog-header\">\n <div class=\"icon-circle warning\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <span class=\"header-title\">Shared View</span>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"dialog-body\">\n <p class=\"message\">\n <strong>\"{{ ViewName }}\"</strong> is shared with other users.\n Changes you save will affect everyone who uses this view.\n </p>\n <
|
|
88
|
+
args: [{ standalone: false, selector: 'mj-shared-view-warning-dialog', template: "<!-- Dialog Backdrop -->\n@if (IsOpen) {\n <div class=\"dialog-backdrop\" (click)=\"OnCancel()\"></div>\n}\n\n<!-- Dialog Panel -->\n<div class=\"dialog-panel\" [class.open]=\"IsOpen\">\n <!-- Header -->\n <div class=\"dialog-header\">\n <div class=\"icon-circle warning\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <span class=\"header-title\">Shared View</span>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"dialog-body\">\n <p class=\"message\">\n <strong>\"{{ ViewName }}\"</strong> is shared with other users.\n Changes you save will affect everyone who uses this view.\n </p>\n <mj-alert Variant=\"warning\" Size=\"sm\" class=\"shared-view-alert-pos\">Other users may be relying on this view's current configuration.</mj-alert>\n </div>\n\n <!-- Footer -->\n <div class=\"dialog-footer\">\n <button class=\"btn btn-primary\" (click)=\"OnUpdateShared()\">\n <i class=\"fa-solid fa-save\"></i>\n Update Shared View\n </button>\n <button class=\"btn btn-secondary\" (click)=\"OnSaveAsCopy()\">\n <i class=\"fa-solid fa-plus\"></i>\n Save As My Copy\n </button>\n <button class=\"btn btn-ghost\" (click)=\"OnCancel()\">\n Cancel\n </button>\n </div>\n</div>\n", styles: ["/* Dialog Backdrop */\n.dialog-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n z-index: 2000;\n animation: fadeIn 0.2s ease;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n/* Dialog Panel */\n.dialog-panel {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0.95);\n width: 440px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);\n z-index: 2001;\n display: flex;\n flex-direction: column;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.2s ease, transform 0.2s ease;\n}\n\n.dialog-panel.open {\n opacity: 1;\n pointer-events: auto;\n transform: translate(-50%, -50%) scale(1);\n}\n\n/* Dialog Header */\n.dialog-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px 24px 0;\n}\n\n.icon-circle {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.icon-circle.warning {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning);\n}\n\n.header-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.close-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 8px;\n cursor: pointer;\n color: var(--mj-text-muted);\n transition: all 0.15s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: auto;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n/* Dialog Body */\n.dialog-body {\n padding: 20px 24px;\n}\n\n.message {\n font-size: 14px;\n color: var(--mj-text-muted);\n line-height: 1.6;\n margin: 0 0 16px 0;\n}\n\n.message strong {\n color: var(--mj-text-primary);\n}\n\n/* Positioning-only helper for the migrated <mj-alert> (box chrome owned by\n the component; the bespoke warning box carried no margins). */\n.shared-view-alert-pos { margin: 0; }\n\n/* Dialog Footer */\n.dialog-footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 24px 20px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* Buttons */\n.btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 9px 16px;\n border: none;\n border-radius: 8px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-primary:hover {\n background: var(--mj-color-info-600);\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n border: 1px solid var(--mj-border-strong);\n}\n\n.btn-secondary:hover {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-text-disabled);\n}\n\n.btn-ghost {\n background: transparent;\n color: var(--mj-text-muted);\n margin-left: auto;\n}\n\n.btn-ghost:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n"] }]
|
|
90
89
|
}], null, { IsOpen: [{
|
|
91
90
|
type: Input
|
|
92
91
|
}], ViewName: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-view-warning-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.ts","../../../src/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC
|
|
1
|
+
{"version":3,"file":"shared-view-warning-dialog.component.js","sourceRoot":"","sources":["../../../src/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.ts","../../../src/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;;;;;ICErE,+BAAkD;IAArB,iMAAS,iBAAU,KAAC;IAAC,iBAAM;;ADK1D;;;;;;;;;;;;;;;;;;GAkBG;AAOH,MAAM,OAAO,gCAAgC;IAClC,MAAM,GAAY,KAAK,CAAC;IACxB,QAAQ,GAAW,EAAE,CAAC;IAErB,MAAM,GAAG,IAAI,YAAY,EAAoB,CAAC;IAC9C,MAAM,GAAG,IAAI,YAAY,EAAQ,CAAC;IAE5C,cAAc;QACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACpC,CAAC;IAED,YAAY;QACV,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;0HAjBU,gCAAgC;6DAAhC,gCAAgC;YC/B7C,kGAAc;YAQV,AADF,AAFF,8BAAgD,aAEnB,aACQ;YAC/B,uBAAiC;YACnC,iBAAM;YACN,+BAA2B;YAAA,2BAAW;YAAA,iBAAO;YAC7C,iCAAuF;YAA7D,6GAAS,cAAU,IAAC;YAC5C,uBAAiC;YAErC,AADE,iBAAS,EACL;YAKF,AADF,AADF,8BAAyB,YACJ,cACT;YAAA,aAAgB;YAAA,iBAAS;YAAC,wGAEpC;YAAA,iBAAI;YACJ,qCAAoE;YAAA,iFAAgE;YACtI,AADsI,iBAAW,EAC3I;YAIJ,AADF,gCAA2B,kBACkC;YAA3B,8GAAS,oBAAgB,IAAC;YACxD,yBAAgC;YAChC,qCACF;YAAA,iBAAS;YACT,mCAA2D;YAAzB,8GAAS,kBAAc,IAAC;YACxD,yBAAgC;YAChC,kCACF;YAAA,iBAAS;YACT,mCAAmD;YAArB,8GAAS,cAAU,IAAC;YAChD,yBACF;YAEJ,AADE,AADE,iBAAS,EACL,EACF;;YAxCN,qCAEC;YAGyB,cAAqB;YAArB,kCAAqB;YAejC,gBAAgB;YAAhB,+CAAgB;;;iFDWjB,gCAAgC;cAN5C,SAAS;6BACI,KAAK,YACP,+BAA+B;;kBAKxC,KAAK;;kBACL,KAAK;;kBAEL,MAAM;;kBACN,MAAM;;kFALI,gCAAgC","sourcesContent":["import { Component, Input, Output, EventEmitter } from '@angular/core';\n\n/**\n * Result of the shared view warning dialog\n */\nexport type SharedViewAction = 'update-shared' | 'save-as-copy' | 'cancel';\n\n/**\n * SharedViewWarningDialogComponent - Warning dialog when saving changes to a shared view\n *\n * Shows when a user attempts to save changes to a view that is shared with other users.\n * Presents three options:\n * - Update Shared View: save changes affecting all users\n * - Save As My Copy: create a personal copy with the changes\n * - Cancel: abort the save\n *\n * @example\n * ```html\n * <mj-shared-view-warning-dialog\n * [IsOpen]=\"showSharedWarning\"\n * [ViewName]=\"currentView.Name\"\n * (Action)=\"onSharedViewAction($event)\"\n * (Cancel)=\"showSharedWarning = false\">\n * </mj-shared-view-warning-dialog>\n * ```\n */\n@Component({\n standalone: false,\n selector: 'mj-shared-view-warning-dialog',\n templateUrl: './shared-view-warning-dialog.component.html',\n styleUrls: ['./shared-view-warning-dialog.component.css']\n})\nexport class SharedViewWarningDialogComponent {\n @Input() IsOpen: boolean = false;\n @Input() ViewName: string = '';\n\n @Output() Action = new EventEmitter<SharedViewAction>();\n @Output() Cancel = new EventEmitter<void>();\n\n OnUpdateShared(): void {\n this.Action.emit('update-shared');\n }\n\n OnSaveAsCopy(): void {\n this.Action.emit('save-as-copy');\n }\n\n OnCancel(): void {\n this.Cancel.emit();\n }\n}\n","<!-- Dialog Backdrop -->\n@if (IsOpen) {\n <div class=\"dialog-backdrop\" (click)=\"OnCancel()\"></div>\n}\n\n<!-- Dialog Panel -->\n<div class=\"dialog-panel\" [class.open]=\"IsOpen\">\n <!-- Header -->\n <div class=\"dialog-header\">\n <div class=\"icon-circle warning\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <span class=\"header-title\">Shared View</span>\n <button class=\"close-btn\" (click)=\"OnCancel()\" title=\"Close\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Body -->\n <div class=\"dialog-body\">\n <p class=\"message\">\n <strong>\"{{ ViewName }}\"</strong> is shared with other users.\n Changes you save will affect everyone who uses this view.\n </p>\n <mj-alert Variant=\"warning\" Size=\"sm\" class=\"shared-view-alert-pos\">Other users may be relying on this view's current configuration.</mj-alert>\n </div>\n\n <!-- Footer -->\n <div class=\"dialog-footer\">\n <button class=\"btn btn-primary\" (click)=\"OnUpdateShared()\">\n <i class=\"fa-solid fa-save\"></i>\n Update Shared View\n </button>\n <button class=\"btn btn-secondary\" (click)=\"OnSaveAsCopy()\">\n <i class=\"fa-solid fa-plus\"></i>\n Save As My Copy\n </button>\n <button class=\"btn btn-ghost\" (click)=\"OnCancel()\">\n Cancel\n </button>\n </div>\n</div>\n"]}
|