@cqa-lib/cqa-ui 1.1.192 → 1.1.193

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.
Files changed (30) hide show
  1. package/esm2020/lib/autocomplete/autocomplete.component.mjs +156 -0
  2. package/esm2020/lib/autocomplete/autocomplete.model.mjs +2 -0
  3. package/esm2020/lib/test-case-details/condition-step/condition-step.component.mjs +505 -17
  4. package/esm2020/lib/test-case-details/delete-steps/delete-steps.component.mjs +32 -11
  5. package/esm2020/lib/test-case-details/loop-step/loop-step.component.mjs +131 -9
  6. package/esm2020/lib/test-case-details/step-details-drawer/step-details-drawer-data.mjs +67 -1
  7. package/esm2020/lib/test-case-details/step-details-drawer/step-details-drawer-field.config.mjs +66 -1
  8. package/esm2020/lib/test-case-details/step-details-drawer/step-details-drawer.component.mjs +112 -191
  9. package/esm2020/lib/test-case-details/step-group/step-group.component.mjs +31 -3
  10. package/esm2020/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.mjs +114 -5
  11. package/esm2020/lib/ui-kit.module.mjs +6 -1
  12. package/esm2020/public-api.mjs +3 -1
  13. package/fesm2015/cqa-lib-cqa-ui.mjs +1423 -444
  14. package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
  15. package/fesm2020/cqa-lib-cqa-ui.mjs +1415 -440
  16. package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
  17. package/lib/autocomplete/autocomplete.component.d.ts +48 -0
  18. package/lib/autocomplete/autocomplete.model.d.ts +10 -0
  19. package/lib/test-case-details/condition-step/condition-step.component.d.ts +73 -4
  20. package/lib/test-case-details/delete-steps/delete-steps.component.d.ts +18 -2
  21. package/lib/test-case-details/loop-step/loop-step.component.d.ts +34 -4
  22. package/lib/test-case-details/step-details-drawer/step-details-drawer-data.d.ts +56 -0
  23. package/lib/test-case-details/step-details-drawer/step-details-drawer-field.config.d.ts +6 -0
  24. package/lib/test-case-details/step-details-drawer/step-details-drawer.component.d.ts +33 -27
  25. package/lib/test-case-details/step-group/step-group.component.d.ts +15 -1
  26. package/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.d.ts +27 -4
  27. package/lib/ui-kit.module.d.ts +127 -126
  28. package/package.json +1 -1
  29. package/public-api.d.ts +2 -0
  30. package/styles.css +1 -1
