@memberjunction/ng-skip-chat 2.76.0 → 2.78.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/base-managed-component.d.ts +39 -0
- package/dist/lib/base-managed-component.d.ts.map +1 -0
- package/dist/lib/base-managed-component.js +62 -0
- package/dist/lib/base-managed-component.js.map +1 -0
- package/dist/lib/dynamic-report/base-report.d.ts.map +1 -1
- package/dist/lib/dynamic-report/base-report.js +12 -3
- package/dist/lib/dynamic-report/base-report.js.map +1 -1
- package/dist/lib/dynamic-report/dynamic-ui-component.d.ts +9 -4
- package/dist/lib/dynamic-report/dynamic-ui-component.d.ts.map +1 -1
- package/dist/lib/dynamic-report/dynamic-ui-component.js +71 -480
- package/dist/lib/dynamic-report/dynamic-ui-component.js.map +1 -1
- package/dist/lib/report-cache.d.ts +1 -0
- package/dist/lib/report-cache.d.ts.map +1 -1
- package/dist/lib/report-cache.js +34 -20
- package/dist/lib/report-cache.js.map +1 -1
- package/dist/lib/skip-chat/skip-chat.component.d.ts +2 -2
- package/dist/lib/skip-chat/skip-chat.component.d.ts.map +1 -1
- package/dist/lib/skip-chat/skip-chat.component.js +31 -31
- package/dist/lib/skip-chat/skip-chat.component.js.map +1 -1
- package/package.json +15 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, EventEmitter, Input, Output, ViewChildren, HostListener } from '@angular/core';
|
|
1
|
+
import { Component, EventEmitter, Input, Output, ViewChildren, HostListener, ChangeDetectionStrategy } from '@angular/core';
|
|
2
2
|
import { CompositeKey, LogError, Metadata } from '@memberjunction/core';
|
|
3
3
|
import { BuildComponentCompleteCode } from '@memberjunction/interactive-component-types';
|
|
4
4
|
import { DrillDownInfo } from '../drill-down-info';
|
|
@@ -167,7 +167,7 @@ function SkipDynamicUIComponentComponent_Conditional_0_For_2_ng_template_2_mj_re
|
|
|
167
167
|
} if (rf & 2) {
|
|
168
168
|
const ɵ$index_4_r3 = i0.ɵɵnextContext(2).$index;
|
|
169
169
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
170
|
-
i0.ɵɵproperty("component", ctx_r1.
|
|
170
|
+
i0.ɵɵproperty("component", ctx_r1.reportOptions[ɵ$index_4_r3].option)("data", ctx_r1.getFlattenedDataContext())("state", ctx_r1.userStates.get(ɵ$index_4_r3) || i0.ɵɵpureFunction0(5, _c0))("utilities", ctx_r1.utilities)("styles", ctx_r1.componentStyles || undefined);
|
|
171
171
|
} }
|
|
172
172
|
function SkipDynamicUIComponentComponent_Conditional_0_For_2_ng_template_2_Conditional_26_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
173
173
|
i0.ɵɵelementStart(0, "details", 45)(1, "summary", 51);
|
|
@@ -179,7 +179,7 @@ function SkipDynamicUIComponentComponent_Conditional_0_For_2_ng_template_2_Condi
|
|
|
179
179
|
} if (rf & 2) {
|
|
180
180
|
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
181
181
|
i0.ɵɵadvance(4);
|
|
182
|
-
i0.ɵɵtextInterpolate(ctx_r1.currentError.technicalDetails);
|
|
182
|
+
i0.ɵɵtextInterpolate(ctx_r1.formatTechnicalDetails(ctx_r1.currentError.technicalDetails));
|
|
183
183
|
} }
|
|
184
184
|
function SkipDynamicUIComponentComponent_Conditional_0_For_2_ng_template_2_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
185
185
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
@@ -286,7 +286,7 @@ function SkipDynamicUIComponentComponent_Conditional_0_For_2_ng_template_2_Templ
|
|
|
286
286
|
i0.ɵɵadvance();
|
|
287
287
|
i0.ɵɵattribute("data-tab-index", ɵ$index_4_r3);
|
|
288
288
|
i0.ɵɵadvance();
|
|
289
|
-
i0.ɵɵproperty("ngIf", !ctx_r1.currentError && ctx_r1.
|
|
289
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.currentError && ctx_r1.reportOptions[ɵ$index_4_r3] && ɵ$index_4_r3 === ctx_r1.selectedReportOptionIndex);
|
|
290
290
|
i0.ɵɵadvance();
|
|
291
291
|
i0.ɵɵconditional(ctx_r1.currentError && ctx_r1.selectedReportOptionIndex === ɵ$index_4_r3 ? 26 : -1);
|
|
292
292
|
} }
|
|
@@ -448,7 +448,7 @@ function SkipDynamicUIComponentComponent_Conditional_1_Conditional_24_Conditiona
|
|
|
448
448
|
} if (rf & 2) {
|
|
449
449
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
450
450
|
i0.ɵɵadvance(4);
|
|
451
|
-
i0.ɵɵtextInterpolate(ctx_r1.currentError.technicalDetails);
|
|
451
|
+
i0.ɵɵtextInterpolate(ctx_r1.formatTechnicalDetails(ctx_r1.currentError.technicalDetails));
|
|
452
452
|
} }
|
|
453
453
|
function SkipDynamicUIComponentComponent_Conditional_1_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
454
454
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
@@ -505,7 +505,7 @@ function SkipDynamicUIComponentComponent_Conditional_1_Conditional_25_mj_react_c
|
|
|
505
505
|
i0.ɵɵelementEnd();
|
|
506
506
|
} if (rf & 2) {
|
|
507
507
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
508
|
-
i0.ɵɵproperty("component", ctx_r1.
|
|
508
|
+
i0.ɵɵproperty("component", ctx_r1.reportOptions[0].option)("data", ctx_r1.getFlattenedDataContext())("state", ctx_r1.userStates.get(0) || i0.ɵɵpureFunction0(5, _c0))("utilities", ctx_r1.utilities)("styles", ctx_r1.componentStyles || undefined);
|
|
509
509
|
} }
|
|
510
510
|
function SkipDynamicUIComponentComponent_Conditional_1_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
511
511
|
i0.ɵɵelementStart(0, "div", 21);
|
|
@@ -514,7 +514,7 @@ function SkipDynamicUIComponentComponent_Conditional_1_Conditional_25_Template(r
|
|
|
514
514
|
} if (rf & 2) {
|
|
515
515
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
516
516
|
i0.ɵɵadvance();
|
|
517
|
-
i0.ɵɵproperty("ngIf", ctx_r1.
|
|
517
|
+
i0.ɵɵproperty("ngIf", ctx_r1.reportOptions[0]);
|
|
518
518
|
} }
|
|
519
519
|
function SkipDynamicUIComponentComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
520
520
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
@@ -598,11 +598,13 @@ export class SkipDynamicUIComponentComponent {
|
|
|
598
598
|
isResizing = false;
|
|
599
599
|
startY = 0;
|
|
600
600
|
startHeight = 0;
|
|
601
|
-
// Cache for component specs
|
|
602
|
-
componentSpecs = new Map();
|
|
601
|
+
// Cache for user states only - component specs come from data
|
|
603
602
|
userStates = new Map();
|
|
604
603
|
utilities = null;
|
|
605
604
|
componentStyles = null;
|
|
605
|
+
// Memoized flattened data context to prevent ExpressionChangedAfterItHasBeenCheckedError
|
|
606
|
+
_flattenedDataContext = null;
|
|
607
|
+
_lastDataContextHash = null;
|
|
606
608
|
// Event handlers from React components
|
|
607
609
|
static librariesInitialized = false;
|
|
608
610
|
constructor(sanitizer, cdr, ngZone, adapter) {
|
|
@@ -665,12 +667,9 @@ export class SkipDynamicUIComponentComponent {
|
|
|
665
667
|
// Update the component info - this can fail if placeholders are missing
|
|
666
668
|
this.UIComponentCode = BuildComponentCompleteCode(selectedOption.option);
|
|
667
669
|
this.ComponentObjectName = selectedOption.option.name;
|
|
668
|
-
//
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
// Trigger change detection after modifying componentSpecs
|
|
672
|
-
this.cdr.detectChanges();
|
|
673
|
-
}
|
|
670
|
+
// No need to cache component specs - they come from the data
|
|
671
|
+
// Just trigger change detection to render the new component
|
|
672
|
+
this.cdr.detectChanges();
|
|
674
673
|
}
|
|
675
674
|
catch (error) {
|
|
676
675
|
console.error('Failed to build component code:', error);
|
|
@@ -735,8 +734,8 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
735
734
|
retryCurrentOption() {
|
|
736
735
|
// Clear the error
|
|
737
736
|
this.currentError = null;
|
|
738
|
-
//
|
|
739
|
-
|
|
737
|
+
// Just clear the error and re-render
|
|
738
|
+
// Component spec comes from reportOptions data
|
|
740
739
|
// Trigger change detection
|
|
741
740
|
this.cdr.detectChanges();
|
|
742
741
|
}
|
|
@@ -937,25 +936,33 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
937
936
|
const runtimeUtils = createRuntimeUtilities();
|
|
938
937
|
this.utilities = runtimeUtils.buildUtilities();
|
|
939
938
|
this.componentStyles = SetupStyles();
|
|
940
|
-
//
|
|
939
|
+
// Initialize user states for all options
|
|
941
940
|
// Use Promise.resolve to avoid ExpressionChangedAfterItHasBeenCheckedError
|
|
942
941
|
if (this.reportOptions.length > 0) {
|
|
943
942
|
Promise.resolve().then(() => {
|
|
944
943
|
this.reportOptions.forEach((_, index) => {
|
|
945
|
-
this.
|
|
944
|
+
if (!this.userStates.has(index)) {
|
|
945
|
+
this.userStates.set(index, {});
|
|
946
|
+
}
|
|
946
947
|
});
|
|
947
948
|
this.cdr.detectChanges();
|
|
948
949
|
});
|
|
949
950
|
}
|
|
950
951
|
}
|
|
951
952
|
ngOnDestroy() {
|
|
952
|
-
// Clean up
|
|
953
|
-
this.componentSpecs.clear();
|
|
953
|
+
// Clean up user states
|
|
954
954
|
this.userStates.clear();
|
|
955
|
+
// Ensure resize listeners are removed if still active
|
|
956
|
+
if (this.isResizing) {
|
|
957
|
+
this.stopResize();
|
|
958
|
+
}
|
|
955
959
|
// The MJReactComponent handles its own cleanup
|
|
956
960
|
}
|
|
957
961
|
ngOnChanges(changes) {
|
|
958
962
|
if (changes['SkipData']) {
|
|
963
|
+
// Clear cached data context when SkipData changes
|
|
964
|
+
this._flattenedDataContext = null;
|
|
965
|
+
this._lastDataContextHash = null;
|
|
959
966
|
const skipData = changes['SkipData'].currentValue;
|
|
960
967
|
if (skipData) {
|
|
961
968
|
this.setupReportOptions(skipData);
|
|
@@ -1020,33 +1027,12 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1020
1027
|
}
|
|
1021
1028
|
}
|
|
1022
1029
|
/**
|
|
1023
|
-
*
|
|
1030
|
+
* Initialize user state for a specific option index
|
|
1024
1031
|
*/
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
if (!
|
|
1028
|
-
|
|
1029
|
-
try {
|
|
1030
|
-
const component = option.option;
|
|
1031
|
-
// Store the component spec
|
|
1032
|
-
this.componentSpecs.set(optionIndex, component);
|
|
1033
|
-
// Initialize user state if not exists
|
|
1034
|
-
if (!this.userStates.has(optionIndex)) {
|
|
1035
|
-
this.userStates.set(optionIndex, {});
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
catch (e) {
|
|
1039
|
-
console.error('Error creating component spec:', e);
|
|
1040
|
-
// Determine the type of error and create a user-friendly message
|
|
1041
|
-
let errorType = 'Component Specification Error';
|
|
1042
|
-
let errorMessage = 'Failed to create component specification.';
|
|
1043
|
-
let technicalDetails = e.toString();
|
|
1044
|
-
this.currentError = {
|
|
1045
|
-
type: errorType,
|
|
1046
|
-
message: errorMessage,
|
|
1047
|
-
technicalDetails: technicalDetails + '\n\nComponent Option: ' + (optionIndex + 1) + '\nComponent Name: ' + option.option.name
|
|
1048
|
-
};
|
|
1049
|
-
LogError(e);
|
|
1032
|
+
initializeUserStateForOption(optionIndex) {
|
|
1033
|
+
// Initialize user state if not exists
|
|
1034
|
+
if (!this.userStates.has(optionIndex)) {
|
|
1035
|
+
this.userStates.set(optionIndex, {});
|
|
1050
1036
|
}
|
|
1051
1037
|
}
|
|
1052
1038
|
/**
|
|
@@ -1069,7 +1055,7 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1069
1055
|
this.currentError = {
|
|
1070
1056
|
type: event.payload.source || 'React Component Error',
|
|
1071
1057
|
message: event.payload.error || 'An unknown error occurred',
|
|
1072
|
-
technicalDetails: event.payload.errorInfo
|
|
1058
|
+
technicalDetails: event.payload.errorInfo
|
|
1073
1059
|
};
|
|
1074
1060
|
}
|
|
1075
1061
|
else {
|
|
@@ -1083,6 +1069,17 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1083
1069
|
this.handleOpenEntityRecord(event.entityName, event.key);
|
|
1084
1070
|
}
|
|
1085
1071
|
getFlattenedDataContext() {
|
|
1072
|
+
// Create a simple hash of the data context to detect changes
|
|
1073
|
+
let currentHash = '';
|
|
1074
|
+
if (this.SkipData?.dataContext) {
|
|
1075
|
+
const loadedItems = this.SkipData.dataContext.Items.filter((i) => i.DataLoaded && i._Data?.length > 0);
|
|
1076
|
+
currentHash = loadedItems.map((item) => `${item.ID}_${item._Data?.length || 0}`).join('_');
|
|
1077
|
+
}
|
|
1078
|
+
// Check if we need to recalculate (data changed)
|
|
1079
|
+
if (this._flattenedDataContext && this._lastDataContextHash === currentHash) {
|
|
1080
|
+
return this._flattenedDataContext;
|
|
1081
|
+
}
|
|
1082
|
+
// Recalculate and cache
|
|
1086
1083
|
const flattenedDataContext = {};
|
|
1087
1084
|
if (this.SkipData?.dataContext) {
|
|
1088
1085
|
const loadedItems = this.SkipData.dataContext.Items.filter((i) => i.DataLoaded && i._Data?.length > 0);
|
|
@@ -1090,7 +1087,9 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1090
1087
|
flattenedDataContext["data_item_" + i] = loadedItems[i]._Data;
|
|
1091
1088
|
}
|
|
1092
1089
|
}
|
|
1093
|
-
|
|
1090
|
+
this._flattenedDataContext = flattenedDataContext;
|
|
1091
|
+
this._lastDataContextHash = currentHash;
|
|
1092
|
+
return this._flattenedDataContext;
|
|
1094
1093
|
}
|
|
1095
1094
|
// Event handler implementations
|
|
1096
1095
|
handleRefreshData() {
|
|
@@ -1132,7 +1131,7 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1132
1131
|
this.currentError = {
|
|
1133
1132
|
type: eventData.source || 'React Component Error',
|
|
1134
1133
|
message: eventData.error || 'An unknown error occurred in the React component',
|
|
1135
|
-
technicalDetails: eventData.stackTrace || eventData.errorInfo?.componentStack ||
|
|
1134
|
+
technicalDetails: eventData.stackTrace || eventData.errorInfo?.componentStack || eventData.errorInfo || null
|
|
1136
1135
|
};
|
|
1137
1136
|
}
|
|
1138
1137
|
// TODO: Handle other custom events as needed
|
|
@@ -1143,6 +1142,25 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1143
1142
|
currentComponent.refresh(data);
|
|
1144
1143
|
}
|
|
1145
1144
|
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Format technical details for display, handling both strings and objects
|
|
1147
|
+
*/
|
|
1148
|
+
formatTechnicalDetails(details) {
|
|
1149
|
+
if (!details) {
|
|
1150
|
+
return 'No technical details available';
|
|
1151
|
+
}
|
|
1152
|
+
if (typeof details === 'string') {
|
|
1153
|
+
return details;
|
|
1154
|
+
}
|
|
1155
|
+
// If it's an object, pretty-print it as JSON
|
|
1156
|
+
try {
|
|
1157
|
+
return JSON.stringify(details, null, 2);
|
|
1158
|
+
}
|
|
1159
|
+
catch (e) {
|
|
1160
|
+
// Fallback for circular references or other JSON issues
|
|
1161
|
+
return String(details);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1146
1164
|
static ɵfac = function SkipDynamicUIComponentComponent_Factory(t) { return new (t || SkipDynamicUIComponentComponent)(i0.ɵɵdirectiveInject(i1.DomSanitizer), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.NgZone), i0.ɵɵdirectiveInject(i2.AngularAdapterService)); };
|
|
1147
1165
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SkipDynamicUIComponentComponent, selectors: [["skip-dynamic-ui-component"]], viewQuery: function SkipDynamicUIComponentComponent_Query(rf, ctx) { if (rf & 1) {
|
|
1148
1166
|
i0.ɵɵviewQuery(MJReactComponent, 5);
|
|
@@ -1155,438 +1173,11 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1155
1173
|
i0.ɵɵtemplate(0, SkipDynamicUIComponentComponent_Conditional_0_Template, 3, 1, "kendo-tabstrip", 0)(1, SkipDynamicUIComponentComponent_Conditional_1_Template, 26, 12, "div", 1);
|
|
1156
1174
|
} if (rf & 2) {
|
|
1157
1175
|
i0.ɵɵconditional(ctx.reportOptions.length > 1 ? 0 : 1);
|
|
1158
|
-
} }, dependencies: [i3.NgIf, i4.TabStripComponent, i4.TabStripTabComponent, i4.TabContentDirective, i4.TabTitleDirective, i5.ButtonComponent, i6.CodeEditorComponent, i2.MJReactComponent], styles: ["[_nghost-%COMP%] {\n
|
|
1176
|
+
} }, dependencies: [i3.NgIf, i4.TabStripComponent, i4.TabStripTabComponent, i4.TabContentDirective, i4.TabTitleDirective, i5.ButtonComponent, i6.CodeEditorComponent, i2.MJReactComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n position: relative;\n}\n\n\n\n.tab-action-bar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background-color: #fafafa;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.tab-actions-left[_ngcontent-%COMP%], \n.tab-actions-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n\n\n.tab-action-button[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n background-color: transparent;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: #333;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.tab-action-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n}\n\n.tab-action-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.tab-action-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.tab-action-button.create-button[_ngcontent-%COMP%], \n.tab-action-button.print-button[_ngcontent-%COMP%] {\n background-color: white;\n color: #333;\n border-color: #e0e0e0;\n}\n\n.tab-action-button.create-button[_ngcontent-%COMP%]:hover:not(:disabled), \n.tab-action-button.print-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n}\n\n\n\n.tab-action-button.toggle-button[_ngcontent-%COMP%] {\n background-color: white;\n color: #666;\n border-color: #e0e0e0;\n}\n\n.tab-action-button.toggle-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n color: #333;\n}\n\n.tab-action-button.toggle-button.active[_ngcontent-%COMP%] {\n background-color: #5B4FE9;\n color: white;\n border-color: #5B4FE9;\n}\n\n.tab-action-button.toggle-button.active[_ngcontent-%COMP%]:hover:not(:disabled) {\n background-color: #4940D4;\n border-color: #4940D4;\n}\n\n\n\n.details-panel[_ngcontent-%COMP%] {\n border-bottom: 1px solid #e0e0e0;\n background-color: #fafafa;\n overflow: hidden;\n transition: height 0.3s ease;\n}\n\n.details-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n height: 100%;\n font-size: 14px;\n line-height: 1.6;\n}\n\n.details-content.code-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n.panel-resizer[_ngcontent-%COMP%] {\n height: 4px;\n background-color: #e0e0e0;\n cursor: ns-resize;\n position: relative;\n transition: background-color 0.2s ease;\n}\n\n.panel-resizer[_ngcontent-%COMP%]:hover {\n background-color: #d0d0d0;\n}\n\n.resizer-handle[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 2px;\n background-color: #999;\n border-radius: 1px;\n}\n\n\n\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(h1) { font-size: 1.5em; margin-top: 0; margin-bottom: 0.5em; }\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(h2) { font-size: 1.3em; margin-top: 1em; margin-bottom: 0.5em; }\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(h3) { font-size: 1.1em; margin-top: 1em; margin-bottom: 0.5em; }\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(ul), .details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(ol) { margin-left: 1.5em; }\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(code) { \n background-color: #f4f4f4; \n padding: 2px 4px; \n border-radius: 3px; \n font-family: 'Courier New', monospace; \n font-size: 0.9em;\n}\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(pre) { \n background-color: #f4f4f4; \n padding: 12px; \n border-radius: 4px; \n overflow-x: auto; \n}\n.details-content[_ngcontent-%COMP%] [_ngcontent-%COMP%]:deep(blockquote) { \n border-left: 4px solid #e0e0e0; \n padding-left: 16px; \n margin-left: 0; \n color: #666; \n}\n\n\n\n .k-tabstrip {\n border: none;\n height: 100%;\n display: flex;\n flex-direction: column;\n margin: 10px 5px 5px 5px;\n}\n\n .k-tabstrip-items {\n background: #f8f9fa;\n border: none;\n border-radius: 8px 8px 0 0;\n flex: 0 0 auto;\n padding: 8px 12px 0 12px;\n gap: 4px;\n display: flex;\n}\n\n .k-tabstrip-items-wrapper {\n height: 100%;\n}\n\n .k-content {\n flex: 1;\n overflow: hidden;\n padding: 0;\n background: white;\n border: 1px solid #e0e0e0;\n border-top: none;\n border-radius: 0 0 8px 8px;\n}\n\n .k-tabstrip .k-item {\n margin-right: 2px;\n border: none;\n background: transparent;\n border-radius: 6px 6px 0 0;\n padding: 2px;\n transition: all 0.2s ease;\n}\n\n .k-tabstrip .k-item.k-selected {\n background: white;\n border: 1px solid #e0e0e0;\n border-bottom: 1px solid white;\n margin-bottom: -1px;\n z-index: 1;\n}\n\n .k-tabstrip .k-link {\n padding: 8px 16px;\n font-weight: 500;\n font-size: 13px;\n color: #666;\n transition: all 0.15s ease;\n border-radius: 4px 4px 0 0;\n background: transparent;\n border: none;\n text-transform: lowercase;\n}\n\n .k-tabstrip .k-link:first-letter {\n text-transform: uppercase;\n}\n\n .k-tabstrip .k-item:hover:not(.k-selected) .k-link {\n color: #333;\n background: rgba(0, 0, 0, 0.04);\n}\n\n .k-tabstrip .k-item.k-selected .k-link {\n color: #1976d2;\n font-weight: 600;\n background: white;\n}\n\n\n\n .k-tabstrip .k-link .star-icon {\n display: inline-block;\n margin-right: 4px;\n color: #ffd700;\n font-size: 12px;\n vertical-align: middle;\n}\n\n\n\n .k-tabstrip-items::before, \n .k-tabstrip-items::after {\n display: none;\n}\n\n .k-tabstrip .k-item::before, \n .k-tabstrip .k-item::after {\n display: none;\n}\n\n\n\n .k-tabstrip .k-link:focus {\n outline: none;\n box-shadow: none;\n}\n\n\n\n .k-tabstrip .k-content.k-state-active {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n\n\n.react-host-container[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}"], changeDetection: 0 });
|
|
1159
1177
|
}
|
|
1160
1178
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SkipDynamicUIComponentComponent, [{
|
|
1161
1179
|
type: Component,
|
|
1162
|
-
args: [{ selector: 'skip-dynamic-ui-component', template: `
|
|
1163
|
-
@if (reportOptions.length > 1) {
|
|
1164
|
-
<!-- Multiple options: show tabs -->
|
|
1165
|
-
<kendo-tabstrip
|
|
1166
|
-
(tabSelect)="onTabSelect($event)"
|
|
1167
|
-
[keepTabContent]="true"
|
|
1168
|
-
style="height: 100%; display: flex; flex-direction: column;">
|
|
1169
|
-
@for (option of reportOptions; track option; let i = $index) {
|
|
1170
|
-
<kendo-tabstrip-tab [selected]="i === selectedReportOptionIndex">
|
|
1171
|
-
<ng-template kendoTabTitle>
|
|
1172
|
-
@if (isTopRanked(i)) {
|
|
1173
|
-
<i class="fa-solid fa-star star-icon"></i>
|
|
1174
|
-
}
|
|
1175
|
-
{{ getTabTitle(i) }}
|
|
1176
|
-
</ng-template>
|
|
1177
|
-
<ng-template kendoTabContent>
|
|
1178
|
-
<div style="height: 100%; display: flex; flex-direction: column;">
|
|
1179
|
-
<!-- Tab Action Bar -->
|
|
1180
|
-
<div class="tab-action-bar">
|
|
1181
|
-
<div class="tab-actions-left">
|
|
1182
|
-
<!-- Toggle buttons for showing/hiding component details -->
|
|
1183
|
-
<button class="tab-action-button toggle-button"
|
|
1184
|
-
(click)="toggleShowFunctionalRequirements()"
|
|
1185
|
-
[class.active]="showFunctionalRequirements"
|
|
1186
|
-
title="Toggle Functional Requirements">
|
|
1187
|
-
<i class="fa-solid fa-list-check"></i>
|
|
1188
|
-
<span>Functional</span>
|
|
1189
|
-
</button>
|
|
1190
|
-
<button class="tab-action-button toggle-button"
|
|
1191
|
-
(click)="toggleShowDataRequirements()"
|
|
1192
|
-
[class.active]="showDataRequirements"
|
|
1193
|
-
title="Toggle Data Requirements">
|
|
1194
|
-
<i class="fa-solid fa-database"></i>
|
|
1195
|
-
<span>Data</span>
|
|
1196
|
-
</button>
|
|
1197
|
-
<button class="tab-action-button toggle-button"
|
|
1198
|
-
(click)="toggleShowTechnicalDesign()"
|
|
1199
|
-
[class.active]="showTechnicalDesign"
|
|
1200
|
-
title="Toggle Technical Design">
|
|
1201
|
-
<i class="fa-solid fa-cogs"></i>
|
|
1202
|
-
<span>Technical</span>
|
|
1203
|
-
</button>
|
|
1204
|
-
<button class="tab-action-button toggle-button"
|
|
1205
|
-
(click)="toggleShowCode()"
|
|
1206
|
-
[class.active]="showCode"
|
|
1207
|
-
title="Toggle Code View">
|
|
1208
|
-
<i class="fa-solid fa-code"></i>
|
|
1209
|
-
<span>Code</span>
|
|
1210
|
-
</button>
|
|
1211
|
-
</div>
|
|
1212
|
-
<div class="tab-actions-right">
|
|
1213
|
-
<button class="tab-action-button create-button"
|
|
1214
|
-
*ngIf="ShowCreateReportButton && !matchingReportID"
|
|
1215
|
-
(click)="createReportForOption(i)"
|
|
1216
|
-
[disabled]="isCreatingReport">
|
|
1217
|
-
<i class="fa-solid fa-plus"></i>
|
|
1218
|
-
<span>Create {{ getComponentTypeName(option) }}</span>
|
|
1219
|
-
</button>
|
|
1220
|
-
<button class="tab-action-button print-button"
|
|
1221
|
-
*ngIf="ShowPrintReport"
|
|
1222
|
-
(click)="PrintReport()"
|
|
1223
|
-
title="Print Report">
|
|
1224
|
-
<i class="fa-solid fa-print"></i>
|
|
1225
|
-
<span>Print Report</span>
|
|
1226
|
-
</button>
|
|
1227
|
-
</div>
|
|
1228
|
-
</div>
|
|
1229
|
-
|
|
1230
|
-
<!-- Main content area with optional details panels -->
|
|
1231
|
-
<div style="flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden;">
|
|
1232
|
-
@if (showFunctionalRequirements || showDataRequirements || showTechnicalDesign || showCode) {
|
|
1233
|
-
<!-- Details panel -->
|
|
1234
|
-
<div class="details-panel" [style.height]="detailsPanelHeight">
|
|
1235
|
-
<kendo-tabstrip style="height: 100%;">
|
|
1236
|
-
@if (showFunctionalRequirements) {
|
|
1237
|
-
<kendo-tabstrip-tab [selected]="true">
|
|
1238
|
-
<ng-template kendoTabTitle>
|
|
1239
|
-
<i class="fa-solid fa-list-check"></i> Functional Requirements
|
|
1240
|
-
</ng-template>
|
|
1241
|
-
<ng-template kendoTabContent>
|
|
1242
|
-
<div class="details-content">
|
|
1243
|
-
<div [innerHTML]="getFormattedFunctionalRequirements(option)"></div>
|
|
1244
|
-
</div>
|
|
1245
|
-
</ng-template>
|
|
1246
|
-
</kendo-tabstrip-tab>
|
|
1247
|
-
}
|
|
1248
|
-
@if (showDataRequirements) {
|
|
1249
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements">
|
|
1250
|
-
<ng-template kendoTabTitle>
|
|
1251
|
-
<i class="fa-solid fa-database"></i> Data Requirements
|
|
1252
|
-
</ng-template>
|
|
1253
|
-
<ng-template kendoTabContent>
|
|
1254
|
-
<div class="details-content">
|
|
1255
|
-
<div [innerHTML]="getFormattedDataRequirements(option)"></div>
|
|
1256
|
-
</div>
|
|
1257
|
-
</ng-template>
|
|
1258
|
-
</kendo-tabstrip-tab>
|
|
1259
|
-
}
|
|
1260
|
-
@if (showTechnicalDesign) {
|
|
1261
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements && !showDataRequirements">
|
|
1262
|
-
<ng-template kendoTabTitle>
|
|
1263
|
-
<i class="fa-solid fa-cogs"></i> Technical Design
|
|
1264
|
-
</ng-template>
|
|
1265
|
-
<ng-template kendoTabContent>
|
|
1266
|
-
<div class="details-content">
|
|
1267
|
-
<div [innerHTML]="getFormattedTechnicalDesign(option)"></div>
|
|
1268
|
-
</div>
|
|
1269
|
-
</ng-template>
|
|
1270
|
-
</kendo-tabstrip-tab>
|
|
1271
|
-
}
|
|
1272
|
-
@if (showCode) {
|
|
1273
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements && !showDataRequirements && !showTechnicalDesign">
|
|
1274
|
-
<ng-template kendoTabTitle>
|
|
1275
|
-
<i class="fa-solid fa-code"></i> Code
|
|
1276
|
-
</ng-template>
|
|
1277
|
-
<ng-template kendoTabContent>
|
|
1278
|
-
<div class="details-content code-content">
|
|
1279
|
-
<mj-code-editor
|
|
1280
|
-
[value]="getComponentCode(option)"
|
|
1281
|
-
[language]="'javascript'"
|
|
1282
|
-
[autoFocus]="false"
|
|
1283
|
-
[indentWithTab]="true"
|
|
1284
|
-
[readonly]="true"
|
|
1285
|
-
style="height: 100%;">
|
|
1286
|
-
</mj-code-editor>
|
|
1287
|
-
</div>
|
|
1288
|
-
</ng-template>
|
|
1289
|
-
</kendo-tabstrip-tab>
|
|
1290
|
-
}
|
|
1291
|
-
</kendo-tabstrip>
|
|
1292
|
-
</div>
|
|
1293
|
-
<!-- Resizer -->
|
|
1294
|
-
<div class="panel-resizer"
|
|
1295
|
-
(mousedown)="startResize($event)"
|
|
1296
|
-
(touchstart)="startResize($event)">
|
|
1297
|
-
<div class="resizer-handle"></div>
|
|
1298
|
-
</div>
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
<!-- React component container -->
|
|
1302
|
-
<div [attr.data-tab-index]="i"
|
|
1303
|
-
style="flex: 1; position: relative; min-height: 0; overflow: auto;">
|
|
1304
|
-
<mj-react-component
|
|
1305
|
-
*ngIf="!currentError && componentSpecs.has(i)"
|
|
1306
|
-
[component]="componentSpecs.get(i)!"
|
|
1307
|
-
[data]="getFlattenedDataContext()"
|
|
1308
|
-
[state]="userStates.get(i) || {}"
|
|
1309
|
-
[utilities]="utilities"
|
|
1310
|
-
[styles]="componentStyles || undefined"
|
|
1311
|
-
(stateChange)="onStateChange(i, $event)"
|
|
1312
|
-
(componentEvent)="onComponentEvent(i, $event)"
|
|
1313
|
-
(refreshData)="handleRefreshData()"
|
|
1314
|
-
(openEntityRecord)="onOpenEntityRecord($event)"
|
|
1315
|
-
style="width: 100%; height: 100%;">
|
|
1316
|
-
</mj-react-component>
|
|
1317
|
-
|
|
1318
|
-
<!-- Error overlay for this tab (shown on top of content when needed) -->
|
|
1319
|
-
@if (currentError && selectedReportOptionIndex === i) {
|
|
1320
|
-
<div style="top: 0;
|
|
1321
|
-
left: 0;
|
|
1322
|
-
right: 0;
|
|
1323
|
-
bottom: 0;
|
|
1324
|
-
display: flex;
|
|
1325
|
-
align-items: flex-start;
|
|
1326
|
-
justify-content: center;
|
|
1327
|
-
padding-top: 20px;
|
|
1328
|
-
background: rgba(255, 255, 255, 0.95);
|
|
1329
|
-
z-index: 10;">
|
|
1330
|
-
<div style="width: 90%;
|
|
1331
|
-
max-width: 600px;
|
|
1332
|
-
height: 500px;
|
|
1333
|
-
background-color: #f8f9fa;
|
|
1334
|
-
border: 2px solid #dc3545;
|
|
1335
|
-
border-radius: 8px;
|
|
1336
|
-
padding: 20px;
|
|
1337
|
-
overflow-y: auto;
|
|
1338
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
|
1339
|
-
<div style="position: relative;">
|
|
1340
|
-
<button kendoButton (click)="copyErrorToClipboard()"
|
|
1341
|
-
style="position: absolute; top: 0; right: 0; font-size: 12px;">
|
|
1342
|
-
<span class="fa-solid fa-copy"></span>
|
|
1343
|
-
Copy Error Details
|
|
1344
|
-
</button>
|
|
1345
|
-
<h3 style="color: #dc3545; margin-top: 0; margin-right: 150px; font-size: 18px;">
|
|
1346
|
-
<span class="fa-solid fa-exclamation-triangle"></span>
|
|
1347
|
-
Component Rendering Error
|
|
1348
|
-
</h3>
|
|
1349
|
-
</div>
|
|
1350
|
-
<p style="margin-bottom: 10px; font-size: 14px;">
|
|
1351
|
-
The selected component option could not be rendered due to the following error:
|
|
1352
|
-
</p>
|
|
1353
|
-
<div style="background-color: #fff; border: 1px solid #dee2e6;
|
|
1354
|
-
border-radius: 4px; padding: 12px; margin-bottom: 12px;
|
|
1355
|
-
font-family: 'Courier New', monospace; font-size: 12px;">
|
|
1356
|
-
<strong>Error Type:</strong> {{ currentError.type }}<br>
|
|
1357
|
-
<strong>Details:</strong> {{ currentError.message }}
|
|
1358
|
-
@if (currentError.technicalDetails) {
|
|
1359
|
-
<details style="margin-top: 8px;">
|
|
1360
|
-
<summary style="cursor: pointer; color: #0056b3;">Technical Details (click to expand)</summary>
|
|
1361
|
-
<pre style="margin-top: 8px; white-space: pre-wrap; word-break: break-word; font-size: 11px;">{{ currentError.technicalDetails }}</pre>
|
|
1362
|
-
</details>
|
|
1363
|
-
}
|
|
1364
|
-
</div>
|
|
1365
|
-
<div style="background-color: #e7f3ff; border: 1px solid #b3d9ff;
|
|
1366
|
-
border-radius: 4px; padding: 12px; margin-bottom: 12px;">
|
|
1367
|
-
<strong style="font-size: 14px;">What to do:</strong>
|
|
1368
|
-
<ol style="margin: 8px 0 0 20px; padding: 0; font-size: 13px;">
|
|
1369
|
-
<li>Try selecting a different report option from the tabs above</li>
|
|
1370
|
-
<li>Copy the error details and send them back to Skip in the chat to get a corrected version</li>
|
|
1371
|
-
<li>Contact your IT department if the issue persists</li>
|
|
1372
|
-
</ol>
|
|
1373
|
-
</div>
|
|
1374
|
-
<button kendoButton (click)="retryCurrentOption()" style="font-size: 13px;">
|
|
1375
|
-
<span class="fa-solid fa-rotate"></span>
|
|
1376
|
-
Retry
|
|
1377
|
-
</button>
|
|
1378
|
-
</div>
|
|
1379
|
-
</div>
|
|
1380
|
-
}
|
|
1381
|
-
</div>
|
|
1382
|
-
</div>
|
|
1383
|
-
</div>
|
|
1384
|
-
</ng-template>
|
|
1385
|
-
</kendo-tabstrip-tab>
|
|
1386
|
-
}
|
|
1387
|
-
</kendo-tabstrip>
|
|
1388
|
-
} @else {
|
|
1389
|
-
<!-- Single option: no tabs needed -->
|
|
1390
|
-
<div style="height: 100%; display: flex; flex-direction: column;">
|
|
1391
|
-
<!-- Tab Action Bar -->
|
|
1392
|
-
<div class="tab-action-bar">
|
|
1393
|
-
<div class="tab-actions-left">
|
|
1394
|
-
<!-- Toggle buttons for showing/hiding component details -->
|
|
1395
|
-
<button class="tab-action-button toggle-button"
|
|
1396
|
-
(click)="toggleShowFunctionalRequirements()"
|
|
1397
|
-
[class.active]="showFunctionalRequirements"
|
|
1398
|
-
title="Toggle Functional Requirements">
|
|
1399
|
-
<i class="fa-solid fa-list-check"></i>
|
|
1400
|
-
<span>Functional</span>
|
|
1401
|
-
</button>
|
|
1402
|
-
<button class="tab-action-button toggle-button"
|
|
1403
|
-
(click)="toggleShowDataRequirements()"
|
|
1404
|
-
[class.active]="showDataRequirements"
|
|
1405
|
-
title="Toggle Data Requirements">
|
|
1406
|
-
<i class="fa-solid fa-database"></i>
|
|
1407
|
-
<span>Data</span>
|
|
1408
|
-
</button>
|
|
1409
|
-
<button class="tab-action-button toggle-button"
|
|
1410
|
-
(click)="toggleShowTechnicalDesign()"
|
|
1411
|
-
[class.active]="showTechnicalDesign"
|
|
1412
|
-
title="Toggle Technical Design">
|
|
1413
|
-
<i class="fa-solid fa-cogs"></i>
|
|
1414
|
-
<span>Technical</span>
|
|
1415
|
-
</button>
|
|
1416
|
-
<button class="tab-action-button toggle-button"
|
|
1417
|
-
(click)="toggleShowCode()"
|
|
1418
|
-
[class.active]="showCode"
|
|
1419
|
-
title="Toggle Code View">
|
|
1420
|
-
<i class="fa-solid fa-code"></i>
|
|
1421
|
-
<span>Code</span>
|
|
1422
|
-
</button>
|
|
1423
|
-
</div>
|
|
1424
|
-
<div class="tab-actions-right">
|
|
1425
|
-
<button class="tab-action-button create-button"
|
|
1426
|
-
*ngIf="ShowCreateReportButton && !matchingReportID"
|
|
1427
|
-
(click)="createReportForOption(0)"
|
|
1428
|
-
[disabled]="isCreatingReport">
|
|
1429
|
-
<i class="fa-solid fa-plus"></i>
|
|
1430
|
-
<span>Create {{ firstOptionComponentTypeName }}</span>
|
|
1431
|
-
</button>
|
|
1432
|
-
<button class="tab-action-button print-button"
|
|
1433
|
-
*ngIf="ShowPrintReport"
|
|
1434
|
-
(click)="PrintReport()"
|
|
1435
|
-
title="Print Report">
|
|
1436
|
-
<i class="fa-solid fa-print"></i>
|
|
1437
|
-
<span>Print Report</span>
|
|
1438
|
-
</button>
|
|
1439
|
-
</div>
|
|
1440
|
-
</div>
|
|
1441
|
-
|
|
1442
|
-
<!-- Main content area with optional details panels -->
|
|
1443
|
-
<div style="flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden;">
|
|
1444
|
-
@if (showFunctionalRequirements || showDataRequirements || showTechnicalDesign || showCode) {
|
|
1445
|
-
<!-- Details panel -->
|
|
1446
|
-
<div class="details-panel" [style.height]="detailsPanelHeight">
|
|
1447
|
-
<kendo-tabstrip style="height: 100%;">
|
|
1448
|
-
@if (showFunctionalRequirements && reportOptions[0]) {
|
|
1449
|
-
<kendo-tabstrip-tab [selected]="true">
|
|
1450
|
-
<ng-template kendoTabTitle>
|
|
1451
|
-
<i class="fa-solid fa-list-check"></i> Functional Requirements
|
|
1452
|
-
</ng-template>
|
|
1453
|
-
<ng-template kendoTabContent>
|
|
1454
|
-
<div class="details-content">
|
|
1455
|
-
<div [innerHTML]="getFormattedFunctionalRequirements(reportOptions[0])"></div>
|
|
1456
|
-
</div>
|
|
1457
|
-
</ng-template>
|
|
1458
|
-
</kendo-tabstrip-tab>
|
|
1459
|
-
}
|
|
1460
|
-
@if (showDataRequirements && reportOptions[0]) {
|
|
1461
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements">
|
|
1462
|
-
<ng-template kendoTabTitle>
|
|
1463
|
-
<i class="fa-solid fa-database"></i> Data Requirements
|
|
1464
|
-
</ng-template>
|
|
1465
|
-
<ng-template kendoTabContent>
|
|
1466
|
-
<div class="details-content">
|
|
1467
|
-
<div [innerHTML]="getFormattedDataRequirements(reportOptions[0])"></div>
|
|
1468
|
-
</div>
|
|
1469
|
-
</ng-template>
|
|
1470
|
-
</kendo-tabstrip-tab>
|
|
1471
|
-
}
|
|
1472
|
-
@if (showTechnicalDesign && reportOptions[0]) {
|
|
1473
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements && !showDataRequirements">
|
|
1474
|
-
<ng-template kendoTabTitle>
|
|
1475
|
-
<i class="fa-solid fa-cogs"></i> Technical Design
|
|
1476
|
-
</ng-template>
|
|
1477
|
-
<ng-template kendoTabContent>
|
|
1478
|
-
<div class="details-content">
|
|
1479
|
-
<div [innerHTML]="getFormattedTechnicalDesign(reportOptions[0])"></div>
|
|
1480
|
-
</div>
|
|
1481
|
-
</ng-template>
|
|
1482
|
-
</kendo-tabstrip-tab>
|
|
1483
|
-
}
|
|
1484
|
-
@if (showCode && reportOptions[0]) {
|
|
1485
|
-
<kendo-tabstrip-tab [selected]="!showFunctionalRequirements && !showDataRequirements && !showTechnicalDesign">
|
|
1486
|
-
<ng-template kendoTabTitle>
|
|
1487
|
-
<i class="fa-solid fa-code"></i> Code
|
|
1488
|
-
</ng-template>
|
|
1489
|
-
<ng-template kendoTabContent>
|
|
1490
|
-
<div class="details-content code-content">
|
|
1491
|
-
<mj-code-editor
|
|
1492
|
-
[language]="'javascript'"
|
|
1493
|
-
[value]="getComponentCode(reportOptions[0])"
|
|
1494
|
-
[autoFocus]="false"
|
|
1495
|
-
[indentWithTab]="true"
|
|
1496
|
-
[readonly]="true"
|
|
1497
|
-
style="height: 100%;">
|
|
1498
|
-
</mj-code-editor>
|
|
1499
|
-
</div>
|
|
1500
|
-
</ng-template>
|
|
1501
|
-
</kendo-tabstrip-tab>
|
|
1502
|
-
}
|
|
1503
|
-
</kendo-tabstrip>
|
|
1504
|
-
</div>
|
|
1505
|
-
<!-- Resizer -->
|
|
1506
|
-
<div class="panel-resizer"
|
|
1507
|
-
(mousedown)="startResize($event)"
|
|
1508
|
-
(touchstart)="startResize($event)">
|
|
1509
|
-
<div class="resizer-handle"></div>
|
|
1510
|
-
</div>
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
<!-- React component container or error display -->
|
|
1514
|
-
@if (currentError) {
|
|
1515
|
-
<!-- Error display container with proper height -->
|
|
1516
|
-
<div style="flex: 1; display: flex; align-items: center; justify-content: center;
|
|
1517
|
-
min-height: 400px; padding: 20px; background: rgba(255, 255, 255, 0.95);">
|
|
1518
|
-
<div style="width: 90%;
|
|
1519
|
-
max-width: 600px;
|
|
1520
|
-
max-height: 80vh;
|
|
1521
|
-
background-color: #f8f9fa;
|
|
1522
|
-
border: 2px solid #dc3545;
|
|
1523
|
-
border-radius: 8px;
|
|
1524
|
-
padding: 20px;
|
|
1525
|
-
overflow-y: auto;
|
|
1526
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
|
1527
|
-
<div style="position: relative;">
|
|
1528
|
-
<button kendoButton (click)="copyErrorToClipboard()"
|
|
1529
|
-
style="position: absolute; top: 0; right: 0; font-size: 12px;">
|
|
1530
|
-
<span class="fa-solid fa-copy"></span>
|
|
1531
|
-
Copy Error Details
|
|
1532
|
-
</button>
|
|
1533
|
-
<h3 style="color: #dc3545; margin-top: 0; margin-right: 150px; font-size: 18px;">
|
|
1534
|
-
<span class="fa-solid fa-exclamation-triangle"></span>
|
|
1535
|
-
Component Rendering Error
|
|
1536
|
-
</h3>
|
|
1537
|
-
</div>
|
|
1538
|
-
<p style="margin-bottom: 10px; font-size: 14px;">
|
|
1539
|
-
The selected component option could not be rendered due to the following error:
|
|
1540
|
-
</p>
|
|
1541
|
-
<div style="background-color: #fff; border: 1px solid #dee2e6;
|
|
1542
|
-
border-radius: 4px; padding: 12px; margin-bottom: 12px;
|
|
1543
|
-
font-family: 'Courier New', monospace; font-size: 12px;">
|
|
1544
|
-
<strong>Error Type:</strong> {{ currentError.type }}<br>
|
|
1545
|
-
<strong>Details:</strong> {{ currentError.message }}
|
|
1546
|
-
@if (currentError.technicalDetails) {
|
|
1547
|
-
<details style="margin-top: 8px;">
|
|
1548
|
-
<summary style="cursor: pointer; color: #0056b3;">Technical Details (click to expand)</summary>
|
|
1549
|
-
<pre style="margin-top: 8px; white-space: pre-wrap; word-break: break-word; font-size: 11px;">{{ currentError.technicalDetails }}</pre>
|
|
1550
|
-
</details>
|
|
1551
|
-
}
|
|
1552
|
-
</div>
|
|
1553
|
-
<div style="background-color: #e7f3ff; border: 1px solid #b3d9ff;
|
|
1554
|
-
border-radius: 4px; padding: 12px; margin-bottom: 12px;">
|
|
1555
|
-
<strong style="font-size: 14px;">What to do:</strong>
|
|
1556
|
-
<ol style="margin: 8px 0 0 20px; padding: 0; font-size: 13px;">
|
|
1557
|
-
<li>Copy the error details and send them back to Skip in the chat to get a corrected version</li>
|
|
1558
|
-
<li>Contact your IT department if the issue persists</li>
|
|
1559
|
-
</ol>
|
|
1560
|
-
</div>
|
|
1561
|
-
<button kendoButton (click)="retryCurrentOption()" style="font-size: 13px;">
|
|
1562
|
-
<span class="fa-solid fa-rotate"></span>
|
|
1563
|
-
Retry
|
|
1564
|
-
</button>
|
|
1565
|
-
</div>
|
|
1566
|
-
</div>
|
|
1567
|
-
} @else {
|
|
1568
|
-
<!-- React component container (only shown when no error) -->
|
|
1569
|
-
<div style="flex: 1; position: relative; min-height: 0; overflow: auto;">
|
|
1570
|
-
<mj-react-component
|
|
1571
|
-
*ngIf="componentSpecs.has(0)"
|
|
1572
|
-
[component]="componentSpecs.get(0)!"
|
|
1573
|
-
[data]="getFlattenedDataContext()"
|
|
1574
|
-
[state]="userStates.get(0) || {}"
|
|
1575
|
-
[utilities]="utilities"
|
|
1576
|
-
[styles]="componentStyles || undefined"
|
|
1577
|
-
(stateChange)="onStateChange(0, $event)"
|
|
1578
|
-
(componentEvent)="onComponentEvent(0, $event)"
|
|
1579
|
-
(refreshData)="handleRefreshData()"
|
|
1580
|
-
(openEntityRecord)="onOpenEntityRecord($event)"
|
|
1581
|
-
style="width: 100%; height: 100%;">
|
|
1582
|
-
</mj-react-component>
|
|
1583
|
-
</div>
|
|
1584
|
-
}
|
|
1585
|
-
</div>
|
|
1586
|
-
</div>
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
`, styles: ["\n :host {\n display: block;\n height: 100%;\n position: relative;\n }\n \n /* Tab Action Bar */\n .tab-action-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background-color: #fafafa;\n border-bottom: 1px solid #e0e0e0;\n }\n \n .tab-actions-left,\n .tab-actions-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n /* Tab Action Buttons */\n .tab-action-button {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n background-color: transparent;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: #333;\n transition: all 0.15s ease;\n white-space: nowrap;\n }\n \n .tab-action-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n }\n \n .tab-action-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n \n .tab-action-button i {\n font-size: 12px;\n }\n \n /* Both buttons use the same white/secondary style */\n .tab-action-button.create-button,\n .tab-action-button.print-button {\n background-color: white;\n color: #333;\n border-color: #e0e0e0;\n }\n \n .tab-action-button.create-button:hover:not(:disabled),\n .tab-action-button.print-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n }\n \n /* Toggle buttons styling */\n .tab-action-button.toggle-button {\n background-color: white;\n color: #666;\n border-color: #e0e0e0;\n }\n \n .tab-action-button.toggle-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n color: #333;\n }\n \n .tab-action-button.toggle-button.active {\n background-color: #5B4FE9;\n color: white;\n border-color: #5B4FE9;\n }\n \n .tab-action-button.toggle-button.active:hover:not(:disabled) {\n background-color: #4940D4;\n border-color: #4940D4;\n }\n \n /* Details panel styling */\n .details-panel {\n border-bottom: 1px solid #e0e0e0;\n background-color: #fafafa;\n overflow: hidden;\n transition: height 0.3s ease;\n }\n \n .details-content {\n padding: 16px;\n overflow-y: auto;\n height: 100%;\n font-size: 14px;\n line-height: 1.6;\n }\n \n .details-content.code-content {\n padding: 0;\n }\n \n /* Panel resizer */\n .panel-resizer {\n height: 4px;\n background-color: #e0e0e0;\n cursor: ns-resize;\n position: relative;\n transition: background-color 0.2s ease;\n }\n \n .panel-resizer:hover {\n background-color: #d0d0d0;\n }\n \n .resizer-handle {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 2px;\n background-color: #999;\n border-radius: 1px;\n }\n \n /* Markdown content styling */\n .details-content :deep(h1) { font-size: 1.5em; margin-top: 0; margin-bottom: 0.5em; }\n .details-content :deep(h2) { font-size: 1.3em; margin-top: 1em; margin-bottom: 0.5em; }\n .details-content :deep(h3) { font-size: 1.1em; margin-top: 1em; margin-bottom: 0.5em; }\n .details-content :deep(ul), .details-content :deep(ol) { margin-left: 1.5em; }\n .details-content :deep(code) { \n background-color: #f4f4f4; \n padding: 2px 4px; \n border-radius: 3px; \n font-family: 'Courier New', monospace; \n font-size: 0.9em;\n }\n .details-content :deep(pre) { \n background-color: #f4f4f4; \n padding: 12px; \n border-radius: 4px; \n overflow-x: auto; \n }\n .details-content :deep(blockquote) { \n border-left: 4px solid #e0e0e0; \n padding-left: 16px; \n margin-left: 0; \n color: #666; \n }\n \n /* Tab styling */\n ::ng-deep .k-tabstrip {\n border: none;\n height: 100%;\n display: flex;\n flex-direction: column;\n margin: 10px 5px 5px 5px;\n }\n \n ::ng-deep .k-tabstrip-items {\n background: #f8f9fa;\n border: none;\n border-radius: 8px 8px 0 0;\n flex: 0 0 auto;\n padding: 8px 12px 0 12px;\n gap: 4px;\n display: flex;\n }\n \n ::ng-deep .k-tabstrip-items-wrapper {\n height: 100%;\n }\n \n ::ng-deep .k-content {\n flex: 1;\n overflow: hidden;\n padding: 0;\n background: white;\n border: 1px solid #e0e0e0;\n border-top: none;\n border-radius: 0 0 8px 8px;\n }\n \n ::ng-deep .k-tabstrip .k-item {\n margin-right: 2px;\n border: none;\n background: transparent;\n border-radius: 6px 6px 0 0;\n padding: 2px;\n transition: all 0.2s ease;\n }\n \n ::ng-deep .k-tabstrip .k-item.k-selected {\n background: white;\n border: 1px solid #e0e0e0;\n border-bottom: 1px solid white;\n margin-bottom: -1px;\n z-index: 1;\n }\n \n ::ng-deep .k-tabstrip .k-link {\n padding: 8px 16px;\n font-weight: 500;\n font-size: 13px;\n color: #666;\n transition: all 0.15s ease;\n border-radius: 4px 4px 0 0;\n background: transparent;\n border: none;\n text-transform: lowercase;\n }\n \n ::ng-deep .k-tabstrip .k-link:first-letter {\n text-transform: uppercase;\n }\n \n ::ng-deep .k-tabstrip .k-item:hover:not(.k-selected) .k-link {\n color: #333;\n background: rgba(0, 0, 0, 0.04);\n }\n \n ::ng-deep .k-tabstrip .k-item.k-selected .k-link {\n color: #1976d2;\n font-weight: 600;\n background: white;\n }\n \n /* Star icon styling */\n ::ng-deep .k-tabstrip .k-link .star-icon {\n display: inline-block;\n margin-right: 4px;\n color: #ffd700;\n font-size: 12px;\n vertical-align: middle;\n }\n \n /* Hide default Kendo tab styling */\n ::ng-deep .k-tabstrip-items::before,\n ::ng-deep .k-tabstrip-items::after {\n display: none;\n }\n \n ::ng-deep .k-tabstrip .k-item::before,\n ::ng-deep .k-tabstrip .k-item::after {\n display: none;\n }\n \n /* Remove focus outline */\n ::ng-deep .k-tabstrip .k-link:focus {\n outline: none;\n box-shadow: none;\n }\n \n /* Make sure tab content fills available space */\n ::ng-deep .k-tabstrip .k-content.k-state-active {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n \n /* React host container */\n .react-host-container {\n width: 100%;\n height: 100%;\n }\n "] }]
|
|
1180
|
+
args: [{ selector: 'skip-dynamic-ui-component', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (reportOptions.length > 1) {\n <!-- Multiple options: show tabs -->\n <kendo-tabstrip \n (tabSelect)=\"onTabSelect($event)\"\n [keepTabContent]=\"true\"\n style=\"height: 100%; display: flex; flex-direction: column;\">\n @for (option of reportOptions; track option; let i = $index) {\n <kendo-tabstrip-tab [selected]=\"i === selectedReportOptionIndex\">\n <ng-template kendoTabTitle>\n @if (isTopRanked(i)) {\n <i class=\"fa-solid fa-star star-icon\"></i>\n }\n {{ getTabTitle(i) }}\n </ng-template>\n <ng-template kendoTabContent>\n <div style=\"height: 100%; display: flex; flex-direction: column;\">\n <!-- Tab Action Bar -->\n <div class=\"tab-action-bar\">\n <div class=\"tab-actions-left\">\n <!-- Toggle buttons for showing/hiding component details -->\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowFunctionalRequirements()\"\n [class.active]=\"showFunctionalRequirements\"\n title=\"Toggle Functional Requirements\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span>Functional</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowDataRequirements()\"\n [class.active]=\"showDataRequirements\"\n title=\"Toggle Data Requirements\">\n <i class=\"fa-solid fa-database\"></i>\n <span>Data</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowTechnicalDesign()\"\n [class.active]=\"showTechnicalDesign\"\n title=\"Toggle Technical Design\">\n <i class=\"fa-solid fa-cogs\"></i>\n <span>Technical</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowCode()\"\n [class.active]=\"showCode\"\n title=\"Toggle Code View\">\n <i class=\"fa-solid fa-code\"></i>\n <span>Code</span>\n </button>\n </div>\n <div class=\"tab-actions-right\">\n <button class=\"tab-action-button create-button\" \n *ngIf=\"ShowCreateReportButton && !matchingReportID\"\n (click)=\"createReportForOption(i)\"\n [disabled]=\"isCreatingReport\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Create {{ getComponentTypeName(option) }}</span>\n </button>\n <button class=\"tab-action-button print-button\" \n *ngIf=\"ShowPrintReport\" \n (click)=\"PrintReport()\"\n title=\"Print Report\">\n <i class=\"fa-solid fa-print\"></i>\n <span>Print Report</span>\n </button>\n </div>\n </div>\n \n <!-- Main content area with optional details panels -->\n <div style=\"flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden;\">\n @if (showFunctionalRequirements || showDataRequirements || showTechnicalDesign || showCode) {\n <!-- Details panel -->\n <div class=\"details-panel\" [style.height]=\"detailsPanelHeight\">\n <kendo-tabstrip style=\"height: 100%;\">\n @if (showFunctionalRequirements) {\n <kendo-tabstrip-tab [selected]=\"true\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-list-check\"></i> Functional Requirements\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedFunctionalRequirements(option)\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showDataRequirements) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-database\"></i> Data Requirements\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedDataRequirements(option)\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showTechnicalDesign) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements && !showDataRequirements\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-cogs\"></i> Technical Design\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedTechnicalDesign(option)\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showCode) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements && !showDataRequirements && !showTechnicalDesign\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-code\"></i> Code\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content code-content\">\n <mj-code-editor\n [value]=\"getComponentCode(option)\"\n [language]=\"'javascript'\"\n [autoFocus]=\"false\"\n [indentWithTab]=\"true\"\n [readonly]=\"true\"\n style=\"height: 100%;\">\n </mj-code-editor>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n </kendo-tabstrip>\n </div>\n <!-- Resizer -->\n <div class=\"panel-resizer\" \n (mousedown)=\"startResize($event)\"\n (touchstart)=\"startResize($event)\">\n <div class=\"resizer-handle\"></div>\n </div>\n }\n \n <!-- React component container -->\n <div [attr.data-tab-index]=\"i\" \n style=\"flex: 1; position: relative; min-height: 0; overflow: auto;\">\n <mj-react-component\n *ngIf=\"!currentError && reportOptions[i] && i === selectedReportOptionIndex\"\n [component]=\"reportOptions[i].option\"\n [data]=\"getFlattenedDataContext()\"\n [state]=\"userStates.get(i) || {}\"\n [utilities]=\"utilities\"\n [styles]=\"componentStyles || undefined\"\n (stateChange)=\"onStateChange(i, $event)\"\n (componentEvent)=\"onComponentEvent(i, $event)\"\n (refreshData)=\"handleRefreshData()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n style=\"width: 100%; height: 100%;\">\n </mj-react-component>\n \n <!-- Error overlay for this tab (shown on top of content when needed) -->\n @if (currentError && selectedReportOptionIndex === i) {\n <div style=\"top: 0; \n left: 0; \n right: 0; \n bottom: 0; \n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 20px;\n background: rgba(255, 255, 255, 0.95);\n z-index: 10;\">\n <div style=\"width: 90%; \n max-width: 600px; \n height: 500px;\n background-color: #f8f9fa; \n border: 2px solid #dc3545; \n border-radius: 8px; \n padding: 20px;\n overflow-y: auto;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\">\n <div style=\"position: relative;\">\n <button kendoButton (click)=\"copyErrorToClipboard()\" \n style=\"position: absolute; top: 0; right: 0; font-size: 12px;\">\n <span class=\"fa-solid fa-copy\"></span>\n Copy Error Details\n </button>\n <h3 style=\"color: #dc3545; margin-top: 0; margin-right: 150px; font-size: 18px;\">\n <span class=\"fa-solid fa-exclamation-triangle\"></span>\n Component Rendering Error\n </h3>\n </div>\n <p style=\"margin-bottom: 10px; font-size: 14px;\">\n The selected component option could not be rendered due to the following error:\n </p>\n <div style=\"background-color: #fff; border: 1px solid #dee2e6; \n border-radius: 4px; padding: 12px; margin-bottom: 12px;\n font-family: 'Courier New', monospace; font-size: 12px;\">\n <strong>Error Type:</strong> {{ currentError.type }}<br>\n <strong>Details:</strong> {{ currentError.message }}\n @if (currentError.technicalDetails) {\n <details style=\"margin-top: 8px;\">\n <summary style=\"cursor: pointer; color: #0056b3;\">Technical Details (click to expand)</summary>\n <pre style=\"margin-top: 8px; white-space: pre-wrap; word-break: break-word; font-size: 11px;\">{{ formatTechnicalDetails(currentError.technicalDetails) }}</pre>\n </details>\n }\n </div>\n <div style=\"background-color: #e7f3ff; border: 1px solid #b3d9ff; \n border-radius: 4px; padding: 12px; margin-bottom: 12px;\">\n <strong style=\"font-size: 14px;\">What to do:</strong>\n <ol style=\"margin: 8px 0 0 20px; padding: 0; font-size: 13px;\">\n <li>Try selecting a different report option from the tabs above</li>\n <li>Copy the error details and send them back to Skip in the chat to get a corrected version</li>\n <li>Contact your IT department if the issue persists</li>\n </ol>\n </div>\n <button kendoButton (click)=\"retryCurrentOption()\" style=\"font-size: 13px;\">\n <span class=\"fa-solid fa-rotate\"></span>\n Retry\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n </kendo-tabstrip>\n} @else {\n <!-- Single option: no tabs needed -->\n <div style=\"height: 100%; display: flex; flex-direction: column;\">\n <!-- Tab Action Bar -->\n <div class=\"tab-action-bar\">\n <div class=\"tab-actions-left\">\n <!-- Toggle buttons for showing/hiding component details -->\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowFunctionalRequirements()\"\n [class.active]=\"showFunctionalRequirements\"\n title=\"Toggle Functional Requirements\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span>Functional</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowDataRequirements()\"\n [class.active]=\"showDataRequirements\"\n title=\"Toggle Data Requirements\">\n <i class=\"fa-solid fa-database\"></i>\n <span>Data</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowTechnicalDesign()\"\n [class.active]=\"showTechnicalDesign\"\n title=\"Toggle Technical Design\">\n <i class=\"fa-solid fa-cogs\"></i>\n <span>Technical</span>\n </button>\n <button class=\"tab-action-button toggle-button\" \n (click)=\"toggleShowCode()\"\n [class.active]=\"showCode\"\n title=\"Toggle Code View\">\n <i class=\"fa-solid fa-code\"></i>\n <span>Code</span>\n </button>\n </div>\n <div class=\"tab-actions-right\">\n <button class=\"tab-action-button create-button\" \n *ngIf=\"ShowCreateReportButton && !matchingReportID\"\n (click)=\"createReportForOption(0)\"\n [disabled]=\"isCreatingReport\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>Create {{ firstOptionComponentTypeName }}</span>\n </button>\n <button class=\"tab-action-button print-button\" \n *ngIf=\"ShowPrintReport\" \n (click)=\"PrintReport()\"\n title=\"Print Report\">\n <i class=\"fa-solid fa-print\"></i>\n <span>Print Report</span>\n </button>\n </div>\n </div>\n \n <!-- Main content area with optional details panels -->\n <div style=\"flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden;\">\n @if (showFunctionalRequirements || showDataRequirements || showTechnicalDesign || showCode) {\n <!-- Details panel -->\n <div class=\"details-panel\" [style.height]=\"detailsPanelHeight\">\n <kendo-tabstrip style=\"height: 100%;\">\n @if (showFunctionalRequirements && reportOptions[0]) {\n <kendo-tabstrip-tab [selected]=\"true\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-list-check\"></i> Functional Requirements\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedFunctionalRequirements(reportOptions[0])\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showDataRequirements && reportOptions[0]) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-database\"></i> Data Requirements\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedDataRequirements(reportOptions[0])\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showTechnicalDesign && reportOptions[0]) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements && !showDataRequirements\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-cogs\"></i> Technical Design\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content\">\n <div [innerHTML]=\"getFormattedTechnicalDesign(reportOptions[0])\"></div>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n @if (showCode && reportOptions[0]) {\n <kendo-tabstrip-tab [selected]=\"!showFunctionalRequirements && !showDataRequirements && !showTechnicalDesign\">\n <ng-template kendoTabTitle>\n <i class=\"fa-solid fa-code\"></i> Code\n </ng-template>\n <ng-template kendoTabContent>\n <div class=\"details-content code-content\">\n <mj-code-editor\n [language]=\"'javascript'\"\n [value]=\"getComponentCode(reportOptions[0])\"\n [autoFocus]=\"false\"\n [indentWithTab]=\"true\"\n [readonly]=\"true\"\n style=\"height: 100%;\">\n </mj-code-editor>\n </div>\n </ng-template>\n </kendo-tabstrip-tab>\n }\n </kendo-tabstrip>\n </div>\n <!-- Resizer -->\n <div class=\"panel-resizer\" \n (mousedown)=\"startResize($event)\"\n (touchstart)=\"startResize($event)\">\n <div class=\"resizer-handle\"></div>\n </div>\n }\n \n <!-- React component container or error display -->\n @if (currentError) {\n <!-- Error display container with proper height -->\n <div style=\"flex: 1; display: flex; align-items: center; justify-content: center; \n min-height: 400px; padding: 20px; background: rgba(255, 255, 255, 0.95);\">\n <div style=\"width: 90%; \n max-width: 600px; \n max-height: 80vh;\n background-color: #f8f9fa; \n border: 2px solid #dc3545; \n border-radius: 8px; \n padding: 20px;\n overflow-y: auto;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\">\n <div style=\"position: relative;\">\n <button kendoButton (click)=\"copyErrorToClipboard()\" \n style=\"position: absolute; top: 0; right: 0; font-size: 12px;\">\n <span class=\"fa-solid fa-copy\"></span>\n Copy Error Details\n </button>\n <h3 style=\"color: #dc3545; margin-top: 0; margin-right: 150px; font-size: 18px;\">\n <span class=\"fa-solid fa-exclamation-triangle\"></span>\n Component Rendering Error\n </h3>\n </div>\n <p style=\"margin-bottom: 10px; font-size: 14px;\">\n The selected component option could not be rendered due to the following error:\n </p>\n <div style=\"background-color: #fff; border: 1px solid #dee2e6; \n border-radius: 4px; padding: 12px; margin-bottom: 12px;\n font-family: 'Courier New', monospace; font-size: 12px;\">\n <strong>Error Type:</strong> {{ currentError.type }}<br>\n <strong>Details:</strong> {{ currentError.message }}\n @if (currentError.technicalDetails) {\n <details style=\"margin-top: 8px;\">\n <summary style=\"cursor: pointer; color: #0056b3;\">Technical Details (click to expand)</summary>\n <pre style=\"margin-top: 8px; white-space: pre-wrap; word-break: break-word; font-size: 11px;\">{{ formatTechnicalDetails(currentError.technicalDetails) }}</pre>\n </details>\n }\n </div>\n <div style=\"background-color: #e7f3ff; border: 1px solid #b3d9ff; \n border-radius: 4px; padding: 12px; margin-bottom: 12px;\">\n <strong style=\"font-size: 14px;\">What to do:</strong>\n <ol style=\"margin: 8px 0 0 20px; padding: 0; font-size: 13px;\">\n <li>Copy the error details and send them back to Skip in the chat to get a corrected version</li>\n <li>Contact your IT department if the issue persists</li>\n </ol>\n </div>\n <button kendoButton (click)=\"retryCurrentOption()\" style=\"font-size: 13px;\">\n <span class=\"fa-solid fa-rotate\"></span>\n Retry\n </button>\n </div>\n </div>\n } @else {\n <!-- React component container (only shown when no error) -->\n <div style=\"flex: 1; position: relative; min-height: 0; overflow: auto;\">\n <mj-react-component\n *ngIf=\"reportOptions[0]\"\n [component]=\"reportOptions[0].option\"\n [data]=\"getFlattenedDataContext()\"\n [state]=\"userStates.get(0) || {}\"\n [utilities]=\"utilities\"\n [styles]=\"componentStyles || undefined\"\n (stateChange)=\"onStateChange(0, $event)\"\n (componentEvent)=\"onComponentEvent(0, $event)\"\n (refreshData)=\"handleRefreshData()\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n style=\"width: 100%; height: 100%;\">\n </mj-react-component>\n </div>\n }\n </div>\n </div>\n}", styles: [":host {\n display: block;\n height: 100%;\n position: relative;\n}\n\n/* Tab Action Bar */\n.tab-action-bar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background-color: #fafafa;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.tab-actions-left,\n.tab-actions-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* Tab Action Buttons */\n.tab-action-button {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n background-color: transparent;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: #333;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.tab-action-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n}\n\n.tab-action-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.tab-action-button i {\n font-size: 12px;\n}\n\n/* Both buttons use the same white/secondary style */\n.tab-action-button.create-button,\n.tab-action-button.print-button {\n background-color: white;\n color: #333;\n border-color: #e0e0e0;\n}\n\n.tab-action-button.create-button:hover:not(:disabled),\n.tab-action-button.print-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n}\n\n/* Toggle buttons styling */\n.tab-action-button.toggle-button {\n background-color: white;\n color: #666;\n border-color: #e0e0e0;\n}\n\n.tab-action-button.toggle-button:hover:not(:disabled) {\n background-color: #f5f5f5;\n border-color: #d0d0d0;\n color: #333;\n}\n\n.tab-action-button.toggle-button.active {\n background-color: #5B4FE9;\n color: white;\n border-color: #5B4FE9;\n}\n\n.tab-action-button.toggle-button.active:hover:not(:disabled) {\n background-color: #4940D4;\n border-color: #4940D4;\n}\n\n/* Details panel styling */\n.details-panel {\n border-bottom: 1px solid #e0e0e0;\n background-color: #fafafa;\n overflow: hidden;\n transition: height 0.3s ease;\n}\n\n.details-content {\n padding: 16px;\n overflow-y: auto;\n height: 100%;\n font-size: 14px;\n line-height: 1.6;\n}\n\n.details-content.code-content {\n padding: 0;\n}\n\n/* Panel resizer */\n.panel-resizer {\n height: 4px;\n background-color: #e0e0e0;\n cursor: ns-resize;\n position: relative;\n transition: background-color 0.2s ease;\n}\n\n.panel-resizer:hover {\n background-color: #d0d0d0;\n}\n\n.resizer-handle {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 40px;\n height: 2px;\n background-color: #999;\n border-radius: 1px;\n}\n\n/* Markdown content styling */\n.details-content :deep(h1) { font-size: 1.5em; margin-top: 0; margin-bottom: 0.5em; }\n.details-content :deep(h2) { font-size: 1.3em; margin-top: 1em; margin-bottom: 0.5em; }\n.details-content :deep(h3) { font-size: 1.1em; margin-top: 1em; margin-bottom: 0.5em; }\n.details-content :deep(ul), .details-content :deep(ol) { margin-left: 1.5em; }\n.details-content :deep(code) { \n background-color: #f4f4f4; \n padding: 2px 4px; \n border-radius: 3px; \n font-family: 'Courier New', monospace; \n font-size: 0.9em;\n}\n.details-content :deep(pre) { \n background-color: #f4f4f4; \n padding: 12px; \n border-radius: 4px; \n overflow-x: auto; \n}\n.details-content :deep(blockquote) { \n border-left: 4px solid #e0e0e0; \n padding-left: 16px; \n margin-left: 0; \n color: #666; \n}\n\n/* Tab styling */\n::ng-deep .k-tabstrip {\n border: none;\n height: 100%;\n display: flex;\n flex-direction: column;\n margin: 10px 5px 5px 5px;\n}\n\n::ng-deep .k-tabstrip-items {\n background: #f8f9fa;\n border: none;\n border-radius: 8px 8px 0 0;\n flex: 0 0 auto;\n padding: 8px 12px 0 12px;\n gap: 4px;\n display: flex;\n}\n\n::ng-deep .k-tabstrip-items-wrapper {\n height: 100%;\n}\n\n::ng-deep .k-content {\n flex: 1;\n overflow: hidden;\n padding: 0;\n background: white;\n border: 1px solid #e0e0e0;\n border-top: none;\n border-radius: 0 0 8px 8px;\n}\n\n::ng-deep .k-tabstrip .k-item {\n margin-right: 2px;\n border: none;\n background: transparent;\n border-radius: 6px 6px 0 0;\n padding: 2px;\n transition: all 0.2s ease;\n}\n\n::ng-deep .k-tabstrip .k-item.k-selected {\n background: white;\n border: 1px solid #e0e0e0;\n border-bottom: 1px solid white;\n margin-bottom: -1px;\n z-index: 1;\n}\n\n::ng-deep .k-tabstrip .k-link {\n padding: 8px 16px;\n font-weight: 500;\n font-size: 13px;\n color: #666;\n transition: all 0.15s ease;\n border-radius: 4px 4px 0 0;\n background: transparent;\n border: none;\n text-transform: lowercase;\n}\n\n::ng-deep .k-tabstrip .k-link:first-letter {\n text-transform: uppercase;\n}\n\n::ng-deep .k-tabstrip .k-item:hover:not(.k-selected) .k-link {\n color: #333;\n background: rgba(0, 0, 0, 0.04);\n}\n\n::ng-deep .k-tabstrip .k-item.k-selected .k-link {\n color: #1976d2;\n font-weight: 600;\n background: white;\n}\n\n/* Star icon styling */\n::ng-deep .k-tabstrip .k-link .star-icon {\n display: inline-block;\n margin-right: 4px;\n color: #ffd700;\n font-size: 12px;\n vertical-align: middle;\n}\n\n/* Hide default Kendo tab styling */\n::ng-deep .k-tabstrip-items::before,\n::ng-deep .k-tabstrip-items::after {\n display: none;\n}\n\n::ng-deep .k-tabstrip .k-item::before,\n::ng-deep .k-tabstrip .k-item::after {\n display: none;\n}\n\n/* Remove focus outline */\n::ng-deep .k-tabstrip .k-link:focus {\n outline: none;\n box-shadow: none;\n}\n\n/* Make sure tab content fills available space */\n::ng-deep .k-tabstrip .k-content.k-state-active {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n/* React host container */\n.react-host-container {\n width: 100%;\n height: 100%;\n}"] }]
|
|
1590
1181
|
}], () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i2.AngularAdapterService }], { UIComponentCode: [{
|
|
1591
1182
|
type: Input
|
|
1592
1183
|
}], ComponentObjectName: [{
|
|
@@ -1612,5 +1203,5 @@ Component Name: ${this.ComponentObjectName || 'Unknown'}`;
|
|
|
1612
1203
|
}], SkipData: [{
|
|
1613
1204
|
type: Input
|
|
1614
1205
|
}] }); })();
|
|
1615
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SkipDynamicUIComponentComponent, { className: "SkipDynamicUIComponentComponent", filePath: "src/lib/dynamic-report/dynamic-ui-component.ts", lineNumber:
|
|
1206
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SkipDynamicUIComponentComponent, { className: "SkipDynamicUIComponentComponent", filePath: "src/lib/dynamic-report/dynamic-ui-component.ts", lineNumber: 18 }); })();
|
|
1616
1207
|
//# sourceMappingURL=dynamic-ui-component.js.map
|