@cqa-lib/cqa-ui 1.1.395 → 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.
@@ -7677,6 +7677,26 @@ class StepRendererComponent {
7677
7677
  return this.getDebugPointSetHandler(this.step);
7678
7678
  return false;
7679
7679
  }
7680
+ /**
7681
+ * Safely trigger change detection on a child component.
7682
+ * Calls detectChanges() only if the child's ngOnInit has already run (i.e. config is built).
7683
+ * Before initialization, falls back to markForCheck() which queues CD for the next cycle
7684
+ * without forcing immediate template evaluation.
7685
+ */
7686
+ safeDetectChanges(componentRef) {
7687
+ if (!(componentRef === null || componentRef === void 0 ? void 0 : componentRef.injector))
7688
+ return;
7689
+ const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7690
+ if (!instanceCdr)
7691
+ return;
7692
+ if (StepRendererComponent.componentInitialized.get(this.container)) {
7693
+ instanceCdr.markForCheck();
7694
+ instanceCdr.detectChanges();
7695
+ }
7696
+ else {
7697
+ instanceCdr.markForCheck();
7698
+ }
7699
+ }
7680
7700
  ngOnChanges(changes) {
7681
7701
  var _a, _b, _c;
7682
7702
  if (!this.container || !this.step)
@@ -7703,13 +7723,7 @@ class StepRendererComponent {
7703
7723
  // Try to update selectedIteration if iterations are available
7704
7724
  this.updateLoopStepSelectedIteration(instance, currentValue);
7705
7725
  // Trigger change detection on the loop-step component
7706
- if (componentRef.injector) {
7707
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7708
- if (instanceCdr) {
7709
- instanceCdr.markForCheck();
7710
- instanceCdr.detectChanges();
7711
- }
7712
- }
7726
+ this.safeDetectChanges(componentRef);
7713
7727
  }
7714
7728
  }
7715
7729
  }
@@ -7727,13 +7741,7 @@ class StepRendererComponent {
7727
7741
  instance.config.stepNumber = currentValue;
7728
7742
  }
7729
7743
  // Trigger change detection on the component instance
7730
- if (componentRef.injector) {
7731
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7732
- if (instanceCdr) {
7733
- instanceCdr.markForCheck();
7734
- instanceCdr.detectChanges();
7735
- }
7736
- }
7744
+ this.safeDetectChanges(componentRef);
7737
7745
  }
7738
7746
  }
7739
7747
  }
@@ -7759,13 +7767,7 @@ class StepRendererComponent {
7759
7767
  }
7760
7768
  }
7761
7769
  // Trigger change detection on the component instance
7762
- if (componentRef.injector) {
7763
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7764
- if (instanceCdr) {
7765
- instanceCdr.markForCheck();
7766
- instanceCdr.detectChanges();
7767
- }
7768
- }
7770
+ this.safeDetectChanges(componentRef);
7769
7771
  }
7770
7772
  }
7771
7773
  // If downloadingStepId changed, update file-download instance isDownloading
@@ -7775,13 +7777,7 @@ class StepRendererComponent {
7775
7777
  if (instance && componentRef && this.getEffectiveStepType(currentStep) === 'file-download') {
7776
7778
  const tid = currentStep.testStepResultId;
7777
7779
  instance.isDownloading = !!tid && this.downloadingStepId === tid;
7778
- if (componentRef.injector) {
7779
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7780
- if (instanceCdr) {
7781
- instanceCdr.markForCheck();
7782
- instanceCdr.detectChanges();
7783
- }
7784
- }
7780
+ this.safeDetectChanges(componentRef);
7785
7781
  }
7786
7782
  }
7787
7783
  // If isDebug, debugPointSet or getDebugPointSetHandler changed (e.g. user toggled debug in portal/Storybook), update nested instance
@@ -7863,13 +7859,7 @@ class StepRendererComponent {
7863
7859
  subscribedEvents.add('stepMoreOptionSelect');
7864
7860
  }
7865
7861
  }
7866
- if (componentRef.injector) {
7867
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
7868
- if (instanceCdr) {
7869
- instanceCdr.markForCheck();
7870
- instanceCdr.detectChanges();
7871
- }
7872
- }
7862
+ this.safeDetectChanges(componentRef);
7873
7863
  }
