@cqa-lib/cqa-ui 1.1.396 → 1.1.397

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.
@@ -7570,6 +7570,26 @@ class StepRendererComponent {
7570
7570
  return this.getDebugPointSetHandler(this.step);
7571
7571
  return false;
7572
7572
  }
7573
+ /**
7574
+ * Safely trigger change detection on a child component.
7575
+ * Calls detectChanges() only if the child's ngOnInit has already run (i.e. config is built).
7576
+ * Before initialization, falls back to markForCheck() which queues CD for the next cycle
7577
+ * without forcing immediate template evaluation.
7578
+ */
7579
+ safeDetectChanges(componentRef) {
7580
+ if (!componentRef?.injector)
7581
+ return;
7582
+ const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7583
+ if (!instanceCdr)
7584
+ return;
7585
+ if (StepRendererComponent.componentInitialized.get(this.container)) {
7586
+ instanceCdr.markForCheck();
7587
+ instanceCdr.detectChanges();
7588
+ }
7589
+ else {
7590
+ instanceCdr.markForCheck();
7591
+ }
7592
+ }
7573
7593
  ngOnChanges(changes) {
7574
7594
  if (!this.container || !this.step)
7575
7595
  return;
@@ -7595,13 +7615,7 @@ class StepRendererComponent {
7595
7615
  // Try to update selectedIteration if iterations are available
7596
7616
  this.updateLoopStepSelectedIteration(instance, currentValue);
7597
7617
  // Trigger change detection on the loop-step component
7598
- if (componentRef.injector) {
7599
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7600
- if (instanceCdr) {
7601
- instanceCdr.markForCheck();
7602
- instanceCdr.detectChanges();
7603
- }
7604
- }
7618
+ this.safeDetectChanges(componentRef);
7605
7619
  }
7606
7620
  }
7607
7621
  }
@@ -7619,13 +7633,7 @@ class StepRendererComponent {
7619
7633
  instance.config.stepNumber = currentValue;
7620
7634
  }
7621
7635
  // Trigger change detection on the component instance
7622
- if (componentRef.injector) {
7623
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7624
- if (instanceCdr) {
7625
- instanceCdr.markForCheck();
7626
- instanceCdr.detectChanges();
7627
- }
7628
- }
7636
+ this.safeDetectChanges(componentRef);
7629
7637
  }
7630
7638
  }
7631
7639
  }
@@ -7651,13 +7659,7 @@ class StepRendererComponent {
7651
7659
  }
7652
7660
  }
7653
7661
  // Trigger change detection on the component instance
7654
- if (componentRef.injector) {
7655
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7656
- if (instanceCdr) {
7657
- instanceCdr.markForCheck();
7658
- instanceCdr.detectChanges();
7659
- }
7660
- }
7662
+ this.safeDetectChanges(componentRef);
7661
7663
  }
7662
7664
  }
7663
7665
  // If downloadingStepId changed, update file-download instance isDownloading
@@ -7667,13 +7669,7 @@ class StepRendererComponent {
7667
7669
  if (instance && componentRef && this.getEffectiveStepType(currentStep) === 'file-download') {
7668
7670
  const tid = currentStep.testStepResultId;
7669
7671
  instance.isDownloading = !!tid && this.downloadingStepId === tid;
7670
- if (componentRef.injector) {
7671
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7672
- if (instanceCdr) {
7673
- instanceCdr.markForCheck();
7674
- instanceCdr.detectChanges();
7675
- }
7676
- }
7672
+ this.safeDetectChanges(componentRef);
7677
7673
  }
7678
7674
  }
7679
7675
  // If isDebug, debugPointSet or getDebugPointSetHandler changed (e.g. user toggled debug in portal/Storybook), update nested instance
@@ -7751,13 +7747,7 @@ class StepRendererComponent {
7751
7747
  subscribedEvents.add('stepMoreOptionSelect');
7752
7748
  }
7753
7749
  }
7754
- if (componentRef.injector) {
7755
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7756
- if (instanceCdr) {
7757
- instanceCdr.markForCheck();
7758
- instanceCdr.detectChanges();
7759
- }
7760
- }
7750
+ this.safeDetectChanges(componentRef);
7761
7751
  }
7762
7752
  }
7763
7753
  // Get step identifiers (use effective type: generateDocument -> file-download)
