@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.
@@ -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.componentSpecs.get(ɵ$index_4_r3))("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);
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.componentSpecs.has(ɵ$index_4_r3));
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.componentSpecs.get(0))("data", ctx_r1.getFlattenedDataContext())("state", ctx_r1.userStates.get(0) || i0.ɵɵpureFunction0(5, _c0))("utilities", ctx_r1.utilities)("styles", ctx_r1.componentStyles || undefined);
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.componentSpecs.has(0));
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 and user states
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
- // Create or update the component spec for this option
669
- if (!this.componentSpecs.has(this.selectedReportOptionIndex)) {
670
- this.createComponentSpecForOption(this.selectedReportOptionIndex);
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
- // Re-create the component spec
739
- this.createComponentSpecForOption(this.selectedReportOptionIndex);
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
- // Create component specs for all options
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.createComponentSpecForOption(index);
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 component specs and states
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
- * Create a component spec for a specific option index
1030
+ * Initialize user state for a specific option index
1024
1031
  */
1025
- createComponentSpecForOption(optionIndex) {
1026
- const option = this.reportOptions[optionIndex];
1027
- if (!option)
1028
- return;
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
- return flattenedDataContext;
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 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 }"] });
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: 721 }); })();
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