7874
7864
  }
7875
7865
  // Get step identifiers (use effective type: generateDocument -> file-download)
@@ -8128,8 +8118,6 @@ class StepRendererComponent {
8128
8118
  if (currentStep.displayType === 'condition' && currentStep.nestedSteps !== undefined) {
8129
8119
  const currentNestedSteps = currentStep.nestedSteps || [];
8130
8120
  const previousNestedSteps = previousStep.nestedSteps || [];
8131
- console.log('🔄 step-renderer: currentNestedSteps', currentNestedSteps);
8132
- console.log('🔄 step-renderer: previousNestedSteps', previousNestedSteps);
8133
8121
  // Use deep comparison to detect content changes, not just reference changes
8134
8122
  // This is critical when switching between IF and ELSE_IF branches
8135
8123
  if (this.hasNestedStepsChanged(currentNestedSteps, previousNestedSteps)) {
@@ -8139,11 +8127,6 @@ class StepRendererComponent {
8139
8127
  instance.config.nestedSteps = [...currentNestedSteps];
8140
8128
  }
8141
8129
  hasChanges = true;
8142
- console.log('🔄 step-renderer: nestedSteps updated for condition-step', {
8143
- stepId: currentStep.id,
8144
- previousCount: previousNestedSteps.length,
8145
- currentCount: currentNestedSteps.length
8146
- });
8147
8130
  }
8148
8131
  }
8149
8132
  // Special handling for file-download (including generateDocument): sync from generateDocumentResult
@@ -8267,19 +8250,7 @@ class StepRendererComponent {
8267
8250
  // Trigger change detection on the component instance if there were changes
8268
8251
  // This ensures only the nested step updates without affecting parent steps
8269
8252
  if (hasChanges) {
8270
- if (componentRef.injector) {
8271
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
8272
- if (instanceCdr) {
8273
- instanceCdr.markForCheck();
8274
- instanceCdr.detectChanges();
8275
- }
8276
- }
8277
- else if (instance.cdr) {
8278
- instance.cdr.detectChanges();
8279
- }
8280
- else if (instance.changeDetectorRef) {
8281
- instance.changeDetectorRef.detectChanges();
8282
- }
8253
+ this.safeDetectChanges(componentRef);
8283
8254
  // Don't call markForCheck on this component to avoid triggering parent re-renders
8284
8255
  }
8285
8256
  }
@@ -8452,6 +8423,7 @@ class StepRendererComponent {
8452
8423
  }
8453
8424
  StepRendererComponent.componentInstances.delete(this.container);
8454
8425
  StepRendererComponent.componentRefs.delete(this.container);
8426
+ StepRendererComponent.componentInitialized.delete(this.container);
8455
8427
  this.lastStepId = currentStepId;
8456
8428
  this.lastStepType = currentStepType;
8457
8429
  }
@@ -8660,7 +8632,6 @@ class StepRendererComponent {
8660
8632
  }
8661
8633
  // Special handling for loop-step: initialize iterations if not present