@@ -0,0 +1,48 @@
1
+ import { EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2
+ import { CqaAutocompleteOption } from './autocomplete.model';
3
+ import * as i0 from "@angular/core";
4
+ declare type AutocompleteSize = 'sm' | 'md' | 'lg';
5
+ export declare class AutocompleteComponent implements OnInit, OnChanges {
6
+ /** Placeholder text for the input */
7
+ placeholder: string;
8
+ /** Options shown in the dropdown (filtered by input when open) */
9
+ options: CqaAutocompleteOption[];
10
+ /** Initial or controlled value (displayed in the input) */
11
+ value: string;
12
+ /** Disable the input */
13
+ disabled: boolean;
14
+ /** Whether to show the clear button when there is text */
15
+ showClear: boolean;
16
+ /** Accessible label for the input */
17
+ ariaLabel: string;
18
+ /** Auto focus the input when rendered */
19
+ autoFocus: boolean;
20
+ /** Size variant (matches search bar widths) */
21
+ size: AutocompleteSize;
22
+ /** Stretch to full width of container */
23
+ fullWidth: boolean;
24
+ /** Emit when the input value changes (e.g. for two-way binding) */
25
+ valueChange: EventEmitter<string>;
26
+ /** Emit when an option is selected from the list (value from option) */
27
+ optionSelect: EventEmitter<CqaAutocompleteOption>;
28
+ /** Emit when the value is cleared via the clear button */
29
+ cleared: EventEmitter<void>;
30
+ inputValue: string;
31
+ panelOpen: boolean;
32
+ private blurTimeout;
33
+ ngOnInit(): void;
34
+ ngOnChanges(changes: SimpleChanges): void;
35
+ readonly widthClasses: Record<AutocompleteSize, string>;
36
+ get displayOptions(): CqaAutocompleteOption[];
37
+ onInput(event: Event): void;
38
+ onFocus(): void;
39
+ onBlur(): void;
40
+ selectOption(option: CqaAutocompleteOption): void;
41
+ clear(): void;
42
+ getOptionLabel(option: CqaAutocompleteOption): string;
43
+ trackByValue(_index: number, option: CqaAutocompleteOption): string;
44
+ onEscape(): void;
45
+ static ɵfac: i0.ɵɵFactoryDeclaration<AutocompleteComponent, never>;
46
+ static ɵcmp: i0.ɵɵComponentDeclaration<AutocompleteComponent, "cqa-autocomplete", never, { "placeholder": "placeholder"; "options": "options"; "value": "value"; "disabled": "disabled"; "showClear": "showClear"; "ariaLabel": "ariaLabel"; "autoFocus": "autoFocus"; "size": "size"; "fullWidth": "fullWidth"; }, { "valueChange": "valueChange"; "optionSelect": "optionSelect"; "cleared": "cleared"; }, never, never>;
47
+ }
48
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Option for the autocomplete dropdown.
3
+ * Use label for display and value for the selected value (e.g. for IDs).
4
+ */
5
+ export interface CqaAutocompleteOption {
6
+ /** Value emitted on selection (e.g. id or code) */
7
+ value: string;
8
+ /** Text shown in the list (defaults to value if omitted) */
9
+ label?: string;
10
+ }
@@ -1,11 +1,13 @@
1
- import { EventEmitter, OnInit } from '@angular/core';
1
+ import { EventEmitter, OnInit, OnChanges, ChangeDetectorRef } from '@angular/core';
2
2
  import { FormBuilder, FormGroup } from '@angular/forms';
3
3
  import { DndDropEvent } from 'ngx-drag-drop';
4
4
  import { ConditionStepConfig, ConditionBranch, TestCaseStepConfig, NormalStepConfig, LoopStepConfig, StepGroupConfig } from '../test-case-step.models';
5
5
  import { DynamicSelectFieldConfig } from '../../dynamic-select/dynamic-select-field.component';
6
+ import { CqaAutocompleteOption } from '../../autocomplete/autocomplete.model';
6
7
  import * as i0 from "@angular/core";
7
- export declare class TestCaseConditionStepComponent implements OnInit {
8
+ export declare class TestCaseConditionStepComponent implements OnInit, OnChanges {
8
9
  private fb;
10
+ private cdr;
9
11
  config: ConditionStepConfig;
10
12
  id: string;
11
13
  stepNumber: number | string;
@@ -15,14 +17,45 @@ export declare class TestCaseConditionStepComponent implements OnInit {
15
17
  isNested: boolean;
16
18
  isInsideLoop: boolean;
17
19
  isReorder: boolean;
20
+ /** Options for the data profile dropdown */
21
+ dataProfileOptions: any[];
22
+ /** Indicates if more data profiles are available for loading */
23
+ hasMoreDataProfiles: boolean;
24
+ /** Loading state for data profiles */
25
+ isLoadingDataProfiles: boolean;
26
+ /** Natural text actions options for while loop condition */
27
+ naturalTextActionsOptions: any[];
28
+ /** Function to process template variables (similar to step-builder-condition) */
29
+ setConditionTemplateVariables: (template: any) => any[];
18
30
  /** When true, header shows inline edit form (fields, operator select, Cancel/Apply) */
19
31
  isEditing: boolean;
32
+ /** Array of ELSE IF branches in edit mode */
33
+ elseIfBranches: Array<{
34
+ id: string;
35
+ form: FormGroup;
36
+ selectedTemplate: any;
37
+ templateVariables: any[];
38
+ templateVariablesForm: FormGroup;
39
+ snapshot: {
40
+ conditionLeft?: string;
41
+ conditionOperator?: string;
42
+ conditionRight?: string;
43
+ };
44
+ }>;
20
45
  /** Form for edit mode; bound to cqa-dynamic-select and cqa-custom-input */
21
46
  editForm: FormGroup;
22
47
  /** Operator dropdown config (IS, IS NOT, CONTAINS, etc.) */
23
48
  operatorSelectConfig: DynamicSelectFieldConfig;
49
+ /** Condition left operand dropdown config (natural text actions with IF_CONDITION) */
50
+ conditionLeftSelectConfig: DynamicSelectFieldConfig;
24
51
  /** Snapshot for Cancel revert */
25
52
  private editSnapshot;
53
+ /** Selected template for IF condition */
54
+ selectedTemplate: any;
55
+ /** Template variables for IF condition */
56
+ templateVariables: any[];
57
+ /** Form group for template variables */
58
+ templateVariablesForm: FormGroup;
26
59
  toggleExpanded: EventEmitter<{
27
60
  config: ConditionStepConfig;
28
61
  expanded: boolean;
@@ -41,6 +74,10 @@ export declare class TestCaseConditionStepComponent implements OnInit {
41
74
  stepIndex: number;
42
75
  }>;
43
76
  addBranch: EventEmitter<void>;
77
+ /** Emitted when user clicks "Add Else" so the parent can call POST test_steps with conditionType CONDITION_ELSE */
78
+ addElse: EventEmitter<{
79
+ conditionStepConfig: ConditionStepConfig;
80
+ }>;
44
81
  deleteBranch: EventEmitter<ConditionBranch>;
45
82
  duplicate: EventEmitter<void>;
46
83
  delete: EventEmitter<void>;
@@ -49,11 +86,36 @@ export declare class TestCaseConditionStepComponent implements OnInit {
49
86
  event: DndDropEvent;
50
87
  targetList: TestCaseStepConfig[];
51
88
  }>;
89
+ /** Emit when more data profiles need to be loaded */
90
+ loadMoreDataProfiles: EventEmitter<string>;
91
+ /** Emit when data profile search query changes */
92
+ searchDataProfiles: EventEmitter<string>;
93
+ /** Emit when a nested step is updated (e.g., Apply button clicked in loop-step edit mode) */
94
+ stepUpdate: EventEmitter<TestCaseStepConfig>;
52
95
  onDndDrop(event: DndDropEvent, branch: ConditionBranch): void;
53
- constructor(fb: FormBuilder);
96
+ constructor(fb: FormBuilder, cdr: ChangeDetectorRef);
54
97
  ngOnInit(): void;
98
+ ngOnChanges(changes: any): void;
99
+ /** Rebuild edit form when naturalTextActionsOptions are loaded to populate from naturalTextActionId */
100
+ private rebuildEditFormWithNaturalTextAction;
55
101
  private buildEditForm;
102
+ private buildElseIfBranch;
56
103
  private buildOperatorSelectConfig;
104
+ /** Update condition left select config with filtered natural text actions (IF_CONDITION only) */
105
+ private updateConditionLeftSelectConfig;
106
+ /** Options for the condition left autocomplete (IF_CONDITION natural text actions) */
107
+ get conditionLeftAutocompleteOptions(): CqaAutocompleteOption[];
108
+ onConditionLeftSelect(option: CqaAutocompleteOption & {
109
+ template?: any;
110
+ }): void;
111
+ private buildTemplateVariablesForm;
112
+ onElseConditionLeftSelect(option: CqaAutocompleteOption & {
113
+ template?: any;
114
+ }, branchId: string): void;
115
+ private buildElseTemplateVariablesForm;
116
+ onAddElse(): void;
117
+ onAddElseBranch(): void;
118
+ onRemoveElse(branchId: string): void;
57
119
  /** Parse condition string into left, operator, right (e.g. "Usertype is Premium") */
58
120
  private parseCondition;
59
121
  /** Build condition string from form values */
@@ -83,12 +145,19 @@ export declare class TestCaseConditionStepComponent implements OnInit {
83
145
  onOpenExternal(): void;
84
146
  onEdit(): void;
85
147
  onEditCancel(): void;
148
+ /**
149
+ * Build payload for one ELSE IF branch (action, naturalTextActionId, templateVariablesData, testDataList)
150
+ * so the parent can create the step via POST then PUT when Apply is clicked.
151
+ */
152
+ private buildElseIfBranchPayload;
86
153
  onEditApply(): void;
87
154
  onEditInDepth(): void;
88
155
  onLink(): void;
89
156
  onDuplicate(): void;
90
157
  onDelete(): void;
91
158
  onMoreOptions(): void;
159
+ /** Get select config for a template variable */
160
+ getSelectConfigForVariable(variable: any, branchIdOrIsElse?: string | boolean): DynamicSelectFieldConfig;
92
161
  static ɵfac: i0.ɵɵFactoryDeclaration<TestCaseConditionStepComponent, never>;
93
- static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseConditionStepComponent, "cqa-test-case-condition-step", never, { "config": "config"; "id": "id"; "stepNumber": "stepNumber"; "condition": "condition"; "branches": "branches"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; }, { "toggleExpanded": "toggleExpanded"; "conditionChange": "conditionChange"; "branchStepChange": "branchStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "addBranch": "addBranch"; "deleteBranch": "deleteBranch"; "duplicate": "duplicate"; "delete": "delete"; "moreOptions": "moreOptions"; "dndDropInZone": "dndDropInZone"; }, never, never>;
162
+ static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseConditionStepComponent, "cqa-test-case-condition-step", never, { "config": "config"; "id": "id"; "stepNumber": "stepNumber"; "condition": "condition"; "branches": "branches"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; "dataProfileOptions": "dataProfileOptions"; "hasMoreDataProfiles": "hasMoreDataProfiles"; "isLoadingDataProfiles": "isLoadingDataProfiles"; "naturalTextActionsOptions": "naturalTextActionsOptions"; "setConditionTemplateVariables": "setConditionTemplateVariables"; }, { "toggleExpanded": "toggleExpanded"; "conditionChange": "conditionChange"; "branchStepChange": "branchStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "addBranch": "addBranch"; "addElse": "addElse"; "deleteBranch": "deleteBranch"; "duplicate": "duplicate"; "delete": "delete"; "moreOptions": "moreOptions"; "dndDropInZone": "dndDropInZone"; "loadMoreDataProfiles": "loadMoreDataProfiles"; "searchDataProfiles": "searchDataProfiles"; "stepUpdate": "stepUpdate"; }, never, never>;
94
163
  }
@@ -7,10 +7,22 @@ import * as i0 from "@angular/core";
7
7
  * warning text, and Cancel / Delete actions. Steps are shown with red/danger styling.
8
8
  */
9
9
  export declare class DeleteStepsComponent {
10
+ data?: {
11
+ stepsToDelete?: TestCaseStepConfig[];
12
+ contextLabel?: string;
13
+ stepImages?: Map<string | number, string>;
14
+ };
10
15
  /** Steps that will be deleted (shown in the list). */
11
16
  stepsToDelete: TestCaseStepConfig[];
12
17
  /** Context label for the sub-heading, e.g. "IF lane", "ELSE", "For loop". */
13
18
  contextLabel: string;
19
+ /** Optional step images/screenshots map: stepId -> imageUrl */
20
+ stepImages: Map<string | number, string>;
21
+ constructor(data?: {
22
+ stepsToDelete?: TestCaseStepConfig[];
23
+ contextLabel?: string;
24
+ stepImages?: Map<string | number, string>;
25
+ });
14
26
  confirmDelete: EventEmitter<void>;
15
27
  cancelled: EventEmitter<void>;
16
28
  get stepsCount(): number;
@@ -21,6 +33,10 @@ export declare class DeleteStepsComponent {
21
33
  private getNormalStepLabel;
22
34
  onCancel(): void;
23
35
  onDelete(): void;
24
- static ɵfac: i0.ɵɵFactoryDeclaration<DeleteStepsComponent, never>;
25
- static ɵcmp: i0.ɵɵComponentDeclaration<DeleteStepsComponent, "cqa-delete-steps", never, { "stepsToDelete": "stepsToDelete"; "contextLabel": "contextLabel"; }, { "confirmDelete": "confirmDelete"; "cancelled": "cancelled"; }, never, never>;
36
+ /** Get step image URL if available */
37
+ getStepImage(step: TestCaseStepConfig): string | null;
38
+ /** Check if step has an image */
39
+ hasStepImage(step: TestCaseStepConfig): boolean;
40
+ static ɵfac: i0.ɵɵFactoryDeclaration<DeleteStepsComponent, [{ optional: true; }]>;
41
+ static ɵcmp: i0.ɵɵComponentDeclaration<DeleteStepsComponent, "cqa-delete-steps", never, {}, { "confirmDelete": "confirmDelete"; "cancelled": "cancelled"; }, never, never>;
26
42
  }
@@ -1,10 +1,11 @@
1
- import { EventEmitter, OnInit } from '@angular/core';
1
+ import { EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core';
2
2
  import { FormBuilder, FormGroup } from '@angular/forms';
3
3
  import { DndDropEvent } from 'ngx-drag-drop';
4
- import { DynamicSelectFieldConfig } from '../../dynamic-select/dynamic-select-field.component';
4
+ import { DynamicSelectFieldConfig, SelectOption } from '../../dynamic-select/dynamic-select-field.component';
5
5
  import { LoopStepConfig, TestCaseStepConfig, NormalStepConfig, ConditionStepConfig, StepGroupConfig } from '../test-case-step.models';
6
+ import { DataProfileOption } from '../../step-builder/step-builder-loop/step-builder-loop.component';
6
7
  import * as i0 from "@angular/core";
7
- export declare class TestCaseLoopStepComponent implements OnInit {
8
+ export declare class TestCaseLoopStepComponent implements OnInit, OnChanges {
8
9
  private fb;
9
10
  config: LoopStepConfig;
10
11
  id: string;
@@ -20,6 +21,14 @@ export declare class TestCaseLoopStepComponent implements OnInit {
20
21
  isNested: boolean;
21
22
  isInsideLoop: boolean;
22
23
  isReorder: boolean;
24
+ /** Options for the data profile dropdown - accepts DataProfileOption objects */
25
+ dataProfileOptions: DataProfileOption[];
26
+ /** Indicates if more data profiles are available for loading */
27
+ hasMoreDataProfiles: boolean;
28
+ /** Loading state for data profiles */
29
+ isLoadingDataProfiles: boolean;
30
+ /** Options for natural text actions (for while loop condition) */
31
+ naturalTextActionsOptions: SelectOption[];
23
32
  toggleExpanded: EventEmitter<{
24
33
  config: LoopStepConfig;
25
34
  expanded: boolean;
@@ -43,6 +52,12 @@ export declare class TestCaseLoopStepComponent implements OnInit {
43
52
  event: DndDropEvent;
44
53
  targetList: TestCaseStepConfig[];
45
54
  }>;
55
+ /** Emit when more data profiles need to be loaded */
56
+ loadMoreDataProfiles: EventEmitter<string>;
57
+ /** Emit when data profile search query changes */
58
+ searchDataProfiles: EventEmitter<string>;
59
+ /** Emit when step is updated (Apply button clicked in edit mode) */
60
+ stepUpdate: EventEmitter<LoopStepConfig>;
46
61
  onDndDrop(event: DndDropEvent): void;
47
62
  /** Expose global constructors for template (Angular templates don't have String/Number) */
48
63
  readonly stringFn: StringConstructor;
@@ -53,17 +68,32 @@ export declare class TestCaseLoopStepComponent implements OnInit {
53
68
  editForm: FormGroup;
54
69
  /** Cached select configs (stable refs to avoid change-detection loops) */
55
70
  forOptionTypeSelectConfig: DynamicSelectFieldConfig;
71
+ testDataProfileSelectConfig: DynamicSelectFieldConfig;
56
72
  startStepSelectConfig: DynamicSelectFieldConfig;
57
73
  endStepSelectConfig: DynamicSelectFieldConfig;
74
+ conditionSelectConfig: DynamicSelectFieldConfig;
58
75
  /** Options for Loop Start / Loop End dropdowns (1-10) */
59
76
  loopStepOptions: number[];
60
77
  /** Local copy of values while editing (for Cancel revert) */
61
78
  private editSnapshot;
62
79
  constructor(fb: FormBuilder);
63
80
  ngOnInit(): void;
81
+ ngOnChanges(changes: SimpleChanges): void;
64
82
  private buildEditForm;
65
83
  /** Build select configs once (same option shape as default stories: id + name) */
66
84
  private buildSelectConfigs;
85
+ /** Update condition select config with natural text actions options */
86
+ private updateConditionSelectConfig;
87
+ /** Update test data profile select config with current options and callbacks */
88
+ private updateTestDataProfileSelectConfig;
89
+ /** Convert DataProfileOption[] to SelectOption[] */
90
+ private convertDataProfileOptionsToSelectOptions;
91
+ /** Handle data profile selection */
92
+ private onDataProfileChange;
93
+ /** Handle search for data profiles */
94
+ private onSearchDataProfiles;
95
+ /** Handle load more data profiles */
96
+ private onLoadMoreDataProfiles;
67
97
  onEditFormFieldChange(controlName: string, value: string | number): void;
68
98
  getLoopTypeLabel(): string;
69
99
  isWhileLoop(): boolean;
@@ -105,5 +135,5 @@ export declare class TestCaseLoopStepComponent implements OnInit {
105
135
  onDelete(): void;
106
136
  onMoreOptions(): void;
107
137
  static ɵfac: i0.ɵɵFactoryDeclaration<TestCaseLoopStepComponent, never>;
108
- static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseLoopStepComponent, "cqa-test-case-loop-step", never, { "config": "config"; "id": "id"; "loopType": "loopType"; "stepNumber": "stepNumber"; "condition": "condition"; "maxIterations": "maxIterations"; "testDataProfile": "testDataProfile"; "startStep": "startStep"; "endStep": "endStep"; "nestedSteps": "nestedSteps"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; }, { "toggleExpanded": "toggleExpanded"; "testDataProfileChange": "testDataProfileChange"; "startStepChange": "startStepChange"; "endStepChange": "endStepChange"; "conditionChange": "conditionChange"; "maxIterationsChange": "maxIterationsChange"; "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "duplicate": "duplicate"; "delete": "delete"; "moreOptions": "moreOptions"; "edit": "edit"; "dndDropInZone": "dndDropInZone"; }, never, never>;
138
+ static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseLoopStepComponent, "cqa-test-case-loop-step", never, { "config": "config"; "id": "id"; "loopType": "loopType"; "stepNumber": "stepNumber"; "condition": "condition"; "maxIterations": "maxIterations"; "testDataProfile": "testDataProfile"; "startStep": "startStep"; "endStep": "endStep"; "nestedSteps": "nestedSteps"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; "dataProfileOptions": "dataProfileOptions"; "hasMoreDataProfiles": "hasMoreDataProfiles"; "isLoadingDataProfiles": "isLoadingDataProfiles"; "naturalTextActionsOptions": "naturalTextActionsOptions"; }, { "toggleExpanded": "toggleExpanded"; "testDataProfileChange": "testDataProfileChange"; "startStepChange": "startStepChange"; "endStepChange": "endStepChange"; "conditionChange": "conditionChange"; "maxIterationsChange": "maxIterationsChange"; "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "duplicate": "duplicate"; "delete": "delete"; "moreOptions": "moreOptions"; "edit": "edit"; "dndDropInZone": "dndDropInZone"; "loadMoreDataProfiles": "loadMoreDataProfiles"; "searchDataProfiles": "searchDataProfiles"; "stepUpdate": "stepUpdate"; }, never, never>;
109
139
  }
@@ -1,7 +1,63 @@
1
1
  import { InjectionToken } from '@angular/core';
2
2
  import { TestCaseStepConfig } from '../test-case-step.models';
3
+ /**
4
+ * API-driven field configuration for the Step Details Drawer.
5
+ * When type is undefined or unknown, treat as 'string' (text input / textfield).
6
+ */
7
+ export interface DynamicFieldConfig {
8
+ key: string;
9
+ label: string;
10
+ /** Rendered control: string (textfield), number, boolean, dropdown, textarea, code. When omitted, defaults to 'string'. */
11
+ type?: 'string' | 'number' | 'boolean' | 'dropdown' | 'textarea' | 'code';
12
+ section?: 'main' | 'constraints' | 'advanced';
13
+ options?: {
14
+ label: string;
15
+ value: unknown;
16
+ }[];
17
+ placeholder?: string;
18
+ required?: boolean;
19
+ rows?: number;
20
+ /** Optional default value when step has no value for this key. */
21
+ defaultValue?: unknown;
22
+ /** Optional sub-label for toggles (e.g. "Only use elements from the attached context"). */
23
+ subLabel?: string;
24
+ /** Optional tip text below the field. */
25
+ tip?: string;
26
+ }
27
+ /**
28
+ * API variable schema (e.g. from natural_test_actions[].variables).
29
+ */
30
+ export interface ApiVariableSchema {
31
+ path?: string;
32
+ default?: unknown;
33
+ mutable?: boolean;
34
+ type?: string;
35
+ /** Dropdown options: array of strings (value and label) or { label, value }[]. */
36
+ options?: string[] | {
37
+ label: string;
38
+ value: unknown;
39
+ }[];
40
+ }
41
+ /** Map of variable key → API variable schema. */
42
+ export declare type ApiVariablesMap = Record<string, ApiVariableSchema>;
43
+ /**
44
+ * Humanizes a variable key for use as label (e.g. "iFrameLocator" → "I Frame Locator").
45
+ */
46
+ export declare function humanizeVariableKey(key: string): string;
47
+ /**
48
+ * Maps API variables (e.g. natural_test_actions[].variables) to DynamicFieldConfig[].
49
+ * Use when the drawer is driven by API response instead of legacy step-type config.
50
+ */
51
+ export declare function mapApiVariablesToDynamicFields(variables: ApiVariablesMap | null | undefined, options?: {
52
+ labels?: Record<string, string>;
53
+ section?: DynamicFieldConfig['section'];
54
+ }): DynamicFieldConfig[];
3
55
  export interface StepDetailsDrawerData {
4
56
  step: TestCaseStepConfig;
5
57
  stepNumber: number | string;
58
+ /** Dynamic field definitions (e.g. from API natural_test_actions.variables). When provided, drawer renders from this array only. */
59
+ dynamicFields: DynamicFieldConfig[];
60
+ /** Optional drawer title (e.g. "API Step Details"). When omitted, defaults to "Step Details". */
61
+ title?: string;
6
62
  }
7
63
  export declare const STEP_DETAILS_DRAWER_DATA: InjectionToken<StepDetailsDrawerData>;
@@ -2,6 +2,7 @@
2
2
  * Configuration for Step Details Drawer (Edit In Depth).
3
3
  * Form is fully dynamic by Step Type – no hardcoded field lists.
4
4
  */
5
+ import type { DynamicFieldConfig } from './step-details-drawer-data';
5
6
  import { TestCaseStepConfig } from '../test-case-step.models';
6
7
  /** Field keys used for configuration-based rendering. */
7
8
  export declare type StepDetailsFieldKey = 'description' | 'metadata' | 'retryCount' | 'advanced' | 'method' | 'url' | 'headers' | 'body' | 'saveOutputAsVariable' | 'agentTask' | 'type' | 'environment' | 'maxRetries' | 'onlyUseAttachedContext' | 'takeScreenshotsWhenVerifying' | 'iframeLocator' | 'otherLocators' | 'continueOnError' | 'disabled';
@@ -49,3 +50,8 @@ export declare const STEP_DETAILS_FIELD_META: Record<StepDetailsFieldKey, StepDe
49
50
  export declare const ADVANCED_TOGGLE_KEYS: StepDetailsFieldKey[];
50
51
  /** Field keys shown inside Advanced (per step type), in addition to ADVANCED_TOGGLE_KEYS. */
51
52
  export declare const ADVANCED_SUBFIELDS_BY_TYPE: Record<StepDetailsStepType, StepDetailsFieldKey[]>;
53
+ /**
54
+ * Converts legacy step-type config to DynamicFieldConfig[] for backward compatibility.
55
+ * Use when opening the drawer without API-provided dynamic fields (e.g. Storybook, migration).
56
+ */
57
+ export declare function getDynamicFieldsFromLegacyConfig(step: TestCaseStepConfig | null | undefined): DynamicFieldConfig[];
@@ -1,15 +1,14 @@
1
1
  import { ChangeDetectorRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2
2
  import { FormBuilder, FormGroup } from '@angular/forms';
3
- import { StepDetailsFieldKey, StepDetailsStepType, StepDetailsFieldSection } from './step-details-drawer-field.config';
4
3
  import { StepDetailsDrawerRef } from './step-details-drawer-ref';
5
- import { StepDetailsDrawerData } from './step-details-drawer-data';
4
+ import { StepDetailsDrawerData, DynamicFieldConfig } from './step-details-drawer-data';
6
5
  import { TestCaseStepConfig } from '../test-case-step.models';
7
6
  import type { DynamicSelectFieldConfig } from '../../dynamic-select/dynamic-select-field.component';
8
7
  import * as i0 from "@angular/core";
9
8
  /**
10
9
  * Step Details Drawer (Edit In Depth).
11
- * Single reusable component; form is dynamic by Step Type via configuration.
12
- * No Priority section. Uses CQA components only.
10
+ * Renders only from the provided DynamicFieldConfig[]; no filtering or step-type-based field logic.
11
+ * Each step instance receives its own complete field configuration. Generic key-based step read/write.
13
12
  */
14
13
  export declare class StepDetailsDrawerComponent implements OnInit, OnChanges {
15
14
  private ref;
@@ -18,43 +17,50 @@ export declare class StepDetailsDrawerComponent implements OnInit, OnChanges {
18
17
  saveChanges: EventEmitter<TestCaseStepConfig>;
19
18
  cancel: EventEmitter<void>;
20
19
  saveAsTemplate: EventEmitter<TestCaseStepConfig>;
21
- /** Optional: when provided (e.g. from Storybook Controls), use instead of STEP_DETAILS_DRAWER_DATA. */
22
20
  stepData: TestCaseStepConfig | null;
23
21
  stepNumberInput: number | string | null;
22
+ /** When provided (e.g. Storybook), use instead of STEP_DETAILS_DRAWER_DATA.dynamicFields. */
23
+ dynamicFieldsInput: DynamicFieldConfig[] | null;
24
+ /** When provided, use as drawer header title (overrides data.title). */
25
+ drawerTitle: string | null;
24
26
  step: TestCaseStepConfig;
25
27
  stepNumber: number | string;
26
- stepType: StepDetailsStepType | null;
27
- visibleFields: StepDetailsFieldKey[];
28
- fieldMeta: Record<StepDetailsFieldKey, import("./step-details-drawer-field.config").StepDetailsFieldMeta>;
29
- advancedToggleKeys: StepDetailsFieldKey[];
28
+ dynamicFields: DynamicFieldConfig[];
29
+ drawerTitleValue: string;
30
30
  advancedExpanded: boolean;
31
- agentTaskExpanded: boolean;
32
31
  form: FormGroup;
33
- /** Cached select configs (stable references per key) to avoid infinite change detection in template. */
34
- readonly selectConfigMap: Record<string, DynamicSelectFieldConfig>;
35
- /** Subfields to show inside Advanced section for current step type. */
36
- get advancedSubfields(): StepDetailsFieldKey[];
32
+ /** Cached select configs per field key (stable refs for change detection). */
33
+ private selectConfigCache;
34
+ /** All fields from the provided array (same reference; used for single source of truth in template). */
35
+ get allFields(): DynamicFieldConfig[];
36
+ /** Fields in main section (section === 'main' or undefined). */
37
+ get mainFields(): DynamicFieldConfig[];
38
+ /** Fields in constraints section. */
39
+ get constraintsFields(): DynamicFieldConfig[];
40
+ /** Fields in advanced section (inside expandable block). */
41
+ get advancedFields(): DynamicFieldConfig[];
42
+ /** True when the field at index is the first in its section (for showing section headers). */
43
+ isFirstInSection(index: number, section: 'main' | 'constraints' | 'advanced'): boolean;
44
+ /** True when the field at index is not in the advanced section (render in main flow). */
45
+ isNonAdvancedField(index: number): boolean;
37
46
  constructor(ref: StepDetailsDrawerRef, fb: FormBuilder, cdr: ChangeDetectorRef, data?: StepDetailsDrawerData);
38
47
  ngOnInit(): void;
39
48
  ngOnChanges(changes: SimpleChanges): void;
40
- private syncStepTypeAndForm;
41
- private buildFormFromStep;
42
- getStepValue(key: StepDetailsFieldKey): unknown;
43
- setStepValue(key: StepDetailsFieldKey, value: unknown): void;
49
+ private buildFormFromDynamicFields;
50
+ /** Read value from step by key. No step-type logic; step is a generic key-value bag. */
51
+ getStepValue(key: string): unknown;
52
+ /** Write value to step by key. No step-type logic; step is a generic key-value bag. */
53
+ setStepValue(key: string, value: unknown): void;
44
54
  onBack(): void;
45
55
  onClose(): void;
46
56
  onCancel(): void;
47
57
  onSaveAsTemplate(): void;
48
58
  onSaveChanges(): void;
49
59
  private applyFormToStep;
50
- /** Build cached map of select configs from field meta (stable refs to prevent CD loops). */
51
- private buildSelectConfigMap;
52
- /** Return cached select config for key (for template use; same reference every time). */
53
- getSelectConfig(key: StepDetailsFieldKey): DynamicSelectFieldConfig | null;
54
- /** Whether this key is the first in its section (for showing section headings). */
55
- isFirstInSection(key: StepDetailsFieldKey, section: StepDetailsFieldSection): boolean;
56
- /** Dynamic drawer title by step type (e.g. "AI Agent Step Details"). */
57
- get drawerTitle(): string;
60
+ /** Build select config for dropdown field (cached per key). */
61
+ getSelectConfig(field: DynamicFieldConfig): DynamicSelectFieldConfig | null;
62
+ /** Resolved header title for template: @Input drawerTitle > injected data.title > default. */
63
+ get displayTitle(): string;
58
64
  static ɵfac: i0.ɵɵFactoryDeclaration<StepDetailsDrawerComponent, [null, null, null, { optional: true; }]>;
59
- static ɵcmp: i0.ɵɵComponentDeclaration<StepDetailsDrawerComponent, "cqa-step-details-drawer", never, { "stepData": "stepData"; "stepNumberInput": "stepNumberInput"; }, { "saveChanges": "saveChanges"; "cancel": "cancel"; "saveAsTemplate": "saveAsTemplate"; }, never, never>;
65
+ static ɵcmp: i0.ɵɵComponentDeclaration<StepDetailsDrawerComponent, "cqa-step-details-drawer", never, { "stepData": "stepData"; "stepNumberInput": "stepNumberInput"; "dynamicFieldsInput": "dynamicFieldsInput"; "drawerTitle": "drawerTitle"; }, { "saveChanges": "saveChanges"; "cancel": "cancel"; "saveAsTemplate": "saveAsTemplate"; }, never, never>;
60
66
  }
@@ -16,6 +16,14 @@ export declare class TestCaseStepGroupComponent implements OnInit, OnChanges, Do
16
16
  isInsideLoop: boolean;
17
17
  isReorder: boolean;
18
18
  loading: boolean;
19
+ /** Options for the data profile dropdown */
20
+ dataProfileOptions: any[];
21
+ /** Indicates if more data profiles are available for loading */
22
+ hasMoreDataProfiles: boolean;
23
+ /** Loading state for data profiles */
24
+ isLoadingDataProfiles: boolean;
25
+ /** Natural text actions options for while loop condition */
26
+ naturalTextActionsOptions: any[];
19
27
  private previousNestedStepsLength;
20
28
  private previousNestedStepsReference;
21
29
  constructor(cdr: ChangeDetectorRef);
@@ -43,6 +51,12 @@ export declare class TestCaseStepGroupComponent implements OnInit, OnChanges, Do
43
51
  event: DndDropEvent;
44
52
  targetList: TestCaseStepConfig[];
45
53
  }>;
54
+ /** Emit when more data profiles need to be loaded */
55
+ loadMoreDataProfiles: EventEmitter<string>;
56
+ /** Emit when data profile search query changes */
57
+ searchDataProfiles: EventEmitter<string>;
58
+ /** Emit when a nested step is updated (e.g., Apply button clicked in loop-step edit mode) */
59
+ stepUpdate: EventEmitter<TestCaseStepConfig>;
46
60
  onDndDrop(event: DndDropEvent): void;
47
61
  ngOnInit(): void;
48
62
  ngOnChanges(changes: SimpleChanges): void;
@@ -74,5 +88,5 @@ export declare class TestCaseStepGroupComponent implements OnInit, OnChanges, Do
74
88
  onNestedConditionAddBranch(nestedStep: ConditionStepConfig, index: number): void;
75
89
  onNestedConditionDeleteBranch(nestedStep: ConditionStepConfig, branch: any, index: number): void;
76
90
  static ɵfac: i0.ɵɵFactoryDeclaration<TestCaseStepGroupComponent, never>;
77
- static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseStepGroupComponent, "cqa-test-case-step-group", never, { "config": "config"; "id": "id"; "stepNumber": "stepNumber"; "groupName": "groupName"; "description": "description"; "reusable": "reusable"; "nestedSteps": "nestedSteps"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; "loading": "loading"; }, { "toggleExpanded": "toggleExpanded"; "groupNameChange": "groupNameChange"; "descriptionChange": "descriptionChange"; "reusableChange": "reusableChange"; "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "openExternal": "openExternal"; "edit": "edit"; "link": "link"; "duplicate": "duplicate"; "delete": "delete"; "dndDropInZone": "dndDropInZone"; }, never, never>;
91
+ static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseStepGroupComponent, "cqa-test-case-step-group", never, { "config": "config"; "id": "id"; "stepNumber": "stepNumber"; "groupName": "groupName"; "description": "description"; "reusable": "reusable"; "nestedSteps": "nestedSteps"; "expanded": "expanded"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "isReorder": "isReorder"; "loading": "loading"; "dataProfileOptions": "dataProfileOptions"; "hasMoreDataProfiles": "hasMoreDataProfiles"; "isLoadingDataProfiles": "isLoadingDataProfiles"; "naturalTextActionsOptions": "naturalTextActionsOptions"; }, { "toggleExpanded": "toggleExpanded"; "groupNameChange": "groupNameChange"; "descriptionChange": "descriptionChange"; "reusableChange": "reusableChange"; "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "openExternal": "openExternal"; "edit": "edit"; "link": "link"; "duplicate": "duplicate"; "delete": "delete"; "dndDropInZone": "dndDropInZone"; "loadMoreDataProfiles": "loadMoreDataProfiles"; "searchDataProfiles": "searchDataProfiles"; "stepUpdate": "stepUpdate"; }, never, never>;
78
92
  }
@@ -1,8 +1,8 @@
1
- import { EventEmitter, ViewContainerRef, OnChanges, SimpleChanges, AfterViewInit, ChangeDetectorRef } from '@angular/core';
1
+ import { EventEmitter, ViewContainerRef, OnChanges, SimpleChanges, AfterViewInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
2
2
  import { TestCaseStepComponentMap } from '../test-case-step-components.token';
3
3
  import { TestCaseStepConfig, ConditionBranch } from '../test-case-step.models';
4
4
  import * as i0 from "@angular/core";
5
- export declare class TestCaseDetailsRendererComponent implements OnChanges, AfterViewInit {
5
+ export declare class TestCaseDetailsRendererComponent implements OnChanges, AfterViewInit, OnDestroy {
6
6
  private componentMap;
7
7
  private cdr;
8
8
  stepHost: ViewContainerRef;
@@ -37,7 +37,9 @@ export declare class TestCaseDetailsRendererComponent implements OnChanges, Afte
37
37
  }>;
38
38
  link: EventEmitter<void>;
39
39
  duplicate: EventEmitter<void>;
40
- delete: EventEmitter<void>;
40
+ delete: EventEmitter<void | {
41
+ step: TestCaseStepConfig;
42
+ }>;
41
43
  viewDetails: EventEmitter<void>;
42
44
  selectionChange: EventEmitter<boolean>;
43
45
  conditionChange: EventEmitter<string>;
@@ -54,6 +56,10 @@ export declare class TestCaseDetailsRendererComponent implements OnChanges, Afte
54
56
  stepIndex: number;
55
57
  }>;
56
58
  addBranch: EventEmitter<void>;
59
+ /** Emitted when user clicks "Add Else" in a condition step; parent should call POST test_steps with conditionType CONDITION_ELSE */
60
+ addElse: EventEmitter<{
61
+ conditionStepConfig: TestCaseStepConfig;
62
+ }>;
57
63
  deleteBranch: EventEmitter<ConditionBranch>;
58
64
  testDataProfileChange: EventEmitter<string>;
59
65
  startStepChange: EventEmitter<number>;
@@ -67,6 +73,22 @@ export declare class TestCaseDetailsRendererComponent implements OnChanges, Afte
67
73
  event: any;
68
74
  targetList: TestCaseStepConfig[];
69
75
  }>;
76
+ /** Data profile options for loop steps */
77
+ dataProfileOptions: any[];
78
+ /** Indicates if more data profiles are available for loading */
79
+ hasMoreDataProfiles: boolean;
80
+ /** Loading state for data profiles */
81
+ isLoadingDataProfiles: boolean;
82
+ /** Natural text actions options for while loop condition */
83
+ naturalTextActionsOptions: any[];
84
+ /** Function to process template variables for condition steps */
85
+ setConditionTemplateVariables: (template: any) => any[];
86
+ /** Emit when more data profiles need to be loaded */
87
+ loadMoreDataProfiles: EventEmitter<string>;
88
+ /** Emit when data profile search query changes */
89
+ searchDataProfiles: EventEmitter<string>;
90
+ /** Emit when a step is updated (e.g., Apply button clicked in loop-step edit mode) */
91
+ stepUpdate: EventEmitter<TestCaseStepConfig>;
70
92
  addStepBetweenClick: EventEmitter<{
71
93
  step: TestCaseStepConfig;
72
94
  index: number;
@@ -78,6 +100,7 @@ export declare class TestCaseDetailsRendererComponent implements OnChanges, Afte
78
100
  private getComponentType;
79
101
  private renderStep;
80
102
  private wireOutputs;
103
+ ngOnDestroy(): void;
81
104
  static ɵfac: i0.ɵɵFactoryDeclaration<TestCaseDetailsRendererComponent, never>;
82
- static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseDetailsRendererComponent, "cqa-test-case-details-renderer", never, { "step": "step"; "index": "index"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "branch": "branch"; "isReorder": "isReorder"; "addStepBetween": "addStepBetween"; }, { "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "toggleExpanded": "toggleExpanded"; "groupNameChange": "groupNameChange"; "descriptionChange": "descriptionChange"; "reusableChange": "reusableChange"; "openExternal": "openExternal"; "edit": "edit"; "link": "link"; "duplicate": "duplicate"; "delete": "delete"; "viewDetails": "viewDetails"; "selectionChange": "selectionChange"; "conditionChange": "conditionChange"; "branchStepChange": "branchStepChange"; "addStepForBranch": "addStepForBranch"; "deleteStepWithBranch": "deleteStepWithBranch"; "addBranch": "addBranch"; "deleteBranch": "deleteBranch"; "testDataProfileChange": "testDataProfileChange"; "startStepChange": "startStepChange"; "endStepChange": "endStepChange"; "maxIterationsChange": "maxIterationsChange"; "eventTypeChange": "eventTypeChange"; "parameterChange": "parameterChange"; "clickAction": "clickAction"; "dndDropInZone": "dndDropInZone"; "addStepBetweenClick": "addStepBetweenClick"; }, never, never>;
105
+ static ɵcmp: i0.ɵɵComponentDeclaration<TestCaseDetailsRendererComponent, "cqa-test-case-details-renderer", never, { "step": "step"; "index": "index"; "isNested": "isNested"; "isInsideLoop": "isInsideLoop"; "branch": "branch"; "isReorder": "isReorder"; "addStepBetween": "addStepBetween"; "dataProfileOptions": "dataProfileOptions"; "hasMoreDataProfiles": "hasMoreDataProfiles"; "isLoadingDataProfiles": "isLoadingDataProfiles"; "naturalTextActionsOptions": "naturalTextActionsOptions"; "setConditionTemplateVariables": "setConditionTemplateVariables"; }, { "nestedStepChange": "nestedStepChange"; "addStep": "addStep"; "deleteStep": "deleteStep"; "toggleExpanded": "toggleExpanded"; "groupNameChange": "groupNameChange"; "descriptionChange": "descriptionChange"; "reusableChange": "reusableChange"; "openExternal": "openExternal"; "edit": "edit"; "link": "link"; "duplicate": "duplicate"; "delete": "delete"; "viewDetails": "viewDetails"; "selectionChange": "selectionChange"; "conditionChange": "conditionChange"; "branchStepChange": "branchStepChange"; "addStepForBranch": "addStepForBranch"; "deleteStepWithBranch": "deleteStepWithBranch"; "addBranch": "addBranch"; "addElse": "addElse"; "deleteBranch": "deleteBranch"; "testDataProfileChange": "testDataProfileChange"; "startStepChange": "startStepChange"; "endStepChange": "endStepChange"; "maxIterationsChange": "maxIterationsChange"; "eventTypeChange": "eventTypeChange"; "parameterChange": "parameterChange"; "clickAction": "clickAction"; "dndDropInZone": "dndDropInZone"; "loadMoreDataProfiles": "loadMoreDataProfiles"; "searchDataProfiles": "searchDataProfiles"; "stepUpdate": "stepUpdate"; "addStepBetweenClick": "addStepBetweenClick"; }, never, never>;
83
106
  }