@@ -8018,8 +8008,6 @@ class StepRendererComponent {
8018
8008
  if (currentStep.displayType === 'condition' && currentStep.nestedSteps !== undefined) {
8019
8009
  const currentNestedSteps = currentStep.nestedSteps || [];
8020
8010
  const previousNestedSteps = previousStep.nestedSteps || [];
8021
- console.log('🔄 step-renderer: currentNestedSteps', currentNestedSteps);
8022
- console.log('🔄 step-renderer: previousNestedSteps', previousNestedSteps);
8023
8011
  // Use deep comparison to detect content changes, not just reference changes
8024
8012
  // This is critical when switching between IF and ELSE_IF branches
8025
8013
  if (this.hasNestedStepsChanged(currentNestedSteps, previousNestedSteps)) {
@@ -8029,11 +8017,6 @@ class StepRendererComponent {
8029
8017
  instance.config.nestedSteps = [...currentNestedSteps];
8030
8018
  }
8031
8019
  hasChanges = true;
8032
- console.log('🔄 step-renderer: nestedSteps updated for condition-step', {
8033
- stepId: currentStep.id,
8034
- previousCount: previousNestedSteps.length,
8035
- currentCount: currentNestedSteps.length
8036
- });
8037
8020
  }
8038
8021
  }
8039
8022
  // Special handling for file-download (including generateDocument): sync from generateDocumentResult
@@ -8157,19 +8140,7 @@ class StepRendererComponent {
8157
8140
  // Trigger change detection on the component instance if there were changes
8158
8141
  // This ensures only the nested step updates without affecting parent steps
8159
8142
  if (hasChanges) {
8160
- if (componentRef.injector) {
8161
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
8162
- if (instanceCdr) {
8163
- instanceCdr.markForCheck();
8164
- instanceCdr.detectChanges();
8165
- }
8166
- }
8167
- else if (instance.cdr) {
8168
- instance.cdr.detectChanges();
8169
- }
8170
- else if (instance.changeDetectorRef) {
8171
- instance.changeDetectorRef.detectChanges();
8172
- }
8143
+ this.safeDetectChanges(componentRef);
8173
8144
  // Don't call markForCheck on this component to avoid triggering parent re-renders
8174
8145
  }
8175
8146
  }
@@ -8338,6 +8309,7 @@ class StepRendererComponent {
8338
8309
  }
8339
8310
  StepRendererComponent.componentInstances.delete(this.container);
8340
8311
  StepRendererComponent.componentRefs.delete(this.container);
8312
+ StepRendererComponent.componentInitialized.delete(this.container);
8341
8313
  this.lastStepId = currentStepId;
8342
8314
  this.lastStepType = currentStepType;
8343
8315
  }
@@ -8541,7 +8513,6 @@ class StepRendererComponent {
8541
8513
  }
8542
8514
  // Special handling for loop-step: initialize iterations if not present