8662
8634
  if (this.isLoopStep(this.step) && !instance.iterations) {
8663
- console.log(" changes['selectedIterationId'] step", this.selectedIterationId, instance.iterations);
8664
8635
  // Use handler if available, otherwise try to initialize from step.executedResult.stepResult
8665
8636
  if (this.getLoopIterationsHandler) {
8666
8637
  instance.iterations = this.getLoopIterationsHandler(this.step);
@@ -8701,7 +8672,6 @@ class StepRendererComponent {
8701
8672
  }
8702
8673
  // Special handling for loop-step: set defaultIteration and selectedIterationId
8703
8674
  if (this.isLoopStep(this.step)) {
8704
- console.log(" changes['selectedIterationId'] step 2", this.selectedIterationId, instance.iterations);
8705
8675
  // Set defaultIteration to 'last' if not already set
8706
8676
  if (!instance.defaultIteration) {
8707
8677
  instance.defaultIteration = 'last';
@@ -9113,9 +9083,11 @@ class StepRendererComponent {
9113
9083
  instanceCdr.markForCheck();
9114
9084
  }
9115
9085
  }
9116
- // Emit ready event after component is created and initialized
9117
- // Use setTimeout to ensure the component is fully rendered
9086
+ // Mark component as initialized after the next CD cycle completes.
9087
+ // By then, the child's ngOnInit will have run and config is built.
9088
+ // After this, safeDetectChanges() will use detectChanges() for immediate updates.
9118
9089
  setTimeout(() => {
9090
+ StepRendererComponent.componentInitialized.set(this.container, true);
9119
9091
  this.componentReady.emit();
9120
9092
  }, 0);
9121
9093
  }
@@ -9179,13 +9151,7 @@ class StepRendererComponent {
9179
9151
  // Update the step object's expanded property to keep it in sync
9180
9152
  this.step.expanded = currentExpanded;
9181
9153
  // Trigger change detection
9182
- if (componentRef.injector) {
9183
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
9184
- if (instanceCdr) {
9185
- instanceCdr.markForCheck();
9186
- instanceCdr.detectChanges();
9187
- }
9188
- }
9154
+ this.safeDetectChanges(componentRef);
9189
9155
  }
9190
9156
  // Check if iterations are now available and we need to update selectedIteration
9191
9157
  if (this.isLoopStep(this.step) && this.selectedIterationId) {
@@ -9197,13 +9163,7 @@ class StepRendererComponent {
9197
9163
  const shouldBeSelected = iterations.find((iter) => iter.id === selectedIterationId);
9198
9164
  if (shouldBeSelected && (currentSelectedIteration === null || currentSelectedIteration === void 0 ? void 0 : currentSelectedIteration.id) !== selectedIterationId) {
9199
9165
  this.updateLoopStepSelectedIteration(instance, selectedIterationId);
9200
- if (componentRef.injector) {
9201
- const instanceCdr = componentRef.injector.get(ChangeDetectorRef, null);
9202
- if (instanceCdr) {
9203
- instanceCdr.markForCheck();
9204
- instanceCdr.detectChanges();
9205
- }
9206
- }
9166
+ this.safeDetectChanges(componentRef);
9207
9167
  }
9208
9168
  }
9209
9169
  }
@@ -9248,6 +9208,10 @@ class StepRendererComponent {
9248
9208
  StepRendererComponent.componentInstances = new WeakMap();
9249
9209
  StepRendererComponent.componentRefs = new WeakMap();
9250
9210
  StepRendererComponent.subscribedEventEmitters = new WeakMap(); // Track which EventEmitters have been subscribed to
9211
+ // Track whether child component's ngOnInit has run (config is built).
9212
+ // detectChanges() must NOT be called before initialization — it forces template
9213
+ // evaluation which crashes on undefined config properties.
9214
+ StepRendererComponent.componentInitialized = new WeakMap();
9251
9215
  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 });
9252
9216
  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 });
