@memberjunction/ng-artifacts 5.10.1 → 5.12.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/artifacts.module.d.ts +2 -1
- package/dist/lib/artifacts.module.d.ts.map +1 -1
- package/dist/lib/artifacts.module.js +7 -3
- package/dist/lib/artifacts.module.js.map +1 -1
- package/dist/lib/components/artifact-message-card.component.js +2 -2
- package/dist/lib/components/artifact-message-card.component.js.map +1 -1
- package/dist/lib/components/artifact-viewer-panel.component.js +2 -2
- package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +2 -0
- package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/component-artifact-viewer.component.js +43 -14
- package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts +75 -0
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts.map +1 -0
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js +569 -0
- package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js.map +1 -0
- package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts +10 -0
- package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/data-artifact-viewer.component.js +44 -11
- package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
- package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js +2 -2
- package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
- package/dist/lib/components/plugins/json-artifact-viewer.component.js +3 -3
- package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +15 -14
|
@@ -12,9 +12,10 @@ import { DataRequirementsViewerComponent } from './data-requirements-viewer/data
|
|
|
12
12
|
import * as i0 from "@angular/core";
|
|
13
13
|
import * as i1 from "@memberjunction/ng-react";
|
|
14
14
|
import * as i2 from "@angular/common";
|
|
15
|
+
import * as i3 from "./component-feedback-panel/component-feedback-panel.component";
|
|
15
16
|
const _c0 = ["reactComponent"];
|
|
16
17
|
function ComponentArtifactViewerComponent_Conditional_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
-
i0.ɵɵelementStart(0, "details",
|
|
18
|
+
i0.ɵɵelementStart(0, "details", 8)(1, "summary");
|
|
18
19
|
i0.ɵɵtext(2, "Technical Details");
|
|
19
20
|
i0.ɵɵelementEnd();
|
|
20
21
|
i0.ɵɵelementStart(3, "pre");
|
|
@@ -27,14 +28,14 @@ function ComponentArtifactViewerComponent_Conditional_2_Conditional_13_Template(
|
|
|
27
28
|
} }
|
|
28
29
|
function ComponentArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
29
30
|
i0.ɵɵelementStart(0, "div", 3);
|
|
30
|
-
i0.ɵɵelement(1, "i",
|
|
31
|
+
i0.ɵɵelement(1, "i", 6);
|
|
31
32
|
i0.ɵɵelementStart(2, "h3");
|
|
32
33
|
i0.ɵɵtext(3);
|
|
33
34
|
i0.ɵɵelementEnd();
|
|
34
35
|
i0.ɵɵelementStart(4, "p");
|
|
35
36
|
i0.ɵɵtext(5, "This component could not be loaded. This usually happens when:");
|
|
36
37
|
i0.ɵɵelementEnd();
|
|
37
|
-
i0.ɵɵelementStart(6, "ul",
|
|
38
|
+
i0.ɵɵelementStart(6, "ul", 7)(7, "li");
|
|
38
39
|
i0.ɵɵtext(8, "The component registry is unavailable or unreachable");
|
|
39
40
|
i0.ɵɵelementEnd();
|
|
40
41
|
i0.ɵɵelementStart(9, "li");
|
|
@@ -43,7 +44,7 @@ function ComponentArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (
|
|
|
43
44
|
i0.ɵɵelementStart(11, "li");
|
|
44
45
|
i0.ɵɵtext(12, "There was a network error during component retrieval");
|
|
45
46
|
i0.ɵɵelementEnd()();
|
|
46
|
-
i0.ɵɵconditionalCreate(13, ComponentArtifactViewerComponent_Conditional_2_Conditional_13_Template, 5, 1, "details",
|
|
47
|
+
i0.ɵɵconditionalCreate(13, ComponentArtifactViewerComponent_Conditional_2_Conditional_13_Template, 5, 1, "details", 8);
|
|
47
48
|
i0.ɵɵelementEnd();
|
|
48
49
|
} if (rf & 2) {
|
|
49
50
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -54,7 +55,7 @@ function ComponentArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (
|
|
|
54
55
|
} }
|
|
55
56
|
function ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
56
57
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
57
|
-
i0.ɵɵelementStart(0, "mj-react-component",
|
|
58
|
+
i0.ɵɵelementStart(0, "mj-react-component", 11, 0);
|
|
58
59
|
i0.ɵɵlistener("componentEvent", function ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template_mj_react_component_componentEvent_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onComponentEvent($event)); })("openEntityRecord", function ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template_mj_react_component_openEntityRecord_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onOpenEntityRecord($event)); })("initialized", function ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template_mj_react_component_initialized_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onReactComponentInitialized()); });
|
|
59
60
|
i0.ɵɵelementEnd();
|
|
60
61
|
} if (rf & 2) {
|
|
@@ -62,8 +63,8 @@ function ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template(r
|
|
|
62
63
|
i0.ɵɵproperty("component", ctx_r0.component);
|
|
63
64
|
} }
|
|
64
65
|
function ComponentArtifactViewerComponent_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
-
i0.ɵɵelementStart(0, "div",
|
|
66
|
-
i0.ɵɵelement(1, "i",
|
|
66
|
+
i0.ɵɵelementStart(0, "div", 10);
|
|
67
|
+
i0.ɵɵelement(1, "i", 12);
|
|
67
68
|
i0.ɵɵelementStart(2, "h3");
|
|
68
69
|
i0.ɵɵtext(3, "Component Specification");
|
|
69
70
|
i0.ɵɵelementEnd();
|
|
@@ -76,7 +77,7 @@ function ComponentArtifactViewerComponent_Conditional_3_Conditional_1_Template(r
|
|
|
76
77
|
} }
|
|
77
78
|
function ComponentArtifactViewerComponent_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
78
79
|
i0.ɵɵelementStart(0, "div", 3);
|
|
79
|
-
i0.ɵɵelement(1, "i",
|
|
80
|
+
i0.ɵɵelement(1, "i", 13);
|
|
80
81
|
i0.ɵɵelementStart(2, "h3");
|
|
81
82
|
i0.ɵɵtext(3, "No Component Loaded");
|
|
82
83
|
i0.ɵɵelementEnd();
|
|
@@ -85,11 +86,27 @@ function ComponentArtifactViewerComponent_Conditional_3_Conditional_2_Template(r
|
|
|
85
86
|
i0.ɵɵelementEnd()();
|
|
86
87
|
} }
|
|
87
88
|
function ComponentArtifactViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
88
|
-
i0.ɵɵconditionalCreate(0, ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template, 2, 1, "mj-react-component",
|
|
89
|
+
i0.ɵɵconditionalCreate(0, ComponentArtifactViewerComponent_Conditional_3_Conditional_0_Template, 2, 1, "mj-react-component", 9)(1, ComponentArtifactViewerComponent_Conditional_3_Conditional_1_Template, 8, 0, "div", 10)(2, ComponentArtifactViewerComponent_Conditional_3_Conditional_2_Template, 6, 0, "div", 3);
|
|
89
90
|
} if (rf & 2) {
|
|
90
91
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
91
92
|
i0.ɵɵconditional(ctx_r0.component && (ctx_r0.component.code || ctx_r0.component.namespace) ? 0 : ctx_r0.component ? 1 : 2);
|
|
92
93
|
} }
|
|
94
|
+
function ComponentArtifactViewerComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
95
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
96
|
+
i0.ɵɵelementStart(0, "button", 14);
|
|
97
|
+
i0.ɵɵlistener("click", function ComponentArtifactViewerComponent_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.ToggleFeedbackPanel()); });
|
|
98
|
+
i0.ɵɵelement(1, "i", 15);
|
|
99
|
+
i0.ɵɵelementEnd();
|
|
100
|
+
} }
|
|
101
|
+
function ComponentArtifactViewerComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
102
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
103
|
+
i0.ɵɵelementStart(0, "mj-component-feedback-panel", 16);
|
|
104
|
+
i0.ɵɵlistener("Closed", function ComponentArtifactViewerComponent_Conditional_5_Template_mj_component_feedback_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.ShowFeedbackPanel = false); });
|
|
105
|
+
i0.ɵɵelementEnd();
|
|
106
|
+
} if (rf & 2) {
|
|
107
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
108
|
+
i0.ɵɵproperty("ComponentSpec", ctx_r0.resolvedComponentSpec)("ReactContainerElement", (ctx_r0.reactComponent == null ? null : ctx_r0.reactComponent.container == null ? null : ctx_r0.reactComponent.container.nativeElement) || null);
|
|
109
|
+
} }
|
|
93
110
|
/**
|
|
94
111
|
* Viewer component for interactive Component artifacts (React-based UI components)
|
|
95
112
|
*
|
|
@@ -118,6 +135,8 @@ let ComponentArtifactViewerComponent = class ComponentArtifactViewerComponent ex
|
|
|
118
135
|
// then fall back to the stripped local spec as last resort.
|
|
119
136
|
return this.reactComponent?.resolvedComponentSpec || this._cachedResolvedSpec || this.component;
|
|
120
137
|
}
|
|
138
|
+
// Feedback panel
|
|
139
|
+
ShowFeedbackPanel = false;
|
|
121
140
|
// Error state
|
|
122
141
|
hasError = false;
|
|
123
142
|
errorMessage = '';
|
|
@@ -302,21 +321,31 @@ let ComponentArtifactViewerComponent = class ComponentArtifactViewerComponent ex
|
|
|
302
321
|
compositeKey: event.key
|
|
303
322
|
});
|
|
304
323
|
}
|
|
324
|
+
ToggleFeedbackPanel() {
|
|
325
|
+
this.ShowFeedbackPanel = !this.ShowFeedbackPanel;
|
|
326
|
+
}
|
|
305
327
|
static ɵfac = function ComponentArtifactViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ComponentArtifactViewerComponent)(i0.ɵɵdirectiveInject(i1.AngularAdapterService)); };
|
|
306
328
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ComponentArtifactViewerComponent, selectors: [["mj-component-artifact-viewer"]], viewQuery: function ComponentArtifactViewerComponent_Query(rf, ctx) { if (rf & 1) {
|
|
307
329
|
i0.ɵɵviewQuery(_c0, 5);
|
|
308
330
|
} if (rf & 2) {
|
|
309
331
|
let _t;
|
|
310
332
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.reactComponent = _t.first);
|
|
311
|
-
} }, outputs: { tabsChanged: "tabsChanged", openEntityRecord: "openEntityRecord" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls:
|
|
333
|
+
} }, outputs: { tabsChanged: "tabsChanged", openEntityRecord: "openEntityRecord" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 6, vars: 4, consts: [["reactComponent", ""], [1, "component-artifact-viewer", 3, "ngClass"], [1, "component-preview"], [1, "error-state"], ["title", "Rate this component", 1, "feedback-toggle-btn"], [3, "ComponentSpec", "ReactContainerElement"], [1, "fa-solid", "fa-exclamation-triangle"], [2, "text-align", "left", "max-width", "500px", "color", "var(--mj-text-muted)", "line-height", "1.6"], [2, "margin-top", "20px"], [3, "component"], [1, "no-code-state"], [3, "componentEvent", "openEntityRecord", "initialized", "component"], [1, "fa-solid", "fa-file-lines"], [1, "fa-solid", "fa-exclamation-circle"], ["title", "Rate this component", 1, "feedback-toggle-btn", 3, "click"], [1, "fa-solid", "fa-comment-dots"], [3, "Closed", "ComponentSpec", "ReactContainerElement"]], template: function ComponentArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
312
334
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2);
|
|
313
335
|
i0.ɵɵconditionalCreate(2, ComponentArtifactViewerComponent_Conditional_2_Template, 14, 2, "div", 3)(3, ComponentArtifactViewerComponent_Conditional_3_Template, 3, 1);
|
|
314
|
-
i0.ɵɵelementEnd()
|
|
336
|
+
i0.ɵɵelementEnd();
|
|
337
|
+
i0.ɵɵconditionalCreate(4, ComponentArtifactViewerComponent_Conditional_4_Template, 2, 0, "button", 4);
|
|
338
|
+
i0.ɵɵconditionalCreate(5, ComponentArtifactViewerComponent_Conditional_5_Template, 1, 2, "mj-component-feedback-panel", 5);
|
|
339
|
+
i0.ɵɵelementEnd();
|
|
315
340
|
} if (rf & 2) {
|
|
316
341
|
i0.ɵɵproperty("ngClass", ctx.cssClass);
|
|
317
342
|
i0.ɵɵadvance(2);
|
|
318
343
|
i0.ɵɵconditional(ctx.hasError ? 2 : 3);
|
|
319
|
-
|
|
344
|
+
i0.ɵɵadvance(2);
|
|
345
|
+
i0.ɵɵconditional(ctx.resolvedComponentSpec ? 4 : -1);
|
|
346
|
+
i0.ɵɵadvance();
|
|
347
|
+
i0.ɵɵconditional(ctx.ShowFeedbackPanel && ctx.resolvedComponentSpec ? 5 : -1);
|
|
348
|
+
} }, dependencies: [i2.NgClass, i1.MJReactComponent, i3.ComponentFeedbackPanelComponent], styles: [".component-artifact-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface);\n}\n\n.component-preview[_ngcontent-%COMP%] {\n flex: 1;\n padding: 15px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n.component-preview[_ngcontent-%COMP%] mj-react-component[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.error-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n text-align: center;\n color: var(--mj-status-error);\n flex: 1;\n min-height: 300px;\n}\n.error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n}\n.error-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n}\n.error-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n color: var(--mj-text-muted);\n}\n.error-state[_ngcontent-%COMP%] details[_ngcontent-%COMP%] {\n margin-top: 16px;\n text-align: left;\n max-width: 600px;\n}\n.error-state[_ngcontent-%COMP%] details[_ngcontent-%COMP%] summary[_ngcontent-%COMP%] {\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 500;\n margin-bottom: 8px;\n}\n.error-state[_ngcontent-%COMP%] details[_ngcontent-%COMP%] summary[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n.error-state[_ngcontent-%COMP%] details[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n padding: 12px;\n border-radius: 4px;\n overflow-x: auto;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n\n\n.no-code-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n text-align: center;\n color: var(--mj-text-muted);\n flex: 1;\n}\n.no-code-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n color: var(--mj-brand-primary);\n}\n.no-code-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.no-code-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n color: var(--mj-text-muted);\n}\n\n\n\n.feedback-toggle-btn[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 16px;\n left: 16px;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n border: none;\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n font-size: 18px;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s ease, transform 0.2s ease;\n z-index: 5;\n}\n\n.feedback-toggle-btn[_ngcontent-%COMP%]:hover {\n background-color: var(--mj-brand-primary-hover, #2563EB);\n transform: scale(1.1);\n}"] });
|
|
320
349
|
};
|
|
321
350
|
ComponentArtifactViewerComponent = __decorate([
|
|
322
351
|
RegisterClass(BaseArtifactViewerPluginComponent, 'ComponentArtifactViewerPlugin')
|
|
@@ -324,7 +353,7 @@ ComponentArtifactViewerComponent = __decorate([
|
|
|
324
353
|
export { ComponentArtifactViewerComponent };
|
|
325
354
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ComponentArtifactViewerComponent, [{
|
|
326
355
|
type: Component,
|
|
327
|
-
args: [{ standalone: false, selector: 'mj-component-artifact-viewer', template: "<div class=\"component-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Component Preview (full screen) -->\n <div class=\"component-preview\">\n @if (hasError) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <h3>{{ errorMessage }}</h3>\n <p>This component could not be loaded. This usually happens when:</p>\n <ul style=\"text-align: left; max-width: 500px; color:
|
|
356
|
+
args: [{ standalone: false, selector: 'mj-component-artifact-viewer', template: "<div class=\"component-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Component Preview (full screen) -->\n <div class=\"component-preview\">\n @if (hasError) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <h3>{{ errorMessage }}</h3>\n <p>This component could not be loaded. This usually happens when:</p>\n <ul style=\"text-align: left; max-width: 500px; color: var(--mj-text-muted); line-height: 1.6;\">\n <li>The component registry is unavailable or unreachable</li>\n <li>The component version does not exist in the registry</li>\n <li>There was a network error during component retrieval</li>\n </ul>\n @if (errorDetails) {\n <details style=\"margin-top: 20px;\">\n <summary>Technical Details</summary>\n <pre>{{ errorDetails }}</pre>\n </details>\n }\n </div>\n } @else {\n <!-- Only render React component if there's code to execute -->\n @if (component && (component.code || component.namespace)) {\n <mj-react-component\n #reactComponent\n [component]=\"component\"\n (componentEvent)=\"onComponentEvent($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (initialized)=\"onReactComponentInitialized()\">\n </mj-react-component>\n } @else if (component) {\n <!-- Component spec exists but no code - show informational message -->\n <div class=\"no-code-state\">\n <i class=\"fa-solid fa-file-lines\"></i>\n <h3>Component Specification</h3>\n <p>This component has specifications but no executable code yet.</p>\n <p>View the Functional, Data, or Spec tabs for details.</p>\n </div>\n } @else {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n <h3>No Component Loaded</h3>\n <p>The component data is missing or invalid.</p>\n </div>\n }\n }\n </div>\n\n <!-- Feedback toggle button -->\n @if (resolvedComponentSpec) {\n <button class=\"feedback-toggle-btn\" (click)=\"ToggleFeedbackPanel()\"\n title=\"Rate this component\">\n <i class=\"fa-solid fa-comment-dots\"></i>\n </button>\n }\n\n <!-- Feedback overlay panel -->\n @if (ShowFeedbackPanel && resolvedComponentSpec) {\n <mj-component-feedback-panel\n [ComponentSpec]=\"resolvedComponentSpec\"\n [ReactContainerElement]=\"reactComponent?.container?.nativeElement || null\"\n (Closed)=\"ShowFeedbackPanel = false\">\n </mj-component-feedback-panel>\n }\n</div>\n\n", styles: [".component-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface);\n}\n\n.component-preview {\n flex: 1;\n padding: 15px;\n overflow: auto;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* Ensure React component takes full height */\n.component-preview mj-react-component {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n text-align: center;\n color: var(--mj-status-error);\n flex: 1;\n min-height: 300px;\n}\n.error-state i {\n font-size: 48px;\n margin-bottom: 16px;\n}\n.error-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n}\n.error-state p {\n margin: 0 0 12px 0;\n color: var(--mj-text-muted);\n}\n.error-state details {\n margin-top: 16px;\n text-align: left;\n max-width: 600px;\n}\n.error-state details summary {\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 500;\n margin-bottom: 8px;\n}\n.error-state details summary:hover {\n color: var(--mj-text-primary);\n}\n.error-state details pre {\n background: var(--mj-bg-surface-sunken);\n padding: 12px;\n border-radius: 4px;\n overflow-x: auto;\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* State for component spec without executable code */\n.no-code-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n text-align: center;\n color: var(--mj-text-muted);\n flex: 1;\n}\n.no-code-state i {\n font-size: 48px;\n margin-bottom: 16px;\n color: var(--mj-brand-primary);\n}\n.no-code-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n color: var(--mj-text-secondary);\n}\n.no-code-state p {\n margin: 0 0 8px 0;\n color: var(--mj-text-muted);\n}\n\n/* Feedback toggle button */\n.feedback-toggle-btn {\n position: absolute;\n bottom: 16px;\n left: 16px;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n border: none;\n background-color: var(--mj-brand-primary, #3B82F6);\n color: var(--mj-text-inverse, #ffffff);\n font-size: 18px;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s ease, transform 0.2s ease;\n z-index: 5;\n}\n\n.feedback-toggle-btn:hover {\n background-color: var(--mj-brand-primary-hover, #2563EB);\n transform: scale(1.1);\n}\n"] }]
|
|
328
357
|
}], () => [{ type: i1.AngularAdapterService }], { reactComponent: [{
|
|
329
358
|
type: ViewChild,
|
|
330
359
|
args: ['reactComponent']
|
|
@@ -333,5 +362,5 @@ export { ComponentArtifactViewerComponent };
|
|
|
333
362
|
}], openEntityRecord: [{
|
|
334
363
|
type: Output
|
|
335
364
|
}] }); })();
|
|
336
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentArtifactViewerComponent, { className: "ComponentArtifactViewerComponent", filePath: "src/lib/components/plugins/component-artifact-viewer.component.ts", lineNumber:
|
|
365
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ComponentArtifactViewerComponent, { className: "ComponentArtifactViewerComponent", filePath: "src/lib/components/plugins/component-artifact-viewer.component.ts", lineNumber: 25 }); })();
|
|
337
366
|
//# sourceMappingURL=component-artifact-viewer.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/component-artifact-viewer.component.ts","../../../../src/lib/components/plugins/component-artifact-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, AfterViewInit, OnInit, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';\nimport { RegisterClass, SafeJSONParse } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent, ArtifactViewerTab } from '../base-artifact-viewer.component';\nimport { MJReactComponent, AngularAdapterService } from '@memberjunction/ng-react';\nimport { BuildComponentCompleteCode, ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { CompositeKey } from '@memberjunction/core';\nimport { DataRequirementsViewerComponent } from './data-requirements-viewer/data-requirements-viewer.component';\n\n/**\n * Viewer component for interactive Component artifacts (React-based UI components)\n *\n * Features:\n * - Live component preview with React rendering\n * - Dynamic tabs for component metadata (via GetAdditionalTabs)\n * - Provides tabs for: Code, Functional Requirements, Technical Design, Data Requirements\n */\n@Component({\n standalone: false,\n selector: 'mj-component-artifact-viewer',\n templateUrl: './component-artifact-viewer.component.html',\n styleUrls: ['./component-artifact-viewer.component.css']\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'ComponentArtifactViewerPlugin')\nexport class ComponentArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, AfterViewInit, OnChanges {\n @ViewChild('reactComponent') reactComponent?: MJReactComponent;\n @Output() tabsChanged = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n\n // Component data\n public component: ComponentSpec | null = null;\n public componentCode: string = \"\";\n public componentName: string = '';\n\n /**\n * Cached resolved spec from the registry, preserved even after the React component\n * is destroyed (e.g., when a render error removes <mj-react-component> from the DOM).\n */\n private _cachedResolvedSpec: ComponentSpec | null = null;\n\n public get resolvedComponentSpec(): ComponentSpec | null {\n // Prefer the live React component's resolved spec (most up-to-date),\n // then fall back to our cached copy (survives DOM destruction),\n // then fall back to the stripped local spec as last resort.\n return this.reactComponent?.resolvedComponentSpec || this._cachedResolvedSpec || this.component;\n }\n\n // Error state\n public hasError = false;\n public errorMessage = '';\n public errorDetails = '';\n\n /**\n * Whether this plugin has content to display in the Display tab.\n * Returns true only if the component has code that can be rendered.\n *\n * IMPORTANT: Uses this.component (synchronously loaded from artifact JSON)\n * instead of resolvedComponentSpec (which depends on async React loading).\n * This ensures hasDisplayContent returns correct value immediately when\n * pluginLoaded fires, before React component finishes loading.\n */\n public override get hasDisplayContent(): boolean {\n // Use this.component directly - it's available synchronously after loadComponentSpec()\n return !!this.component?.namespace || !!this.component?.code\n }\n\n constructor(private adapter: AngularAdapterService) {\n super();\n }\n\n async ngOnChanges(changes: SimpleChanges): Promise<void> {\n // When artifactVersion input changes, reload the component spec\n if (changes['artifactVersion']) {\n this.loadComponentSpec();\n // Notify parent that tabs may have changed (on subsequent changes)\n if (!changes['artifactVersion'].firstChange) {\n this.tabsChanged.emit();\n }\n }\n }\n\n /**\n * Synchronously load the component spec from artifact content.\n * This is intentionally synchronous so that tabs are available immediately\n * when the parent queries GetAdditionalTabs() after pluginLoaded fires.\n */\n private loadComponentSpec(): void {\n try {\n // Clear cached resolved spec from previous version so stale data doesn't persist\n this._cachedResolvedSpec = null;\n\n if (this.artifactVersion?.Content) {\n this.component = SafeJSONParse(this.artifactVersion.Content) as ComponentSpec;\n this.extractComponentParts();\n } else {\n throw new Error('Artifact content is empty');\n }\n } catch (error) {\n console.error('Failed to load component spec:', error);\n this.hasError = true;\n this.errorMessage = 'Failed to load component';\n this.errorDetails = error instanceof Error ? error.message : String(error);\n }\n }\n\n /**\n * Component initialization.\n * Note: loadComponentSpec() is called in ngOnChanges which runs before ngOnInit,\n * ensuring tabs are available when pluginLoaded fires.\n * The async adapter initialization happens here and doesn't block tab availability.\n */\n async ngOnInit(): Promise<void> {\n // Initialize Angular adapter for React components (async operation)\n try {\n await this.adapter.initialize();\n } catch (error) {\n console.error('Failed to initialize Angular adapter:', error);\n this.hasError = true;\n this.errorMessage = 'Failed to initialize component runtime';\n this.errorDetails = error instanceof Error ? error.message : String(error);\n }\n }\n\n async ngAfterViewInit(): Promise<void> {\n // Component initialization happens automatically via mj-react-component\n }\n\n /**\n * Provide additional tabs for viewing component metadata\n */\n public GetAdditionalTabs(): ArtifactViewerTab[] {\n const tabs: ArtifactViewerTab[] = [];\n\n const resolvedComponent = this.resolvedComponentSpec;\n\n if (!resolvedComponent) {\n return tabs;\n }\n\n // Functional Requirements tab\n if (resolvedComponent.functionalRequirements) {\n tabs.push({\n label: 'Functional',\n icon: 'fa-clipboard-list',\n contentType: 'markdown',\n content: resolvedComponent.functionalRequirements\n });\n }\n\n // Technical Design tab\n if (resolvedComponent.technicalDesign) {\n tabs.push({\n label: 'Technical',\n icon: 'fa-wrench',\n contentType: 'markdown',\n content: resolvedComponent.technicalDesign\n });\n }\n\n // Data Requirements tab - uses custom component for rich visualization\n if (resolvedComponent.dataRequirements) {\n tabs.push({\n label: 'Data',\n icon: 'fa-database',\n contentType: 'component',\n component: DataRequirementsViewerComponent,\n componentInputs: { dataRequirements: resolvedComponent.dataRequirements }\n });\n }\n\n // Code tab (lazy-loaded) - only show if there's actual code\n if (resolvedComponent.code && resolvedComponent.code.trim()) {\n tabs.push({\n label: 'Code',\n icon: 'fa-code',\n contentType: 'code',\n language: 'typescript',\n content: () => BuildComponentCompleteCode(resolvedComponent)\n });\n }\n\n // Spec tab - Shows fully resolved component spec in JSON format (rightmost)\n tabs.push({\n label: 'Spec',\n icon: 'fa-file-code',\n contentType: 'json',\n content: () => JSON.stringify(resolvedComponent, null, 2),\n language: 'json'\n });\n\n return tabs;\n }\n\n /**\n * Remove standard JSON tab since we provide \"Resolved JSON\" custom tab\n * The custom tab shows the fully resolved component spec instead of raw artifact JSON\n */\n public GetStandardTabRemovals(): string[] {\n return ['JSON'];\n }\n\n private extractComponentParts(): void {\n if (this.resolvedComponentSpec?.name) {\n this.componentName = this.resolvedComponentSpec.name;\n }\n if (this.resolvedComponentSpec?.code) {\n this.componentCode = BuildComponentCompleteCode(this.resolvedComponentSpec);\n }\n }\n\n /**\n * Called when MJReactComponent finishes loading the full component spec from the registry.\n * The full spec may contain Functional, Technical, and Data tabs not in the stripped spec.\n * Caches the resolved spec so it survives DOM destruction (e.g., if the component fails to\n * render and <mj-react-component> is removed by the @if/else block).\n * Emits tabsChanged so the parent panel re-evaluates allTabs and renders the new tab labels.\n */\n onReactComponentInitialized(): void {\n if (this.reactComponent?.resolvedComponentSpec &&\n this.reactComponent.resolvedComponentSpec !== this.component) {\n // Cache the resolved spec so it's available even after the React component is destroyed\n this._cachedResolvedSpec = this.reactComponent.resolvedComponentSpec;\n this.tabsChanged.emit();\n }\n }\n\n onComponentEvent(event: unknown): void {\n console.log('Component event:', event);\n\n // Handle error events from React component\n if (event && typeof event === 'object' && 'type' in event && event.type === 'error') {\n const errorEvent = event as { type: 'error'; payload: { error: string; source: string } };\n this.hasError = true;\n this.errorMessage = 'Component Failed to Load';\n this.errorDetails = errorEvent.payload.error || 'Unknown error occurred while loading the component';\n }\n }\n\n /**\n * Handle entity record open request from React component\n * Propagates the event up to parent components\n */\n onOpenEntityRecord(event: {entityName: string; key: CompositeKey}): void {\n // Transform to use 'compositeKey' name for consistency with Angular components\n this.openEntityRecord.emit({\n entityName: event.entityName,\n compositeKey: event.key\n });\n }\n}\n","<div class=\"component-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Component Preview (full screen) -->\n <div class=\"component-preview\">\n @if (hasError) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <h3>{{ errorMessage }}</h3>\n <p>This component could not be loaded. This usually happens when:</p>\n <ul style=\"text-align: left; max-width: 500px; color: #6c757d; line-height: 1.6;\">\n <li>The component registry is unavailable or unreachable</li>\n <li>The component version does not exist in the registry</li>\n <li>There was a network error during component retrieval</li>\n </ul>\n @if (errorDetails) {\n <details style=\"margin-top: 20px;\">\n <summary>Technical Details</summary>\n <pre>{{ errorDetails }}</pre>\n </details>\n }\n </div>\n } @else {\n <!-- Only render React component if there's code to execute -->\n @if (component && (component.code || component.namespace)) {\n <mj-react-component\n #reactComponent\n [component]=\"component\"\n (componentEvent)=\"onComponentEvent($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (initialized)=\"onReactComponentInitialized()\">\n </mj-react-component>\n } @else if (component) {\n <!-- Component spec exists but no code - show informational message -->\n <div class=\"no-code-state\">\n <i class=\"fa-solid fa-file-lines\"></i>\n <h3>Component Specification</h3>\n <p>This component has specifications but no executable code yet.</p>\n <p>View the Functional, Data, or Spec tabs for details.</p>\n </div>\n } @else {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n <h3>No Component Loaded</h3>\n <p>The component data is missing or invalid.</p>\n </div>\n }\n }\n </div>\n</div>\n\n"]}
|
|
1
|
+
{"version":3,"file":"component-artifact-viewer.component.js","sourceRoot":"","sources":["../../../../src/lib/components/plugins/component-artifact-viewer.component.ts","../../../../src/lib/components/plugins/component-artifact-viewer.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, AfterViewInit, OnInit, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';\nimport { RegisterClass, SafeJSONParse } from '@memberjunction/global';\nimport { BaseArtifactViewerPluginComponent, ArtifactViewerTab } from '../base-artifact-viewer.component';\nimport { MJReactComponent, AngularAdapterService } from '@memberjunction/ng-react';\nimport { BuildComponentCompleteCode, ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { CompositeKey } from '@memberjunction/core';\nimport { DataRequirementsViewerComponent } from './data-requirements-viewer/data-requirements-viewer.component';\nimport { ComponentFeedbackPanelComponent } from './component-feedback-panel/component-feedback-panel.component';\n\n/**\n * Viewer component for interactive Component artifacts (React-based UI components)\n *\n * Features:\n * - Live component preview with React rendering\n * - Dynamic tabs for component metadata (via GetAdditionalTabs)\n * - Provides tabs for: Code, Functional Requirements, Technical Design, Data Requirements\n */\n@Component({\n standalone: false,\n selector: 'mj-component-artifact-viewer',\n templateUrl: './component-artifact-viewer.component.html',\n styleUrls: ['./component-artifact-viewer.component.css']\n})\n@RegisterClass(BaseArtifactViewerPluginComponent, 'ComponentArtifactViewerPlugin')\nexport class ComponentArtifactViewerComponent extends BaseArtifactViewerPluginComponent implements OnInit, AfterViewInit, OnChanges {\n @ViewChild('reactComponent') reactComponent?: MJReactComponent;\n @Output() tabsChanged = new EventEmitter<void>();\n @Output() openEntityRecord = new EventEmitter<{entityName: string; compositeKey: CompositeKey}>();\n\n // Component data\n public component: ComponentSpec | null = null;\n public componentCode: string = \"\";\n public componentName: string = '';\n\n /**\n * Cached resolved spec from the registry, preserved even after the React component\n * is destroyed (e.g., when a render error removes <mj-react-component> from the DOM).\n */\n private _cachedResolvedSpec: ComponentSpec | null = null;\n\n public get resolvedComponentSpec(): ComponentSpec | null {\n // Prefer the live React component's resolved spec (most up-to-date),\n // then fall back to our cached copy (survives DOM destruction),\n // then fall back to the stripped local spec as last resort.\n return this.reactComponent?.resolvedComponentSpec || this._cachedResolvedSpec || this.component;\n }\n\n // Feedback panel\n public ShowFeedbackPanel = false;\n\n // Error state\n public hasError = false;\n public errorMessage = '';\n public errorDetails = '';\n\n /**\n * Whether this plugin has content to display in the Display tab.\n * Returns true only if the component has code that can be rendered.\n *\n * IMPORTANT: Uses this.component (synchronously loaded from artifact JSON)\n * instead of resolvedComponentSpec (which depends on async React loading).\n * This ensures hasDisplayContent returns correct value immediately when\n * pluginLoaded fires, before React component finishes loading.\n */\n public override get hasDisplayContent(): boolean {\n // Use this.component directly - it's available synchronously after loadComponentSpec()\n return !!this.component?.namespace || !!this.component?.code\n }\n\n constructor(private adapter: AngularAdapterService) {\n super();\n }\n\n async ngOnChanges(changes: SimpleChanges): Promise<void> {\n // When artifactVersion input changes, reload the component spec\n if (changes['artifactVersion']) {\n this.loadComponentSpec();\n // Notify parent that tabs may have changed (on subsequent changes)\n if (!changes['artifactVersion'].firstChange) {\n this.tabsChanged.emit();\n }\n }\n }\n\n /**\n * Synchronously load the component spec from artifact content.\n * This is intentionally synchronous so that tabs are available immediately\n * when the parent queries GetAdditionalTabs() after pluginLoaded fires.\n */\n private loadComponentSpec(): void {\n try {\n // Clear cached resolved spec from previous version so stale data doesn't persist\n this._cachedResolvedSpec = null;\n\n if (this.artifactVersion?.Content) {\n this.component = SafeJSONParse(this.artifactVersion.Content) as ComponentSpec;\n this.extractComponentParts();\n } else {\n throw new Error('Artifact content is empty');\n }\n } catch (error) {\n console.error('Failed to load component spec:', error);\n this.hasError = true;\n this.errorMessage = 'Failed to load component';\n this.errorDetails = error instanceof Error ? error.message : String(error);\n }\n }\n\n /**\n * Component initialization.\n * Note: loadComponentSpec() is called in ngOnChanges which runs before ngOnInit,\n * ensuring tabs are available when pluginLoaded fires.\n * The async adapter initialization happens here and doesn't block tab availability.\n */\n async ngOnInit(): Promise<void> {\n // Initialize Angular adapter for React components (async operation)\n try {\n await this.adapter.initialize();\n } catch (error) {\n console.error('Failed to initialize Angular adapter:', error);\n this.hasError = true;\n this.errorMessage = 'Failed to initialize component runtime';\n this.errorDetails = error instanceof Error ? error.message : String(error);\n }\n }\n\n async ngAfterViewInit(): Promise<void> {\n // Component initialization happens automatically via mj-react-component\n }\n\n /**\n * Provide additional tabs for viewing component metadata\n */\n public GetAdditionalTabs(): ArtifactViewerTab[] {\n const tabs: ArtifactViewerTab[] = [];\n\n const resolvedComponent = this.resolvedComponentSpec;\n\n if (!resolvedComponent) {\n return tabs;\n }\n\n // Functional Requirements tab\n if (resolvedComponent.functionalRequirements) {\n tabs.push({\n label: 'Functional',\n icon: 'fa-clipboard-list',\n contentType: 'markdown',\n content: resolvedComponent.functionalRequirements\n });\n }\n\n // Technical Design tab\n if (resolvedComponent.technicalDesign) {\n tabs.push({\n label: 'Technical',\n icon: 'fa-wrench',\n contentType: 'markdown',\n content: resolvedComponent.technicalDesign\n });\n }\n\n // Data Requirements tab - uses custom component for rich visualization\n if (resolvedComponent.dataRequirements) {\n tabs.push({\n label: 'Data',\n icon: 'fa-database',\n contentType: 'component',\n component: DataRequirementsViewerComponent,\n componentInputs: { dataRequirements: resolvedComponent.dataRequirements }\n });\n }\n\n // Code tab (lazy-loaded) - only show if there's actual code\n if (resolvedComponent.code && resolvedComponent.code.trim()) {\n tabs.push({\n label: 'Code',\n icon: 'fa-code',\n contentType: 'code',\n language: 'typescript',\n content: () => BuildComponentCompleteCode(resolvedComponent)\n });\n }\n\n // Spec tab - Shows fully resolved component spec in JSON format (rightmost)\n tabs.push({\n label: 'Spec',\n icon: 'fa-file-code',\n contentType: 'json',\n content: () => JSON.stringify(resolvedComponent, null, 2),\n language: 'json'\n });\n\n return tabs;\n }\n\n /**\n * Remove standard JSON tab since we provide \"Resolved JSON\" custom tab\n * The custom tab shows the fully resolved component spec instead of raw artifact JSON\n */\n public GetStandardTabRemovals(): string[] {\n return ['JSON'];\n }\n\n private extractComponentParts(): void {\n if (this.resolvedComponentSpec?.name) {\n this.componentName = this.resolvedComponentSpec.name;\n }\n if (this.resolvedComponentSpec?.code) {\n this.componentCode = BuildComponentCompleteCode(this.resolvedComponentSpec);\n }\n }\n\n /**\n * Called when MJReactComponent finishes loading the full component spec from the registry.\n * The full spec may contain Functional, Technical, and Data tabs not in the stripped spec.\n * Caches the resolved spec so it survives DOM destruction (e.g., if the component fails to\n * render and <mj-react-component> is removed by the @if/else block).\n * Emits tabsChanged so the parent panel re-evaluates allTabs and renders the new tab labels.\n */\n onReactComponentInitialized(): void {\n if (this.reactComponent?.resolvedComponentSpec &&\n this.reactComponent.resolvedComponentSpec !== this.component) {\n // Cache the resolved spec so it's available even after the React component is destroyed\n this._cachedResolvedSpec = this.reactComponent.resolvedComponentSpec;\n this.tabsChanged.emit();\n }\n }\n\n onComponentEvent(event: unknown): void {\n console.log('Component event:', event);\n\n // Handle error events from React component\n if (event && typeof event === 'object' && 'type' in event && event.type === 'error') {\n const errorEvent = event as { type: 'error'; payload: { error: string; source: string } };\n this.hasError = true;\n this.errorMessage = 'Component Failed to Load';\n this.errorDetails = errorEvent.payload.error || 'Unknown error occurred while loading the component';\n }\n }\n\n /**\n * Handle entity record open request from React component\n * Propagates the event up to parent components\n */\n onOpenEntityRecord(event: {entityName: string; key: CompositeKey}): void {\n // Transform to use 'compositeKey' name for consistency with Angular components\n this.openEntityRecord.emit({\n entityName: event.entityName,\n compositeKey: event.key\n });\n }\n\n ToggleFeedbackPanel(): void {\n this.ShowFeedbackPanel = !this.ShowFeedbackPanel;\n }\n}\n","<div class=\"component-artifact-viewer\" [ngClass]=\"cssClass\">\n <!-- Component Preview (full screen) -->\n <div class=\"component-preview\">\n @if (hasError) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <h3>{{ errorMessage }}</h3>\n <p>This component could not be loaded. This usually happens when:</p>\n <ul style=\"text-align: left; max-width: 500px; color: var(--mj-text-muted); line-height: 1.6;\">\n <li>The component registry is unavailable or unreachable</li>\n <li>The component version does not exist in the registry</li>\n <li>There was a network error during component retrieval</li>\n </ul>\n @if (errorDetails) {\n <details style=\"margin-top: 20px;\">\n <summary>Technical Details</summary>\n <pre>{{ errorDetails }}</pre>\n </details>\n }\n </div>\n } @else {\n <!-- Only render React component if there's code to execute -->\n @if (component && (component.code || component.namespace)) {\n <mj-react-component\n #reactComponent\n [component]=\"component\"\n (componentEvent)=\"onComponentEvent($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (initialized)=\"onReactComponentInitialized()\">\n </mj-react-component>\n } @else if (component) {\n <!-- Component spec exists but no code - show informational message -->\n <div class=\"no-code-state\">\n <i class=\"fa-solid fa-file-lines\"></i>\n <h3>Component Specification</h3>\n <p>This component has specifications but no executable code yet.</p>\n <p>View the Functional, Data, or Spec tabs for details.</p>\n </div>\n } @else {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-circle\"></i>\n <h3>No Component Loaded</h3>\n <p>The component data is missing or invalid.</p>\n </div>\n }\n }\n </div>\n\n <!-- Feedback toggle button -->\n @if (resolvedComponentSpec) {\n <button class=\"feedback-toggle-btn\" (click)=\"ToggleFeedbackPanel()\"\n title=\"Rate this component\">\n <i class=\"fa-solid fa-comment-dots\"></i>\n </button>\n }\n\n <!-- Feedback overlay panel -->\n @if (ShowFeedbackPanel && resolvedComponentSpec) {\n <mj-component-feedback-panel\n [ComponentSpec]=\"resolvedComponentSpec\"\n [ReactContainerElement]=\"reactComponent?.container?.nativeElement || null\"\n (Closed)=\"ShowFeedbackPanel = false\">\n </mj-component-feedback-panel>\n }\n</div>\n\n"]}
|
package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { EventEmitter, OnDestroy } from '@angular/core';
|
|
2
|
+
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Flattened tree item for rendering the component hierarchy
|
|
6
|
+
*/
|
|
7
|
+
interface TreeItem {
|
|
8
|
+
spec: ComponentSpec;
|
|
9
|
+
depth: number;
|
|
10
|
+
hasChildren: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Component feedback panel that displays component hierarchy tree
|
|
14
|
+
* and allows users to select components and provide star ratings with comments.
|
|
15
|
+
* Registry-agnostic: works with any component registry (Skip, MJ Central, etc.)
|
|
16
|
+
*/
|
|
17
|
+
export declare class ComponentFeedbackPanelComponent implements OnDestroy {
|
|
18
|
+
ComponentSpec: ComponentSpec | null;
|
|
19
|
+
ReactContainerElement: HTMLElement | null;
|
|
20
|
+
ConversationId: string | null;
|
|
21
|
+
ConversationDetailId: string | null;
|
|
22
|
+
Closed: EventEmitter<void>;
|
|
23
|
+
SelectedSpec: ComponentSpec | null;
|
|
24
|
+
StarRating: number;
|
|
25
|
+
HoverRating: number;
|
|
26
|
+
FeedbackComments: string;
|
|
27
|
+
IsSubmitting: boolean;
|
|
28
|
+
SubmitSuccess: boolean;
|
|
29
|
+
SubmitError: string;
|
|
30
|
+
ExpandedNodes: Set<string>;
|
|
31
|
+
private highlightOverlay;
|
|
32
|
+
private hoverOverlay;
|
|
33
|
+
private resizeObserver;
|
|
34
|
+
private containerClickHandler;
|
|
35
|
+
private cdr;
|
|
36
|
+
GetTreeItems(): TreeItem[];
|
|
37
|
+
private buildTree;
|
|
38
|
+
ToggleNode(spec: ComponentSpec, event: MouseEvent): void;
|
|
39
|
+
IsNodeExpanded(spec: ComponentSpec): boolean;
|
|
40
|
+
SelectComponent(spec: ComponentSpec): void;
|
|
41
|
+
IsSelected(spec: ComponentSpec): boolean;
|
|
42
|
+
GetIndentation(depth: number): string;
|
|
43
|
+
SetRating(stars: number): void;
|
|
44
|
+
SetHoverRating(stars: number): void;
|
|
45
|
+
ClearHoverRating(): void;
|
|
46
|
+
GetDisplayRating(): number;
|
|
47
|
+
IsStarFilled(index: number): boolean;
|
|
48
|
+
ResetForm(): void;
|
|
49
|
+
CanSubmit(): boolean;
|
|
50
|
+
SubmitFeedback(): Promise<void>;
|
|
51
|
+
HoverTreeItem(spec: ComponentSpec): void;
|
|
52
|
+
ClearTreeItemHover(): void;
|
|
53
|
+
private showHoverOverlay;
|
|
54
|
+
private removeHoverOverlay;
|
|
55
|
+
private HighlightComponent;
|
|
56
|
+
private ensureContainerPositioned;
|
|
57
|
+
/**
|
|
58
|
+
* Gets the effective bounding rect for a component marker element.
|
|
59
|
+
* display:contents elements return zero-size rects, so we compute
|
|
60
|
+
* the union bounding box of their children instead.
|
|
61
|
+
*/
|
|
62
|
+
private getEffectiveRect;
|
|
63
|
+
private positionOverlay;
|
|
64
|
+
private installContainerClickListener;
|
|
65
|
+
private removeContainerClickListener;
|
|
66
|
+
private findSpecByName;
|
|
67
|
+
private walkSpecTree;
|
|
68
|
+
private ClearHighlight;
|
|
69
|
+
ClosePanel(): void;
|
|
70
|
+
ngOnDestroy(): void;
|
|
71
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ComponentFeedbackPanelComponent, never>;
|
|
72
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ComponentFeedbackPanelComponent, "mj-component-feedback-panel", never, { "ComponentSpec": { "alias": "ComponentSpec"; "required": false; }; "ReactContainerElement": { "alias": "ReactContainerElement"; "required": false; }; "ConversationId": { "alias": "ConversationId"; "required": false; }; "ConversationDetailId": { "alias": "ConversationDetailId"; "required": false; }; }, { "Closed": "Closed"; }, never, never, true, never>;
|
|
73
|
+
}
|
|
74
|
+
export {};
|
|
75
|
+
//# sourceMappingURL=component-feedback-panel.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-feedback-panel.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,SAAS,EAA6B,MAAM,eAAe,CAAC;AAI7G,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;;AAE5E;;GAEG;AACH,UAAU,QAAQ;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAOa,+BAAgC,YAAW,SAAS;IACtD,aAAa,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC3C,qBAAqB,EAAE,WAAW,GAAG,IAAI,CAAQ;IACjD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C,MAAM,qBAA4B;IAGrC,YAAY,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC1C,UAAU,SAAK;IACf,WAAW,SAAK;IAChB,gBAAgB,SAAM;IACtB,YAAY,UAAS;IACrB,aAAa,UAAS;IACtB,WAAW,SAAM;IAGjB,aAAa,cAAqB;IAGzC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,qBAAqB,CAA0C;IAEvE,OAAO,CAAC,GAAG,CAA6B;IAIxC,YAAY,IAAI,QAAQ,EAAE;IAQ1B,OAAO,CAAC,SAAS;IAcjB,UAAU,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IASxD,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAI5C,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAM1C,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAIxC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAMrC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI9B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC,gBAAgB,IAAI,IAAI;IAIxB,gBAAgB,IAAI,MAAM;IAI1B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMpC,SAAS,IAAI,IAAI;IAQjB,SAAS,IAAI,OAAO;IAId,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CrC,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAKxC,kBAAkB,IAAI,IAAI;IAI1B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,yBAAyB;IAQjC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,6BAA6B;IA0BrC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,cAAc;IAWtB,UAAU,IAAI,IAAI;IAKlB,WAAW,IAAI,IAAI;yCAxWR,+BAA+B;2CAA/B,+BAA+B;CA2W3C"}
|