8543
8515
  if (this.isLoopStep(this.step) && !instance.iterations) {
8544
- console.log(" changes['selectedIterationId'] step", this.selectedIterationId, instance.iterations);
8545
8516
  // Use handler if available, otherwise try to initialize from step.executedResult.stepResult
8546
8517
  if (this.getLoopIterationsHandler) {
8547
8518
  instance.iterations = this.getLoopIterationsHandler(this.step);
@@ -8582,7 +8553,6 @@ class StepRendererComponent {
8582
8553
  }
8583
8554
  // Special handling for loop-step: set defaultIteration and selectedIterationId
8584
8555
  if (this.isLoopStep(this.step)) {
8585
- console.log(" changes['selectedIterationId'] step 2", this.selectedIterationId, instance.iterations);
8586
8556
  // Set defaultIteration to 'last' if not already set
8587
8557
  if (!instance.defaultIteration) {
8588
8558
  instance.defaultIteration = 'last';
@@ -8995,9 +8965,11 @@ class StepRendererComponent {
8995
8965
  instanceCdr.markForCheck();
8996
8966
  }
8997
8967
  }
8998
- // Emit ready event after component is created and initialized
8999
- // Use setTimeout to ensure the component is fully rendered
8968
+ // Mark component as initialized after the next CD cycle completes.
8969
+ // By then, the child's ngOnInit will have run and config is built.
8970
+ // After this, safeDetectChanges() will use detectChanges() for immediate updates.
9000
8971
  setTimeout(() => {
8972
+ StepRendererComponent.componentInitialized.set(this.container, true);
9001
8973
  this.componentReady.emit();
9002
8974
  }, 0);
9003
8975
  }
@@ -9060,13 +9032,7 @@ class StepRendererComponent {
9060
9032
  // Update the step object's expanded property to keep it in sync
9061
9033
  this.step.expanded = currentExpanded;
9062
9034
  // Trigger change detection
9063
- if (componentRef.injector) {
9064
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
9065
- if (instanceCdr) {
9066
- instanceCdr.markForCheck();
9067
- instanceCdr.detectChanges();
9068
- }
9069
- }
9035
+ this.safeDetectChanges(componentRef);
9070
9036
  }
9071
9037
  // Check if iterations are now available and we need to update selectedIteration
9072
9038
  if (this.isLoopStep(this.step) && this.selectedIterationId) {
@@ -9078,13 +9044,7 @@ class StepRendererComponent {
9078
9044
  const shouldBeSelected = iterations.find((iter) => iter.id === selectedIterationId);
9079
9045
  if (shouldBeSelected && currentSelectedIteration?.id !== selectedIterationId) {
9080
9046
  this.updateLoopStepSelectedIteration(instance, selectedIterationId);
9081
- if (componentRef.injector) {
9082
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
9083
- if (instanceCdr) {
9084
- instanceCdr.markForCheck();
9085
- instanceCdr.detectChanges();
9086
- }
9087
- }
9047
+ this.safeDetectChanges(componentRef);
9088
9048
  }
9089
9049
  }
9090
9050
  }
@@ -9129,6 +9089,10 @@ class StepRendererComponent {
9129
9089
  StepRendererComponent.componentInstances = new WeakMap();
9130
9090
  StepRendererComponent.componentRefs = new WeakMap();
9131
9091
  StepRendererComponent.subscribedEventEmitters = new WeakMap(); // Track which EventEmitters have been subscribed to
9092
+ // Track whether child component's ngOnInit has run (config is built).
9093
+ // detectChanges() must NOT be called before initialization — it forces template
9094
+ // evaluation which crashes on undefined config properties.
9095
+ StepRendererComponent.componentInitialized = new WeakMap();
9132
9096
  StepRendererComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepRendererComponent, deps: [{ token: STEP_COMPONENT_MAP }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
9133
9097
  StepRendererComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepRendererComponent, selector: "cqa-step-renderer", inputs: { step: "step", onExpandHandler: "onExpandHandler", getConditionBranchesHandler: "getConditionBranchesHandler", isStepLoadingHandler: "isStepLoadingHandler", isStepExpandedHandler: "isStepExpandedHandler", convertMsToSecondsHandler: "convertMsToSecondsHandler", formatFailureDetailsHandler: "formatFailureDetailsHandler", getSelfHealAnalysisHandler: "getSelfHealAnalysisHandler", onMakeCurrentBaselineHandler: "onMakeCurrentBaselineHandler", onUploadBaselineHandler: "onUploadBaselineHandler", onAnalyzeHandler: "onAnalyzeHandler", onViewFullLogsHandler: "onViewFullLogsHandler", onSelfHealActionHandler: "onSelfHealActionHandler", getSelfHealLoadingStatesHandler: "getSelfHealLoadingStatesHandler", isUploadingBaseline: "isUploadingBaseline", isMakingCurrentBaseline: "isMakingCurrentBaseline", selectedIterationId: "selectedIterationId", getLoopIterationsHandler: "getLoopIterationsHandler", getApiAssertionsHandler: "getApiAssertionsHandler", formatActionsHandler: "formatActionsHandler", onViewAllIterationsHandler: "onViewAllIterationsHandler", onConditionBranchClickHandler: "onConditionBranchClickHandler", onStepClickHandler: "onStepClickHandler", onJsonPathCopiedHandler: "onJsonPathCopiedHandler", onDownloadHandler: "onDownloadHandler", onFilePathCopiedHandler: "onFilePathCopiedHandler", onTextCopiedHandler: "onTextCopiedHandler", jumpToTimestampHandler: "jumpToTimestampHandler", downloadingStepId: "downloadingStepId", isLive: "isLive", isDebug: "isDebug", debugPointSet: "debugPointSet", getDebugPointSetHandler: "getDebugPointSetHandler", onDebugPointChangeHandler: "onDebugPointChangeHandler", onEditStepHandler: "onEditStepHandler", addStepMenuOptions: "addStepMenuOptions", onAddStepOptionSelectHandler: "onAddStepOptionSelectHandler", stepMoreMenuOptions: "stepMoreMenuOptions", onStepMoreOptionSelectHandler: "onStepMoreOptionSelectHandler", getAddStepMenuOptionsForNested: "getAddStepMenuOptionsForNested", getStepMoreMenuOptionsForNested: "getStepMoreMenuOptionsForNested", stepNumber: "stepNumber", parentSkipped: "parentSkipped" }, outputs: { addStepOptionSelect: "addStepOptionSelect", stepMoreOptionSelect: "stepMoreOptionSelect", addStepInsideLoop: "addStepInsideLoop", componentReady: "componentReady" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: '<ng-container #container></ng-container>', isInline: true });
9134
9098
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepRendererComponent, decorators: [{