9253
9217
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepRendererComponent, decorators: [{
@@ -31143,7 +31107,7 @@ class TemplateVariablesFormComponent {
31143
31107
  this.cdr.markForCheck();
31144
31108
  }
31145
31109
  ngOnChanges(changes) {
31146
- var _a, _b, _c;
31110
+ var _a, _b, _c, _d;
31147
31111
  if (changes['templateVariables'] || changes['variablesForm'] || changes['elementOptions'] ||
31148
31112
  changes['hasMoreElements'] || changes['isLoadingElements'] ||
31149
31113
  changes['parameterOptions'] || changes['hasMoreParameters'] || changes['isLoadingParameters'] ||
@@ -31378,24 +31342,26 @@ class TemplateVariablesFormComponent {
31378
31342
  this.cdr.markForCheck();
31379
31343
  }
31380
31344
  }
31381
- // If parameter options changed and we have default values, try to initialize them.
31382
- // IMPORTANT: only do this on the FIRST time parameterOptions arrive, otherwise every
31383
- // search (which also updates parameterOptions) would re-run initializeTestDataVariables()
31384
- // and reset the test-data type dropdown back to 'plain-text'.
31345
+ // Re-run initializeTestDataVariables whenever parameterOptions changes and there are still
31346
+ // variables that need initialization (have profileId but missing profile name or dataSet).
31347
+ // We do NOT use firstChange here because the saved profile may arrive in a second API call
31348
+ // (id@<profileId>) after the initial paginated list, so firstChange would miss it.
31349
+ // The inner some() guard ensures we only re-run when variables are still incomplete,
31350
+ // preventing unnecessary re-runs on user search updates.
31385
31351
  if (changes['parameterOptions'] &&
31386
- changes['parameterOptions'].firstChange &&
31387
31352
  this.parameterOptions.length > 0 &&
31388
- ((this.defaultTestDataProfileId && this.defaultTestDataStartIndex != null) ||
31389
- (
31390
- // Check if any variable has selectedTestDataProfileId but is missing selectedTestDataProfile or selectedDataSet
31391
- // This happens when loading a saved step - setTemplateVariables sets the ID, but we need parameterOptions to set the name and data set
31392
- (_b = this.templateVariables) === null || _b === void 0 ? void 0 : _b.some(v => this.needsDataTypeDropdown(v) &&
31393
- v.dataType === 'parameter' &&
31394
- v.selectedTestDataProfileId != null &&
31395
- (!v.selectedTestDataProfile || !v.selectedDataSet))) ||
31353
+ (
31354
+ // Check if any variable has selectedTestDataProfileId but is missing selectedTestDataProfile or selectedDataSet
31355
+ // This happens when loading a saved step - setTemplateVariables sets the ID, but we need parameterOptions to set the name and data set
31356
+ ((_b = this.templateVariables) === null || _b === void 0 ? void 0 : _b.some(v => this.needsDataTypeDropdown(v) &&
31357
+ v.dataType === 'parameter' &&
31358
+ v.selectedTestDataProfileId != null &&
31359
+ (!v.selectedTestDataProfile || !v.selectedDataSet))) ||
31360
+ (this.defaultTestDataProfileId && this.defaultTestDataStartIndex != null &&
31361
+ ((_c = this.templateVariables) === null || _c === void 0 ? void 0 : _c.some(v => this.needsDataTypeDropdown(v) && v.dataType === 'parameter' && !v.selectedTestDataProfile))) ||
31396
31362
  // The extra uninitialized-variable check below is debug-only: only run it in debug mode
31397
31363
  // to avoid double-initialising variables in non-debug step-builder flows.
31398
- (this.isDebug && ((_c = this.templateVariables) === null || _c === void 0 ? void 0 : _c.some(v => this.needsDataTypeDropdown(v) && v.dataType === 'parameter' && !v.selectedTestDataProfile))))) {
31364
+ (this.isDebug && ((_d = this.templateVariables) === null || _d === void 0 ? void 0 : _d.some(v => this.needsDataTypeDropdown(v) && v.dataType === 'parameter' && !v.selectedTestDataProfile))))) {
31399
31365
  console.log("parameterOptions InitializeTestDataVariables", changes['parameterOptions']);
31400
31366
  // Re-initialize to set default values now that parameterOptions are available
31401
31367
  this.initializeTestDataVariables();
@@ -31606,14 +31572,22 @@ class TemplateVariablesFormComponent {
31606
31572
  // For environment type, parse the value to extract environment and parameter
31607
31573
  if (dataType === 'environment') {
31608
31574
  // Environment values are in format *|parameterName|
31609
- // We need to find which environment this parameter belongs to
31610
31575
  const paramName = rawValue;
31611
31576
  if (paramName) {
31612
- // Find the environment that contains this parameter
31613
- const envOption = this.environmentOptions.find(env => env.name === paramName);
31577
+ // If we have a saved environmentId, use it for an exact match (env-{id}-{param})
31578
+ // to avoid selecting the wrong environment when multiple environments share param names.
31579
+ let envOption;
31580
+ if (variable.selectedEnvironmentId != null) {
31581
+ const exactId = `env-${variable.selectedEnvironmentId}-${paramName}`;
31582
+ envOption = this.environmentOptions.find(env => env.id === exactId);
31583
+ }
31584
+ // Fallback: match by param name only (legacy / first-time save)
31585
+ if (!envOption) {
31586
+ envOption = this.environmentOptions.find(env => env.name === paramName);
31587
+ }
31614
31588
  if (envOption) {
31615
31589
  variable.selectedEnvironment = envOption.environment;
31616
- // Extract and store environment ID
31590
+ // Extract and store environment ID from the option id
31617
31591
  const idMatch = envOption.id.match(/env-(\d+)-/);
31618
31592
  if (idMatch && idMatch[1]) {
31619
31593
  variable.selectedEnvironmentId = parseInt(idMatch[1], 10);