@cqa-lib/cqa-ui 1.1.185 → 1.1.187
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/lib/execution-screen/main-step-collapse/main-step-collapse.component.mjs +20 -3
- package/esm2020/lib/simulator/simulator.component.mjs +188 -346
- package/esm2020/lib/step-builder/step-builder-api/step-builder-api.component.mjs +132 -7
- package/esm2020/lib/step-builder/step-builder-database/step-builder-database.component.mjs +4 -5
- package/esm2020/lib/test-case-details/condition-step/condition-step.component.mjs +1 -1
- package/esm2020/lib/test-case-details/loop-step/loop-step.component.mjs +1 -1
- package/esm2020/lib/test-case-details/normal-step/normal-step.component.mjs +24 -32
- package/esm2020/lib/test-case-details/step-group/step-group.component.mjs +1 -1
- package/esm2020/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.mjs +15 -3
- package/esm2020/lib/test-case-details/test-case-step.models.mjs +1 -1
- package/esm2020/lib/test-case-details/test-data-modal/test-data-modal-data.mjs +1 -1
- package/esm2020/lib/test-case-details/test-data-modal/test-data-modal.component.mjs +51 -17
- package/fesm2015/cqa-lib-cqa-ui.mjs +436 -416
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +424 -404
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/execution-screen/main-step-collapse/main-step-collapse.component.d.ts +6 -3
- package/lib/simulator/simulator.component.d.ts +10 -22
- package/lib/step-builder/step-builder-api/step-builder-api.component.d.ts +6 -0
- package/lib/test-case-details/normal-step/normal-step.component.d.ts +7 -2
- package/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.d.ts +7 -1
- package/lib/test-case-details/test-case-step.models.d.ts +1 -0
- package/lib/test-case-details/test-data-modal/test-data-modal-data.d.ts +6 -1
- package/lib/test-case-details/test-data-modal/test-data-modal.component.d.ts +11 -7
- package/package.json +1 -1
- package/styles.css +1 -1
|
@@ -3,7 +3,7 @@ import { EventEmitter, Component, Input, Output, HostListener, ViewChildren, Vie
|
|
|
3
3
|
import * as i2 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
5
|
import * as i2$1 from '@angular/forms';
|
|
6
|
-
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, FormBuilder, Validators, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
7
7
|
import * as i1 from '@angular/material/icon';
|
|
8
8
|
import { MatIconModule } from '@angular/material/icon';
|
|
9
9
|
import * as i3$1 from '@angular/material/menu';
|
|
@@ -11271,6 +11271,8 @@ class MainStepCollapseComponent {
|
|
|
11271
11271
|
this.viewStepsAsRedirect = false;
|
|
11272
11272
|
/** When redirecting, open link in new tab. Default true */
|
|
11273
11273
|
this.viewStepsOpenInNewTab = true;
|
|
11274
|
+
/** Optional initial item id to expand (e.g. first failed prerequisite). When set and present in items, that item is expanded on load. */
|
|
11275
|
+
this.initialExpandedItemId = null;
|
|
11274
11276
|
this.viewSteps = new EventEmitter();
|
|
11275
11277
|
this.headerButtonClick = new EventEmitter();
|
|
11276
11278
|
this.expandedChange = new EventEmitter();
|
|
@@ -11279,11 +11281,25 @@ class MainStepCollapseComponent {
|
|
|
11279
11281
|
}
|
|
11280
11282
|
ngOnInit() {
|
|
11281
11283
|
this.isExpanded = this.expanded;
|
|
11284
|
+
this.applyInitialExpandedItemId();
|
|
11282
11285
|
}
|
|
11283
11286
|
ngOnChanges(changes) {
|
|
11284
11287
|
if (changes['expanded']) {
|
|
11285
11288
|
this.isExpanded = this.expanded;
|
|
11286
11289
|
}
|
|
11290
|
+
if (changes['initialExpandedItemId'] || changes['items']) {
|
|
11291
|
+
this.applyInitialExpandedItemId();
|
|
11292
|
+
}
|
|
11293
|
+
}
|
|
11294
|
+
applyInitialExpandedItemId() {
|
|
11295
|
+
var _a;
|
|
11296
|
+
if (this.initialExpandedItemId == null || !((_a = this.items) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
11297
|
+
return;
|
|
11298
|
+
}
|
|
11299
|
+
const match = this.items.find((item) => item.id == this.initialExpandedItemId);
|
|
11300
|
+
if (match) {
|
|
11301
|
+
this.expandedItemId = match.id;
|
|
11302
|
+
}
|
|
11287
11303
|
}
|
|
11288
11304
|
toggle() {
|
|
11289
11305
|
this.isExpanded = !this.isExpanded;
|
|
@@ -11335,7 +11351,7 @@ class MainStepCollapseComponent {
|
|
|
11335
11351
|
this.viewSteps.emit(item);
|
|
11336
11352
|
}
|
|
11337
11353
|
isItemExpanded(itemId) {
|
|
11338
|
-
return this.expandedItemId
|
|
11354
|
+
return this.expandedItemId == itemId;
|
|
11339
11355
|
}
|
|
11340
11356
|
getDisplayCount() {
|
|
11341
11357
|
var _a;
|
|
@@ -11365,7 +11381,7 @@ class MainStepCollapseComponent {
|
|
|
11365
11381
|
}
|
|
11366
11382
|
}
|
|
11367
11383
|
MainStepCollapseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MainStepCollapseComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11368
|
-
MainStepCollapseComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: MainStepCollapseComponent, selector: "cqa-main-step-collapse", inputs: { title: "title", items: "items", expanded: "expanded", icon: "icon", count: "count", itemContentTemplate: "itemContentTemplate", headerButtons: "headerButtons", viewStepsAsRedirect: "viewStepsAsRedirect", getViewStepsUrl: "getViewStepsUrl", viewStepsOpenInNewTab: "viewStepsOpenInNewTab" }, outputs: { viewSteps: "viewSteps", headerButtonClick: "headerButtonClick", expandedChange: "expandedChange" }, host: { classAttribute: "cqa-ui-root" }, queries: [{ propertyName: "itemContentTpl", first: true, predicate: ["itemContent"], descendants: true, read: TemplateRef }], usesOnChanges: true, ngImport: i0, template: "<!-- Header -->\n<div\n class=\"cqa-mt-2 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-px-3 cqa-py-2 cqa-cursor-pointer cqa-bg-[#EEF2FF] cqa-rounded-[4px] cqa-border cqa-border-[#C6D2FF] cqa-border-solid\"\n (click)=\"toggle()\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-w-full\">\n <!-- Chevron Icon (Left) -->\n <!-- <svg [class.cqa-rotate-180]=\"isExpanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#3F51B5\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> -->\n <div><svg [class.cqa-rotate-180]=\"isExpanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#4F39F6\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- Chain-Link Icon (if configured, otherwise default) -->\n <!-- <div *ngIf=\"icon && icon.type === 'folder'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.6666 11.6667C11.976 11.6667 12.2728 11.5437 12.4916 11.325C12.7104 11.1062 12.8333 10.8094 12.8333 10.5V4.66667C12.8333 4.35725 12.7104 4.0605 12.4916 3.84171C12.2728 3.62292 11.976 3.5 11.6666 3.5H7.05829C6.86318 3.50191 6.67069 3.45486 6.49847 3.36314C6.32624 3.27142 6.17977 3.13797 6.07246 2.975L5.59996 2.275C5.49373 2.11369 5.34911 1.98128 5.17908 1.88965C5.00906 1.79802 4.81894 1.75003 4.62579 1.75H2.33329C2.02387 1.75 1.72713 1.87292 1.50833 2.09171C1.28954 2.3105 1.16663 2.60725 1.16663 2.91667V10.5C1.16663 10.8094 1.28954 11.1062 1.50833 11.325C1.72713 11.5437 2.02387 11.6667 2.33329 11.6667H11.6666Z\" fill=\"#EFF6FF\" stroke=\"#3F51B5\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n <div *ngIf=\"icon && icon.type === 'loop'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"16\" height=\"16\" rx=\"4\" fill=\"#EBECFD\"/>\n <path d=\"M9.66663 4.66666L11 5.99999L9.66663 7.33332\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.66667V7.33333C5 6.97971 5.14048 6.64057 5.39052 6.39052C5.64057 6.14048 5.97971 6 6.33333 6H11\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.33333 11.3333L5 9.99999L6.33333 8.66666\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11 8.33334V8.66668C11 9.0203 10.8595 9.35944 10.6095 9.60949C10.3594 9.85953 10.0203 10 9.66667 10H5\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div> -->\n <!-- Bar Icon (Bulleted List) -->\n <div *ngIf=\"icon && icon.type === 'bar'\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- First bullet and line -->\n <circle cx=\"3\" cy=\"5\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"5\" x2=\"17\" y2=\"5\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Second bullet and line -->\n <circle cx=\"3\" cy=\"10\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"10\" x2=\"17\" y2=\"10\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Third bullet and line -->\n <circle cx=\"3\" cy=\"15\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"15\" x2=\"17\" y2=\"15\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </div>\n\n <!-- Default Chain-Link Icon (when no icon or icon type is not specified) -->\n <div *ngIf=\"!icon || (icon.type !== 'bar' && icon.type !== 'folder' && icon.type !== 'loop' && icon.type !== 'custom')\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M7.50033 14.1663H5.83366C4.72859 14.1663 3.66878 13.7274 2.88738 12.946C2.10598 12.1646 1.66699 11.1047 1.66699 9.99967C1.66699 8.89461 2.10598 7.8348 2.88738 7.0534C3.66878 6.27199 4.72859 5.83301 5.83366 5.83301H7.50033\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12.5 5.83301H14.1667C15.2717 5.83301 16.3315 6.27199 17.1129 7.0534C17.8943 7.8348 18.3333 8.89461 18.3333 9.99967C18.3333 11.1047 17.8943 12.1646 17.1129 12.946C16.3315 13.7274 15.2717 14.1663 14.1667 14.1663H12.5\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.66699 10H13.3337\" stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Custom Icon -->\n <div *ngIf=\"icon && icon.type === 'custom' && icon.svg\" [innerHTML]=\"icon.svg\"></div>\n\n <!-- Title -->\n <span class=\"cqa-font-semibold cqa-text-[14px] cqa-leading-[17px] cqa-text-[#312C85] cqa-flex-1\">\n {{ title }}\n </span>\n\n <!-- Badge and dynamic header buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" (click)=\"$event.stopPropagation()\">\n <ng-container *ngFor=\"let btn of headerButtons; let i = index\">\n <cqa-button\n [text]=\"btn.text\"\n [icon]=\"btn.icon\"\n [variant]=\"btn.variant || 'outlined'\"\n [disabled]=\"btn.disabled\"\n [tooltip]=\"btn.tooltip\"\n [customClass]=\"btn.customClass\"\n [btnSize]=\"btn.btnSize || 'sm'\"\n (clicked)=\"onHeaderButtonClick(btn, i, $event)\">\n </cqa-button>\n </ng-container>\n <span\n class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-bg-[#C6D2FF] cqa-text-[12px] cqa-leading-[16px] cqa-text-[#432DD7]\">\n {{ getDisplayCount() }}\n </span>\n </div>\n </div>\n</div>\n\n<!-- Expanded Content -->\n<div *ngIf=\"isExpanded\" class=\"cqa-mt-2 cqa-flex cqa-flex-col cqa-gap-2 cqa-px-2.5\">\n <!-- When there are no items, display ng-content directly -->\n <ng-container *ngIf=\"!items || items.length === 0\">\n <ng-content></ng-content>\n </ng-container>\n\n <!-- When items exist, display them -->\n <div *ngFor=\"let item of items\">\n\n <!-- Item Header -->\n <div class=\"cqa-bg-white cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-md cqa-overflow-hidden\">\n <div class=\"cqa-py-2 cqa-px-3 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3\">\n <!-- Left side: Status and Title -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-1\">\n <!-- Status Icon (Filled Green Circle with Checkmark) -->\n <div>\n <!-- Success -->\n <svg *ngIf=\"item.status === 'success'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_48_121)\">\n <path\n d=\"M10.0003 18.3337C14.6027 18.3337 18.3337 14.6027 18.3337 10.0003C18.3337 5.39795 14.6027 1.66699 10.0003 1.66699C5.39795 1.66699 1.66699 5.39795 1.66699 10.0003C1.66699 14.6027 5.39795 18.3337 10.0003 18.3337Z\"\n stroke=\"#00A63E\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.5 9.99967L9.16667 11.6663L12.5 8.33301\" stroke=\"#00A63E\" stroke-width=\"1.66667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_48_121\">\n <rect width=\"20\" height=\"20\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n <!-- Failed -->\n <svg *ngIf=\"item.status === 'failed'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#EF4444\" />\n <path d=\"M7 7L13 13M13 7L7 13\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n <!-- Pending -->\n <svg *ngIf=\"item.status === 'pending'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#9CA3AF\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <!-- Running -->\n <svg *ngIf=\"item.status === 'running'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#3B82F6\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n \n <!-- Title -->\n <span class=\"cqa-text-[14px] cqa-leading-[18px]\" style=\"word-break: break-word;\">\n {{ item.title }}\n </span>\n </div>\n \n <!-- Right side: Duration and View Steps Link -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Duration with Clock Icon -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6 11C8.76142 11 11 8.76142 11 6C11 3.23858 8.76142 1 6 1C3.23858 1 1 3.23858 1 6C1 8.76142 3.23858 11 6 11Z\"\n stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6 3V6L8 7\" stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <span class=\"cqa-text-[14px] cqa-leading-[20px] cqa-text-[#6A7282]\">\n {{ formatDuration(item.duration) }}\n </span>\n </div>\n \n <!-- View Steps Link: redirect mode (navigates to URL) or inline mode (toggle expand) -->\n <a *ngIf=\"hasViewStepsRedirectUrl(item)\"\n [href]=\"getItemViewStepsUrl(item)\"\n [attr.target]=\"viewStepsOpenInNewTab ? '_blank' : null\"\n [attr.rel]=\"viewStepsOpenInNewTab ? 'noopener noreferrer' : null\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>View steps</span>\n <svg class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n <a *ngIf=\"!hasViewStepsRedirectUrl(item)\" href=\"#\" (click)=\"onViewSteps(item, $event)\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>{{ isItemExpanded(item.id) ? 'Hide steps' : 'View steps' }}</span>\n <svg [class.cqa-rotate-90]=\"isItemExpanded(item.id)\" class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n </div>\n </div>\n\n <!-- Steps Content (shown when item is expanded) -->\n <div *ngIf=\"isItemExpanded(item.id)\">\n <!-- Custom template via TemplateRef (from @ContentChild or @Input) - passes item as context -->\n <ng-container *ngIf=\"itemContentTpl || itemContentTemplate\">\n <div class=\"cqa-p-3\">\n <ng-container\n *ngTemplateOutlet=\"(itemContentTpl || itemContentTemplate)!; context: { $implicit: item, item: item }\"></ng-container>\n </div>\n </ng-container>\n\n <!-- Custom content projection via ng-content - displayed for all expanded items -->\n <ng-content select=\"[itemContent]\"></ng-content>\n </div>\n </div>\n</div>\n\n<!-- Custom content projection after all items - for steps loaded after API call -->\n<ng-content select=\"[afterItems]\"></ng-content>", components: [{ type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
|
|
11384
|
+
MainStepCollapseComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: MainStepCollapseComponent, selector: "cqa-main-step-collapse", inputs: { title: "title", items: "items", expanded: "expanded", icon: "icon", count: "count", itemContentTemplate: "itemContentTemplate", headerButtons: "headerButtons", viewStepsAsRedirect: "viewStepsAsRedirect", getViewStepsUrl: "getViewStepsUrl", viewStepsOpenInNewTab: "viewStepsOpenInNewTab", initialExpandedItemId: "initialExpandedItemId" }, outputs: { viewSteps: "viewSteps", headerButtonClick: "headerButtonClick", expandedChange: "expandedChange" }, host: { classAttribute: "cqa-ui-root" }, queries: [{ propertyName: "itemContentTpl", first: true, predicate: ["itemContent"], descendants: true, read: TemplateRef }], usesOnChanges: true, ngImport: i0, template: "<!-- Header -->\n<div\n class=\"cqa-mt-2 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-px-3 cqa-py-2 cqa-cursor-pointer cqa-bg-[#EEF2FF] cqa-rounded-[4px] cqa-border cqa-border-[#C6D2FF] cqa-border-solid\"\n (click)=\"toggle()\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-w-full\">\n <!-- Chevron Icon (Left) -->\n <!-- <svg [class.cqa-rotate-180]=\"isExpanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#3F51B5\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> -->\n <div><svg [class.cqa-rotate-180]=\"isExpanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#4F39F6\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- Chain-Link Icon (if configured, otherwise default) -->\n <!-- <div *ngIf=\"icon && icon.type === 'folder'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.6666 11.6667C11.976 11.6667 12.2728 11.5437 12.4916 11.325C12.7104 11.1062 12.8333 10.8094 12.8333 10.5V4.66667C12.8333 4.35725 12.7104 4.0605 12.4916 3.84171C12.2728 3.62292 11.976 3.5 11.6666 3.5H7.05829C6.86318 3.50191 6.67069 3.45486 6.49847 3.36314C6.32624 3.27142 6.17977 3.13797 6.07246 2.975L5.59996 2.275C5.49373 2.11369 5.34911 1.98128 5.17908 1.88965C5.00906 1.79802 4.81894 1.75003 4.62579 1.75H2.33329C2.02387 1.75 1.72713 1.87292 1.50833 2.09171C1.28954 2.3105 1.16663 2.60725 1.16663 2.91667V10.5C1.16663 10.8094 1.28954 11.1062 1.50833 11.325C1.72713 11.5437 2.02387 11.6667 2.33329 11.6667H11.6666Z\" fill=\"#EFF6FF\" stroke=\"#3F51B5\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n <div *ngIf=\"icon && icon.type === 'loop'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"16\" height=\"16\" rx=\"4\" fill=\"#EBECFD\"/>\n <path d=\"M9.66663 4.66666L11 5.99999L9.66663 7.33332\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.66667V7.33333C5 6.97971 5.14048 6.64057 5.39052 6.39052C5.64057 6.14048 5.97971 6 6.33333 6H11\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.33333 11.3333L5 9.99999L6.33333 8.66666\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11 8.33334V8.66668C11 9.0203 10.8595 9.35944 10.6095 9.60949C10.3594 9.85953 10.0203 10 9.66667 10H5\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div> -->\n <!-- Bar Icon (Bulleted List) -->\n <div *ngIf=\"icon && icon.type === 'bar'\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- First bullet and line -->\n <circle cx=\"3\" cy=\"5\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"5\" x2=\"17\" y2=\"5\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Second bullet and line -->\n <circle cx=\"3\" cy=\"10\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"10\" x2=\"17\" y2=\"10\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Third bullet and line -->\n <circle cx=\"3\" cy=\"15\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"15\" x2=\"17\" y2=\"15\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </div>\n\n <!-- Default Chain-Link Icon (when no icon or icon type is not specified) -->\n <div *ngIf=\"!icon || (icon.type !== 'bar' && icon.type !== 'folder' && icon.type !== 'loop' && icon.type !== 'custom')\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M7.50033 14.1663H5.83366C4.72859 14.1663 3.66878 13.7274 2.88738 12.946C2.10598 12.1646 1.66699 11.1047 1.66699 9.99967C1.66699 8.89461 2.10598 7.8348 2.88738 7.0534C3.66878 6.27199 4.72859 5.83301 5.83366 5.83301H7.50033\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12.5 5.83301H14.1667C15.2717 5.83301 16.3315 6.27199 17.1129 7.0534C17.8943 7.8348 18.3333 8.89461 18.3333 9.99967C18.3333 11.1047 17.8943 12.1646 17.1129 12.946C16.3315 13.7274 15.2717 14.1663 14.1667 14.1663H12.5\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.66699 10H13.3337\" stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Custom Icon -->\n <div *ngIf=\"icon && icon.type === 'custom' && icon.svg\" [innerHTML]=\"icon.svg\"></div>\n\n <!-- Title -->\n <span class=\"cqa-font-semibold cqa-text-[14px] cqa-leading-[17px] cqa-text-[#312C85] cqa-flex-1\">\n {{ title }}\n </span>\n\n <!-- Badge and dynamic header buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" (click)=\"$event.stopPropagation()\">\n <ng-container *ngFor=\"let btn of headerButtons; let i = index\">\n <cqa-button\n [text]=\"btn.text\"\n [icon]=\"btn.icon\"\n [variant]=\"btn.variant || 'outlined'\"\n [disabled]=\"btn.disabled\"\n [tooltip]=\"btn.tooltip\"\n [customClass]=\"btn.customClass\"\n [btnSize]=\"btn.btnSize || 'sm'\"\n (clicked)=\"onHeaderButtonClick(btn, i, $event)\">\n </cqa-button>\n </ng-container>\n <span\n class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-bg-[#C6D2FF] cqa-text-[12px] cqa-leading-[16px] cqa-text-[#432DD7]\">\n {{ getDisplayCount() }}\n </span>\n </div>\n </div>\n</div>\n\n<!-- Expanded Content -->\n<div *ngIf=\"isExpanded\" class=\"cqa-mt-2 cqa-flex cqa-flex-col cqa-gap-2 cqa-px-2.5\">\n <!-- When there are no items, display ng-content directly -->\n <ng-container *ngIf=\"!items || items.length === 0\">\n <ng-content></ng-content>\n </ng-container>\n\n <!-- When items exist, display them -->\n <div *ngFor=\"let item of items\">\n\n <!-- Item Header -->\n <div class=\"cqa-bg-white cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-md cqa-overflow-hidden\">\n <div class=\"cqa-py-2 cqa-px-3 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3\">\n <!-- Left side: Status and Title -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-1\">\n <!-- Status Icon (Filled Green Circle with Checkmark) -->\n <div>\n <!-- Success -->\n <svg *ngIf=\"item.status === 'success'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_48_121)\">\n <path\n d=\"M10.0003 18.3337C14.6027 18.3337 18.3337 14.6027 18.3337 10.0003C18.3337 5.39795 14.6027 1.66699 10.0003 1.66699C5.39795 1.66699 1.66699 5.39795 1.66699 10.0003C1.66699 14.6027 5.39795 18.3337 10.0003 18.3337Z\"\n stroke=\"#00A63E\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.5 9.99967L9.16667 11.6663L12.5 8.33301\" stroke=\"#00A63E\" stroke-width=\"1.66667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_48_121\">\n <rect width=\"20\" height=\"20\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n <!-- Failed -->\n <svg *ngIf=\"item.status === 'failed'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#EF4444\" />\n <path d=\"M7 7L13 13M13 7L7 13\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n <!-- Pending -->\n <svg *ngIf=\"item.status === 'pending'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#9CA3AF\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <!-- Running -->\n <svg *ngIf=\"item.status === 'running'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#3B82F6\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n \n <!-- Title -->\n <span class=\"cqa-text-[14px] cqa-leading-[18px]\" style=\"word-break: break-word;\">\n {{ item.title }}\n </span>\n </div>\n \n <!-- Right side: Duration and View Steps Link -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Duration with Clock Icon -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6 11C8.76142 11 11 8.76142 11 6C11 3.23858 8.76142 1 6 1C3.23858 1 1 3.23858 1 6C1 8.76142 3.23858 11 6 11Z\"\n stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6 3V6L8 7\" stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <span class=\"cqa-text-[14px] cqa-leading-[20px] cqa-text-[#6A7282]\">\n {{ formatDuration(item.duration) }}\n </span>\n </div>\n \n <!-- View Steps Link: redirect mode (navigates to URL) or inline mode (toggle expand) -->\n <a *ngIf=\"hasViewStepsRedirectUrl(item)\"\n [href]=\"getItemViewStepsUrl(item)\"\n [attr.target]=\"viewStepsOpenInNewTab ? '_blank' : null\"\n [attr.rel]=\"viewStepsOpenInNewTab ? 'noopener noreferrer' : null\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>View steps</span>\n <svg class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n <a *ngIf=\"!hasViewStepsRedirectUrl(item)\" href=\"#\" (click)=\"onViewSteps(item, $event)\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>{{ isItemExpanded(item.id) ? 'Hide steps' : 'View steps' }}</span>\n <svg [class.cqa-rotate-90]=\"isItemExpanded(item.id)\" class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n </div>\n </div>\n\n <!-- Steps Content (shown when item is expanded) -->\n <div *ngIf=\"isItemExpanded(item.id)\">\n <!-- Custom template via TemplateRef (from @ContentChild or @Input) - passes item as context -->\n <ng-container *ngIf=\"itemContentTpl || itemContentTemplate\">\n <div class=\"cqa-p-3\">\n <ng-container\n *ngTemplateOutlet=\"(itemContentTpl || itemContentTemplate)!; context: { $implicit: item, item: item }\"></ng-container>\n </div>\n </ng-container>\n\n <!-- Custom content projection via ng-content - displayed for all expanded items -->\n <ng-content select=\"[itemContent]\"></ng-content>\n </div>\n </div>\n</div>\n\n<!-- Custom content projection after all items - for steps loaded after API call -->\n<ng-content select=\"[afterItems]\"></ng-content>", components: [{ type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }] });
|
|
11369
11385
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: MainStepCollapseComponent, decorators: [{
|
|
11370
11386
|
type: Component,
|
|
11371
11387
|
args: [{ selector: 'cqa-main-step-collapse', host: { class: 'cqa-ui-root' }, template: "<!-- Header -->\n<div\n class=\"cqa-mt-2 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3 cqa-px-3 cqa-py-2 cqa-cursor-pointer cqa-bg-[#EEF2FF] cqa-rounded-[4px] cqa-border cqa-border-[#C6D2FF] cqa-border-solid\"\n (click)=\"toggle()\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-w-full\">\n <!-- Chevron Icon (Left) -->\n <!-- <svg [class.cqa-rotate-180]=\"isExpanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#3F51B5\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> -->\n <div><svg [class.cqa-rotate-180]=\"isExpanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#4F39F6\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- Chain-Link Icon (if configured, otherwise default) -->\n <!-- <div *ngIf=\"icon && icon.type === 'folder'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.6666 11.6667C11.976 11.6667 12.2728 11.5437 12.4916 11.325C12.7104 11.1062 12.8333 10.8094 12.8333 10.5V4.66667C12.8333 4.35725 12.7104 4.0605 12.4916 3.84171C12.2728 3.62292 11.976 3.5 11.6666 3.5H7.05829C6.86318 3.50191 6.67069 3.45486 6.49847 3.36314C6.32624 3.27142 6.17977 3.13797 6.07246 2.975L5.59996 2.275C5.49373 2.11369 5.34911 1.98128 5.17908 1.88965C5.00906 1.79802 4.81894 1.75003 4.62579 1.75H2.33329C2.02387 1.75 1.72713 1.87292 1.50833 2.09171C1.28954 2.3105 1.16663 2.60725 1.16663 2.91667V10.5C1.16663 10.8094 1.28954 11.1062 1.50833 11.325C1.72713 11.5437 2.02387 11.6667 2.33329 11.6667H11.6666Z\" fill=\"#EFF6FF\" stroke=\"#3F51B5\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n <div *ngIf=\"icon && icon.type === 'loop'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"16\" height=\"16\" rx=\"4\" fill=\"#EBECFD\"/>\n <path d=\"M9.66663 4.66666L11 5.99999L9.66663 7.33332\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.66667V7.33333C5 6.97971 5.14048 6.64057 5.39052 6.39052C5.64057 6.14048 5.97971 6 6.33333 6H11\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.33333 11.3333L5 9.99999L6.33333 8.66666\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11 8.33334V8.66668C11 9.0203 10.8595 9.35944 10.6095 9.60949C10.3594 9.85953 10.0203 10 9.66667 10H5\" stroke=\"#3F51B5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div> -->\n <!-- Bar Icon (Bulleted List) -->\n <div *ngIf=\"icon && icon.type === 'bar'\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- First bullet and line -->\n <circle cx=\"3\" cy=\"5\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"5\" x2=\"17\" y2=\"5\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Second bullet and line -->\n <circle cx=\"3\" cy=\"10\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"10\" x2=\"17\" y2=\"10\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <!-- Third bullet and line -->\n <circle cx=\"3\" cy=\"15\" r=\"2\" fill=\"#4F39F6\"/>\n <line x1=\"7\" y1=\"15\" x2=\"17\" y2=\"15\" stroke=\"#4F39F6\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </div>\n\n <!-- Default Chain-Link Icon (when no icon or icon type is not specified) -->\n <div *ngIf=\"!icon || (icon.type !== 'bar' && icon.type !== 'folder' && icon.type !== 'loop' && icon.type !== 'custom')\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M7.50033 14.1663H5.83366C4.72859 14.1663 3.66878 13.7274 2.88738 12.946C2.10598 12.1646 1.66699 11.1047 1.66699 9.99967C1.66699 8.89461 2.10598 7.8348 2.88738 7.0534C3.66878 6.27199 4.72859 5.83301 5.83366 5.83301H7.50033\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12.5 5.83301H14.1667C15.2717 5.83301 16.3315 6.27199 17.1129 7.0534C17.8943 7.8348 18.3333 8.89461 18.3333 9.99967C18.3333 11.1047 17.8943 12.1646 17.1129 12.946C16.3315 13.7274 15.2717 14.1663 14.1667 14.1663H12.5\"\n stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6.66699 10H13.3337\" stroke=\"#4F39F6\" stroke-width=\"1.66667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Custom Icon -->\n <div *ngIf=\"icon && icon.type === 'custom' && icon.svg\" [innerHTML]=\"icon.svg\"></div>\n\n <!-- Title -->\n <span class=\"cqa-font-semibold cqa-text-[14px] cqa-leading-[17px] cqa-text-[#312C85] cqa-flex-1\">\n {{ title }}\n </span>\n\n <!-- Badge and dynamic header buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" (click)=\"$event.stopPropagation()\">\n <ng-container *ngFor=\"let btn of headerButtons; let i = index\">\n <cqa-button\n [text]=\"btn.text\"\n [icon]=\"btn.icon\"\n [variant]=\"btn.variant || 'outlined'\"\n [disabled]=\"btn.disabled\"\n [tooltip]=\"btn.tooltip\"\n [customClass]=\"btn.customClass\"\n [btnSize]=\"btn.btnSize || 'sm'\"\n (clicked)=\"onHeaderButtonClick(btn, i, $event)\">\n </cqa-button>\n </ng-container>\n <span\n class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-bg-[#C6D2FF] cqa-text-[12px] cqa-leading-[16px] cqa-text-[#432DD7]\">\n {{ getDisplayCount() }}\n </span>\n </div>\n </div>\n</div>\n\n<!-- Expanded Content -->\n<div *ngIf=\"isExpanded\" class=\"cqa-mt-2 cqa-flex cqa-flex-col cqa-gap-2 cqa-px-2.5\">\n <!-- When there are no items, display ng-content directly -->\n <ng-container *ngIf=\"!items || items.length === 0\">\n <ng-content></ng-content>\n </ng-container>\n\n <!-- When items exist, display them -->\n <div *ngFor=\"let item of items\">\n\n <!-- Item Header -->\n <div class=\"cqa-bg-white cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-md cqa-overflow-hidden\">\n <div class=\"cqa-py-2 cqa-px-3 cqa-flex cqa-items-center cqa-justify-between cqa-gap-3\">\n <!-- Left side: Status and Title -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-1\">\n <!-- Status Icon (Filled Green Circle with Checkmark) -->\n <div>\n <!-- Success -->\n <svg *ngIf=\"item.status === 'success'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_48_121)\">\n <path\n d=\"M10.0003 18.3337C14.6027 18.3337 18.3337 14.6027 18.3337 10.0003C18.3337 5.39795 14.6027 1.66699 10.0003 1.66699C5.39795 1.66699 1.66699 5.39795 1.66699 10.0003C1.66699 14.6027 5.39795 18.3337 10.0003 18.3337Z\"\n stroke=\"#00A63E\" stroke-width=\"1.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.5 9.99967L9.16667 11.6663L12.5 8.33301\" stroke=\"#00A63E\" stroke-width=\"1.66667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_48_121\">\n <rect width=\"20\" height=\"20\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n <!-- Failed -->\n <svg *ngIf=\"item.status === 'failed'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#EF4444\" />\n <path d=\"M7 7L13 13M13 7L7 13\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n <!-- Pending -->\n <svg *ngIf=\"item.status === 'pending'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#9CA3AF\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <!-- Running -->\n <svg *ngIf=\"item.status === 'running'\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"10\" cy=\"10\" r=\"8\" fill=\"#3B82F6\" />\n <path d=\"M10 6V10L13 12\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n \n <!-- Title -->\n <span class=\"cqa-text-[14px] cqa-leading-[18px]\" style=\"word-break: break-word;\">\n {{ item.title }}\n </span>\n </div>\n \n <!-- Right side: Duration and View Steps Link -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Duration with Clock Icon -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-1\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6 11C8.76142 11 11 8.76142 11 6C11 3.23858 8.76142 1 6 1C3.23858 1 1 3.23858 1 6C1 8.76142 3.23858 11 6 11Z\"\n stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M6 3V6L8 7\" stroke=\"#6A7282\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n <span class=\"cqa-text-[14px] cqa-leading-[20px] cqa-text-[#6A7282]\">\n {{ formatDuration(item.duration) }}\n </span>\n </div>\n \n <!-- View Steps Link: redirect mode (navigates to URL) or inline mode (toggle expand) -->\n <a *ngIf=\"hasViewStepsRedirectUrl(item)\"\n [href]=\"getItemViewStepsUrl(item)\"\n [attr.target]=\"viewStepsOpenInNewTab ? '_blank' : null\"\n [attr.rel]=\"viewStepsOpenInNewTab ? 'noopener noreferrer' : null\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>View steps</span>\n <svg class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n <a *ngIf=\"!hasViewStepsRedirectUrl(item)\" href=\"#\" (click)=\"onViewSteps(item, $event)\"\n class=\"cqa-text-[12px] cqa-leading-[15px] cqa-font-semibold cqa-text-[#3F43EE] cqa-no-underline cqa-flex cqa-items-center cqa-gap-1 hover:cqa-underline\">\n <span>{{ isItemExpanded(item.id) ? 'Hide steps' : 'View steps' }}</span>\n <svg [class.cqa-rotate-90]=\"isItemExpanded(item.id)\" class=\"cqa-transition-transform\" width=\"16\" height=\"15\"\n viewBox=\"0 0 16 15\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M8.6552 12.8184L7.55413 11.7668L10.852 8.5864H2.83984V7.05032H10.852L7.55413 3.87506L8.6552 2.81836L13.8398 7.81836L8.6552 12.8184Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n </div>\n </div>\n\n <!-- Steps Content (shown when item is expanded) -->\n <div *ngIf=\"isItemExpanded(item.id)\">\n <!-- Custom template via TemplateRef (from @ContentChild or @Input) - passes item as context -->\n <ng-container *ngIf=\"itemContentTpl || itemContentTemplate\">\n <div class=\"cqa-p-3\">\n <ng-container\n *ngTemplateOutlet=\"(itemContentTpl || itemContentTemplate)!; context: { $implicit: item, item: item }\"></ng-container>\n </div>\n </ng-container>\n\n <!-- Custom content projection via ng-content - displayed for all expanded items -->\n <ng-content select=\"[itemContent]\"></ng-content>\n </div>\n </div>\n</div>\n\n<!-- Custom content projection after all items - for steps loaded after API call -->\n<ng-content select=\"[afterItems]\"></ng-content>", styles: [] }]
|
|
@@ -11389,6 +11405,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
11389
11405
|
type: Input
|
|
11390
11406
|
}], viewStepsOpenInNewTab: [{
|
|
11391
11407
|
type: Input
|
|
11408
|
+
}], initialExpandedItemId: [{
|
|
11409
|
+
type: Input
|
|
11392
11410
|
}], itemContentTpl: [{
|
|
11393
11411
|
type: ContentChild,
|
|
11394
11412
|
args: ['itemContent', { read: TemplateRef }]
|
|
@@ -11459,7 +11477,6 @@ class SimulatorComponent {
|
|
|
11459
11477
|
this.speedControlClickOutsideHandler = null;
|
|
11460
11478
|
this.preloadVideoElement = null;
|
|
11461
11479
|
this.preloadAllVideoElement = null;
|
|
11462
|
-
this.targetGlobalTimeDuringSwitch = null;
|
|
11463
11480
|
this.traceViewerLoading = false;
|
|
11464
11481
|
this.traceViewerError = false;
|
|
11465
11482
|
this.isCorrectDeviceFrameAvailable = false;
|
|
@@ -11593,6 +11610,9 @@ class SimulatorComponent {
|
|
|
11593
11610
|
get isPlayerSwitching() {
|
|
11594
11611
|
return this.playerState === 'switching';
|
|
11595
11612
|
}
|
|
11613
|
+
get shouldApplySmallHeightClasses() {
|
|
11614
|
+
return typeof window !== 'undefined' && window.innerHeight < 600 && this.platformType === 'browser' && this.isLive;
|
|
11615
|
+
}
|
|
11596
11616
|
get effectiveBrowserViewPort() {
|
|
11597
11617
|
const defaultViewport = { width: 1280, height: 720 };
|
|
11598
11618
|
if (!this.browserViewPort) {
|
|
@@ -11740,52 +11760,12 @@ class SimulatorComponent {
|
|
|
11740
11760
|
return;
|
|
11741
11761
|
this.enqueueOperation(() => this.seekToTimeInternal(milliseconds));
|
|
11742
11762
|
}
|
|
11743
|
-
/**
|
|
11744
|
-
* Seek to a global time on the combined timeline (converts to segment + local time)
|
|
11745
|
-
*/
|
|
11746
|
-
seekToGlobalTime(globalTimeMs) {
|
|
11747
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
11748
|
-
const total = this.totalDuration;
|
|
11749
|
-
if (total <= 0)
|
|
11750
|
-
return;
|
|
11751
|
-
const clampedGlobal = Math.max(0, Math.min(globalTimeMs, total));
|
|
11752
|
-
const boundaries = this.segmentBoundaries;
|
|
11753
|
-
let segmentIndex = 0;
|
|
11754
|
-
let segmentStart = 0;
|
|
11755
|
-
for (let i = 0; i < boundaries.length; i++) {
|
|
11756
|
-
if (clampedGlobal < boundaries[i]) {
|
|
11757
|
-
segmentIndex = i;
|
|
11758
|
-
segmentStart = i === 0 ? 0 : boundaries[i - 1];
|
|
11759
|
-
break;
|
|
11760
|
-
}
|
|
11761
|
-
segmentIndex = i;
|
|
11762
|
-
segmentStart = i === 0 ? 0 : boundaries[i - 1];
|
|
11763
|
-
}
|
|
11764
|
-
if (boundaries.length > 0 && clampedGlobal >= boundaries[boundaries.length - 1]) {
|
|
11765
|
-
segmentIndex = boundaries.length - 1;
|
|
11766
|
-
segmentStart = segmentIndex === 0 ? 0 : boundaries[segmentIndex - 1];
|
|
11767
|
-
}
|
|
11768
|
-
const localTimeMs = clampedGlobal - segmentStart;
|
|
11769
|
-
if (this.currentVideoIndex === segmentIndex) {
|
|
11770
|
-
yield this.seekToTimeInternal(localTimeMs);
|
|
11771
|
-
// Update progress after seek in same segment
|
|
11772
|
-
if (this.totalDuration > 0) {
|
|
11773
|
-
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / this.totalDuration) * 100));
|
|
11774
|
-
}
|
|
11775
|
-
}
|
|
11776
|
-
else {
|
|
11777
|
-
const cumulativeTimestamp = segmentStart + localTimeMs;
|
|
11778
|
-
yield this.switchToVideoAndSeekInternal(cumulativeTimestamp);
|
|
11779
|
-
// Progress is already updated inside switchToVideoAndSeekInternal
|
|
11780
|
-
}
|
|
11781
|
-
});
|
|
11782
|
-
}
|
|
11783
11763
|
/**
|
|
11784
11764
|
* Seek video internal implementation (no enqueue - called from queue)
|
|
11785
11765
|
* This prevents pipeline read errors during rapid seek operations
|
|
11786
11766
|
*/
|
|
11787
11767
|
seekToTimeInternal(milliseconds) {
|
|
11788
|
-
var _a;
|
|
11768
|
+
var _a, _b;
|
|
11789
11769
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11790
11770
|
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
11791
11771
|
if (!video || !video.duration)
|
|
@@ -11812,11 +11792,13 @@ class SimulatorComponent {
|
|
|
11812
11792
|
this.lastSetDuration = milliseconds;
|
|
11813
11793
|
// Wait briefly for seek to complete (prevents rapid seek issues)
|
|
11814
11794
|
yield new Promise(resolve => setTimeout(resolve, 50));
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11795
|
+
// Per-video progress (0-100% of current video)
|
|
11796
|
+
const durationMs = video.duration * 1000;
|
|
11797
|
+
if (durationMs > 0) {
|
|
11798
|
+
this.progress = Math.min(100, Math.max(0, (video.currentTime * 1000 / durationMs) * 100));
|
|
11818
11799
|
}
|
|
11819
|
-
this.
|
|
11800
|
+
const segmentStart = this.currentVideoIndex === 0 ? 0 : ((_b = this.segmentBoundaries[this.currentVideoIndex - 1]) !== null && _b !== void 0 ? _b : 0);
|
|
11801
|
+
this.videoTimeUpdate.emit(segmentStart + video.currentTime * 1000);
|
|
11820
11802
|
// Set to paused state (user must explicitly play)
|
|
11821
11803
|
this.playerState = 'paused';
|
|
11822
11804
|
console.log('[Simulator] seekToTimeInternal: seek complete', {
|
|
@@ -11902,7 +11884,7 @@ class SimulatorComponent {
|
|
|
11902
11884
|
* This eliminates FFmpegDemuxer errors and play promise interruptions
|
|
11903
11885
|
*/
|
|
11904
11886
|
playVideoInternal() {
|
|
11905
|
-
var _a, _b, _c, _d
|
|
11887
|
+
var _a, _b, _c, _d;
|
|
11906
11888
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11907
11889
|
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
11908
11890
|
if (!video) {
|
|
@@ -11914,91 +11896,6 @@ class SimulatorComponent {
|
|
|
11914
11896
|
console.log('[Simulator] playVideoInternal: already playing, skipping');
|
|
11915
11897
|
return;
|
|
11916
11898
|
}
|
|
11917
|
-
if (this.hasMultipleVideos && this.videoUrls) {
|
|
11918
|
-
const total = this.totalDuration;
|
|
11919
|
-
const currentGlobalTime = this.globalCurrentTime;
|
|
11920
|
-
const isAtEnd = total > 0 && (this.progress >= 100 || currentGlobalTime >= total);
|
|
11921
|
-
const isLastVideo = this.currentVideoIndex >= this.videoUrls.length - 1;
|
|
11922
|
-
const isLastVideoAtEnd = isLastVideo && video.duration && video.currentTime >= video.duration - 0.1;
|
|
11923
|
-
if (isAtEnd || isLastVideoAtEnd) {
|
|
11924
|
-
console.log('[Simulator] playVideoInternal: all videos completed, resetting to first video', {
|
|
11925
|
-
progress: this.progress,
|
|
11926
|
-
currentGlobalTime,
|
|
11927
|
-
total,
|
|
11928
|
-
currentVideoIndex: this.currentVideoIndex,
|
|
11929
|
-
isAtEnd,
|
|
11930
|
-
isLastVideoAtEnd
|
|
11931
|
-
});
|
|
11932
|
-
// Reset to first video at 0 progress
|
|
11933
|
-
this.currentVideoIndex = 0;
|
|
11934
|
-
this.progress = 0;
|
|
11935
|
-
this.targetGlobalTimeDuringSwitch = 0;
|
|
11936
|
-
this.hitMarkers.clear();
|
|
11937
|
-
// Switch to first video and seek to 0
|
|
11938
|
-
yield this.switchToVideoAndSeekInternal(0);
|
|
11939
|
-
// Update video reference after switch
|
|
11940
|
-
const videoAfterSwitch = (_b = this.vplayer) === null || _b === void 0 ? void 0 : _b.nativeElement;
|
|
11941
|
-
if (!videoAfterSwitch) {
|
|
11942
|
-
console.error('[Simulator] playVideoInternal: video element not found after switch');
|
|
11943
|
-
return;
|
|
11944
|
-
}
|
|
11945
|
-
// Continue with normal play logic below
|
|
11946
|
-
// The video element reference has changed, so we'll use videoAfterSwitch
|
|
11947
|
-
// But we need to wait for metadata again
|
|
11948
|
-
if (videoAfterSwitch.readyState < HTMLMediaElement.HAVE_METADATA) {
|
|
11949
|
-
yield new Promise((resolve, reject) => {
|
|
11950
|
-
const onLoadedMetadata = () => {
|
|
11951
|
-
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
11952
|
-
videoAfterSwitch.removeEventListener('error', onError);
|
|
11953
|
-
resolve();
|
|
11954
|
-
};
|
|
11955
|
-
const onError = () => {
|
|
11956
|
-
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
11957
|
-
videoAfterSwitch.removeEventListener('error', onError);
|
|
11958
|
-
reject(new Error('Failed to load video metadata'));
|
|
11959
|
-
};
|
|
11960
|
-
videoAfterSwitch.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
11961
|
-
videoAfterSwitch.addEventListener('error', onError, { once: true });
|
|
11962
|
-
setTimeout(() => {
|
|
11963
|
-
videoAfterSwitch.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
11964
|
-
videoAfterSwitch.removeEventListener('error', onError);
|
|
11965
|
-
if (videoAfterSwitch.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
11966
|
-
resolve();
|
|
11967
|
-
}
|
|
11968
|
-
else {
|
|
11969
|
-
reject(new Error('Timeout waiting for metadata'));
|
|
11970
|
-
}
|
|
11971
|
-
}, 500);
|
|
11972
|
-
});
|
|
11973
|
-
}
|
|
11974
|
-
// Set state to loading
|
|
11975
|
-
this.playerState = 'loading';
|
|
11976
|
-
try {
|
|
11977
|
-
yield videoAfterSwitch.play();
|
|
11978
|
-
this.playerState = 'playing';
|
|
11979
|
-
this.isPlaying = true;
|
|
11980
|
-
this.playPromise = null;
|
|
11981
|
-
this.videoPlay.emit();
|
|
11982
|
-
this.isVideoPlayingChange.emit(true);
|
|
11983
|
-
this.targetGlobalTimeDuringSwitch = null;
|
|
11984
|
-
console.log('[Simulator] playVideoInternal: restarted from first video');
|
|
11985
|
-
return;
|
|
11986
|
-
}
|
|
11987
|
-
catch (err) {
|
|
11988
|
-
this.playerState = 'error';
|
|
11989
|
-
this.isPlaying = false;
|
|
11990
|
-
this.playPromise = null;
|
|
11991
|
-
this.isVideoPlayingChange.emit(false);
|
|
11992
|
-
if (err.name === 'AbortError') {
|
|
11993
|
-
this.playerState = 'paused';
|
|
11994
|
-
}
|
|
11995
|
-
else {
|
|
11996
|
-
console.error('[Simulator] playVideoInternal: failed after reset', err);
|
|
11997
|
-
}
|
|
11998
|
-
return;
|
|
11999
|
-
}
|
|
12000
|
-
}
|
|
12001
|
-
}
|
|
12002
11899
|
console.log('[Simulator] playVideoInternal: starting', {
|
|
12003
11900
|
playerState: this.playerState,
|
|
12004
11901
|
currentTime: video.currentTime,
|
|
@@ -12020,17 +11917,6 @@ class SimulatorComponent {
|
|
|
12020
11917
|
};
|
|
12021
11918
|
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
12022
11919
|
video.addEventListener('error', onError, { once: true });
|
|
12023
|
-
// Timeout fallback
|
|
12024
|
-
setTimeout(() => {
|
|
12025
|
-
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
12026
|
-
video.removeEventListener('error', onError);
|
|
12027
|
-
if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
12028
|
-
resolve();
|
|
12029
|
-
}
|
|
12030
|
-
else {
|
|
12031
|
-
reject(new Error('Timeout waiting for metadata'));
|
|
12032
|
-
}
|
|
12033
|
-
}, 500);
|
|
12034
11920
|
});
|
|
12035
11921
|
}
|
|
12036
11922
|
// Clear hit markers if starting from beginning
|
|
@@ -12042,7 +11928,7 @@ class SimulatorComponent {
|
|
|
12042
11928
|
this.playerState = 'loading';
|
|
12043
11929
|
try {
|
|
12044
11930
|
// Verify video element is still available before playing
|
|
12045
|
-
const currentVideo = (
|
|
11931
|
+
const currentVideo = (_b = this.vplayer) === null || _b === void 0 ? void 0 : _b.nativeElement;
|
|
12046
11932
|
if (!currentVideo || currentVideo !== video) {
|
|
12047
11933
|
console.warn('[Simulator] playVideoInternal: video element changed or unavailable');
|
|
12048
11934
|
this.playerState = 'paused';
|
|
@@ -12053,7 +11939,7 @@ class SimulatorComponent {
|
|
|
12053
11939
|
// Await play promise - this is critical
|
|
12054
11940
|
yield video.play();
|
|
12055
11941
|
// Verify video element is still available after play promise resolves
|
|
12056
|
-
const videoAfterPlay = (
|
|
11942
|
+
const videoAfterPlay = (_c = this.vplayer) === null || _c === void 0 ? void 0 : _c.nativeElement;
|
|
12057
11943
|
if (!videoAfterPlay || videoAfterPlay !== video) {
|
|
12058
11944
|
console.warn('[Simulator] playVideoInternal: video element changed during play');
|
|
12059
11945
|
this.playerState = 'paused';
|
|
@@ -12071,17 +11957,19 @@ class SimulatorComponent {
|
|
|
12071
11957
|
currentTime: video.currentTime,
|
|
12072
11958
|
playerState: this.playerState
|
|
12073
11959
|
});
|
|
12074
|
-
// Check early markers (non-blocking, doesn't need to be queued)
|
|
12075
11960
|
setTimeout(() => {
|
|
12076
|
-
|
|
12077
|
-
|
|
11961
|
+
var _a, _b;
|
|
11962
|
+
if (this.isPlaying && ((_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement)) {
|
|
11963
|
+
const v = this.vplayer.nativeElement;
|
|
11964
|
+
const segmentStart = this.currentVideoIndex === 0 ? 0 : ((_b = this.segmentBoundaries[this.currentVideoIndex - 1]) !== null && _b !== void 0 ? _b : 0);
|
|
11965
|
+
this.checkMarkerHit(segmentStart + v.currentTime * 1000);
|
|
12078
11966
|
}
|
|
12079
11967
|
}, 50);
|
|
12080
11968
|
}
|
|
12081
11969
|
catch (err) {
|
|
12082
11970
|
// Play failed
|
|
12083
11971
|
// Check if video element is still available
|
|
12084
|
-
const videoAfterError = (
|
|
11972
|
+
const videoAfterError = (_d = this.vplayer) === null || _d === void 0 ? void 0 : _d.nativeElement;
|
|
12085
11973
|
if (!videoAfterError || videoAfterError !== video) {
|
|
12086
11974
|
console.warn('[Simulator] playVideoInternal: video element changed during error');
|
|
12087
11975
|
this.playerState = 'paused';
|
|
@@ -12186,39 +12074,90 @@ class SimulatorComponent {
|
|
|
12186
12074
|
}
|
|
12187
12075
|
return [];
|
|
12188
12076
|
}
|
|
12189
|
-
get
|
|
12190
|
-
|
|
12191
|
-
if (
|
|
12192
|
-
|
|
12077
|
+
get currentVideoMarkers() {
|
|
12078
|
+
let markersToProcess;
|
|
12079
|
+
if (!this.hasMultipleVideos) {
|
|
12080
|
+
markersToProcess = this.stepMarkers;
|
|
12193
12081
|
}
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
return this.targetGlobalTimeDuringSwitch;
|
|
12082
|
+
else {
|
|
12083
|
+
const boundaries = this.getVideoDurationBoundaries();
|
|
12084
|
+
if (boundaries.length === 0 || this.currentVideoIndex >= boundaries.length) {
|
|
12085
|
+
markersToProcess = this.stepMarkers;
|
|
12199
12086
|
}
|
|
12200
|
-
|
|
12087
|
+
else {
|
|
12088
|
+
const currentBoundary = boundaries[this.currentVideoIndex];
|
|
12089
|
+
markersToProcess = this.stepMarkers
|
|
12090
|
+
.filter(marker => {
|
|
12091
|
+
return marker.cumulativeDuration >= currentBoundary.start &&
|
|
12092
|
+
marker.cumulativeDuration < currentBoundary.end;
|
|
12093
|
+
})
|
|
12094
|
+
.map(marker => this.adjustChildStepsDuration(marker, currentBoundary.start, currentBoundary.start, currentBoundary.end));
|
|
12095
|
+
}
|
|
12096
|
+
}
|
|
12097
|
+
return this.flattenMarkers(markersToProcess);
|
|
12098
|
+
}
|
|
12099
|
+
adjustChildStepsDuration(marker, adjustment, videoStart, videoEnd) {
|
|
12100
|
+
const adjustedMarker = Object.assign(Object.assign({}, marker), { cumulativeDuration: marker.cumulativeDuration - adjustment });
|
|
12101
|
+
if (marker.childSteps && marker.childSteps.length > 0) {
|
|
12102
|
+
adjustedMarker.childSteps = marker.childSteps
|
|
12103
|
+
.filter(child => child.cumulativeDuration >= videoStart && child.cumulativeDuration < videoEnd)
|
|
12104
|
+
.map(child => {
|
|
12105
|
+
const adjustedChild = Object.assign(Object.assign({}, child), { cumulativeDuration: child.cumulativeDuration - adjustment });
|
|
12106
|
+
if (child.childSteps && child.childSteps.length > 0) {
|
|
12107
|
+
adjustedChild.childSteps = child.childSteps
|
|
12108
|
+
.filter(nestedChild => nestedChild.cumulativeDuration >= videoStart && nestedChild.cumulativeDuration < videoEnd)
|
|
12109
|
+
.map(nestedChild => this.adjustChildStepsDuration(nestedChild, adjustment, videoStart, videoEnd));
|
|
12110
|
+
}
|
|
12111
|
+
return adjustedChild;
|
|
12112
|
+
});
|
|
12201
12113
|
}
|
|
12202
|
-
|
|
12203
|
-
return segmentStart + video.currentTime * 1000;
|
|
12114
|
+
return adjustedMarker;
|
|
12204
12115
|
}
|
|
12205
|
-
|
|
12206
|
-
var _a
|
|
12116
|
+
getStepLeftPosition(step) {
|
|
12117
|
+
var _a;
|
|
12207
12118
|
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
12208
|
-
if (!(video === null || video === void 0 ? void 0 : video.duration)
|
|
12119
|
+
if (!(video === null || video === void 0 ? void 0 : video.duration))
|
|
12209
12120
|
return 0;
|
|
12210
|
-
const
|
|
12211
|
-
return
|
|
12121
|
+
const durationMs = video.duration * 1000;
|
|
12122
|
+
return (step.cumulativeDuration / durationMs) * 100;
|
|
12212
12123
|
}
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12124
|
+
getStepColor(step) {
|
|
12125
|
+
return step.level === 1 ? '#000000' : '#6366F1';
|
|
12126
|
+
}
|
|
12127
|
+
getStepResultColor(step) {
|
|
12128
|
+
return this.getGlobalMarkerResultColor(step.result);
|
|
12129
|
+
}
|
|
12130
|
+
getGlobalMarkerColor(level) {
|
|
12131
|
+
return level === 1 ? '#000000' : '#FFA500';
|
|
12132
|
+
}
|
|
12133
|
+
getGlobalMarkerResultColor(result) {
|
|
12134
|
+
switch (result) {
|
|
12135
|
+
case 'SUCCESS':
|
|
12136
|
+
return '#12B76A';
|
|
12137
|
+
case 'FAILURE':
|
|
12138
|
+
return '#B91C1C';
|
|
12139
|
+
case 'ABORTED':
|
|
12140
|
+
return '#F79009';
|
|
12141
|
+
case 'SKIPPED':
|
|
12142
|
+
return '#667085';
|
|
12143
|
+
default:
|
|
12144
|
+
return '#6366F1';
|
|
12145
|
+
}
|
|
12146
|
+
}
|
|
12147
|
+
onMarkerClick(event, marker) {
|
|
12148
|
+
var _a;
|
|
12149
|
+
event.stopPropagation();
|
|
12150
|
+
event.preventDefault();
|
|
12151
|
+
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
12152
|
+
if (!(video === null || video === void 0 ? void 0 : video.duration))
|
|
12153
|
+
return;
|
|
12154
|
+
const targetTimeMs = marker.cumulativeDuration;
|
|
12155
|
+
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12156
|
+
yield this.seekToTimeInternal(targetTimeMs);
|
|
12157
|
+
if (marker.testStepId != null) {
|
|
12158
|
+
this.hitMarkers.add(marker.testStepId);
|
|
12159
|
+
this.markerHit.emit(marker);
|
|
12160
|
+
}
|
|
12222
12161
|
}));
|
|
12223
12162
|
}
|
|
12224
12163
|
get currentVideoUrl() {
|
|
@@ -12260,37 +12199,35 @@ class SimulatorComponent {
|
|
|
12260
12199
|
if (!this.hasMultipleVideos)
|
|
12261
12200
|
return;
|
|
12262
12201
|
if (this.currentVideoIndex > 0) {
|
|
12263
|
-
this.currentVideoIndex
|
|
12264
|
-
this.resetVideoState();
|
|
12202
|
+
this.enqueueOperation(() => this.switchToVideoAndResetInternal(this.currentVideoIndex - 1));
|
|
12265
12203
|
}
|
|
12266
12204
|
}
|
|
12267
12205
|
nextVideo() {
|
|
12268
12206
|
if (!this.hasMultipleVideos)
|
|
12269
12207
|
return;
|
|
12270
12208
|
if (this.videoUrls && this.currentVideoIndex < this.videoUrls.length - 1) {
|
|
12271
|
-
this.currentVideoIndex
|
|
12272
|
-
this.resetVideoState();
|
|
12209
|
+
this.enqueueOperation(() => this.switchToVideoAndResetInternal(this.currentVideoIndex + 1));
|
|
12273
12210
|
}
|
|
12274
12211
|
}
|
|
12275
12212
|
onTimelineClick(event) {
|
|
12276
|
-
var _a;
|
|
12277
|
-
if (!((_a = this.timelineBar) === null || _a === void 0 ? void 0 : _a.nativeElement))
|
|
12213
|
+
var _a, _b;
|
|
12214
|
+
if (!((_a = this.timelineBar) === null || _a === void 0 ? void 0 : _a.nativeElement) || !((_b = this.vplayer) === null || _b === void 0 ? void 0 : _b.nativeElement))
|
|
12215
|
+
return;
|
|
12216
|
+
const video = this.vplayer.nativeElement;
|
|
12217
|
+
if (!video.duration || !isFinite(video.duration))
|
|
12278
12218
|
return;
|
|
12279
12219
|
const rect = this.timelineBar.nativeElement.getBoundingClientRect();
|
|
12280
12220
|
const clickX = event.clientX - rect.left;
|
|
12281
12221
|
const percent = Math.max(0, Math.min(1, clickX / rect.width));
|
|
12282
|
-
const
|
|
12283
|
-
if (total <= 0)
|
|
12284
|
-
return;
|
|
12285
|
-
const globalTimeMs = percent * total;
|
|
12222
|
+
const targetTimeMs = percent * video.duration * 1000;
|
|
12286
12223
|
const shouldResumePlaying = this.isPlaying;
|
|
12287
12224
|
console.log('[Simulator] onTimelineClick', {
|
|
12288
12225
|
percent,
|
|
12289
|
-
|
|
12226
|
+
targetTimeMs,
|
|
12290
12227
|
shouldResumePlaying
|
|
12291
12228
|
});
|
|
12292
12229
|
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12293
|
-
yield this.
|
|
12230
|
+
yield this.seekToTimeInternal(targetTimeMs);
|
|
12294
12231
|
if (shouldResumePlaying) {
|
|
12295
12232
|
yield new Promise(resolve => setTimeout(resolve, 100));
|
|
12296
12233
|
yield this.playVideoInternal();
|
|
@@ -12325,11 +12262,11 @@ class SimulatorComponent {
|
|
|
12325
12262
|
this.progress = percent * 100; // Global timeline position
|
|
12326
12263
|
}
|
|
12327
12264
|
stopDrag() {
|
|
12265
|
+
var _a;
|
|
12328
12266
|
if (!this.dragging)
|
|
12329
12267
|
return;
|
|
12330
12268
|
this.dragging = false;
|
|
12331
12269
|
this.removeDragListeners();
|
|
12332
|
-
// CRITICAL: Capture the playing state BEFORE any async operations
|
|
12333
12270
|
const shouldResumePlaying = this.wasPlayingBeforeDrag;
|
|
12334
12271
|
console.log('[Simulator] stopDrag: drag ended', {
|
|
12335
12272
|
progress: this.progress,
|
|
@@ -12337,19 +12274,15 @@ class SimulatorComponent {
|
|
|
12337
12274
|
shouldResumePlaying: shouldResumePlaying,
|
|
12338
12275
|
currentPlayerState: this.playerState
|
|
12339
12276
|
});
|
|
12340
|
-
const
|
|
12341
|
-
if (
|
|
12277
|
+
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
12278
|
+
if (!video || !video.duration || !isFinite(video.duration))
|
|
12342
12279
|
return;
|
|
12343
|
-
const
|
|
12344
|
-
// CRITICAL FIX: Queue both seek and resume play together
|
|
12345
|
-
// This ensures seek completes before attempting to play
|
|
12280
|
+
const targetTimeMs = (this.progress / 100) * video.duration * 1000;
|
|
12346
12281
|
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12347
|
-
|
|
12348
|
-
yield this.seekToGlobalTime(globalTimeMs);
|
|
12349
|
-
// If video was playing before drag, resume it
|
|
12282
|
+
yield this.seekToTimeInternal(targetTimeMs);
|
|
12350
12283
|
if (shouldResumePlaying) {
|
|
12351
12284
|
console.log('[Simulator] stopDrag: resuming playback after seek', {
|
|
12352
|
-
|
|
12285
|
+
targetTimeMs,
|
|
12353
12286
|
playerState: this.playerState
|
|
12354
12287
|
});
|
|
12355
12288
|
// Wait a bit longer to ensure seek is fully complete
|
|
@@ -12415,19 +12348,18 @@ class SimulatorComponent {
|
|
|
12415
12348
|
this.attachVideoListeners();
|
|
12416
12349
|
}
|
|
12417
12350
|
onVideoEnded() {
|
|
12418
|
-
var _a;
|
|
12419
12351
|
this.isPlaying = false;
|
|
12420
12352
|
this.playerState = 'paused';
|
|
12421
12353
|
this.videoPause.emit();
|
|
12422
12354
|
this.isVideoPlayingChange.emit(false);
|
|
12423
|
-
//
|
|
12355
|
+
// Switch to next video and reset to 0
|
|
12424
12356
|
if (this.hasMultipleVideos && this.videoUrls && this.currentVideoIndex < this.videoUrls.length - 1) {
|
|
12425
|
-
|
|
12426
|
-
const segmentStart = nextIndex === 0 ? 0 : ((_a = this.segmentBoundaries[nextIndex - 1]) !== null && _a !== void 0 ? _a : 0);
|
|
12357
|
+
this.currentVideoIndex += 1;
|
|
12427
12358
|
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12428
|
-
var
|
|
12429
|
-
yield this.
|
|
12430
|
-
|
|
12359
|
+
var _a;
|
|
12360
|
+
yield this.resetVideoStateInternal();
|
|
12361
|
+
yield new Promise(resolve => setTimeout(resolve, 100));
|
|
12362
|
+
if (((_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement) && this.currentVideoUrl) {
|
|
12431
12363
|
yield this.playVideoInternal();
|
|
12432
12364
|
}
|
|
12433
12365
|
}));
|
|
@@ -12445,30 +12377,22 @@ class SimulatorComponent {
|
|
|
12445
12377
|
return;
|
|
12446
12378
|
let lastUpdate = 0;
|
|
12447
12379
|
const handler = () => {
|
|
12380
|
+
var _a;
|
|
12448
12381
|
const now = Date.now();
|
|
12449
12382
|
if (now - lastUpdate < 100)
|
|
12450
12383
|
return;
|
|
12451
12384
|
lastUpdate = now;
|
|
12452
12385
|
const currentMs = video.currentTime * 1000;
|
|
12453
12386
|
if (!this.dragging && this.playerState !== 'switching') {
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
const currentGlobal = this.getActualGlobalTime();
|
|
12459
|
-
const tolerance = this.isPlaying ? 1000 : 500; // More tolerance when playing
|
|
12460
|
-
if (Math.abs(currentGlobal - this.targetGlobalTimeDuringSwitch) < tolerance) {
|
|
12461
|
-
this.targetGlobalTimeDuringSwitch = null;
|
|
12462
|
-
}
|
|
12463
|
-
}
|
|
12464
|
-
// globalCurrentTime now handles override logic - use it directly
|
|
12465
|
-
if (total > 0) {
|
|
12466
|
-
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / total) * 100));
|
|
12387
|
+
// Per-video progress (0-100% of current video)
|
|
12388
|
+
const durationMs = video.duration * 1000;
|
|
12389
|
+
if (durationMs > 0) {
|
|
12390
|
+
this.progress = Math.min(100, Math.max(0, (currentMs / durationMs) * 100));
|
|
12467
12391
|
}
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
this.
|
|
12471
|
-
|
|
12392
|
+
// Emit cumulative time for parent (step highlighting)
|
|
12393
|
+
const segmentStart = this.currentVideoIndex === 0 ? 0 : ((_a = this.segmentBoundaries[this.currentVideoIndex - 1]) !== null && _a !== void 0 ? _a : 0);
|
|
12394
|
+
this.videoTimeUpdate.emit(segmentStart + currentMs);
|
|
12395
|
+
this.checkMarkerHit(segmentStart + currentMs);
|
|
12472
12396
|
this.maybePreloadNextSegment();
|
|
12473
12397
|
}
|
|
12474
12398
|
};
|
|
@@ -12672,48 +12596,10 @@ class SimulatorComponent {
|
|
|
12672
12596
|
// Mark as hit and emit event
|
|
12673
12597
|
this.hitMarkers.add(marker.testStepId);
|
|
12674
12598
|
this.markerHit.emit(marker);
|
|
12675
|
-
console.log('[Simulator] Marker hit detected', {
|
|
12676
|
-
testStepId: marker.testStepId,
|
|
12677
|
-
cumulativeDuration: marker.cumulativeDuration,
|
|
12678
|
-
currentTime: globalTimeMs,
|
|
12679
|
-
timeDifference,
|
|
12680
|
-
title: marker.title,
|
|
12681
|
-
level: marker.level
|
|
12682
|
-
});
|
|
12683
12599
|
break; // Only emit one marker per check
|
|
12684
12600
|
}
|
|
12685
12601
|
}
|
|
12686
12602
|
}
|
|
12687
|
-
getGlobalMarkerResultColor(result) {
|
|
12688
|
-
switch (result) {
|
|
12689
|
-
case 'SUCCESS':
|
|
12690
|
-
return '#12B76A';
|
|
12691
|
-
case 'FAILURE':
|
|
12692
|
-
return '#B91C1C';
|
|
12693
|
-
case 'ABORTED':
|
|
12694
|
-
return '#F79009';
|
|
12695
|
-
case 'SKIPPED':
|
|
12696
|
-
return '#667085';
|
|
12697
|
-
default:
|
|
12698
|
-
return '#6366F1';
|
|
12699
|
-
}
|
|
12700
|
-
}
|
|
12701
|
-
getGlobalMarkerColor(level) {
|
|
12702
|
-
return level === 1 ? '#000000' : '#FFA500';
|
|
12703
|
-
}
|
|
12704
|
-
onMarkerClick(event, marker) {
|
|
12705
|
-
event.stopPropagation();
|
|
12706
|
-
event.preventDefault();
|
|
12707
|
-
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12708
|
-
yield this.seekToGlobalTime(marker.globalTime);
|
|
12709
|
-
if (marker.testStepId != null) {
|
|
12710
|
-
this.hitMarkers.add(marker.testStepId);
|
|
12711
|
-
const fullMarker = this.flattenMarkers(this.stepMarkers).find(m => m.testStepId === marker.testStepId);
|
|
12712
|
-
if (fullMarker)
|
|
12713
|
-
this.markerHit.emit(fullMarker);
|
|
12714
|
-
}
|
|
12715
|
-
}));
|
|
12716
|
-
}
|
|
12717
12603
|
toggleFullScreen() {
|
|
12718
12604
|
var _a, _b;
|
|
12719
12605
|
const wasPlaying = this.isPlaying;
|
|
@@ -12769,20 +12655,15 @@ class SimulatorComponent {
|
|
|
12769
12655
|
}
|
|
12770
12656
|
onSegmentChange(value) {
|
|
12771
12657
|
this.currentView = value;
|
|
12772
|
-
// Pause video when switching away from video view
|
|
12773
12658
|
if (this.currentView !== 'video') {
|
|
12774
12659
|
this.pauseVideo();
|
|
12775
12660
|
this.progress = 0;
|
|
12776
12661
|
}
|
|
12777
12662
|
else {
|
|
12778
|
-
// Reset everything when switching back to video view
|
|
12779
12663
|
this.enqueueOperation(() => __awaiter(this, void 0, void 0, function* () {
|
|
12780
12664
|
yield this.resetVideoStateInternal();
|
|
12781
|
-
// If multiple videos, reset to first video
|
|
12782
12665
|
if (this.hasMultipleVideos && this.videoUrls) {
|
|
12783
12666
|
this.currentVideoIndex = 0;
|
|
12784
|
-
this.targetGlobalTimeDuringSwitch = 0;
|
|
12785
|
-
// Switch to first video and seek to 0
|
|
12786
12667
|
yield this.switchToVideoAndSeekInternal(0);
|
|
12787
12668
|
}
|
|
12788
12669
|
}));
|
|
@@ -12980,6 +12861,66 @@ class SimulatorComponent {
|
|
|
12980
12861
|
}
|
|
12981
12862
|
return null;
|
|
12982
12863
|
}
|
|
12864
|
+
switchToVideoAndResetInternal(targetVideoIndex) {
|
|
12865
|
+
var _a, _b;
|
|
12866
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12867
|
+
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
12868
|
+
if (!video || !this.videoUrls || targetVideoIndex < 0 || targetVideoIndex >= this.videoUrls.length) {
|
|
12869
|
+
return;
|
|
12870
|
+
}
|
|
12871
|
+
if (this.currentVideoIndex === targetVideoIndex) {
|
|
12872
|
+
yield this.resetVideoStateInternal();
|
|
12873
|
+
return;
|
|
12874
|
+
}
|
|
12875
|
+
this.playerState = 'switching';
|
|
12876
|
+
try {
|
|
12877
|
+
video.pause();
|
|
12878
|
+
this.isPlaying = false;
|
|
12879
|
+
this.playPromise = null;
|
|
12880
|
+
this.videoPause.emit();
|
|
12881
|
+
this.isVideoPlayingChange.emit(false);
|
|
12882
|
+
this.currentVideoIndex = targetVideoIndex;
|
|
12883
|
+
yield new Promise((resolve, reject) => {
|
|
12884
|
+
let resolved = false;
|
|
12885
|
+
const cleanup = () => {
|
|
12886
|
+
if (resolved)
|
|
12887
|
+
return;
|
|
12888
|
+
resolved = true;
|
|
12889
|
+
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
12890
|
+
video.removeEventListener('error', onError);
|
|
12891
|
+
};
|
|
12892
|
+
const onLoadedMetadata = () => {
|
|
12893
|
+
cleanup();
|
|
12894
|
+
resolve();
|
|
12895
|
+
};
|
|
12896
|
+
const onError = () => {
|
|
12897
|
+
cleanup();
|
|
12898
|
+
reject(new Error('Failed to load video'));
|
|
12899
|
+
};
|
|
12900
|
+
setTimeout(() => {
|
|
12901
|
+
if (resolved)
|
|
12902
|
+
return;
|
|
12903
|
+
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
12904
|
+
video.addEventListener('error', onError, { once: true });
|
|
12905
|
+
}, 100);
|
|
12906
|
+
});
|
|
12907
|
+
video.currentTime = 0;
|
|
12908
|
+
this.progress = 0;
|
|
12909
|
+
this.playPromise = null;
|
|
12910
|
+
this.hitMarkers.clear();
|
|
12911
|
+
this.lastSetDuration = -1;
|
|
12912
|
+
const segmentStart = targetVideoIndex === 0 ? 0 : ((_b = this.segmentBoundaries[targetVideoIndex - 1]) !== null && _b !== void 0 ? _b : 0);
|
|
12913
|
+
this.videoTimeUpdate.emit(segmentStart);
|
|
12914
|
+
}
|
|
12915
|
+
catch (err) {
|
|
12916
|
+
console.error('[Simulator] switchToVideoAndReset failed:', err);
|
|
12917
|
+
this.progress = 0;
|
|
12918
|
+
}
|
|
12919
|
+
finally {
|
|
12920
|
+
this.playerState = 'paused';
|
|
12921
|
+
}
|
|
12922
|
+
});
|
|
12923
|
+
}
|
|
12983
12924
|
switchToVideoAndSeek(cumulativeTimestamp) {
|
|
12984
12925
|
this.enqueueOperation(() => this.switchToVideoAndSeekInternal(cumulativeTimestamp));
|
|
12985
12926
|
}
|
|
@@ -13006,20 +12947,13 @@ class SimulatorComponent {
|
|
|
13006
12947
|
const video = (_a = this.vplayer) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
13007
12948
|
if (!video)
|
|
13008
12949
|
return;
|
|
13009
|
-
const total = this.totalDuration;
|
|
13010
|
-
this.targetGlobalTimeDuringSwitch = cumulativeTimestamp;
|
|
13011
|
-
if (total > 0) {
|
|
13012
|
-
this.progress = Math.min(100, Math.max(0, (cumulativeTimestamp / total) * 100));
|
|
13013
|
-
}
|
|
13014
12950
|
this.playerState = 'switching';
|
|
13015
12951
|
try {
|
|
13016
|
-
// CRITICAL: Pause before switching source
|
|
13017
12952
|
video.pause();
|
|
13018
12953
|
this.isPlaying = false;
|
|
13019
12954
|
this.playPromise = null;
|
|
13020
12955
|
this.videoPause.emit();
|
|
13021
12956
|
this.isVideoPlayingChange.emit(false);
|
|
13022
|
-
// Switch video source
|
|
13023
12957
|
this.currentVideoIndex = targetVideoIndex;
|
|
13024
12958
|
yield new Promise((resolve, reject) => {
|
|
13025
12959
|
let resolved = false;
|
|
@@ -13029,20 +12963,13 @@ class SimulatorComponent {
|
|
|
13029
12963
|
resolved = true;
|
|
13030
12964
|
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
13031
12965
|
video.removeEventListener('error', onError);
|
|
13032
|
-
clearTimeout(timeoutId);
|
|
13033
12966
|
};
|
|
13034
12967
|
const onLoadedMetadata = () => {
|
|
13035
12968
|
cleanup();
|
|
13036
|
-
console.log('[Simulator] switchToVideoAndSeek: loadedmetadata', {
|
|
13037
|
-
readyState: video.readyState,
|
|
13038
|
-
duration: video.duration,
|
|
13039
|
-
currentTime: video.currentTime
|
|
13040
|
-
});
|
|
13041
12969
|
resolve();
|
|
13042
12970
|
};
|
|
13043
12971
|
const onError = () => {
|
|
13044
12972
|
cleanup();
|
|
13045
|
-
console.error('[Simulator] switchToVideoAndSeek: video error');
|
|
13046
12973
|
reject(new Error('Failed to load video'));
|
|
13047
12974
|
};
|
|
13048
12975
|
setTimeout(() => {
|
|
@@ -13051,121 +12978,51 @@ class SimulatorComponent {
|
|
|
13051
12978
|
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
13052
12979
|
video.addEventListener('error', onError, { once: true });
|
|
13053
12980
|
}, 100);
|
|
13054
|
-
const timeoutId = setTimeout(() => {
|
|
13055
|
-
cleanup();
|
|
13056
|
-
if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
13057
|
-
console.log('[Simulator] switchToVideoAndSeek: metadata timeout but video ready', {
|
|
13058
|
-
readyState: video.readyState,
|
|
13059
|
-
duration: video.duration
|
|
13060
|
-
});
|
|
13061
|
-
resolve();
|
|
13062
|
-
}
|
|
13063
|
-
else {
|
|
13064
|
-
console.error('[Simulator] switchToVideoAndSeek: metadata timeout and video not ready');
|
|
13065
|
-
reject(new Error('Timeout waiting for video to load'));
|
|
13066
|
-
}
|
|
13067
|
-
}, 2000);
|
|
13068
12981
|
});
|
|
13069
|
-
// Seek to the target position using 'seeked' event for reliability
|
|
13070
12982
|
const seekSeconds = relativeTimestamp / 1000;
|
|
13071
12983
|
const targetTime = Math.max(0, Math.min(seekSeconds, video.duration || seekSeconds));
|
|
13072
|
-
console.log('[Simulator] switchToVideoAndSeek: setting currentTime', {
|
|
13073
|
-
targetTime,
|
|
13074
|
-
seekSeconds,
|
|
13075
|
-
relativeTimestamp,
|
|
13076
|
-
videoDuration: video.duration
|
|
13077
|
-
});
|
|
13078
12984
|
yield new Promise((resolve) => {
|
|
13079
|
-
let resolved = false;
|
|
13080
12985
|
const onSeeked = () => {
|
|
13081
|
-
if (resolved)
|
|
13082
|
-
return;
|
|
13083
|
-
resolved = true;
|
|
13084
12986
|
video.removeEventListener('seeked', onSeeked);
|
|
13085
12987
|
clearTimeout(timeoutId);
|
|
13086
|
-
console.log('[Simulator] switchToVideoAndSeek: seeked event fired', {
|
|
13087
|
-
currentTime: video.currentTime,
|
|
13088
|
-
targetTime,
|
|
13089
|
-
diff: Math.abs(video.currentTime - targetTime)
|
|
13090
|
-
});
|
|
13091
|
-
// Small delay to ensure browser has processed the seek
|
|
13092
12988
|
setTimeout(() => resolve(), 100);
|
|
13093
12989
|
};
|
|
13094
12990
|
video.addEventListener('seeked', onSeeked, { once: true });
|
|
13095
12991
|
video.currentTime = targetTime;
|
|
13096
|
-
// Fallback timeout
|
|
13097
12992
|
const timeoutId = setTimeout(() => {
|
|
13098
|
-
if (resolved)
|
|
13099
|
-
return;
|
|
13100
|
-
resolved = true;
|
|
13101
12993
|
video.removeEventListener('seeked', onSeeked);
|
|
13102
|
-
console.log('[Simulator] switchToVideoAndSeek: seeked timeout, current time is', video.currentTime);
|
|
13103
12994
|
resolve();
|
|
13104
12995
|
}, 1000);
|
|
13105
12996
|
});
|
|
13106
12997
|
this.lastSetDuration = cumulativeTimestamp;
|
|
13107
|
-
// Double-check: if video is not at target, force it again
|
|
13108
12998
|
if (Math.abs(video.currentTime - targetTime) > 0.5) {
|
|
13109
|
-
console.warn('[Simulator] switchToVideoAndSeek: video not at target after seeked, forcing again', {
|
|
13110
|
-
currentTime: video.currentTime,
|
|
13111
|
-
targetTime
|
|
13112
|
-
});
|
|
13113
12999
|
video.currentTime = targetTime;
|
|
13114
13000
|
yield new Promise(resolve => setTimeout(resolve, 200));
|
|
13115
13001
|
}
|
|
13116
|
-
//
|
|
13117
|
-
const
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
actualGlobal,
|
|
13121
|
-
targetGlobal: cumulativeTimestamp,
|
|
13122
|
-
diff: Math.abs(actualGlobal - cumulativeTimestamp),
|
|
13123
|
-
actualVideoTime,
|
|
13124
|
-
targetVideoTime: targetTime,
|
|
13125
|
-
videoDiff: Math.abs(actualVideoTime - targetTime)
|
|
13126
|
-
});
|
|
13127
|
-
// Clear override only if video is actually at the target
|
|
13128
|
-
const tolerance = 500;
|
|
13129
|
-
if (Math.abs(actualGlobal - cumulativeTimestamp) < tolerance) {
|
|
13130
|
-
this.targetGlobalTimeDuringSwitch = null;
|
|
13131
|
-
console.log('[Simulator] switchToVideoAndSeek: cleared override - video at target');
|
|
13132
|
-
}
|
|
13133
|
-
// Update UI with actual current position
|
|
13134
|
-
if (total > 0) {
|
|
13135
|
-
this.progress = Math.min(100, Math.max(0, (this.globalCurrentTime / total) * 100));
|
|
13002
|
+
// Per-video progress
|
|
13003
|
+
const durationMs = video.duration * 1000;
|
|
13004
|
+
if (durationMs > 0) {
|
|
13005
|
+
this.progress = Math.min(100, Math.max(0, (video.currentTime * 1000 / durationMs) * 100));
|
|
13136
13006
|
}
|
|
13137
|
-
this.videoTimeUpdate.emit(
|
|
13007
|
+
this.videoTimeUpdate.emit(cumulativeTimestamp);
|
|
13138
13008
|
}
|
|
13139
13009
|
catch (err) {
|
|
13140
13010
|
console.error('[Simulator] switchToVideoAndSeek failed:', err);
|
|
13141
|
-
|
|
13142
|
-
if (total > 0) {
|
|
13143
|
-
this.progress = Math.min(100, Math.max(0, (cumulativeTimestamp / total) * 100));
|
|
13144
|
-
}
|
|
13011
|
+
this.progress = 0;
|
|
13145
13012
|
this.videoTimeUpdate.emit(cumulativeTimestamp);
|
|
13146
13013
|
}
|
|
13147
13014
|
finally {
|
|
13148
13015
|
this.playerState = 'paused';
|
|
13149
13016
|
this.hitMarkers.clear();
|
|
13150
|
-
|
|
13151
|
-
// or will be cleared by timeupdate handler when video reaches target
|
|
13152
|
-
}
|
|
13153
|
-
console.log('[Simulator] switchToVideoAndSeek: complete', {
|
|
13154
|
-
currentVideoIndex: this.currentVideoIndex,
|
|
13155
|
-
videoCurrentTime: video.currentTime,
|
|
13156
|
-
globalCurrentTime: this.globalCurrentTime,
|
|
13157
|
-
targetGlobalTimeDuringSwitch: this.targetGlobalTimeDuringSwitch,
|
|
13158
|
-
playerState: this.playerState,
|
|
13159
|
-
progress: this.progress
|
|
13160
|
-
});
|
|
13017
|
+
}
|
|
13161
13018
|
});
|
|
13162
13019
|
}
|
|
13163
13020
|
}
|
|
13164
13021
|
SimulatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
13165
|
-
SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause", markerHit: "markerHit", isVideoPlayingChange: "isVideoPlayingChange" }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBarRef", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainerRef", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(globalCurrentTime / 1000) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of globalStepMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"totalDuration > 0 ? (marker.globalTime / totalDuration) * 100 : 0\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(totalDuration / 1000) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i2$3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
13022
|
+
SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause", markerHit: "markerHit", isVideoPlayingChange: "isVideoPlayingChange" }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBarRef", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainerRef", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device', '!cqa-h-full !cqa-max-h-[500px]': shouldApplySmallHeightClasses}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-97px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i2$3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
13166
13023
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, decorators: [{
|
|
13167
13024
|
type: Component,
|
|
13168
|
-
args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-83px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(globalCurrentTime / 1000) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-flex-1\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of globalStepMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"totalDuration > 0 ? (marker.globalTime / totalDuration) * 100 : 0\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(totalDuration / 1000) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
|
|
13025
|
+
args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <ng-container *ngIf=\"hasDeviceFrame;\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-max-h-full cqa-h-full': platformType !== 'browser' || !isLive, 'cqa-min-w-max': platformType === 'device', '!cqa-h-full !cqa-max-h-[500px]': shouldApplySmallHeightClasses}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-z-20': platformType === 'browser', 'cqa-bg-white': platformType !== 'browser'}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-py-4 cqa-flex cqa-items-center cqa-max-h-[calc(100%-97px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-py-4 cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" [ngClass]=\"{'cqa-p-4': platformType === 'browser'}\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
|
|
13169
13026
|
}], ctorParameters: function () { return [{ type: i1$1.DomSanitizer }]; }, propDecorators: { videoUrl: [{
|
|
13170
13027
|
type: Input
|
|
13171
13028
|
}], videoUrls: [{
|
|
@@ -16490,12 +16347,12 @@ const PARAMETER_FILTER_TABS = [
|
|
|
16490
16347
|
];
|
|
16491
16348
|
/** Mock runtime variable suggestions (replace with API when integrating). */
|
|
16492
16349
|
const RUNTIME_SUGGESTED_VALUES = [
|
|
16493
|
-
'
|
|
16494
|
-
'
|
|
16495
|
-
'
|
|
16496
|
-
'
|
|
16497
|
-
'
|
|
16498
|
-
'
|
|
16350
|
+
'runtime.MaxWaitTime',
|
|
16351
|
+
'runtime.session_id',
|
|
16352
|
+
'runtime.auth_token',
|
|
16353
|
+
'runtime.step_index',
|
|
16354
|
+
'runtime.timestamp',
|
|
16355
|
+
'runtime.test_name',
|
|
16499
16356
|
];
|
|
16500
16357
|
class TestDataModalComponent {
|
|
16501
16358
|
constructor(fb, cdr, ref, data) {
|
|
@@ -16506,11 +16363,15 @@ class TestDataModalComponent {
|
|
|
16506
16363
|
this.apply = new EventEmitter();
|
|
16507
16364
|
this.cancel = new EventEmitter();
|
|
16508
16365
|
this.editInDepth = new EventEmitter();
|
|
16366
|
+
this.parameterCreate = new EventEmitter();
|
|
16367
|
+
this.parameterEdit = new EventEmitter();
|
|
16368
|
+
this.environmentCreate = new EventEmitter();
|
|
16369
|
+
this.environmentEdit = new EventEmitter();
|
|
16509
16370
|
this.tabSegments = TAB_SEGMENTS;
|
|
16510
16371
|
this.parameterFilterTabs = PARAMETER_FILTER_TABS;
|
|
16511
|
-
/**
|
|
16372
|
+
/** Parameter list from input, falls back to mock data if not provided. */
|
|
16512
16373
|
this.parameters = MOCK_PARAMETERS;
|
|
16513
|
-
/**
|
|
16374
|
+
/** Environment list from input, falls back to mock data if not provided. */
|
|
16514
16375
|
this.environmentItems = MOCK_ENVIRONMENT_ITEMS;
|
|
16515
16376
|
/** Runtime tab: suggested variable chips. */
|
|
16516
16377
|
this.runtimeSuggestedValues = RUNTIME_SUGGESTED_VALUES;
|
|
@@ -16538,6 +16399,13 @@ class TestDataModalComponent {
|
|
|
16538
16399
|
this.environmentSearchQuery = (_g = data.environmentSearchQuery) !== null && _g !== void 0 ? _g : '';
|
|
16539
16400
|
this.selectedEnvironmentId = (_h = data.selectedEnvironmentId) !== null && _h !== void 0 ? _h : null;
|
|
16540
16401
|
this.runtimeValue = (_j = data.runtimeValue) !== null && _j !== void 0 ? _j : '';
|
|
16402
|
+
// Set parameters and environmentItems from data if provided
|
|
16403
|
+
if (data.parameters !== undefined) {
|
|
16404
|
+
this.parameters = data.parameters;
|
|
16405
|
+
}
|
|
16406
|
+
if (data.environmentItems !== undefined) {
|
|
16407
|
+
this.environmentItems = data.environmentItems;
|
|
16408
|
+
}
|
|
16541
16409
|
}
|
|
16542
16410
|
}
|
|
16543
16411
|
ngOnInit() {
|
|
@@ -16670,12 +16538,12 @@ class TestDataModalComponent {
|
|
|
16670
16538
|
this.onEditFormFieldChange('value', param.name);
|
|
16671
16539
|
}
|
|
16672
16540
|
}
|
|
16673
|
-
onParameterEdit(
|
|
16674
|
-
|
|
16541
|
+
onParameterEdit(paramId) {
|
|
16542
|
+
this.parameterEdit.emit(paramId);
|
|
16675
16543
|
}
|
|
16676
16544
|
onCreateNewVariable(event) {
|
|
16677
16545
|
event.preventDefault();
|
|
16678
|
-
|
|
16546
|
+
this.parameterCreate.emit();
|
|
16679
16547
|
}
|
|
16680
16548
|
onEnvironmentSearchInput(value) {
|
|
16681
16549
|
this.onEditFormFieldChange('environmentSearchQuery', value);
|
|
@@ -16689,12 +16557,12 @@ class TestDataModalComponent {
|
|
|
16689
16557
|
this.onEditFormFieldChange('value', item.name);
|
|
16690
16558
|
}
|
|
16691
16559
|
}
|
|
16692
|
-
onEnvironmentEdit(
|
|
16693
|
-
|
|
16560
|
+
onEnvironmentEdit(itemId) {
|
|
16561
|
+
this.environmentEdit.emit(itemId);
|
|
16694
16562
|
}
|
|
16695
16563
|
onCreateNewEnvironment(event) {
|
|
16696
16564
|
event.preventDefault();
|
|
16697
|
-
|
|
16565
|
+
this.environmentCreate.emit();
|
|
16698
16566
|
}
|
|
16699
16567
|
/** Runtime tab: insert suggested value into the runtime input field. */
|
|
16700
16568
|
onRuntimeChipInsert(snippet) {
|
|
@@ -16714,6 +16582,17 @@ class TestDataModalComponent {
|
|
|
16714
16582
|
else if (this.activeTab === 'environment') {
|
|
16715
16583
|
valueToApply = this.selectedEnvironmentId ? (_d = (_c = this.environmentItems.find((e) => e.id === this.selectedEnvironmentId)) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : '' : '';
|
|
16716
16584
|
}
|
|
16585
|
+
// Wrap valueToApply based on active tab
|
|
16586
|
+
if (this.activeTab === 'parameter' && valueToApply) {
|
|
16587
|
+
valueToApply = `@|${valueToApply}|`;
|
|
16588
|
+
}
|
|
16589
|
+
else if (this.activeTab === 'runtime' && valueToApply) {
|
|
16590
|
+
valueToApply = `$|${valueToApply}|`;
|
|
16591
|
+
}
|
|
16592
|
+
else if (this.activeTab === 'environment' && valueToApply) {
|
|
16593
|
+
valueToApply = `*|${valueToApply}|`;
|
|
16594
|
+
}
|
|
16595
|
+
// plain-text tab: no wrapping, use value as is
|
|
16717
16596
|
// Build result with only the active tab's data, clear other tabs' data
|
|
16718
16597
|
const result = {
|
|
16719
16598
|
value: valueToApply,
|
|
@@ -16753,7 +16632,7 @@ class TestDataModalComponent {
|
|
|
16753
16632
|
}
|
|
16754
16633
|
}
|
|
16755
16634
|
TestDataModalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestDataModalComponent, deps: [{ token: i2$1.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: TEST_DATA_MODAL_REF }, { token: TEST_DATA_MODAL_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
16756
|
-
TestDataModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestDataModalComponent, selector: "cqa-test-data-modal", outputs: { apply: "apply", cancel: "cancel", editInDepth: "editInDepth" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div\n class=\"cqa-bg-white cqa-rounded-[12px] cqa-shadow-lg cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-w-[500px] cqa-flex cqa-flex-col cqa-gap-[12px] cqa-p-2 cqa-box-border cqa-min-h-0\">\n <!-- Header: title left; Need help? + close icon right -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2 cqa-px-4\">\n <h2 class=\"cqa-text-[16px] cqa-leading-[24px] cqa-font-bold cqa-text-[#111827] cqa-m-0 cqa-font-[600]\">\n Test Data\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-h-[28px]\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex cqa-items-center\"\n (mouseenter)=\"showHelpTooltip = true\" (mouseleave)=\"showHelpTooltip = false\">\n <a *ngIf=\"helpUrl\" href=\"#\" (click)=\"onHelp($event)\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[21px] cqa-no-underline hover:cqa-underline cqa-cursor-pointer\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </a>\n <span *ngIf=\"!helpUrl\" class=\"cqa-flex cqa-items-center cqa-gap-1.5 cqa-font-[500] cqa-text-[10px] cqa-cursor-default\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0 cqa-text-[#3F43EE]\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip-nolink)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip-nolink\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </span>\n <!-- Custom tooltip (exact spec: 306\u00D720 content, 6px radius, #0A0A0A, no arrow) -->\n <div *ngIf=\"showHelpTooltip\"\n class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100] cqa-top-[-24px] cqa-left-[-125px]\"\n role=\"tooltip\">\n <div\n class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap cqa-w-[306px] cqa-min-h-[20px] cqa-rounded-[6px] cqa-py-1 cqa-px-2 cqa-bg-[#0A0A0A] cqa-leading-[20px] cqa-text-[8px]\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-min-h-[28px] cqa-min-w-[28px] cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-p-0\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px] !cqa-block !cqa-leading-none\">close</mat-icon>\n </button>\n </div>\n </div>\n\n <!-- Line below header (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Tabs: Plain Text, Parameter, Environment, Runtime (bound to editForm like Loop Step) -->\n <div class=\"cqa-w-full cqa-test-data-modal-tabs\">\n <cqa-segment-control\n [segments]=\"tabSegments\"\n [value]=\"editForm.get('activeTab')?.value ?? activeTab\"\n (valueChange)=\"onTabChange($event)\">\n </cqa-segment-control>\n </div>\n\n <!-- Content per tab: flex-1 min-h-0 so Parameter/Environment/Runtime content can scroll -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-h-0\"\n [class.cqa-flex-1]=\"activeTab === 'parameter' || activeTab === 'environment' || activeTab === 'runtime'\">\n <!-- Plain Text tab (form-bound like Loop Step editForm + onEditFormFieldChange) -->\n <ng-container *ngIf=\"activeTab === 'plain-text'\">\n <cqa-custom-input\n label=\"Value\"\n [value]=\"editForm.get('value')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('value', $event)\"\n placeholder=\"https://example.com/dashboard\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#0A0A0A] cqa-m-0\">\n Enter a static text value that won't change during execution.\n </p>\n </ng-container>\n\n <!-- Parameter tab: Variable Library -->\n <ng-container *ngIf=\"activeTab === 'parameter'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Variable Library header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Variable Library\n </h3>\n <a href=\"#\" (click)=\"onCreateNewVariable($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Filter tabs: All, Global, Local (blue underline under active label only) -->\n <div class=\"cqa-flex cqa-w-full cqa-flex-shrink-0\">\n <button *ngFor=\"let tab of parameterFilterTabs\" type=\"button\"\n (click)=\"onParameterScopeFilterChange(tab.value)\"\n class=\"cqa-flex-1 cqa-py-0 cqa-px-3 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-bg-transparent cqa-cursor-pointer cqa-transition-colors cqa-flex cqa-justify-center cqa-items-center\"\n [class.cqa-text-[#6B7280]]=\"parameterScopeFilter !== tab.value\">\n <span class=\"cqa-test-data-param-filter-label cqa-inline-block cqa-pb-0.5\"\n [class.cqa-test-data-param-filter-active]=\"parameterScopeFilter === tab.value\">\n {{ tab.label }}\n </span>\n </button>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('parameterSearchQuery')?.value ?? ''\"\n (input)=\"onParameterSearchInput($any($event.target).value)\"\n placeholder=\"Search library\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search library\"\n />\n </div>\n <!-- Parameter list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[200px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"parameterListConfig\"\n [selectedId]=\"selectedParameterId\"\n emptyMessage=\"No parameters match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onParameterSelect($event)\"\n (itemEdit)=\"onParameterEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Environment tab: Variable library by environment -->\n <ng-container *ngIf=\"activeTab === 'environment'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Section header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Environment\n </h3>\n <a href=\"#\" (click)=\"onCreateNewEnvironment($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('environmentSearchQuery')?.value ?? ''\"\n (input)=\"onEnvironmentSearchInput($any($event.target).value)\"\n placeholder=\"Search Environment\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search Environment\"\n />\n </div>\n <!-- Environment list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[220px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"environmentListConfig\"\n [selectedId]=\"selectedEnvironmentId\"\n emptyMessage=\"No environment variables match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onEnvironmentSelect($event)\"\n (itemEdit)=\"onEnvironmentEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Runtime tab: dynamic value injector -->\n <ng-container *ngIf=\"activeTab === 'runtime'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-h-0 cqa-h-full cqa-overflow-y-auto\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0 cqa-flex-shrink-0\">\n Runtime\n </h3>\n <div class=\"cqa-flex-shrink-0\">\n <cqa-custom-input\n [value]=\"editForm.get('runtimeValue')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('runtimeValue', $event)\"\n placeholder=\"input text\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280] cqa-mt-1.5 cqa-mb-0\">\n Values resolved during test execution based on session and step state.\n </p>\n </div>\n <!-- Recommended: suggestion chips -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-flex-shrink-0\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px] cqa-text-[#9CA3AF]\" aria-hidden=\"true\">schedule</mat-icon>\n <span class=\"cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151]\">Recommended</span>\n </div>\n <div class=\"cqa-test-data-runtime-chips-scroll cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-min-w-0 cqa-pb-1\">\n <button\n *ngFor=\"let snippet of runtimeSuggestedValues\"\n type=\"button\"\n (click)=\"onRuntimeChipInsert(snippet)\"\n class=\"cqa-flex-shrink-0 cqa-px-3 cqa-py-1.5 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151] cqa-bg-[#F3F4F6] cqa-rounded-full hover:cqa-bg-[#E5E7EB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] cqa-transition-colors cqa-whitespace-nowrap\">\n {{ snippet }}\n </button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Line below content (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Footer: Cancel, Apply (full width in one row) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [text]=\"'Cancel'\" [fullWidth]=\"true\" (clicked)=\"onCancel()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"'Apply'\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#3F43EE]'\"></cqa-button>\n </div>\n </div>\n <a href=\"#\" (click)=\"onEditInDepth($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-1.5 cqa-no-underline hover:cqa-no-underline cqa-self-center\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">open_in_new</mat-icon>\n Edit in depth (open detailed right panel)\n </a>\n </div>\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ItemListComponent, selector: "cqa-item-list", inputs: ["items", "selectedId", "emptyMessage", "scrollable"], outputs: ["itemSelect", "itemEdit"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16635
|
+
TestDataModalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestDataModalComponent, selector: "cqa-test-data-modal", inputs: { parameters: "parameters", environmentItems: "environmentItems" }, outputs: { apply: "apply", cancel: "cancel", editInDepth: "editInDepth", parameterCreate: "parameterCreate", parameterEdit: "parameterEdit", environmentCreate: "environmentCreate", environmentEdit: "environmentEdit" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div\n class=\"cqa-bg-white cqa-rounded-[12px] cqa-shadow-lg cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-w-[500px] cqa-flex cqa-flex-col cqa-gap-[12px] cqa-p-2 cqa-box-border cqa-min-h-0\">\n <!-- Header: title left; Need help? + close icon right -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2 cqa-px-4\">\n <h2 class=\"cqa-text-[16px] cqa-leading-[24px] cqa-font-bold cqa-text-[#111827] cqa-m-0 cqa-font-[600]\">\n Test Data\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-h-[28px]\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex cqa-items-center\"\n (mouseenter)=\"showHelpTooltip = true\" (mouseleave)=\"showHelpTooltip = false\">\n <a *ngIf=\"helpUrl\" href=\"#\" (click)=\"onHelp($event)\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[21px] cqa-no-underline hover:cqa-underline cqa-cursor-pointer\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </a>\n <span *ngIf=\"!helpUrl\" class=\"cqa-flex cqa-items-center cqa-gap-1.5 cqa-font-[500] cqa-text-[10px] cqa-cursor-default\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0 cqa-text-[#3F43EE]\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip-nolink)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip-nolink\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </span>\n <!-- Custom tooltip (exact spec: 306\u00D720 content, 6px radius, #0A0A0A, no arrow) -->\n <div *ngIf=\"showHelpTooltip\"\n class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100] cqa-top-[-24px] cqa-left-[-125px]\"\n role=\"tooltip\">\n <div\n class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap cqa-w-[306px] cqa-min-h-[20px] cqa-rounded-[6px] cqa-py-1 cqa-px-2 cqa-bg-[#0A0A0A] cqa-leading-[20px] cqa-text-[8px]\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-min-h-[28px] cqa-min-w-[28px] cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-p-0\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px] !cqa-block !cqa-leading-none\">close</mat-icon>\n </button>\n </div>\n </div>\n\n <!-- Line below header (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Tabs: Plain Text, Parameter, Environment, Runtime (bound to editForm like Loop Step) -->\n <div class=\"cqa-w-full cqa-test-data-modal-tabs\">\n <cqa-segment-control\n [segments]=\"tabSegments\"\n [value]=\"editForm.get('activeTab')?.value ?? activeTab\"\n (valueChange)=\"onTabChange($event)\">\n </cqa-segment-control>\n </div>\n\n <!-- Content per tab: flex-1 min-h-0 so Parameter/Environment/Runtime content can scroll -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-h-0\"\n [class.cqa-flex-1]=\"activeTab === 'parameter' || activeTab === 'environment' || activeTab === 'runtime'\">\n <!-- Plain Text tab (form-bound like Loop Step editForm + onEditFormFieldChange) -->\n <ng-container *ngIf=\"activeTab === 'plain-text'\">\n <cqa-custom-input\n label=\"Value\"\n [value]=\"editForm.get('value')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('value', $event)\"\n placeholder=\"https://example.com/dashboard\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#0A0A0A] cqa-m-0\">\n Enter a static text value that won't change during execution.\n </p>\n </ng-container>\n\n <!-- Parameter tab: Variable Library -->\n <ng-container *ngIf=\"activeTab === 'parameter'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Variable Library header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Variable Library\n </h3>\n <a href=\"#\" (click)=\"onCreateNewVariable($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Filter tabs: All, Global, Local (blue underline under active label only) -->\n <div class=\"cqa-flex cqa-w-full cqa-flex-shrink-0\">\n <button *ngFor=\"let tab of parameterFilterTabs\" type=\"button\"\n (click)=\"onParameterScopeFilterChange(tab.value)\"\n class=\"cqa-flex-1 cqa-py-0 cqa-px-3 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-bg-transparent cqa-cursor-pointer cqa-transition-colors cqa-flex cqa-justify-center cqa-items-center\"\n [class.cqa-text-[#6B7280]]=\"parameterScopeFilter !== tab.value\">\n <span class=\"cqa-test-data-param-filter-label cqa-inline-block cqa-pb-0.5\"\n [class.cqa-test-data-param-filter-active]=\"parameterScopeFilter === tab.value\">\n {{ tab.label }}\n </span>\n </button>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('parameterSearchQuery')?.value ?? ''\"\n (input)=\"onParameterSearchInput($any($event.target).value)\"\n placeholder=\"Search library\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search library\"\n />\n </div>\n <!-- Parameter list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[200px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"parameterListConfig\"\n [selectedId]=\"selectedParameterId\"\n emptyMessage=\"No parameters match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onParameterSelect($event)\"\n (itemEdit)=\"onParameterEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Environment tab: Variable library by environment -->\n <ng-container *ngIf=\"activeTab === 'environment'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Section header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Environment\n </h3>\n <a href=\"#\" (click)=\"onCreateNewEnvironment($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('environmentSearchQuery')?.value ?? ''\"\n (input)=\"onEnvironmentSearchInput($any($event.target).value)\"\n placeholder=\"Search Environment\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search Environment\"\n />\n </div>\n <!-- Environment list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[220px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"environmentListConfig\"\n [selectedId]=\"selectedEnvironmentId\"\n emptyMessage=\"No environment variables match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onEnvironmentSelect($event)\"\n (itemEdit)=\"onEnvironmentEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Runtime tab: dynamic value injector -->\n <ng-container *ngIf=\"activeTab === 'runtime'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-h-0 cqa-h-full cqa-overflow-y-auto\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0 cqa-flex-shrink-0\">\n Runtime\n </h3>\n <div class=\"cqa-flex-shrink-0\">\n <cqa-custom-input\n [value]=\"editForm.get('runtimeValue')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('runtimeValue', $event)\"\n placeholder=\"input text\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280] cqa-mt-1.5 cqa-mb-0\">\n Values resolved during test execution based on session and step state.\n </p>\n </div>\n <!-- Recommended: suggestion chips -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-flex-shrink-0\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px] cqa-text-[#9CA3AF]\" aria-hidden=\"true\">schedule</mat-icon>\n <span class=\"cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151]\">Recommended</span>\n </div>\n <div class=\"cqa-test-data-runtime-chips-scroll cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-min-w-0 cqa-pb-1\">\n <button\n *ngFor=\"let snippet of runtimeSuggestedValues\"\n type=\"button\"\n (click)=\"onRuntimeChipInsert(snippet)\"\n class=\"cqa-flex-shrink-0 cqa-px-3 cqa-py-1.5 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151] cqa-bg-[#F3F4F6] cqa-rounded-full hover:cqa-bg-[#E5E7EB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] cqa-transition-colors cqa-whitespace-nowrap\">\n {{ snippet }}\n </button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Line below content (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Footer: Cancel, Apply (full width in one row) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [text]=\"'Cancel'\" [fullWidth]=\"true\" (clicked)=\"onCancel()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"'Apply'\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#3F43EE]'\"></cqa-button>\n </div>\n </div>\n <a href=\"#\" (click)=\"onEditInDepth($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-1.5 cqa-no-underline hover:cqa-no-underline cqa-self-center\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">open_in_new</mat-icon>\n Edit in depth (open detailed right panel)\n </a>\n </div>\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ItemListComponent, selector: "cqa-item-list", inputs: ["items", "selectedId", "emptyMessage", "scrollable"], outputs: ["itemSelect", "itemEdit"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16757
16636
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestDataModalComponent, decorators: [{
|
|
16758
16637
|
type: Component,
|
|
16759
16638
|
args: [{ selector: 'cqa-test-data-modal', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"cqa-bg-white cqa-rounded-[12px] cqa-shadow-lg cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-w-[500px] cqa-flex cqa-flex-col cqa-gap-[12px] cqa-p-2 cqa-box-border cqa-min-h-0\">\n <!-- Header: title left; Need help? + close icon right -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2 cqa-px-4\">\n <h2 class=\"cqa-text-[16px] cqa-leading-[24px] cqa-font-bold cqa-text-[#111827] cqa-m-0 cqa-font-[600]\">\n Test Data\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-min-h-[28px]\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex cqa-items-center\"\n (mouseenter)=\"showHelpTooltip = true\" (mouseleave)=\"showHelpTooltip = false\">\n <a *ngIf=\"helpUrl\" href=\"#\" (click)=\"onHelp($event)\"\n class=\"cqa-flex cqa-items-center cqa-gap-1 cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[21px] cqa-no-underline hover:cqa-underline cqa-cursor-pointer\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </a>\n <span *ngIf=\"!helpUrl\" class=\"cqa-flex cqa-items-center cqa-gap-1.5 cqa-font-[500] cqa-text-[10px] cqa-cursor-default\">\n <svg width=\"17\" height=\"16\" viewBox=\"0 0 17 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" class=\"cqa-flex-shrink-0 cqa-text-[#3F43EE]\" aria-hidden=\"true\">\n <g clip-path=\"url(#test-data-help-clip-nolink)\">\n <path d=\"M8.50033 14.6663C12.4123 14.6663 15.5837 11.6816 15.5837 7.99967C15.5837 4.31778 12.4123 1.33301 8.50033 1.33301C4.58831 1.33301 1.41699 4.31778 1.41699 7.99967C1.41699 11.6816 4.58831 14.6663 8.50033 14.6663Z\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.43848 6.00038C6.60501 5.55483 6.93371 5.17912 7.36636 4.9398C7.79901 4.70049 8.30769 4.61301 8.80231 4.69285C9.29693 4.7727 9.74556 5.01473 10.0687 5.37607C10.3919 5.7374 10.5688 6.19473 10.5681 6.66705C10.5681 8.00038 8.44306 8.66705 8.44306 8.66705\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.5 11.333H8.50966\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </g>\n <defs>\n <clipPath id=\"test-data-help-clip-nolink\">\n <rect width=\"17\" height=\"16\" fill=\"white\"/>\n </clipPath>\n </defs>\n </svg>\n Need help ?\n </span>\n <!-- Custom tooltip (exact spec: 306\u00D720 content, 6px radius, #0A0A0A, no arrow) -->\n <div *ngIf=\"showHelpTooltip\"\n class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100] cqa-top-[-24px] cqa-left-[-125px]\"\n role=\"tooltip\">\n <div\n class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap cqa-w-[306px] cqa-min-h-[20px] cqa-rounded-[6px] cqa-py-1 cqa-px-2 cqa-bg-[#0A0A0A] cqa-leading-[20px] cqa-text-[8px]\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-min-h-[28px] cqa-min-w-[28px] cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-p-0\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px] !cqa-block !cqa-leading-none\">close</mat-icon>\n </button>\n </div>\n </div>\n\n <!-- Line below header (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Tabs: Plain Text, Parameter, Environment, Runtime (bound to editForm like Loop Step) -->\n <div class=\"cqa-w-full cqa-test-data-modal-tabs\">\n <cqa-segment-control\n [segments]=\"tabSegments\"\n [value]=\"editForm.get('activeTab')?.value ?? activeTab\"\n (valueChange)=\"onTabChange($event)\">\n </cqa-segment-control>\n </div>\n\n <!-- Content per tab: flex-1 min-h-0 so Parameter/Environment/Runtime content can scroll -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-1.5 cqa-min-h-0\"\n [class.cqa-flex-1]=\"activeTab === 'parameter' || activeTab === 'environment' || activeTab === 'runtime'\">\n <!-- Plain Text tab (form-bound like Loop Step editForm + onEditFormFieldChange) -->\n <ng-container *ngIf=\"activeTab === 'plain-text'\">\n <cqa-custom-input\n label=\"Value\"\n [value]=\"editForm.get('value')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('value', $event)\"\n placeholder=\"https://example.com/dashboard\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#0A0A0A] cqa-m-0\">\n Enter a static text value that won't change during execution.\n </p>\n </ng-container>\n\n <!-- Parameter tab: Variable Library -->\n <ng-container *ngIf=\"activeTab === 'parameter'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Variable Library header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Variable Library\n </h3>\n <a href=\"#\" (click)=\"onCreateNewVariable($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Filter tabs: All, Global, Local (blue underline under active label only) -->\n <div class=\"cqa-flex cqa-w-full cqa-flex-shrink-0\">\n <button *ngFor=\"let tab of parameterFilterTabs\" type=\"button\"\n (click)=\"onParameterScopeFilterChange(tab.value)\"\n class=\"cqa-flex-1 cqa-py-0 cqa-px-3 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-bg-transparent cqa-cursor-pointer cqa-transition-colors cqa-flex cqa-justify-center cqa-items-center\"\n [class.cqa-text-[#6B7280]]=\"parameterScopeFilter !== tab.value\">\n <span class=\"cqa-test-data-param-filter-label cqa-inline-block cqa-pb-0.5\"\n [class.cqa-test-data-param-filter-active]=\"parameterScopeFilter === tab.value\">\n {{ tab.label }}\n </span>\n </button>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('parameterSearchQuery')?.value ?? ''\"\n (input)=\"onParameterSearchInput($any($event.target).value)\"\n placeholder=\"Search library\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search library\"\n />\n </div>\n <!-- Parameter list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[200px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"parameterListConfig\"\n [selectedId]=\"selectedParameterId\"\n emptyMessage=\"No parameters match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onParameterSelect($event)\"\n (itemEdit)=\"onParameterEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Environment tab: Variable library by environment -->\n <ng-container *ngIf=\"activeTab === 'environment'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-min-h-0 cqa-flex-1 cqa-min-h-[18rem]\">\n <!-- Section header -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-flex-shrink-0\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0\">\n Environment\n </h3>\n <a href=\"#\" (click)=\"onCreateNewEnvironment($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-no-underline hover:cqa-opacity-90 cqa-cursor-pointer\">\n Create New +\n </a>\n </div>\n <!-- Search: bound to editForm (same pattern as Loop Step control binding) -->\n <div class=\"cqa-flex-shrink-0 cqa-relative cqa-flex cqa-items-center\">\n <span class=\"cqa-absolute cqa-left-4 cqa-top-0 cqa-bottom-0 cqa-flex cqa-items-center cqa-justify-center cqa-pointer-events-none cqa-text-[#6B7280] cqa-leading-none\" aria-hidden=\"true\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">search</mat-icon>\n </span>\n <input\n type=\"text\"\n [value]=\"editForm.get('environmentSearchQuery')?.value ?? ''\"\n (input)=\"onEnvironmentSearchInput($any($event.target).value)\"\n placeholder=\"Search Environment\"\n class=\"cqa-test-data-search-input cqa-w-full cqa-pl-10 cqa-pr-4 cqa-py-2.5 cqa-text-sm cqa-leading-5 cqa-text-[#0A0A0A] placeholder:cqa-text-[#9CA3AF] focus:cqa-outline-none focus:cqa-border-[#3B82F6] focus:cqa-ring-1 focus:cqa-ring-[#3B82F6]\"\n aria-label=\"Search Environment\"\n />\n </div>\n <!-- Environment list (scrollable, search-integrated via filtered list binding) -->\n <div class=\"cqa-min-h-[220px] cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-item-list\n [items]=\"environmentListConfig\"\n [selectedId]=\"selectedEnvironmentId\"\n emptyMessage=\"No environment variables match your search.\"\n [scrollable]=\"true\"\n (itemSelect)=\"onEnvironmentSelect($event)\"\n (itemEdit)=\"onEnvironmentEdit($event)\">\n </cqa-item-list>\n </div>\n </div>\n </ng-container>\n\n <!-- Runtime tab: dynamic value injector -->\n <ng-container *ngIf=\"activeTab === 'runtime'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-min-h-0 cqa-h-full cqa-overflow-y-auto\">\n <h3 class=\"cqa-text-[12px] cqa-leading-[20px] cqa-font-semibold cqa-text-[#111827] cqa-m-0 cqa-flex-shrink-0\">\n Runtime\n </h3>\n <div class=\"cqa-flex-shrink-0\">\n <cqa-custom-input\n [value]=\"editForm.get('runtimeValue')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('runtimeValue', $event)\"\n placeholder=\"input text\"\n [fullWidth]=\"true\"\n size=\"md\">\n </cqa-custom-input>\n <p class=\"cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280] cqa-mt-1.5 cqa-mb-0\">\n Values resolved during test execution based on session and step state.\n </p>\n </div>\n <!-- Recommended: suggestion chips -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2 cqa-flex-shrink-0\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px] cqa-text-[#9CA3AF]\" aria-hidden=\"true\">schedule</mat-icon>\n <span class=\"cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151]\">Recommended</span>\n </div>\n <div class=\"cqa-test-data-runtime-chips-scroll cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-min-w-0 cqa-pb-1\">\n <button\n *ngFor=\"let snippet of runtimeSuggestedValues\"\n type=\"button\"\n (click)=\"onRuntimeChipInsert(snippet)\"\n class=\"cqa-flex-shrink-0 cqa-px-3 cqa-py-1.5 cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-text-[#374151] cqa-bg-[#F3F4F6] cqa-rounded-full hover:cqa-bg-[#E5E7EB] focus:cqa-outline-none focus-visible:cqa-ring-2 focus-visible:cqa-ring-[#3F43EE] cqa-transition-colors cqa-whitespace-nowrap\">\n {{ snippet }}\n </button>\n </div>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Line below content (full width of modal, no side margin) -->\n <div class=\"cqa--mx-2 cqa-w-[calc(100%+1rem)] cqa-flex-shrink-0\">\n <div class=\"cqa-h-px cqa-w-full cqa-bg-[#E5E7EB]\" role=\"presentation\"></div>\n </div>\n\n <!-- Footer: Cancel, Apply (full width in one row) -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-flex cqa-items-stretch cqa-gap-2 cqa-w-full\">\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [text]=\"'Cancel'\" [fullWidth]=\"true\" (clicked)=\"onCancel()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"'Apply'\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[12px] cqa-py-[9px] cqa-border-[#3F43EE]'\"></cqa-button>\n </div>\n </div>\n <a href=\"#\" (click)=\"onEditInDepth($event)\"\n class=\"cqa-text-[#3F43EE] cqa-text-[12px] cqa-leading-[18px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-1.5 cqa-no-underline hover:cqa-no-underline cqa-self-center\">\n <mat-icon class=\"!cqa-w-4 !cqa-h-4 !cqa-text-[16px]\">open_in_new</mat-icon>\n Edit in depth (open detailed right panel)\n </a>\n </div>\n</div>\n" }]
|
|
@@ -16773,6 +16652,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
16773
16652
|
type: Output
|
|
16774
16653
|
}], editInDepth: [{
|
|
16775
16654
|
type: Output
|
|
16655
|
+
}], parameterCreate: [{
|
|
16656
|
+
type: Output
|
|
16657
|
+
}], parameterEdit: [{
|
|
16658
|
+
type: Output
|
|
16659
|
+
}], environmentCreate: [{
|
|
16660
|
+
type: Output
|
|
16661
|
+
}], environmentEdit: [{
|
|
16662
|
+
type: Output
|
|
16663
|
+
}], parameters: [{
|
|
16664
|
+
type: Input
|
|
16665
|
+
}], environmentItems: [{
|
|
16666
|
+
type: Input
|
|
16776
16667
|
}] } });
|
|
16777
16668
|
|
|
16778
16669
|
class TestDataModalService {
|
|
@@ -16863,12 +16754,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
16863
16754
|
}], ctorParameters: function () { return [{ type: i1$6.Overlay }, { type: i0.Injector }]; } });
|
|
16864
16755
|
|
|
16865
16756
|
class TestCaseNormalStepComponent {
|
|
16866
|
-
constructor(customEditStep, elementPopup, testDataModal, cdr, ngZone) {
|
|
16757
|
+
constructor(customEditStep, elementPopup, testDataModal, cdr, ngZone, sanitizer) {
|
|
16867
16758
|
this.customEditStep = customEditStep;
|
|
16868
16759
|
this.elementPopup = elementPopup;
|
|
16869
16760
|
this.testDataModal = testDataModal;
|
|
16870
16761
|
this.cdr = cdr;
|
|
16871
16762
|
this.ngZone = ngZone;
|
|
16763
|
+
this.sanitizer = sanitizer;
|
|
16872
16764
|
this.parameters = [];
|
|
16873
16765
|
this.selected = false;
|
|
16874
16766
|
this.disabled = false;
|
|
@@ -16883,6 +16775,7 @@ class TestCaseNormalStepComponent {
|
|
|
16883
16775
|
this.delete = new EventEmitter();
|
|
16884
16776
|
this.moreOptions = new EventEmitter();
|
|
16885
16777
|
this.selectionChange = new EventEmitter();
|
|
16778
|
+
this.clickAction = new EventEmitter();
|
|
16886
16779
|
this.eventTypeDropdownOpen = false;
|
|
16887
16780
|
/** Stored test data modal state for reopening with same selections. */
|
|
16888
16781
|
this.testDataModalState = null;
|
|
@@ -16959,6 +16852,7 @@ class TestCaseNormalStepComponent {
|
|
|
16959
16852
|
}
|
|
16960
16853
|
ngOnInit() {
|
|
16961
16854
|
if (this.config) {
|
|
16855
|
+
this.action = this.config.action || '';
|
|
16962
16856
|
this.stepNumber = this.config.stepNumber;
|
|
16963
16857
|
this.eventType = this.config.eventType;
|
|
16964
16858
|
this.parameters = this.config.parameters || [];
|
|
@@ -16970,31 +16864,10 @@ class TestCaseNormalStepComponent {
|
|
|
16970
16864
|
return this.eventTypeConfigs.find(etc => etc.type === this.eventType) || this.eventTypeConfigs[0];
|
|
16971
16865
|
}
|
|
16972
16866
|
getActionDescription() {
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
case 'navigate':
|
|
16976
|
-
return 'Navigate to';
|
|
16977
|
-
case 'type':
|
|
16978
|
-
return 'Type';
|
|
16979
|
-
case 'click':
|
|
16980
|
-
return 'Click on';
|
|
16981
|
-
case 'doubleClick':
|
|
16982
|
-
return 'Double click on';
|
|
16983
|
-
case 'pressEnter':
|
|
16984
|
-
return 'Press Enter on';
|
|
16985
|
-
case 'enter':
|
|
16986
|
-
return 'Enter';
|
|
16987
|
-
case 'wait':
|
|
16988
|
-
return 'Wait';
|
|
16989
|
-
case 'verify':
|
|
16990
|
-
return 'Verify';
|
|
16991
|
-
case 'custom':
|
|
16992
|
-
return 'Custom step';
|
|
16993
|
-
case 'ai-agent':
|
|
16994
|
-
return 'AI Agent';
|
|
16995
|
-
default:
|
|
16996
|
-
return '';
|
|
16867
|
+
if (this.action) {
|
|
16868
|
+
return this.action ? this.sanitizer.bypassSecurityTrustHtml(this.action) : '';
|
|
16997
16869
|
}
|
|
16870
|
+
return '';
|
|
16998
16871
|
}
|
|
16999
16872
|
getActionSuffix() {
|
|
17000
16873
|
switch (this.eventType) {
|
|
@@ -17225,13 +17098,18 @@ class TestCaseNormalStepComponent {
|
|
|
17225
17098
|
this.closeEventTypeDropdown();
|
|
17226
17099
|
}
|
|
17227
17100
|
}
|
|
17101
|
+
clickOnAction(event) {
|
|
17102
|
+
event.preventDefault();
|
|
17103
|
+
event.stopPropagation();
|
|
17104
|
+
this.clickAction.emit(event);
|
|
17105
|
+
}
|
|
17228
17106
|
}
|
|
17229
|
-
TestCaseNormalStepComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseNormalStepComponent, deps: [{ token: CustomEditStepService }, { token: ElementPopupService }, { token: TestDataModalService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
17230
|
-
TestCaseNormalStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseNormalStepComponent, selector: "cqa-test-case-normal-step", inputs: { config: "config", stepNumber: "stepNumber", eventType: "eventType", parameters: "parameters", selected: "selected", disabled: "disabled", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder" }, outputs: { eventTypeChange: "eventTypeChange", parameterChange: "parameterChange", edit: "edit", link: "link", duplicate: "duplicate", delete: "delete", moreOptions: "moreOptions", selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "dropdownContainer", first: true, predicate: ["dropdownContainer"], descendants: true }, { propertyName: "descriptionTrigger", first: true, predicate: ["descriptionTrigger"], descendants: true }, { propertyName: "testDataTrigger", first: true, predicate: ["testDataTrigger"], descendants: true }, { propertyName: "editTrigger", first: true, predicate: ["editTrigger"], descendants: true }, { propertyName: "elementTrigger", first: true, predicate: ["elementTrigger"], descendants: true }], ngImport: i0, template: "<div [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-[12.5px] ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\" style=\"border-bottom: 1px solid #E5E7EB;\">\n\n <div class=\"cqa-inline-flex cqa-items-center\">\n <!-- Drag Handle Icon (when isReorder is true) - 9-dot grid (3x3) -->\n <div *ngIf=\"isReorder\" class=\"cqa-mr-2 cqa-cursor-move cqa-text-[#6B7280] hover:cqa-text-[#111827]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n </svg>\n </div>\n <!-- Checkbox (when isReorder is false) -->\n <label *ngIf=\"!isReorder\" class=\"cqa-flex cqa-items-center cqa-cursor-pointer cqa-relative cqa-mr-2\">\n <input type=\"checkbox\"\n [ngModel]=\"selected\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectionChange($event)\"\n class=\"cqa-h-4 cqa-w-4 cqa-cursor-pointer cqa-transition-all cqa-appearance-none cqa-rounded shadow hover:cqa-shadow-md cqa-border cqa-border-solid cqa-border-slate-300 cqa-flex-shrink-0\"\n [class.cqa-bg-[#3F43EE]]=\"selected\"\n [class.cqa-border-[#3F43EE]]=\"selected\"\n id=\"check\" />\n <span class=\"cqa-absolute cqa-text-white cqa-top-1/2 cqa-left-1/2 cqa--translate-x-1/2 cqa--translate-y-1/2 cqa-pointer-events-none cqa-flex cqa-items-center cqa-justify-center\"\n [class.cqa-opacity-0]=\"!selected\"\n [class.cqa-opacity-100]=\"selected\">\n <svg width=\"12\" height=\"13\" viewBox=\"0 0 12 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10 3.125L4.5 8.625L2 6.125\" stroke=\"white\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n </label>\n </div>\n\n <!-- Step Number -->\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px] cqa-min-w-[32px]\">\n {{ stepNumber }}\n </span>\n\n <!-- Event Type Selector (Pill Button) #### (click)=\"toggleEventTypeDropdown(); $event.stopPropagation()\" -->\n <div class=\"cqa-relative\" #dropdownContainer>\n <button type=\"button\" \n [style.background-color]=\"getCurrentEventTypeConfig().backgroundColor\"\n [style.color]=\"getCurrentEventTypeConfig().color\" [style.border-color]=\"getCurrentEventTypeConfig().color\"\n class=\"cqa-px-2.5 cqa-py-1 cqa-rounded-lg cqa-flex cqa-items-center cqa-gap-2 cqa-cursor-pointer\">\n <!-- Icon -->\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'paper_plane'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 6.41663L12.8333 1.16663L7.58333 12.25L6.41667 7.58329L1.75 6.41663Z\" stroke=\"#432DD7\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'star'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.797 9.04165C5.74492 8.83977 5.63969 8.65554 5.49227 8.50812C5.34485 8.3607 5.16062 8.25548 4.95875 8.2034L1.38 7.28057C1.31894 7.26324 1.2652 7.22646 1.22694 7.17583C1.18867 7.12519 1.16797 7.06345 1.16797 6.99998C1.16797 6.93651 1.18867 6.87478 1.22694 6.82414C1.2652 6.7735 1.31894 6.73673 1.38 6.7194L4.95875 5.79598C5.16055 5.74395 5.34473 5.63882 5.49215 5.49151C5.63956 5.34419 5.74483 5.16008 5.797 4.95832L6.71983 1.37957C6.73698 1.31827 6.77372 1.26427 6.82443 1.2258C6.87515 1.18733 6.93705 1.1665 7.0007 1.1665C7.06436 1.1665 7.12626 1.18733 7.17698 1.2258C7.22769 1.26427 7.26442 1.31827 7.28158 1.37957L8.20383 4.95832C8.25591 5.16019 8.36113 5.34442 8.50855 5.49184C8.65597 5.63926 8.8402 5.74449 9.04208 5.79657L12.6208 6.71882C12.6824 6.73579 12.7366 6.77249 12.7753 6.82328C12.814 6.87407 12.8349 6.93614 12.8349 6.99998C12.8349 7.06382 12.814 7.1259 12.7753 7.17669C12.7366 7.22748 12.6824 7.26417 12.6208 7.28115L9.04208 8.2034C8.8402 8.25548 8.65597 8.3607 8.50855 8.50812C8.36113 8.65554 8.25591 8.83977 8.20383 9.04165L7.281 12.6204C7.26384 12.6817 7.22711 12.7357 7.17639 12.7742C7.12568 12.8126 7.06377 12.8335 7.00012 12.8335C6.93647 12.8335 6.87456 12.8126 6.82385 12.7742C6.77314 12.7357 6.7364 12.6817 6.71925 12.6204L5.797 9.04165Z\"\n stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M11.666 1.75V4.08333\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M12.8333 2.91663H10.5\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.33398 9.91663V11.0833\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.91667 10.5H1.75\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'T'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.33398 4.08325V2.33325H11.6673V4.08325\" stroke=\"#8200DB\" stroke-width=\"1.16667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.25 11.6667H8.75\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M7 2.33325V11.6666\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 1.75L5.87417 11.6492L7.33833 7.33833L11.6492 5.87417L1.75 1.75Z\" stroke=\"#1447E6\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.58398 7.58325L11.084 11.0833\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'enter'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.0833 1.75L11.0833 5.83333L2.91667 5.83333\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7.58333 1.75L11.0833 5.25L7.58333 8.75\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91667 8.75L2.91667 12.25\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'clock'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6.99935 12.8334C10.221 12.8334 12.8327 10.2217 12.8327 7.00008C12.8327 3.77842 10.221 1.16675 6.99935 1.16675C3.77769 1.16675 1.16602 3.77842 1.16602 7.00008C1.16602 10.2217 3.77769 12.8334 6.99935 12.8334Z\"\n stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7 3.5V7L9.33333 8.16667\" stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n\n <!-- Label -->\n <span class=\"cqa-text-[#432DD7] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium\">{{\n getCurrentEventTypeConfig().label }}</span>\n </button>\n\n <!-- Dropdown Menu -->\n <div *ngIf=\"eventTypeDropdownOpen\" (click)=\"$event.stopPropagation()\"\n class=\"cqa-absolute cqa-top-full cqa-left-0 cqa-mt-1 cqa-bg-white cqa-rounded-lg cqa-shadow-lg cqa-border cqa-border-gray-200 cqa-z-50 cqa-min-w-[150px] cqa-py-1\">\n <button *ngFor=\"let etc of eventTypeConfigs\" type=\"button\" (click)=\"onEventTypeSelect(etc.type)\"\n [class.cqa-bg-primary-50]=\"eventType === etc.type\"\n class=\"cqa-w-full cqa-px-3 cqa-py-2 cqa-text-left cqa-flex cqa-items-center cqa-gap-2 hover:cqa-bg-gray-50 cqa-transition-colors\">\n <span *ngIf=\"etc.icon === 'paper_plane'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 5.5L11 1M11 1L7.5 11L6 6.5L1 5.5M11 1L1 5.5\" stroke=\"currentColor\" stroke-width=\"1.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'star'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 1L7.5 4.5L11 5L7.5 5.5L6 9L4.5 5.5L1 5L4.5 4.5L6 1Z\" fill=\"currentColor\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'T'\">\n T\n </span>\n <span *ngIf=\"etc.icon === 'cursor'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 2L9 1L10 8L7 7L5 9L4 7L2 2Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> \n </span>\n <span *ngIf=\"etc.icon === 'enter'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9.5 1.5L9.5 5L2 5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.5 1.5L9.5 4.5L6.5 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2 7.5L2 10.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'clock'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"6\" r=\"5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M6 3V6L8 7\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </span>\n <span>{{ etc.label }}</span>\n </button>\n </div>\n </div>\n\n <!-- Action Description -->\n <span class=\"cqa-text-[#111827] cqa-text-[14px] cqa-leading-[18px]\" *ngIf=\"getActionDescription()\">\n {{ getActionDescription() }}\n </span>\n\n <!-- Parameters -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Navigate: URL as clickable trigger for Test Data modal -->\n <span *ngIf=\"eventType === 'navigate' && getNavigateUrlParameter()\" #testDataTrigger\n (click)=\"openTestDataModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ getNavigateUrlParameter()?.value || getNavigateUrlParameter()?.displayValue }}\n </span>\n \n <!-- Other event types: loop through parameters (navigate excluded) -->\n <ng-container *ngFor=\"let param of parameters; let i = index\">\n <!-- Skip navigate parameters in the loop (already shown above) -->\n <ng-container *ngIf=\"eventType !== 'navigate'\">\n\n <!-- Type: First param (text value like {{username}}) -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Type: \"into\" text -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n into\n </span>\n\n <!-- Type: Second param (selector) -->\n <span *ngIf=\"eventType === 'type' && i === 1\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Selector input/display -->\n <span *ngIf=\"eventType === 'click' && param.name === 'element'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Suffix text (like \"if Present\") -->\n <span *ngIf=\"eventType === 'click' && param.name === 'suffix'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Double Click: Selector input/display -->\n <span *ngIf=\"eventType === 'doubleClick' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Press Enter: Selector input/display with HTML support -->\n <span *ngIf=\"eventType === 'pressEnter' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- Enter: Value display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"in the\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n in the\n </span>\n\n <!-- Enter: Label display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"field\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n field\n </span>\n\n <!-- Wait: Duration input -->\n <input *ngIf=\"eventType === 'wait' && param.name === 'duration'\" type=\"number\" [value]=\"param.value\"\n (input)=\"onParameterChange(param, $any($event.target).value)\" placeholder=\"2\"\n class=\"cqa-w-16 cqa-px-2 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#9E9EE3] cqa-bg-[#D1C4E9] cqa-text-[#3F43EE] cqa-text-sm cqa-font-medium cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-[#3F43EE] focus:cqa-ring-opacity-50\" />\n <span *ngIf=\"eventType === 'wait' && param.name === 'duration'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n seconds\n </span>\n\n <!-- Wait: Element selector -->\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n for element\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" \n #elementTrigger\n (click)=\"openElementPopup($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-cursor-pointer cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n to be visible\n </span>\n\n <!-- Custom: Description (clickable to open Step Description modal; pass $event so modal opens below this trigger) -->\n <span *ngIf=\"eventType === 'custom'\" #descriptionTrigger\n (click)=\"openStepDescriptionModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- AI Agent: Instructions -->\n <span *ngIf=\"eventType === 'ai-agent'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n </ng-container>\n </ng-container>\n </div>\n\n <!-- AI Agent View Details Link -->\n <a *ngIf=\"eventType === 'ai-agent'\" href=\"#\" (click)=\"onMoreOptions(); $event.preventDefault()\" class=\"cqa-ml-auto cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-2 cqa-no-underline\">View Details<svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg></a>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-ml-auto cqa-px-[7px]\">\n <button type=\"button\" #editTrigger (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
17107
|
+
TestCaseNormalStepComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseNormalStepComponent, deps: [{ token: CustomEditStepService }, { token: ElementPopupService }, { token: TestDataModalService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
17108
|
+
TestCaseNormalStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseNormalStepComponent, selector: "cqa-test-case-normal-step", inputs: { config: "config", stepNumber: "stepNumber", action: "action", eventType: "eventType", parameters: "parameters", selected: "selected", disabled: "disabled", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder" }, outputs: { eventTypeChange: "eventTypeChange", parameterChange: "parameterChange", edit: "edit", link: "link", duplicate: "duplicate", delete: "delete", moreOptions: "moreOptions", selectionChange: "selectionChange", clickAction: "clickAction" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "dropdownContainer", first: true, predicate: ["dropdownContainer"], descendants: true }, { propertyName: "descriptionTrigger", first: true, predicate: ["descriptionTrigger"], descendants: true }, { propertyName: "testDataTrigger", first: true, predicate: ["testDataTrigger"], descendants: true }, { propertyName: "editTrigger", first: true, predicate: ["editTrigger"], descendants: true }, { propertyName: "elementTrigger", first: true, predicate: ["elementTrigger"], descendants: true }], ngImport: i0, template: "<div [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-[12.5px] ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\" style=\"border-bottom: 1px solid #E5E7EB;\">\n\n <div class=\"cqa-inline-flex cqa-items-center\">\n <!-- Drag Handle Icon (when isReorder is true) - 9-dot grid (3x3) -->\n <div *ngIf=\"isReorder\" class=\"cqa-mr-2 cqa-cursor-move cqa-text-[#6B7280] hover:cqa-text-[#111827]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n </svg>\n </div>\n <!-- Checkbox (when isReorder is false) -->\n <label *ngIf=\"!isReorder\" class=\"cqa-flex cqa-items-center cqa-cursor-pointer cqa-relative cqa-mr-2\">\n <input type=\"checkbox\"\n [ngModel]=\"selected\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectionChange($event)\"\n class=\"cqa-h-4 cqa-w-4 cqa-cursor-pointer cqa-transition-all cqa-appearance-none cqa-rounded shadow hover:cqa-shadow-md cqa-border cqa-border-solid cqa-border-slate-300 cqa-flex-shrink-0\"\n [class.cqa-bg-[#3F43EE]]=\"selected\"\n [class.cqa-border-[#3F43EE]]=\"selected\"\n id=\"check\" />\n <span class=\"cqa-absolute cqa-text-white cqa-top-1/2 cqa-left-1/2 cqa--translate-x-1/2 cqa--translate-y-1/2 cqa-pointer-events-none cqa-flex cqa-items-center cqa-justify-center\"\n [class.cqa-opacity-0]=\"!selected\"\n [class.cqa-opacity-100]=\"selected\">\n <svg width=\"12\" height=\"13\" viewBox=\"0 0 12 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10 3.125L4.5 8.625L2 6.125\" stroke=\"white\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n </label>\n </div>\n\n <!-- Step Number -->\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px] cqa-min-w-[32px]\">\n {{ stepNumber }}\n </span>\n\n <!-- Event Type Selector (Pill Button) #### (click)=\"toggleEventTypeDropdown(); $event.stopPropagation()\" -->\n <div class=\"cqa-relative\" #dropdownContainer>\n <button type=\"button\" \n [style.background-color]=\"getCurrentEventTypeConfig().backgroundColor\"\n [style.color]=\"getCurrentEventTypeConfig().color\" [style.border-color]=\"getCurrentEventTypeConfig().color\"\n class=\"cqa-px-2.5 cqa-py-1 cqa-rounded-lg cqa-flex cqa-items-center cqa-gap-2 cqa-cursor-pointer\">\n <!-- Icon -->\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'paper_plane'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 6.41663L12.8333 1.16663L7.58333 12.25L6.41667 7.58329L1.75 6.41663Z\" stroke=\"#432DD7\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'star'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.797 9.04165C5.74492 8.83977 5.63969 8.65554 5.49227 8.50812C5.34485 8.3607 5.16062 8.25548 4.95875 8.2034L1.38 7.28057C1.31894 7.26324 1.2652 7.22646 1.22694 7.17583C1.18867 7.12519 1.16797 7.06345 1.16797 6.99998C1.16797 6.93651 1.18867 6.87478 1.22694 6.82414C1.2652 6.7735 1.31894 6.73673 1.38 6.7194L4.95875 5.79598C5.16055 5.74395 5.34473 5.63882 5.49215 5.49151C5.63956 5.34419 5.74483 5.16008 5.797 4.95832L6.71983 1.37957C6.73698 1.31827 6.77372 1.26427 6.82443 1.2258C6.87515 1.18733 6.93705 1.1665 7.0007 1.1665C7.06436 1.1665 7.12626 1.18733 7.17698 1.2258C7.22769 1.26427 7.26442 1.31827 7.28158 1.37957L8.20383 4.95832C8.25591 5.16019 8.36113 5.34442 8.50855 5.49184C8.65597 5.63926 8.8402 5.74449 9.04208 5.79657L12.6208 6.71882C12.6824 6.73579 12.7366 6.77249 12.7753 6.82328C12.814 6.87407 12.8349 6.93614 12.8349 6.99998C12.8349 7.06382 12.814 7.1259 12.7753 7.17669C12.7366 7.22748 12.6824 7.26417 12.6208 7.28115L9.04208 8.2034C8.8402 8.25548 8.65597 8.3607 8.50855 8.50812C8.36113 8.65554 8.25591 8.83977 8.20383 9.04165L7.281 12.6204C7.26384 12.6817 7.22711 12.7357 7.17639 12.7742C7.12568 12.8126 7.06377 12.8335 7.00012 12.8335C6.93647 12.8335 6.87456 12.8126 6.82385 12.7742C6.77314 12.7357 6.7364 12.6817 6.71925 12.6204L5.797 9.04165Z\"\n stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M11.666 1.75V4.08333\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M12.8333 2.91663H10.5\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.33398 9.91663V11.0833\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.91667 10.5H1.75\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'T'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.33398 4.08325V2.33325H11.6673V4.08325\" stroke=\"#8200DB\" stroke-width=\"1.16667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.25 11.6667H8.75\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M7 2.33325V11.6666\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 1.75L5.87417 11.6492L7.33833 7.33833L11.6492 5.87417L1.75 1.75Z\" stroke=\"#1447E6\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.58398 7.58325L11.084 11.0833\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'enter'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.0833 1.75L11.0833 5.83333L2.91667 5.83333\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7.58333 1.75L11.0833 5.25L7.58333 8.75\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91667 8.75L2.91667 12.25\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'clock'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6.99935 12.8334C10.221 12.8334 12.8327 10.2217 12.8327 7.00008C12.8327 3.77842 10.221 1.16675 6.99935 1.16675C3.77769 1.16675 1.16602 3.77842 1.16602 7.00008C1.16602 10.2217 3.77769 12.8334 6.99935 12.8334Z\"\n stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7 3.5V7L9.33333 8.16667\" stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n\n <!-- Label -->\n <span class=\"cqa-text-[#432DD7] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium\">{{\n getCurrentEventTypeConfig().label }}</span>\n </button>\n\n <!-- Dropdown Menu -->\n <div *ngIf=\"eventTypeDropdownOpen\" (click)=\"$event.stopPropagation()\"\n class=\"cqa-absolute cqa-top-full cqa-left-0 cqa-mt-1 cqa-bg-white cqa-rounded-lg cqa-shadow-lg cqa-border cqa-border-gray-200 cqa-z-50 cqa-min-w-[150px] cqa-py-1\">\n <button *ngFor=\"let etc of eventTypeConfigs\" type=\"button\" (click)=\"onEventTypeSelect(etc.type)\"\n [class.cqa-bg-primary-50]=\"eventType === etc.type\"\n class=\"cqa-w-full cqa-px-3 cqa-py-2 cqa-text-left cqa-flex cqa-items-center cqa-gap-2 hover:cqa-bg-gray-50 cqa-transition-colors\">\n <span *ngIf=\"etc.icon === 'paper_plane'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 5.5L11 1M11 1L7.5 11L6 6.5L1 5.5M11 1L1 5.5\" stroke=\"currentColor\" stroke-width=\"1.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'star'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 1L7.5 4.5L11 5L7.5 5.5L6 9L4.5 5.5L1 5L4.5 4.5L6 1Z\" fill=\"currentColor\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'T'\">\n T\n </span>\n <span *ngIf=\"etc.icon === 'cursor'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 2L9 1L10 8L7 7L5 9L4 7L2 2Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> \n </span>\n <span *ngIf=\"etc.icon === 'enter'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9.5 1.5L9.5 5L2 5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.5 1.5L9.5 4.5L6.5 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2 7.5L2 10.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'clock'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"6\" r=\"5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M6 3V6L8 7\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </span>\n <span>{{ etc.label }}</span>\n </button>\n </div>\n </div>\n\n <!-- Action Description -->\n <span class=\"cqa-text-[#111827] cqa-text-[14px] cqa-leading-[18px]\" *ngIf=\"getActionDescription()\"\n [innerHTML]=\"getActionDescription()\" (click)=\"clickOnAction($event)\">\n </span>\n\n <!-- Parameters -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\" *ngIf=\"false\">\n <!-- Navigate: URL as clickable trigger for Test Data modal -->\n <span *ngIf=\"eventType === 'navigate' && getNavigateUrlParameter()\" #testDataTrigger\n (click)=\"openTestDataModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ getNavigateUrlParameter()?.value || getNavigateUrlParameter()?.displayValue }}\n </span>\n \n <!-- Other event types: loop through parameters (navigate excluded) -->\n <ng-container *ngFor=\"let param of parameters; let i = index\">\n <!-- Skip navigate parameters in the loop (already shown above) -->\n <ng-container *ngIf=\"eventType !== 'navigate'\">\n\n <!-- Type: First param (text value like {{username}}) -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Type: \"into\" text -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n into\n </span>\n\n <!-- Type: Second param (selector) -->\n <span *ngIf=\"eventType === 'type' && i === 1\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Selector input/display -->\n <span *ngIf=\"eventType === 'click' && param.name === 'element'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Suffix text (like \"if Present\") -->\n <span *ngIf=\"eventType === 'click' && param.name === 'suffix'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Double Click: Selector input/display -->\n <span *ngIf=\"eventType === 'doubleClick' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Press Enter: Selector input/display with HTML support -->\n <span *ngIf=\"eventType === 'pressEnter' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- Enter: Value display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"in the\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n in the\n </span>\n\n <!-- Enter: Label display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"field\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n field\n </span>\n\n <!-- Wait: Duration input -->\n <input *ngIf=\"eventType === 'wait' && param.name === 'duration'\" type=\"number\" [value]=\"param.value\"\n (input)=\"onParameterChange(param, $any($event.target).value)\" placeholder=\"2\"\n class=\"cqa-w-16 cqa-px-2 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#9E9EE3] cqa-bg-[#D1C4E9] cqa-text-[#3F43EE] cqa-text-sm cqa-font-medium cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-[#3F43EE] focus:cqa-ring-opacity-50\" />\n <span *ngIf=\"eventType === 'wait' && param.name === 'duration'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n seconds\n </span>\n\n <!-- Wait: Element selector -->\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n for element\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" \n #elementTrigger\n (click)=\"openElementPopup($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-cursor-pointer cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n to be visible\n </span>\n\n <!-- Custom: Description (clickable to open Step Description modal; pass $event so modal opens below this trigger) -->\n <span *ngIf=\"eventType === 'custom'\" #descriptionTrigger\n (click)=\"openStepDescriptionModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- AI Agent: Instructions -->\n <span *ngIf=\"eventType === 'ai-agent'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n </ng-container>\n </ng-container>\n </div>\n\n <!-- AI Agent View Details Link -->\n <a *ngIf=\"eventType === 'ai-agent'\" href=\"#\" (click)=\"onMoreOptions(); $event.preventDefault()\" class=\"cqa-ml-auto cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-2 cqa-no-underline\">View Details<svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg></a>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-ml-auto cqa-px-[7px]\">\n <button type=\"button\" #editTrigger (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
17231
17109
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseNormalStepComponent, decorators: [{
|
|
17232
17110
|
type: Component,
|
|
17233
|
-
args: [{ selector: 'cqa-test-case-normal-step', host: { class: 'cqa-ui-root' }, styles: [STEP_ROW_ACTIONS_STYLES], template: "<div [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-[12.5px] ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\" style=\"border-bottom: 1px solid #E5E7EB;\">\n\n <div class=\"cqa-inline-flex cqa-items-center\">\n <!-- Drag Handle Icon (when isReorder is true) - 9-dot grid (3x3) -->\n <div *ngIf=\"isReorder\" class=\"cqa-mr-2 cqa-cursor-move cqa-text-[#6B7280] hover:cqa-text-[#111827]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n </svg>\n </div>\n <!-- Checkbox (when isReorder is false) -->\n <label *ngIf=\"!isReorder\" class=\"cqa-flex cqa-items-center cqa-cursor-pointer cqa-relative cqa-mr-2\">\n <input type=\"checkbox\"\n [ngModel]=\"selected\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectionChange($event)\"\n class=\"cqa-h-4 cqa-w-4 cqa-cursor-pointer cqa-transition-all cqa-appearance-none cqa-rounded shadow hover:cqa-shadow-md cqa-border cqa-border-solid cqa-border-slate-300 cqa-flex-shrink-0\"\n [class.cqa-bg-[#3F43EE]]=\"selected\"\n [class.cqa-border-[#3F43EE]]=\"selected\"\n id=\"check\" />\n <span class=\"cqa-absolute cqa-text-white cqa-top-1/2 cqa-left-1/2 cqa--translate-x-1/2 cqa--translate-y-1/2 cqa-pointer-events-none cqa-flex cqa-items-center cqa-justify-center\"\n [class.cqa-opacity-0]=\"!selected\"\n [class.cqa-opacity-100]=\"selected\">\n <svg width=\"12\" height=\"13\" viewBox=\"0 0 12 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10 3.125L4.5 8.625L2 6.125\" stroke=\"white\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n </label>\n </div>\n\n <!-- Step Number -->\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px] cqa-min-w-[32px]\">\n {{ stepNumber }}\n </span>\n\n <!-- Event Type Selector (Pill Button) #### (click)=\"toggleEventTypeDropdown(); $event.stopPropagation()\" -->\n <div class=\"cqa-relative\" #dropdownContainer>\n <button type=\"button\" \n [style.background-color]=\"getCurrentEventTypeConfig().backgroundColor\"\n [style.color]=\"getCurrentEventTypeConfig().color\" [style.border-color]=\"getCurrentEventTypeConfig().color\"\n class=\"cqa-px-2.5 cqa-py-1 cqa-rounded-lg cqa-flex cqa-items-center cqa-gap-2 cqa-cursor-pointer\">\n <!-- Icon -->\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'paper_plane'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 6.41663L12.8333 1.16663L7.58333 12.25L6.41667 7.58329L1.75 6.41663Z\" stroke=\"#432DD7\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'star'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.797 9.04165C5.74492 8.83977 5.63969 8.65554 5.49227 8.50812C5.34485 8.3607 5.16062 8.25548 4.95875 8.2034L1.38 7.28057C1.31894 7.26324 1.2652 7.22646 1.22694 7.17583C1.18867 7.12519 1.16797 7.06345 1.16797 6.99998C1.16797 6.93651 1.18867 6.87478 1.22694 6.82414C1.2652 6.7735 1.31894 6.73673 1.38 6.7194L4.95875 5.79598C5.16055 5.74395 5.34473 5.63882 5.49215 5.49151C5.63956 5.34419 5.74483 5.16008 5.797 4.95832L6.71983 1.37957C6.73698 1.31827 6.77372 1.26427 6.82443 1.2258C6.87515 1.18733 6.93705 1.1665 7.0007 1.1665C7.06436 1.1665 7.12626 1.18733 7.17698 1.2258C7.22769 1.26427 7.26442 1.31827 7.28158 1.37957L8.20383 4.95832C8.25591 5.16019 8.36113 5.34442 8.50855 5.49184C8.65597 5.63926 8.8402 5.74449 9.04208 5.79657L12.6208 6.71882C12.6824 6.73579 12.7366 6.77249 12.7753 6.82328C12.814 6.87407 12.8349 6.93614 12.8349 6.99998C12.8349 7.06382 12.814 7.1259 12.7753 7.17669C12.7366 7.22748 12.6824 7.26417 12.6208 7.28115L9.04208 8.2034C8.8402 8.25548 8.65597 8.3607 8.50855 8.50812C8.36113 8.65554 8.25591 8.83977 8.20383 9.04165L7.281 12.6204C7.26384 12.6817 7.22711 12.7357 7.17639 12.7742C7.12568 12.8126 7.06377 12.8335 7.00012 12.8335C6.93647 12.8335 6.87456 12.8126 6.82385 12.7742C6.77314 12.7357 6.7364 12.6817 6.71925 12.6204L5.797 9.04165Z\"\n stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M11.666 1.75V4.08333\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M12.8333 2.91663H10.5\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.33398 9.91663V11.0833\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.91667 10.5H1.75\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'T'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.33398 4.08325V2.33325H11.6673V4.08325\" stroke=\"#8200DB\" stroke-width=\"1.16667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.25 11.6667H8.75\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M7 2.33325V11.6666\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 1.75L5.87417 11.6492L7.33833 7.33833L11.6492 5.87417L1.75 1.75Z\" stroke=\"#1447E6\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.58398 7.58325L11.084 11.0833\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'enter'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.0833 1.75L11.0833 5.83333L2.91667 5.83333\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7.58333 1.75L11.0833 5.25L7.58333 8.75\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91667 8.75L2.91667 12.25\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'clock'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6.99935 12.8334C10.221 12.8334 12.8327 10.2217 12.8327 7.00008C12.8327 3.77842 10.221 1.16675 6.99935 1.16675C3.77769 1.16675 1.16602 3.77842 1.16602 7.00008C1.16602 10.2217 3.77769 12.8334 6.99935 12.8334Z\"\n stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7 3.5V7L9.33333 8.16667\" stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n\n <!-- Label -->\n <span class=\"cqa-text-[#432DD7] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium\">{{\n getCurrentEventTypeConfig().label }}</span>\n </button>\n\n <!-- Dropdown Menu -->\n <div *ngIf=\"eventTypeDropdownOpen\" (click)=\"$event.stopPropagation()\"\n class=\"cqa-absolute cqa-top-full cqa-left-0 cqa-mt-1 cqa-bg-white cqa-rounded-lg cqa-shadow-lg cqa-border cqa-border-gray-200 cqa-z-50 cqa-min-w-[150px] cqa-py-1\">\n <button *ngFor=\"let etc of eventTypeConfigs\" type=\"button\" (click)=\"onEventTypeSelect(etc.type)\"\n [class.cqa-bg-primary-50]=\"eventType === etc.type\"\n class=\"cqa-w-full cqa-px-3 cqa-py-2 cqa-text-left cqa-flex cqa-items-center cqa-gap-2 hover:cqa-bg-gray-50 cqa-transition-colors\">\n <span *ngIf=\"etc.icon === 'paper_plane'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 5.5L11 1M11 1L7.5 11L6 6.5L1 5.5M11 1L1 5.5\" stroke=\"currentColor\" stroke-width=\"1.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'star'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 1L7.5 4.5L11 5L7.5 5.5L6 9L4.5 5.5L1 5L4.5 4.5L6 1Z\" fill=\"currentColor\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'T'\">\n T\n </span>\n <span *ngIf=\"etc.icon === 'cursor'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 2L9 1L10 8L7 7L5 9L4 7L2 2Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> \n </span>\n <span *ngIf=\"etc.icon === 'enter'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9.5 1.5L9.5 5L2 5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.5 1.5L9.5 4.5L6.5 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2 7.5L2 10.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'clock'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"6\" r=\"5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M6 3V6L8 7\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </span>\n <span>{{ etc.label }}</span>\n </button>\n </div>\n </div>\n\n <!-- Action Description -->\n <span class=\"cqa-text-[#111827] cqa-text-[14px] cqa-leading-[18px]\" *ngIf=\"getActionDescription()\">\n {{ getActionDescription() }}\n </span>\n\n <!-- Parameters -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\">\n <!-- Navigate: URL as clickable trigger for Test Data modal -->\n <span *ngIf=\"eventType === 'navigate' && getNavigateUrlParameter()\" #testDataTrigger\n (click)=\"openTestDataModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ getNavigateUrlParameter()?.value || getNavigateUrlParameter()?.displayValue }}\n </span>\n \n <!-- Other event types: loop through parameters (navigate excluded) -->\n <ng-container *ngFor=\"let param of parameters; let i = index\">\n <!-- Skip navigate parameters in the loop (already shown above) -->\n <ng-container *ngIf=\"eventType !== 'navigate'\">\n\n <!-- Type: First param (text value like {{username}}) -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Type: \"into\" text -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n into\n </span>\n\n <!-- Type: Second param (selector) -->\n <span *ngIf=\"eventType === 'type' && i === 1\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Selector input/display -->\n <span *ngIf=\"eventType === 'click' && param.name === 'element'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Suffix text (like \"if Present\") -->\n <span *ngIf=\"eventType === 'click' && param.name === 'suffix'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Double Click: Selector input/display -->\n <span *ngIf=\"eventType === 'doubleClick' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Press Enter: Selector input/display with HTML support -->\n <span *ngIf=\"eventType === 'pressEnter' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- Enter: Value display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"in the\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n in the\n </span>\n\n <!-- Enter: Label display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"field\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n field\n </span>\n\n <!-- Wait: Duration input -->\n <input *ngIf=\"eventType === 'wait' && param.name === 'duration'\" type=\"number\" [value]=\"param.value\"\n (input)=\"onParameterChange(param, $any($event.target).value)\" placeholder=\"2\"\n class=\"cqa-w-16 cqa-px-2 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#9E9EE3] cqa-bg-[#D1C4E9] cqa-text-[#3F43EE] cqa-text-sm cqa-font-medium cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-[#3F43EE] focus:cqa-ring-opacity-50\" />\n <span *ngIf=\"eventType === 'wait' && param.name === 'duration'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n seconds\n </span>\n\n <!-- Wait: Element selector -->\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n for element\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" \n #elementTrigger\n (click)=\"openElementPopup($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-cursor-pointer cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n to be visible\n </span>\n\n <!-- Custom: Description (clickable to open Step Description modal; pass $event so modal opens below this trigger) -->\n <span *ngIf=\"eventType === 'custom'\" #descriptionTrigger\n (click)=\"openStepDescriptionModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- AI Agent: Instructions -->\n <span *ngIf=\"eventType === 'ai-agent'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n </ng-container>\n </ng-container>\n </div>\n\n <!-- AI Agent View Details Link -->\n <a *ngIf=\"eventType === 'ai-agent'\" href=\"#\" (click)=\"onMoreOptions(); $event.preventDefault()\" class=\"cqa-ml-auto cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-2 cqa-no-underline\">View Details<svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg></a>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-ml-auto cqa-px-[7px]\">\n <button type=\"button\" #editTrigger (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>" }]
|
|
17234
|
-
}], ctorParameters: function () { return [{ type: CustomEditStepService }, { type: ElementPopupService }, { type: TestDataModalService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }]; }, propDecorators: { dropdownContainer: [{
|
|
17111
|
+
args: [{ selector: 'cqa-test-case-normal-step', host: { class: 'cqa-ui-root' }, styles: [STEP_ROW_ACTIONS_STYLES], template: "<div [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-[12.5px] ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\" style=\"border-bottom: 1px solid #E5E7EB;\">\n\n <div class=\"cqa-inline-flex cqa-items-center\">\n <!-- Drag Handle Icon (when isReorder is true) - 9-dot grid (3x3) -->\n <div *ngIf=\"isReorder\" class=\"cqa-mr-2 cqa-cursor-move cqa-text-[#6B7280] hover:cqa-text-[#111827]\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"3\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"3\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"8\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"3\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"8\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n <circle cx=\"13\" cy=\"13\" r=\"1.5\" fill=\"currentColor\"/>\n </svg>\n </div>\n <!-- Checkbox (when isReorder is false) -->\n <label *ngIf=\"!isReorder\" class=\"cqa-flex cqa-items-center cqa-cursor-pointer cqa-relative cqa-mr-2\">\n <input type=\"checkbox\"\n [ngModel]=\"selected\"\n [disabled]=\"disabled\"\n (ngModelChange)=\"onSelectionChange($event)\"\n class=\"cqa-h-4 cqa-w-4 cqa-cursor-pointer cqa-transition-all cqa-appearance-none cqa-rounded shadow hover:cqa-shadow-md cqa-border cqa-border-solid cqa-border-slate-300 cqa-flex-shrink-0\"\n [class.cqa-bg-[#3F43EE]]=\"selected\"\n [class.cqa-border-[#3F43EE]]=\"selected\"\n id=\"check\" />\n <span class=\"cqa-absolute cqa-text-white cqa-top-1/2 cqa-left-1/2 cqa--translate-x-1/2 cqa--translate-y-1/2 cqa-pointer-events-none cqa-flex cqa-items-center cqa-justify-center\"\n [class.cqa-opacity-0]=\"!selected\"\n [class.cqa-opacity-100]=\"selected\">\n <svg width=\"12\" height=\"13\" viewBox=\"0 0 12 13\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10 3.125L4.5 8.625L2 6.125\" stroke=\"white\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </span>\n </label>\n </div>\n\n <!-- Step Number -->\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px] cqa-min-w-[32px]\">\n {{ stepNumber }}\n </span>\n\n <!-- Event Type Selector (Pill Button) #### (click)=\"toggleEventTypeDropdown(); $event.stopPropagation()\" -->\n <div class=\"cqa-relative\" #dropdownContainer>\n <button type=\"button\" \n [style.background-color]=\"getCurrentEventTypeConfig().backgroundColor\"\n [style.color]=\"getCurrentEventTypeConfig().color\" [style.border-color]=\"getCurrentEventTypeConfig().color\"\n class=\"cqa-px-2.5 cqa-py-1 cqa-rounded-lg cqa-flex cqa-items-center cqa-gap-2 cqa-cursor-pointer\">\n <!-- Icon -->\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'paper_plane'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 6.41663L12.8333 1.16663L7.58333 12.25L6.41667 7.58329L1.75 6.41663Z\" stroke=\"#432DD7\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'star'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.797 9.04165C5.74492 8.83977 5.63969 8.65554 5.49227 8.50812C5.34485 8.3607 5.16062 8.25548 4.95875 8.2034L1.38 7.28057C1.31894 7.26324 1.2652 7.22646 1.22694 7.17583C1.18867 7.12519 1.16797 7.06345 1.16797 6.99998C1.16797 6.93651 1.18867 6.87478 1.22694 6.82414C1.2652 6.7735 1.31894 6.73673 1.38 6.7194L4.95875 5.79598C5.16055 5.74395 5.34473 5.63882 5.49215 5.49151C5.63956 5.34419 5.74483 5.16008 5.797 4.95832L6.71983 1.37957C6.73698 1.31827 6.77372 1.26427 6.82443 1.2258C6.87515 1.18733 6.93705 1.1665 7.0007 1.1665C7.06436 1.1665 7.12626 1.18733 7.17698 1.2258C7.22769 1.26427 7.26442 1.31827 7.28158 1.37957L8.20383 4.95832C8.25591 5.16019 8.36113 5.34442 8.50855 5.49184C8.65597 5.63926 8.8402 5.74449 9.04208 5.79657L12.6208 6.71882C12.6824 6.73579 12.7366 6.77249 12.7753 6.82328C12.814 6.87407 12.8349 6.93614 12.8349 6.99998C12.8349 7.06382 12.814 7.1259 12.7753 7.17669C12.7366 7.22748 12.6824 7.26417 12.6208 7.28115L9.04208 8.2034C8.8402 8.25548 8.65597 8.3607 8.50855 8.50812C8.36113 8.65554 8.25591 8.83977 8.20383 9.04165L7.281 12.6204C7.26384 12.6817 7.22711 12.7357 7.17639 12.7742C7.12568 12.8126 7.06377 12.8335 7.00012 12.8335C6.93647 12.8335 6.87456 12.8126 6.82385 12.7742C6.77314 12.7357 6.7364 12.6817 6.71925 12.6204L5.797 9.04165Z\"\n stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M11.666 1.75V4.08333\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M12.8333 2.91663H10.5\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.33398 9.91663V11.0833\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M2.91667 10.5H1.75\" stroke=\"#7008E7\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'T'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.33398 4.08325V2.33325H11.6673V4.08325\" stroke=\"#8200DB\" stroke-width=\"1.16667\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.25 11.6667H8.75\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M7 2.33325V11.6666\" stroke=\"#8200DB\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 1.75L5.87417 11.6492L7.33833 7.33833L11.6492 5.87417L1.75 1.75Z\" stroke=\"#1447E6\"\n stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7.58398 7.58325L11.084 11.0833\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'enter'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.0833 1.75L11.0833 5.83333L2.91667 5.83333\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M7.58333 1.75L11.0833 5.25L7.58333 8.75\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.91667 8.75L2.91667 12.25\" stroke=\"#1447E6\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"getCurrentEventTypeConfig().icon === 'clock'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M6.99935 12.8334C10.221 12.8334 12.8327 10.2217 12.8327 7.00008C12.8327 3.77842 10.221 1.16675 6.99935 1.16675C3.77769 1.16675 1.16602 3.77842 1.16602 7.00008C1.16602 10.2217 3.77769 12.8334 6.99935 12.8334Z\"\n stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M7 3.5V7L9.33333 8.16667\" stroke=\"#364153\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n\n <!-- Label -->\n <span class=\"cqa-text-[#432DD7] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium\">{{\n getCurrentEventTypeConfig().label }}</span>\n </button>\n\n <!-- Dropdown Menu -->\n <div *ngIf=\"eventTypeDropdownOpen\" (click)=\"$event.stopPropagation()\"\n class=\"cqa-absolute cqa-top-full cqa-left-0 cqa-mt-1 cqa-bg-white cqa-rounded-lg cqa-shadow-lg cqa-border cqa-border-gray-200 cqa-z-50 cqa-min-w-[150px] cqa-py-1\">\n <button *ngFor=\"let etc of eventTypeConfigs\" type=\"button\" (click)=\"onEventTypeSelect(etc.type)\"\n [class.cqa-bg-primary-50]=\"eventType === etc.type\"\n class=\"cqa-w-full cqa-px-3 cqa-py-2 cqa-text-left cqa-flex cqa-items-center cqa-gap-2 hover:cqa-bg-gray-50 cqa-transition-colors\">\n <span *ngIf=\"etc.icon === 'paper_plane'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1 5.5L11 1M11 1L7.5 11L6 6.5L1 5.5M11 1L1 5.5\" stroke=\"currentColor\" stroke-width=\"1.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'star'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 1L7.5 4.5L11 5L7.5 5.5L6 9L4.5 5.5L1 5L4.5 4.5L6 1Z\" fill=\"currentColor\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'T'\">\n T\n </span>\n <span *ngIf=\"etc.icon === 'cursor'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2 2L9 1L10 8L7 7L5 9L4 7L2 2Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'cursor-double'\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8.16667 2.3916L7 3.49993\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.97487 4.66662L1.2832 4.19995\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.50091 7L2.39258 8.16667\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.19922 1.28345L4.66589 2.97511\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.27114 5.65255C5.24852 5.59926 5.24234 5.54043 5.25338 5.48361C5.26443 5.42678 5.2922 5.37455 5.33313 5.33362C5.37407 5.29269 5.4263 5.26492 5.48312 5.25387C5.53994 5.24283 5.59877 5.24901 5.65206 5.27163L12.0687 7.89663C12.1258 7.92006 12.174 7.961 12.2064 8.01357C12.2388 8.06613 12.2536 8.12761 12.2488 8.18915C12.244 8.25069 12.2198 8.30912 12.1797 8.35603C12.1396 8.40295 12.0856 8.43592 12.0256 8.45021L9.48864 9.05746C9.38391 9.08248 9.28815 9.13599 9.21196 9.21208C9.13578 9.28816 9.08213 9.38385 9.05698 9.48855L8.45031 12.026C8.43617 12.0863 8.40323 12.1405 8.35626 12.1808C8.30928 12.2211 8.25071 12.2454 8.189 12.2502C8.1273 12.255 8.06567 12.2401 8.01302 12.2075C7.96037 12.175 7.91944 12.1266 7.89614 12.0692L5.27114 5.65255Z\" stroke=\"#1447E6\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg> \n </span>\n <span *ngIf=\"etc.icon === 'enter'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M9.5 1.5L9.5 5L2 5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.5 1.5L9.5 4.5L6.5 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2 7.5L2 10.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </span>\n <span *ngIf=\"etc.icon === 'clock'\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"6\" cy=\"6\" r=\"5\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M6 3V6L8 7\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </span>\n <span>{{ etc.label }}</span>\n </button>\n </div>\n </div>\n\n <!-- Action Description -->\n <span class=\"cqa-text-[#111827] cqa-text-[14px] cqa-leading-[18px]\" *ngIf=\"getActionDescription()\"\n [innerHTML]=\"getActionDescription()\" (click)=\"clickOnAction($event)\">\n </span>\n\n <!-- Parameters -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3\" *ngIf=\"false\">\n <!-- Navigate: URL as clickable trigger for Test Data modal -->\n <span *ngIf=\"eventType === 'navigate' && getNavigateUrlParameter()\" #testDataTrigger\n (click)=\"openTestDataModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\">\n {{ getNavigateUrlParameter()?.value || getNavigateUrlParameter()?.displayValue }}\n </span>\n \n <!-- Other event types: loop through parameters (navigate excluded) -->\n <ng-container *ngFor=\"let param of parameters; let i = index\">\n <!-- Skip navigate parameters in the loop (already shown above) -->\n <ng-container *ngIf=\"eventType !== 'navigate'\">\n\n <!-- Type: First param (text value like {{username}}) -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Type: \"into\" text -->\n <span *ngIf=\"eventType === 'type' && i === 0\" class=\"cqa-text-gray-900 cqa-text-sm\">\n into\n </span>\n\n <!-- Type: Second param (selector) -->\n <span *ngIf=\"eventType === 'type' && i === 1\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Selector input/display -->\n <span *ngIf=\"eventType === 'click' && param.name === 'element'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Click: Suffix text (like \"if Present\") -->\n <span *ngIf=\"eventType === 'click' && param.name === 'suffix'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n {{ param.value }}\n </span>\n\n <!-- Double Click: Selector input/display -->\n <span *ngIf=\"eventType === 'doubleClick' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Press Enter: Selector input/display with HTML support -->\n <span *ngIf=\"eventType === 'pressEnter' && i === 0\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- Enter: Value display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"in the\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'value'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n in the\n </span>\n\n <!-- Enter: Label display with quotes (like click action) -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n\n <!-- Enter: \"field\" text -->\n <span *ngIf=\"eventType === 'enter' && param.name === 'label'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n field\n </span>\n\n <!-- Wait: Duration input -->\n <input *ngIf=\"eventType === 'wait' && param.name === 'duration'\" type=\"number\" [value]=\"param.value\"\n (input)=\"onParameterChange(param, $any($event.target).value)\" placeholder=\"2\"\n class=\"cqa-w-16 cqa-px-2 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#9E9EE3] cqa-bg-[#D1C4E9] cqa-text-[#3F43EE] cqa-text-sm cqa-font-medium cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-[#3F43EE] focus:cqa-ring-opacity-50\" />\n <span *ngIf=\"eventType === 'wait' && param.name === 'duration'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n seconds\n </span>\n\n <!-- Wait: Element selector -->\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n for element\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" \n #elementTrigger\n (click)=\"openElementPopup($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-cursor-pointer cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n <span *ngIf=\"eventType === 'wait' && param.name === 'element'\" class=\"cqa-text-gray-900 cqa-text-sm\">\n to be visible\n </span>\n\n <!-- Custom: Description (clickable to open Step Description modal; pass $event so modal opens below this trigger) -->\n <span *ngIf=\"eventType === 'custom'\" #descriptionTrigger\n (click)=\"openStepDescriptionModal($event)\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC] cqa-cursor-pointer hover:cqa-opacity-90\"\n [innerHTML]=\"param.displayValue || param.value\">\n </span>\n\n <!-- AI Agent: Instructions -->\n <span *ngIf=\"eventType === 'ai-agent'\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ param.displayValue || param.value }}\n </span>\n </ng-container>\n </ng-container>\n </div>\n\n <!-- AI Agent View Details Link -->\n <a *ngIf=\"eventType === 'ai-agent'\" href=\"#\" (click)=\"onMoreOptions(); $event.preventDefault()\" class=\"cqa-ml-auto cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-2 cqa-no-underline\">View Details<svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg></a>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-ml-auto cqa-px-[7px]\">\n <button type=\"button\" #editTrigger (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>" }]
|
|
17112
|
+
}], ctorParameters: function () { return [{ type: CustomEditStepService }, { type: ElementPopupService }, { type: TestDataModalService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1$1.DomSanitizer }]; }, propDecorators: { dropdownContainer: [{
|
|
17235
17113
|
type: ViewChild,
|
|
17236
17114
|
args: ['dropdownContainer', { static: false }]
|
|
17237
17115
|
}], descriptionTrigger: [{
|
|
@@ -17250,6 +17128,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
17250
17128
|
type: Input
|
|
17251
17129
|
}], stepNumber: [{
|
|
17252
17130
|
type: Input
|
|
17131
|
+
}], action: [{
|
|
17132
|
+
type: Input
|
|
17253
17133
|
}], eventType: [{
|
|
17254
17134
|
type: Input
|
|
17255
17135
|
}], parameters: [{
|
|
@@ -17280,6 +17160,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
17280
17160
|
type: Output
|
|
17281
17161
|
}], selectionChange: [{
|
|
17282
17162
|
type: Output
|
|
17163
|
+
}], clickAction: [{
|
|
17164
|
+
type: Output
|
|
17283
17165
|
}], onDocumentClick: [{
|
|
17284
17166
|
type: HostListener,
|
|
17285
17167
|
args: ['document:click', ['$event']]
|
|
@@ -17362,6 +17244,7 @@ class TestCaseDetailsRendererComponent {
|
|
|
17362
17244
|
this.isInsideLoop = false;
|
|
17363
17245
|
/** When true, enables drag-and-drop reordering and shows drag handle icon instead of checkbox */
|
|
17364
17246
|
this.isReorder = false;
|
|
17247
|
+
this.addStepBetween = false;
|
|
17365
17248
|
this.nestedStepChange = new EventEmitter();
|
|
17366
17249
|
this.addStep = new EventEmitter();
|
|
17367
17250
|
this.deleteStep = new EventEmitter();
|
|
@@ -17388,8 +17271,10 @@ class TestCaseDetailsRendererComponent {
|
|
|
17388
17271
|
this.maxIterationsChange = new EventEmitter();
|
|
17389
17272
|
this.eventTypeChange = new EventEmitter();
|
|
17390
17273
|
this.parameterChange = new EventEmitter();
|
|
17274
|
+
this.clickAction = new EventEmitter();
|
|
17391
17275
|
/** Emitted when a step is dropped in a nested dropzone (step-group, loop, condition). Payload: { event, targetList }. */
|
|
17392
17276
|
this.dndDropInZone = new EventEmitter();
|
|
17277
|
+
this.addStepBetweenClick = new EventEmitter();
|
|
17393
17278
|
this.componentRef = null;
|
|
17394
17279
|
}
|
|
17395
17280
|
ngAfterViewInit() {
|
|
@@ -17510,14 +17395,16 @@ class TestCaseDetailsRendererComponent {
|
|
|
17510
17395
|
wire('maxIterationsChange', this.maxIterationsChange);
|
|
17511
17396
|
wire('eventTypeChange', this.eventTypeChange);
|
|
17512
17397
|
wire('parameterChange', this.parameterChange);
|
|
17398
|
+
wire('clickAction', this.clickAction);
|
|
17513
17399
|
wire('dndDropInZone', this.dndDropInZone);
|
|
17400
|
+
wire('addStepBetweenClick', this.addStepBetweenClick);
|
|
17514
17401
|
}
|
|
17515
17402
|
}
|
|
17516
17403
|
TestCaseDetailsRendererComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsRendererComponent, deps: [{ token: TEST_CASE_STEP_COMPONENT_MAP }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
17517
|
-
TestCaseDetailsRendererComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: { step: "step", index: "index", isNested: "isNested", isInsideLoop: "isInsideLoop", branch: "branch", isReorder: "isReorder" }, outputs: { 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", dndDropInZone: "dndDropInZone" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "stepHost", first: true, predicate: ["stepHost"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-relative\">\n <ng-container #stepHost></ng-container>\n <button class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]
|
|
17404
|
+
TestCaseDetailsRendererComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: { step: "step", index: "index", isNested: "isNested", isInsideLoop: "isInsideLoop", branch: "branch", isReorder: "isReorder", addStepBetween: "addStepBetween" }, outputs: { 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" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "stepHost", first: true, predicate: ["stepHost"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-relative\">\n <button *ngIf=\"addStepBetween\" class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]\" (click)=\"addStepBetweenClick.emit({step: step, index: index})\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" fill=\"white\"/><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" stroke=\"#3F43EE\" stroke-width=\"2\"/><path d=\"M8.5 12H15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 8.5V15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <ng-container #stepHost></ng-container>\n <button *ngIf=\"addStepBetween\" class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]\" (click)=\"addStepBetweenClick.emit({step: step, index: index})\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" fill=\"white\"/><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" stroke=\"#3F43EE\" stroke-width=\"2\"/><path d=\"M8.5 12H15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 8.5V15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n</div>", directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
17518
17405
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseDetailsRendererComponent, decorators: [{
|
|
17519
17406
|
type: Component,
|
|
17520
|
-
args: [{ selector: 'cqa-test-case-details-renderer', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-relative\">\n <ng-container #stepHost></ng-container>\n <button class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]
|
|
17407
|
+
args: [{ selector: 'cqa-test-case-details-renderer', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-relative\">\n <button *ngIf=\"addStepBetween\" class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]\" (click)=\"addStepBetweenClick.emit({step: step, index: index})\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" fill=\"white\"/><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" stroke=\"#3F43EE\" stroke-width=\"2\"/><path d=\"M8.5 12H15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 8.5V15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <ng-container #stepHost></ng-container>\n <button *ngIf=\"addStepBetween\" class=\"cqa-absolute cqa-top-[calc(100%-12px)] cqa-left-[50%] cqa-translate-x-[-50%] cqa-p-0 cqa-z-[1]\" (click)=\"addStepBetweenClick.emit({step: step, index: index})\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" fill=\"white\"/><rect x=\"1\" y=\"1\" width=\"21.1822\" height=\"22\" rx=\"10.5911\" stroke=\"#3F43EE\" stroke-width=\"2\"/><path d=\"M8.5 12H15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 8.5V15.5\" stroke=\"#3F43EE\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n</div>" }]
|
|
17521
17408
|
}], ctorParameters: function () {
|
|
17522
17409
|
return [{ type: undefined, decorators: [{
|
|
17523
17410
|
type: Inject,
|
|
@@ -17538,6 +17425,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
17538
17425
|
type: Input
|
|
17539
17426
|
}], isReorder: [{
|
|
17540
17427
|
type: Input
|
|
17428
|
+
}], addStepBetween: [{
|
|
17429
|
+
type: Input
|
|
17541
17430
|
}], nestedStepChange: [{
|
|
17542
17431
|
type: Output
|
|
17543
17432
|
}], addStep: [{
|
|
@@ -17590,8 +17479,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
17590
17479
|
type: Output
|
|
17591
17480
|
}], parameterChange: [{
|
|
17592
17481
|
type: Output
|
|
17482
|
+
}], clickAction: [{
|
|
17483
|
+
type: Output
|
|
17593
17484
|
}], dndDropInZone: [{
|
|
17594
17485
|
type: Output
|
|
17486
|
+
}], addStepBetweenClick: [{
|
|
17487
|
+
type: Output
|
|
17595
17488
|
}] } });
|
|
17596
17489
|
|
|
17597
17490
|
class TestCaseLoopStepComponent {
|
|
@@ -17896,7 +17789,7 @@ class TestCaseLoopStepComponent {
|
|
|
17896
17789
|
}
|
|
17897
17790
|
}
|
|
17898
17791
|
TestCaseLoopStepComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseLoopStepComponent, deps: [{ token: i2$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
17899
|
-
TestCaseLoopStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseLoopStepComponent, selector: "cqa-test-case-loop-step", inputs: { 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" }, outputs: { 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" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col\">\n <!-- Inline Edit Mode: Frame 2147224910 - flex row, 1056\u00D736, gap 12px, flex-none -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- Loop Type Label -->\n <div class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getLoopTypeLabel() }}\n </div>\n\n <!-- FOR LOOP inline edit: cqa-dynamic-select (same usage as default stories) -->\n <ng-container *ngIf=\"loopType === 'for'\">\n <!-- First select: width 216.25px, height 36px, gap 4px, opacity 1 -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"forOptionTypeSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-custom-input [value]=\"editForm.get('testDataProfile')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('testDataProfile', $event)\" placeholder=\"Testdataprofile\"\n class=\"cqa-w-full cqa-max-w-[216px]\" size=\"sm\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"startStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"endStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n </ng-container>\n\n <!-- WHILE LOOP inline edit -->\n <ng-container *ngIf=\"isWhileLoop()\">\n <cqa-custom-input [value]=\"editForm.get('condition')?.value ?? ''\" class=\"cqa-w-full cqa-max-w-[216px]\"\n (valueChange)=\"onEditFormFieldChange('condition', $event)\" placeholder='element \".selector\" exists' size=\"sm\">\n </cqa-custom-input>\n </ng-container>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\"\n (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\"\n (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n </div>\n\n <!-- Loop Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\"\n [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Loop Icon -->\n <div *ngIf=\"loopType === 'for'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div *ngIf=\"loopType === 'while'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Loop Type Label -->\n <span class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-none\">\n {{ getLoopTypeLabel() }}\n </span>\n\n <!-- For Loop Controls -->\n <div *ngIf=\"loopType === 'for'\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2\">\n <!-- Test Data Profile Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"testDataProfile\" [class.cqa-text-primary]=\"testDataProfile\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getTestDataProfileLabel() }}\n </button>\n\n <!-- Start Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"startStep\" [class.cqa-text-primary]=\"startStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getStartStepLabel() }}\n </button>\n\n <!-- End Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"endStep\" [class.cqa-text-primary]=\"endStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getEndStepLabel() }}\n </button>\n </div>\n\n <!-- While Loop Condition (only show if condition exists) -->\n <div *ngIf=\"isWhileLoop() && condition\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2 cqa-flex-1\">\n <span class=\"cqa-text-gray-700 cqa-text-sm\">\n While\n </span>\n <span class=\"cqa-text-gray-900 cqa-text-sm\" [innerHTML]=\"getConditionDisplay()\"></span>\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\"\n class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer *ngFor=\"let step of nestedSteps; let i = index\" [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\" (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END Marker -->\n <div\n [class]=\"'cqa-pl-4 cqa-py-1 cqa-bg-[#DBEAFE80] cqa-text-[#1C398E] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\"\n style=\"border-top: 1px solid #BEDBFF;\">\n {{ getEndLabel() }}\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "dndDropInZone"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
17792
|
+
TestCaseLoopStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseLoopStepComponent, selector: "cqa-test-case-loop-step", inputs: { 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" }, outputs: { 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" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col\">\n <!-- Inline Edit Mode: Frame 2147224910 - flex row, 1056\u00D736, gap 12px, flex-none -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- Loop Type Label -->\n <div class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getLoopTypeLabel() }}\n </div>\n\n <!-- FOR LOOP inline edit: cqa-dynamic-select (same usage as default stories) -->\n <ng-container *ngIf=\"loopType === 'for'\">\n <!-- First select: width 216.25px, height 36px, gap 4px, opacity 1 -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"forOptionTypeSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-custom-input [value]=\"editForm.get('testDataProfile')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('testDataProfile', $event)\" placeholder=\"Testdataprofile\"\n class=\"cqa-w-full cqa-max-w-[216px]\" size=\"sm\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"startStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"endStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n </ng-container>\n\n <!-- WHILE LOOP inline edit -->\n <ng-container *ngIf=\"isWhileLoop()\">\n <cqa-custom-input [value]=\"editForm.get('condition')?.value ?? ''\" class=\"cqa-w-full cqa-max-w-[216px]\"\n (valueChange)=\"onEditFormFieldChange('condition', $event)\" placeholder='element \".selector\" exists' size=\"sm\">\n </cqa-custom-input>\n </ng-container>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\"\n (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\"\n (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n </div>\n\n <!-- Loop Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\"\n [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Loop Icon -->\n <div *ngIf=\"loopType === 'for'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div *ngIf=\"loopType === 'while'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Loop Type Label -->\n <span class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-none\">\n {{ getLoopTypeLabel() }}\n </span>\n\n <!-- For Loop Controls -->\n <div *ngIf=\"loopType === 'for'\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2\">\n <!-- Test Data Profile Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"testDataProfile\" [class.cqa-text-primary]=\"testDataProfile\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getTestDataProfileLabel() }}\n </button>\n\n <!-- Start Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"startStep\" [class.cqa-text-primary]=\"startStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getStartStepLabel() }}\n </button>\n\n <!-- End Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"endStep\" [class.cqa-text-primary]=\"endStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getEndStepLabel() }}\n </button>\n </div>\n\n <!-- While Loop Condition (only show if condition exists) -->\n <div *ngIf=\"isWhileLoop() && condition\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2 cqa-flex-1\">\n <span class=\"cqa-text-gray-700 cqa-text-sm\">\n While\n </span>\n <span class=\"cqa-text-gray-900 cqa-text-sm\" [innerHTML]=\"getConditionDisplay()\"></span>\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\"\n class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer *ngFor=\"let step of nestedSteps; let i = index\" [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\" (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END Marker -->\n <div\n [class]=\"'cqa-pl-4 cqa-py-1 cqa-bg-[#DBEAFE80] cqa-text-[#1C398E] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\"\n style=\"border-top: 1px solid #BEDBFF;\">\n {{ getEndLabel() }}\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder", "addStepBetween"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "clickAction", "dndDropInZone", "addStepBetweenClick"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
17900
17793
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseLoopStepComponent, decorators: [{
|
|
17901
17794
|
type: Component,
|
|
17902
17795
|
args: [{ selector: 'cqa-test-case-loop-step', host: { class: 'cqa-ui-root' }, styles: [STEP_ROW_ACTIONS_STYLES], template: "<div class=\"cqa-flex cqa-flex-col\">\n <!-- Inline Edit Mode: Frame 2147224910 - flex row, 1056\u00D736, gap 12px, flex-none -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- Loop Type Label -->\n <div class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getLoopTypeLabel() }}\n </div>\n\n <!-- FOR LOOP inline edit: cqa-dynamic-select (same usage as default stories) -->\n <ng-container *ngIf=\"loopType === 'for'\">\n <!-- First select: width 216.25px, height 36px, gap 4px, opacity 1 -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"forOptionTypeSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-custom-input [value]=\"editForm.get('testDataProfile')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('testDataProfile', $event)\" placeholder=\"Testdataprofile\"\n class=\"cqa-w-full cqa-max-w-[216px]\" size=\"sm\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"startStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"endStepSelectConfig\"\n class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n </ng-container>\n\n <!-- WHILE LOOP inline edit -->\n <ng-container *ngIf=\"isWhileLoop()\">\n <cqa-custom-input [value]=\"editForm.get('condition')?.value ?? ''\" class=\"cqa-w-full cqa-max-w-[216px]\"\n (valueChange)=\"onEditFormFieldChange('condition', $event)\" placeholder='element \".selector\" exists' size=\"sm\">\n </cqa-custom-input>\n </ng-container>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\"\n fill=\"#3F43EE\" />\n </svg>\n </a>\n </div>\n\n <div class=\"cqa-flex cqa-items-center cqa-gap-1.5\">\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\"\n (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\"\n (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n </div>\n\n <!-- Loop Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\"\n [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Loop Icon -->\n <div *ngIf=\"loopType === 'for'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#1C398E\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#1C398E\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n <div *ngIf=\"loopType === 'while'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M11.334 1.33325L14.0007 3.99992L11.334 6.66659\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M2 7.33333V6.66667C2 5.95942 2.28095 5.28115 2.78105 4.78105C3.28115 4.28095 3.95942 4 4.66667 4H14\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.66667 14.6666L2 11.9999L4.66667 9.33325\" stroke=\"#59168B\" stroke-width=\"1.33333\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M14 8.66675V9.33341C14 10.0407 13.719 10.7189 13.219 11.219C12.7189 11.7191 12.0406 12.0001 11.3333 12.0001H2\"\n stroke=\"#59168B\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Loop Type Label -->\n <span class=\"cqa-font-semibold cqa-text-[#1C398E] cqa-text-[12px] cqa-leading-none\">\n {{ getLoopTypeLabel() }}\n </span>\n\n <!-- For Loop Controls -->\n <div *ngIf=\"loopType === 'for'\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2\">\n <!-- Test Data Profile Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"testDataProfile\" [class.cqa-text-primary]=\"testDataProfile\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getTestDataProfileLabel() }}\n </button>\n\n <!-- Start Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"startStep\" [class.cqa-text-primary]=\"startStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getStartStepLabel() }}\n </button>\n\n <!-- End Button -->\n <button type=\"button\" [class.cqa-bg-primary-100]=\"endStep\" [class.cqa-text-primary]=\"endStep\"\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">\n {{ getEndStepLabel() }}\n </button>\n </div>\n\n <!-- While Loop Condition (only show if condition exists) -->\n <div *ngIf=\"isWhileLoop() && condition\" class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-ml-2 cqa-flex-1\">\n <span class=\"cqa-text-gray-700 cqa-text-sm\">\n While\n </span>\n <span class=\"cqa-text-gray-900 cqa-text-sm\" [innerHTML]=\"getConditionDisplay()\"></span>\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\"\n class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\"\n class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer *ngFor=\"let step of nestedSteps; let i = index\" [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\" (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer [step]=\"step\" [index]=\"i\"\n [isNested]=\"true\" [isInsideLoop]=\"true\" [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\" (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\" (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\" (duplicate)=\"onNestedStepChange(step, i)\" (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\" (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\">\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END Marker -->\n <div\n [class]=\"'cqa-pl-4 cqa-py-1 cqa-bg-[#DBEAFE80] cqa-text-[#1C398E] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\"\n style=\"border-top: 1px solid #BEDBFF;\">\n {{ getEndLabel() }}\n </div>\n </div>\n</div>" }]
|
|
@@ -18207,7 +18100,7 @@ class TestCaseConditionStepComponent {
|
|
|
18207
18100
|
}
|
|
18208
18101
|
}
|
|
18209
18102
|
TestCaseConditionStepComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseConditionStepComponent, deps: [{ token: i2$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
18210
|
-
TestCaseConditionStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseConditionStepComponent, selector: "cqa-test-case-condition-step", inputs: { config: "config", id: "id", stepNumber: "stepNumber", condition: "condition", branches: "branches", expanded: "expanded", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder" }, outputs: { toggleExpanded: "toggleExpanded", conditionChange: "conditionChange", branchStepChange: "branchStepChange", addStep: "addStep", deleteStep: "deleteStep", addBranch: "addBranch", deleteBranch: "deleteBranch", duplicate: "duplicate", delete: "delete", moreOptions: "moreOptions", dndDropInZone: "dndDropInZone" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div [class]=\"'cqa-flex cqa-flex-col cqa-border cqa-border-solid cqa-border-[#E5E7EB] ' + (isNested ? ' cqa-pl-[24px]' : '')\">\n <!-- Inline Edit Mode: CONDITION tag, three fields, IF/ELSE chips, Edit In depth, Cancel/Apply -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- CONDITION Tag (orange) -->\n <span class=\"cqa-px-1.5 cqa-rounded-md cqa-text-[#EA580C] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#FFEDD5]\">\n CONDITION\n </span>\n\n <!-- First field: left operand (e.g. Usertype) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionLeft')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionLeft', $event)\"\n placeholder=\"Usertype\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- Operator: dynamic-select (IS, IS NOT, etc.) -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"operatorSelectConfig\" class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n\n <!-- Third field: right operand (e.g. Premium) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionRight')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionRight', $event)\"\n placeholder=\"Premium\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- IF / ELSE indicators -->\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#DCFCE7] cqa-text-[#008236] cqa-border cqa-border-solid cqa-border-[#B9F8CF] cqa-flex cqa-items-center cqa-gap-1.5\">\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.66634 2L2.99967 5.66667L1.33301 4\" stroke=\"#008236\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n IF\n </span>\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#F3F4F6] cqa-text-[#99A1AF] cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-flex cqa-items-center cqa-gap-1.5\">\n Add ELSE\n </span>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg>\n </a> \n </div>\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\" (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\" (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n\n <!-- Condition Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\" [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- IF/ELSE Icon -->\n <div><svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 2V10\" stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12 6C13.1046 6 14 5.10457 14 4C14 2.89543 13.1046 2 12 2C10.8954 2 10 2.89543 10 4C10 5.10457 10.8954 6 12 6Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4 14C5.10457 14 6 13.1046 6 12C6 10.8954 5.10457 10 4 10C2.89543 10 2 10.8954 2 12C2 13.1046 2.89543 14 4 14Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M12 6C12 7.5913 11.3679 9.11742 10.2426 10.2426C9.11742 11.3679 7.5913 12 6 12\" stroke=\"#7B3306\"\n stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- IF/ELSE Label -->\n <span class=\"cqa-font-semibold cqa-text-[#7B3306] cqa-text-[12px] cqa-leading-none\">\n IF / ELSE\n </span>\n\n <!-- Condition Input -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-ml-2 cqa-flex-1\">\n <span [innerHTML]=\"condition\"></span>\n <!-- <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n If\n </span>\n <span\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">.success-message</span>\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n is visible\n </span> -->\n <!-- <input\n type=\"text\"\n [value]=\"condition\"\n (input)=\"onConditionChange($any($event.target).value)\"\n placeholder=\"element `.success-message` is visible\"\n class=\"cqa-px-3 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-gray-300 cqa-bg-white cqa-text-gray-900 cqa-text-sm cqa-flex-1 cqa-max-w-md cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-primary focus:cqa-ring-opacity-50\"\n /> -->\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Branches -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branches (IF TRUE, ELSE IF, ELSE) -->\n <div *ngFor=\"let branch of branches\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branch Header -->\n <div\n [class]=\"'cqa-px-4 cqa-py-2 cqa-text-[12px] cqa-leading-[15px] cqa-flex cqa-items-center cqa-gap-2 ' + getBranchTextColor(branch) + ' ' + getBranchColorClass(branch)\">\n <span>{{ getBranchLabel(branch) }}</span>\n <span *ngIf=\"branch.action\" [innerHTML]=\"branch.action\" class=\"cqa-text-[#111827]\"></span>\n </div>\n\n <!-- Branch Content (Nested Steps \u2013 renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of branch.nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event, branch)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of branch.nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n </div>\n\n <!-- END IF Marker -->\n <div [class]=\"'cqa-pl-4 cqa-py-1 cqa-text-[#7B3306] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\" style=\"border-top: 1px solid #E5E7EB;\">\n END IF\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "dndDropInZone"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
18103
|
+
TestCaseConditionStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseConditionStepComponent, selector: "cqa-test-case-condition-step", inputs: { config: "config", id: "id", stepNumber: "stepNumber", condition: "condition", branches: "branches", expanded: "expanded", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder" }, outputs: { toggleExpanded: "toggleExpanded", conditionChange: "conditionChange", branchStepChange: "branchStepChange", addStep: "addStep", deleteStep: "deleteStep", addBranch: "addBranch", deleteBranch: "deleteBranch", duplicate: "duplicate", delete: "delete", moreOptions: "moreOptions", dndDropInZone: "dndDropInZone" }, host: { classAttribute: "cqa-ui-root" }, ngImport: i0, template: "<div [class]=\"'cqa-flex cqa-flex-col cqa-border cqa-border-solid cqa-border-[#E5E7EB] ' + (isNested ? ' cqa-pl-[24px]' : '')\">\n <!-- Inline Edit Mode: CONDITION tag, three fields, IF/ELSE chips, Edit In depth, Cancel/Apply -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- CONDITION Tag (orange) -->\n <span class=\"cqa-px-1.5 cqa-rounded-md cqa-text-[#EA580C] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#FFEDD5]\">\n CONDITION\n </span>\n\n <!-- First field: left operand (e.g. Usertype) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionLeft')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionLeft', $event)\"\n placeholder=\"Usertype\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- Operator: dynamic-select (IS, IS NOT, etc.) -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"operatorSelectConfig\" class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n\n <!-- Third field: right operand (e.g. Premium) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionRight')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionRight', $event)\"\n placeholder=\"Premium\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- IF / ELSE indicators -->\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#DCFCE7] cqa-text-[#008236] cqa-border cqa-border-solid cqa-border-[#B9F8CF] cqa-flex cqa-items-center cqa-gap-1.5\">\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.66634 2L2.99967 5.66667L1.33301 4\" stroke=\"#008236\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n IF\n </span>\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#F3F4F6] cqa-text-[#99A1AF] cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-flex cqa-items-center cqa-gap-1.5\">\n Add ELSE\n </span>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg>\n </a> \n </div>\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\" (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\" (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n\n <!-- Condition Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\" [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- IF/ELSE Icon -->\n <div><svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 2V10\" stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12 6C13.1046 6 14 5.10457 14 4C14 2.89543 13.1046 2 12 2C10.8954 2 10 2.89543 10 4C10 5.10457 10.8954 6 12 6Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4 14C5.10457 14 6 13.1046 6 12C6 10.8954 5.10457 10 4 10C2.89543 10 2 10.8954 2 12C2 13.1046 2.89543 14 4 14Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M12 6C12 7.5913 11.3679 9.11742 10.2426 10.2426C9.11742 11.3679 7.5913 12 6 12\" stroke=\"#7B3306\"\n stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- IF/ELSE Label -->\n <span class=\"cqa-font-semibold cqa-text-[#7B3306] cqa-text-[12px] cqa-leading-none\">\n IF / ELSE\n </span>\n\n <!-- Condition Input -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-ml-2 cqa-flex-1\">\n <span [innerHTML]=\"condition\"></span>\n <!-- <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n If\n </span>\n <span\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">.success-message</span>\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n is visible\n </span> -->\n <!-- <input\n type=\"text\"\n [value]=\"condition\"\n (input)=\"onConditionChange($any($event.target).value)\"\n placeholder=\"element `.success-message` is visible\"\n class=\"cqa-px-3 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-gray-300 cqa-bg-white cqa-text-gray-900 cqa-text-sm cqa-flex-1 cqa-max-w-md cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-primary focus:cqa-ring-opacity-50\"\n /> -->\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Branches -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branches (IF TRUE, ELSE IF, ELSE) -->\n <div *ngFor=\"let branch of branches\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branch Header -->\n <div\n [class]=\"'cqa-px-4 cqa-py-2 cqa-text-[12px] cqa-leading-[15px] cqa-flex cqa-items-center cqa-gap-2 ' + getBranchTextColor(branch) + ' ' + getBranchColorClass(branch)\">\n <span>{{ getBranchLabel(branch) }}</span>\n <span *ngIf=\"branch.action\" [innerHTML]=\"branch.action\" class=\"cqa-text-[#111827]\"></span>\n </div>\n\n <!-- Branch Content (Nested Steps \u2013 renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of branch.nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event, branch)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of branch.nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n </div>\n\n <!-- END IF Marker -->\n <div [class]=\"'cqa-pl-4 cqa-py-1 cqa-text-[#7B3306] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\" style=\"border-top: 1px solid #E5E7EB;\">\n END IF\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder", "addStepBetween"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "clickAction", "dndDropInZone", "addStepBetweenClick"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
18211
18104
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseConditionStepComponent, decorators: [{
|
|
18212
18105
|
type: Component,
|
|
18213
18106
|
args: [{ selector: 'cqa-test-case-condition-step', host: { class: 'cqa-ui-root' }, styles: [STEP_ROW_ACTIONS_STYLES], template: "<div [class]=\"'cqa-flex cqa-flex-col cqa-border cqa-border-solid cqa-border-[#E5E7EB] ' + (isNested ? ' cqa-pl-[24px]' : '')\">\n <!-- Inline Edit Mode: CONDITION tag, three fields, IF/ELSE chips, Edit In depth, Cancel/Apply -->\n <div *ngIf=\"isEditing\" class=\"cqa-py-2.5 cqa-px-4 cqa-flex cqa-items-center cqa-gap-3 cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-flex-grow\">\n <!-- CONDITION Tag (orange) -->\n <span class=\"cqa-px-1.5 cqa-rounded-md cqa-text-[#EA580C] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#FFEDD5]\">\n CONDITION\n </span>\n\n <!-- First field: left operand (e.g. Usertype) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionLeft')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionLeft', $event)\"\n placeholder=\"Usertype\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- Operator: dynamic-select (IS, IS NOT, etc.) -->\n <cqa-dynamic-select [form]=\"editForm\" [config]=\"operatorSelectConfig\" class=\"cqa-w-full cqa-max-w-[216px]\"></cqa-dynamic-select>\n\n <!-- Third field: right operand (e.g. Premium) -->\n <cqa-custom-input\n [value]=\"editForm.get('conditionRight')?.value ?? ''\"\n (valueChange)=\"onEditFormFieldChange('conditionRight', $event)\"\n placeholder=\"Premium\"\n class=\"cqa-w-full cqa-max-w-[216px]\"\n size=\"sm\">\n </cqa-custom-input>\n\n <!-- IF / ELSE indicators -->\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#DCFCE7] cqa-text-[#008236] cqa-border cqa-border-solid cqa-border-[#B9F8CF] cqa-flex cqa-items-center cqa-gap-1.5\">\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.66634 2L2.99967 5.66667L1.33301 4\" stroke=\"#008236\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n IF\n </span>\n <span class=\"cqa-px-2 cqa-py-[2px] cqa-rounded-[4px] cqa-text-[8px] cqa-leading-[12px] cqa-bg-[#F3F4F6] cqa-text-[#99A1AF] cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-flex cqa-items-center cqa-gap-1.5\">\n Add ELSE\n </span>\n\n <!-- Edit In depth link -->\n <a href=\"#\" (click)=\"onEditInDepth(); $event.preventDefault()\"\n class=\"cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-flex cqa-items-center cqa-gap-[2px] cqa-no-underline\">\n Edit In depth\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.03809 6.74329L2.62809 7.33329L5.96142 3.99996L2.62809 0.666626L2.03809 1.25663L4.78142 3.99996L2.03809 6.74329Z\" fill=\"#3F43EE\"/></svg>\n </a> \n </div>\n <!-- Cancel / Apply -->\n <cqa-button variant=\"outlined\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Cancel'\" (clicked)=\"onEditCancel()\"></cqa-button>\n <cqa-button variant=\"filled\" btnSize=\"lg\" [customClass]=\"'cqa-text-[14px] cqa-py-[9px]'\" [text]=\"'Apply'\" (clicked)=\"onEditApply()\"></cqa-button>\n </div>\n\n <!-- Condition Header (normal view when not editing) -->\n <div *ngIf=\"!isEditing\" [class]=\"'step-row cqa-flex cqa-items-center cqa-gap-3 cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"!expanded\" class=\"cqa-transition-transform\" width=\"16\" height=\"16\"\n viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 10L8 6L4 10\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- IF/ELSE Icon -->\n <div><svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 2V10\" stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M12 6C13.1046 6 14 5.10457 14 4C14 2.89543 13.1046 2 12 2C10.8954 2 10 2.89543 10 4C10 5.10457 10.8954 6 12 6Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4 14C5.10457 14 6 13.1046 6 12C6 10.8954 5.10457 10 4 10C2.89543 10 2 10.8954 2 12C2 13.1046 2.89543 14 4 14Z\"\n stroke=\"#7B3306\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M12 6C12 7.5913 11.3679 9.11742 10.2426 10.2426C9.11742 11.3679 7.5913 12 6 12\" stroke=\"#7B3306\"\n stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg></div>\n\n <!-- IF/ELSE Label -->\n <span class=\"cqa-font-semibold cqa-text-[#7B3306] cqa-text-[12px] cqa-leading-none\">\n IF / ELSE\n </span>\n\n <!-- Condition Input -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-3 cqa-ml-2 cqa-flex-1\">\n <span [innerHTML]=\"condition\"></span>\n <!-- <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n If\n </span>\n <span\n class=\"cqa-py-0.5 cqa-px-2 cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[17px] cqa-font-semibold cqa-border cqa-border-solid cqa-border-[#8A8CF4] cqa-rounded cqa-bg-[#D8D9FC]\">.success-message</span>\n <span class=\"cqa-text-[#6B7280] cqa-text-[14px] cqa-leading-[18px]\">\n is visible\n </span> -->\n <!-- <input\n type=\"text\"\n [value]=\"condition\"\n (input)=\"onConditionChange($any($event.target).value)\"\n placeholder=\"element `.success-message` is visible\"\n class=\"cqa-px-3 cqa-py-1.5 cqa-rounded-lg cqa-border cqa-border-gray-300 cqa-bg-white cqa-text-gray-900 cqa-text-sm cqa-flex-1 cqa-max-w-md cqa-outline-none focus:cqa-ring-2 focus:cqa-ring-primary focus:cqa-ring-opacity-50\"\n /> -->\n </div>\n\n <!-- Steps Summary -->\n <div\n class=\"cqa-ml-auto cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </div>\n\n <!-- Action Icons: Edit, Link, Duplicate, Delete (show on hover) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-3 cqa-px-[7px]\">\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n </button>\n </div>\n </div>\n\n <!-- Expanded Content with Branches -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branches (IF TRUE, ELSE IF, ELSE) -->\n <div *ngFor=\"let branch of branches\" class=\"cqa-flex cqa-flex-col\">\n <!-- Branch Header -->\n <div\n [class]=\"'cqa-px-4 cqa-py-2 cqa-text-[12px] cqa-leading-[15px] cqa-flex cqa-items-center cqa-gap-2 ' + getBranchTextColor(branch) + ' ' + getBranchColorClass(branch)\">\n <span>{{ getBranchLabel(branch) }}</span>\n <span *ngIf=\"branch.action\" [innerHTML]=\"branch.action\" class=\"cqa-text-[#111827]\"></span>\n </div>\n\n <!-- Branch Content (Nested Steps \u2013 renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"!isReorder\" class=\"cqa-flex cqa-flex-col\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of branch.nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event, branch)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of branch.nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [branch]=\"branch\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (branchStepChange)=\"onBranchStepChange($event.branch, $event.step, $event.stepIndex)\"\n (addStepForBranch)=\"onAddStep($event.branch)\"\n (deleteStepWithBranch)=\"onDeleteStep($event.branch, $event.stepIndex)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, branch, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onBranchStepChange(branch, step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onBranchStepChange(branch, step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onBranchStepChange(branch, step, i)\"\n (openExternal)=\"onBranchStepChange(branch, step, i)\"\n (edit)=\"onBranchStepChange(branch, step, i)\"\n (link)=\"onBranchStepChange(branch, step, i)\"\n (duplicate)=\"onBranchStepChange(branch, step, i)\"\n (conditionChange)=\"$any(step).condition = $event; onBranchStepChange(branch, step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step)); onBranchStepChange(branch, step, i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event); onBranchStepChange(branch, step, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onBranchStepChange(branch, step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onBranchStepChange(branch, step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onBranchStepChange(branch, step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onBranchStepChange(branch, step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onBranchStepChange(branch, step, i)\"\n (parameterChange)=\"onBranchStepChange(branch, step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onBranchStepChange(branch, step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n </div>\n\n <!-- END IF Marker -->\n <div [class]=\"'cqa-pl-4 cqa-py-1 cqa-text-[#7B3306] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium'\" style=\"border-top: 1px solid #E5E7EB;\">\n END IF\n </div>\n </div>\n</div>" }]
|
|
@@ -18456,7 +18349,7 @@ class TestCaseStepGroupComponent {
|
|
|
18456
18349
|
}
|
|
18457
18350
|
}
|
|
18458
18351
|
TestCaseStepGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseStepGroupComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
18459
|
-
TestCaseStepGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseStepGroupComponent, selector: "cqa-test-case-step-group", inputs: { config: "config", id: "id", stepNumber: "stepNumber", groupName: "groupName", description: "description", reusable: "reusable", nestedSteps: "nestedSteps", expanded: "expanded", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder", loading: "loading" }, outputs: { 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" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div [class]=\"'cqa-flex cqa-flex-col'\">\n <!-- Step Group Header -->\n <div [class]=\"'step-row cqa-flex cqa-gap-3 cqa-items-center cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"expanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Folder Icon -->\n <div>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M15 15C15.3978 15 15.7794 14.842 16.0607 14.5607C16.342 14.2794 16.5 13.8978 16.5 13.5V6C16.5 5.60217 16.342 5.22064 16.0607 4.93934C15.7794 4.65804 15.3978 4.5 15 4.5H9.075C8.82413 4.50246 8.57666 4.44196 8.35523 4.32403C8.13379 4.20611 7.94547 4.03453 7.8075 3.825L7.2 2.925C7.06342 2.7176 6.87748 2.54736 6.65887 2.42955C6.44027 2.31174 6.19583 2.25004 5.9475 2.25H3C2.60218 2.25 2.22064 2.40804 1.93934 2.68934C1.65804 2.97064 1.5 3.35218 1.5 3.75V13.5C1.5 13.8978 1.65804 14.2794 1.93934 14.5607C2.22064 14.842 2.60218 15 3 15H15Z\"\n fill=\"#EFF6FF\" stroke=\"#60A5FA\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Group Name and Description -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-gap-[2px]\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Group Name Input -->\n <p class=\"cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[18px] cqa-font-bold\">{{groupName}}</p>\n <!-- Reusable Tag -->\n <span *ngIf=\"reusable\"\n class=\"cqa-px-2 cqa-py-[1.5px] cqa-rounded-lg cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#D8D9FC] cqa-border cqa-border-solid cqa-border-[#8A8CF4]\">\n Reusable\n </span>\n </div>\n\n <!-- Description -->\n <p class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-leading-[15px]\">{{description}}</p>\n </div>\n\n <!-- Steps Summary and Action Icons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n\n <!-- External Link Icon -->\n <button type=\"button\" (click)=\"onOpenExternal(); $event.stopPropagation()\" title=\"Open in new tab\"\n class=\"cqa-p-0 cqa-text-[#99999E] hover:cqa-text-[#1447E6]\">\n <svg width=\"16\" height=\"17\" viewBox=\"0 0 16 17\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 8.66667V12.6667C12 13.0203 11.8595 13.3594 11.6095 13.6095C11.3594 13.8595 11.0203 14 10.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V5.33333C2 4.97971 2.14048 4.64057 2.39052 4.39052C2.64057 4.14048 2.97971 4 3.33333 4H7.33333M10 2H14M14 2V6M14 2L6.66667 9.33333\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Steps Summary -->\n <span class=\"cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </span>\n\n <!-- Action Icons (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-[14px] cqa-ml-auto cqa-px-[7px]\">\n\n <!-- Edit Icon -->\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Link Icon -->\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_609_26588)\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_609_26588\">\n <rect width=\"14\" height=\"14\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </button>\n\n <!-- Duplicate Icon -->\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Delete Icon -->\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Loading Indicator -->\n <div *ngIf=\"loading\" class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-8 cqa-px-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-gap-3\">\n <!-- Spinner -->\n <svg class=\"cqa-animate-spin cqa-h-6 cqa-w-6 cqa-text-[#3F43EE]\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"cqa-opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"cqa-opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n <span class=\"cqa-text-[#6B7280] cqa-text-sm\">Loading steps...</span>\n </div>\n </div>\n \n <!-- Nested Steps Content (only show when not loading) -->\n <div *ngIf=\"!loading\" class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col\" *ngIf=\"!isReorder\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END GROUP Marker -->\n <div [class]=\"'cqa-pl-8 cqa-py-2 cqa-border-t cqa-border-[#D1C4E9] cqa-bg-[#D1C4E9]'\">\n <span class=\"cqa-font-bold cqa-text-white cqa-text-sm cqa-uppercase\">\n END GROUP\n </span>\n </div>\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "dndDropInZone"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
18352
|
+
TestCaseStepGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TestCaseStepGroupComponent, selector: "cqa-test-case-step-group", inputs: { config: "config", id: "id", stepNumber: "stepNumber", groupName: "groupName", description: "description", reusable: "reusable", nestedSteps: "nestedSteps", expanded: "expanded", isNested: "isNested", isInsideLoop: "isInsideLoop", isReorder: "isReorder", loading: "loading" }, outputs: { 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" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div [class]=\"'cqa-flex cqa-flex-col'\">\n <!-- Step Group Header -->\n <div [class]=\"'step-row cqa-flex cqa-gap-3 cqa-items-center cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"expanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Folder Icon -->\n <div>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M15 15C15.3978 15 15.7794 14.842 16.0607 14.5607C16.342 14.2794 16.5 13.8978 16.5 13.5V6C16.5 5.60217 16.342 5.22064 16.0607 4.93934C15.7794 4.65804 15.3978 4.5 15 4.5H9.075C8.82413 4.50246 8.57666 4.44196 8.35523 4.32403C8.13379 4.20611 7.94547 4.03453 7.8075 3.825L7.2 2.925C7.06342 2.7176 6.87748 2.54736 6.65887 2.42955C6.44027 2.31174 6.19583 2.25004 5.9475 2.25H3C2.60218 2.25 2.22064 2.40804 1.93934 2.68934C1.65804 2.97064 1.5 3.35218 1.5 3.75V13.5C1.5 13.8978 1.65804 14.2794 1.93934 14.5607C2.22064 14.842 2.60218 15 3 15H15Z\"\n fill=\"#EFF6FF\" stroke=\"#60A5FA\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Group Name and Description -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-gap-[2px]\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Group Name Input -->\n <p class=\"cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[18px] cqa-font-bold\">{{groupName}}</p>\n <!-- Reusable Tag -->\n <span *ngIf=\"reusable\"\n class=\"cqa-px-2 cqa-py-[1.5px] cqa-rounded-lg cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#D8D9FC] cqa-border cqa-border-solid cqa-border-[#8A8CF4]\">\n Reusable\n </span>\n </div>\n\n <!-- Description -->\n <p class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-leading-[15px]\">{{description}}</p>\n </div>\n\n <!-- Steps Summary and Action Icons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n\n <!-- External Link Icon -->\n <button type=\"button\" (click)=\"onOpenExternal(); $event.stopPropagation()\" title=\"Open in new tab\"\n class=\"cqa-p-0 cqa-text-[#99999E] hover:cqa-text-[#1447E6]\">\n <svg width=\"16\" height=\"17\" viewBox=\"0 0 16 17\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 8.66667V12.6667C12 13.0203 11.8595 13.3594 11.6095 13.6095C11.3594 13.8595 11.0203 14 10.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V5.33333C2 4.97971 2.14048 4.64057 2.39052 4.39052C2.64057 4.14048 2.97971 4 3.33333 4H7.33333M10 2H14M14 2V6M14 2L6.66667 9.33333\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Steps Summary -->\n <span class=\"cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </span>\n\n <!-- Action Icons (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-[14px] cqa-ml-auto cqa-px-[7px]\">\n\n <!-- Edit Icon -->\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Link Icon -->\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_609_26588)\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_609_26588\">\n <rect width=\"14\" height=\"14\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </button>\n\n <!-- Duplicate Icon -->\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Delete Icon -->\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Loading Indicator -->\n <div *ngIf=\"loading\" class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-8 cqa-px-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-gap-3\">\n <!-- Spinner -->\n <svg class=\"cqa-animate-spin cqa-h-6 cqa-w-6 cqa-text-[#3F43EE]\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"cqa-opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"cqa-opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n <span class=\"cqa-text-[#6B7280] cqa-text-sm\">Loading steps...</span>\n </div>\n </div>\n \n <!-- Nested Steps Content (only show when not loading) -->\n <div *ngIf=\"!loading\" class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col\" *ngIf=\"!isReorder\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END GROUP Marker -->\n <div [class]=\"'cqa-pl-8 cqa-py-2 cqa-border-t cqa-border-[#D1C4E9] cqa-bg-[#D1C4E9]'\">\n <span class=\"cqa-font-bold cqa-text-white cqa-text-sm cqa-uppercase\">\n END GROUP\n </span>\n </div>\n </div>\n </div>\n</div>", styles: [".step-actions{opacity:0;transition:opacity .15s ease}.step-row:hover .step-actions{opacity:1}\n"], components: [{ type: TestCaseDetailsRendererComponent, selector: "cqa-test-case-details-renderer", inputs: ["step", "index", "isNested", "isInsideLoop", "branch", "isReorder", "addStepBetween"], outputs: ["nestedStepChange", "addStep", "deleteStep", "toggleExpanded", "groupNameChange", "descriptionChange", "reusableChange", "openExternal", "edit", "link", "duplicate", "delete", "viewDetails", "selectionChange", "conditionChange", "branchStepChange", "addStepForBranch", "deleteStepWithBranch", "addBranch", "deleteBranch", "testDataProfileChange", "startStepChange", "endStepChange", "maxIterationsChange", "eventTypeChange", "parameterChange", "clickAction", "dndDropInZone", "addStepBetweenClick"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.DndDropzoneDirective, selector: "[dndDropzone]", inputs: ["dndDropzone", "dndEffectAllowed", "dndAllowExternal", "dndHorizontal", "dndDragoverClass", "dndDropzoneDisabledClass", "dndDisableIf", "dndDisableDropIf"], outputs: ["dndDragover", "dndDrop"] }, { type: i7.DndPlaceholderRefDirective, selector: "[dndPlaceholderRef]" }, { type: i7.DndDraggableDirective, selector: "[dndDraggable]", inputs: ["dndDraggable", "dndEffectAllowed", "dndType", "dndDraggingClass", "dndDraggingSourceClass", "dndDraggableDisabledClass", "dndDragImageOffsetFunction", "dndDisableIf", "dndDisableDragIf"], outputs: ["dndStart", "dndDrag", "dndEnd", "dndMoved", "dndCopied", "dndLinked", "dndCanceled"] }] });
|
|
18460
18353
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TestCaseStepGroupComponent, decorators: [{
|
|
18461
18354
|
type: Component,
|
|
18462
18355
|
args: [{ selector: 'cqa-test-case-step-group', host: { class: 'cqa-ui-root' }, styles: [STEP_ROW_ACTIONS_STYLES], template: "<div [class]=\"'cqa-flex cqa-flex-col'\">\n <!-- Step Group Header -->\n <div [class]=\"'step-row cqa-flex cqa-gap-3 cqa-items-center cqa-py-2 ' + (isInsideLoop ? 'cqa-pl-10 cqa-pr-4' : 'cqa-px-4')\">\n <!-- Expand/Collapse Icon -->\n <button type=\"button\" (click)=\"onToggleExpanded()\" class=\"cqa-p-0\">\n <svg [class.cqa-rotate-180]=\"expanded\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4 6L8 10L12 6\" stroke=\"#6B7280\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Folder Icon -->\n <div>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M15 15C15.3978 15 15.7794 14.842 16.0607 14.5607C16.342 14.2794 16.5 13.8978 16.5 13.5V6C16.5 5.60217 16.342 5.22064 16.0607 4.93934C15.7794 4.65804 15.3978 4.5 15 4.5H9.075C8.82413 4.50246 8.57666 4.44196 8.35523 4.32403C8.13379 4.20611 7.94547 4.03453 7.8075 3.825L7.2 2.925C7.06342 2.7176 6.87748 2.54736 6.65887 2.42955C6.44027 2.31174 6.19583 2.25004 5.9475 2.25H3C2.60218 2.25 2.22064 2.40804 1.93934 2.68934C1.65804 2.97064 1.5 3.35218 1.5 3.75V13.5C1.5 13.8978 1.65804 14.2794 1.93934 14.5607C2.22064 14.842 2.60218 15 3 15H15Z\"\n fill=\"#EFF6FF\" stroke=\"#60A5FA\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </div>\n\n <!-- Group Name and Description -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-gap-[2px]\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Group Name Input -->\n <p class=\"cqa-text-[#3F43EE] cqa-text-[14px] cqa-leading-[18px] cqa-font-bold\">{{groupName}}</p>\n <!-- Reusable Tag -->\n <span *ngIf=\"reusable\"\n class=\"cqa-px-2 cqa-py-[1.5px] cqa-rounded-lg cqa-text-[#3F43EE] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-bg-[#D8D9FC] cqa-border cqa-border-solid cqa-border-[#8A8CF4]\">\n Reusable\n </span>\n </div>\n\n <!-- Description -->\n <p class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-leading-[15px]\">{{description}}</p>\n </div>\n\n <!-- Steps Summary and Action Icons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n\n <!-- External Link Icon -->\n <button type=\"button\" (click)=\"onOpenExternal(); $event.stopPropagation()\" title=\"Open in new tab\"\n class=\"cqa-p-0 cqa-text-[#99999E] hover:cqa-text-[#1447E6]\">\n <svg width=\"16\" height=\"17\" viewBox=\"0 0 16 17\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M12 8.66667V12.6667C12 13.0203 11.8595 13.3594 11.6095 13.6095C11.3594 13.8595 11.0203 14 10.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V5.33333C2 4.97971 2.14048 4.64057 2.39052 4.39052C2.64057 4.14048 2.97971 4 3.33333 4H7.33333M10 2H14M14 2V6M14 2L6.66667 9.33333\"\n stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Steps Summary -->\n <span class=\"cqa-border cqa-border-solid cqa-border-[#E5E5E5] cqa-rounded-lg cqa-py-0.5 cqa-px-2 cqa-text-[#0A0A0A] cqa-text-[12px] cqa-leading-[15px]\">\n {{ getStepsSummary() }}\n </span>\n\n <!-- Action Icons (show on hover, same as API step) -->\n <div class=\"step-actions cqa-flex cqa-items-center cqa-gap-[14px] cqa-ml-auto cqa-px-[7px]\">\n\n <!-- Edit Icon -->\n <button type=\"button\" (click)=\"onEdit(); $event.stopPropagation()\" title=\"Edit\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7 11.6666H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M9.55208 2.1128C9.7843 1.88058 10.0993 1.75012 10.4277 1.75012C10.7561 1.75012 11.071 1.88058 11.3033 2.1128C11.5355 2.34502 11.6659 2.65998 11.6659 2.98838C11.6659 3.31679 11.5355 3.63175 11.3033 3.86397L4.29742 10.8704C4.15864 11.0092 3.9871 11.1107 3.79867 11.1656L2.12333 11.6544C2.07314 11.669 2.01993 11.6699 1.96928 11.6569C1.91863 11.6439 1.8724 11.6176 1.83543 11.5806C1.79846 11.5437 1.7721 11.4974 1.75913 11.4468C1.74615 11.3961 1.74703 11.3429 1.76167 11.2927L2.2505 9.61738C2.30546 9.42916 2.40698 9.25783 2.54567 9.11922L9.55208 2.1128Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Link Icon -->\n <button type=\"button\" (click)=\"onLink(); $event.stopPropagation()\" title=\"Link\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <g clip-path=\"url(#clip0_609_26588)\">\n <path\n d=\"M5.00065 9.91671H3.66732C2.78326 9.91671 1.93542 9.60942 1.3103 9.06244C0.685174 8.51545 0.333984 7.77359 0.333984 7.00004C0.333984 6.22649 0.685174 5.48463 1.3103 4.93765C1.93542 4.39066 2.78326 4.08337 3.66732 4.08337H5.00065\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M9 4.08337H10.3333C11.2174 4.08337 12.0652 4.39066 12.6904 4.93765C13.3155 5.48463 13.6667 6.22649 13.6667 7.00004C13.6667 7.77359 13.3155 8.51545 12.6904 9.06244C12.0652 9.60942 11.2174 9.91671 10.3333 9.91671H9\"\n stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M4.33398 7H9.66732\" stroke=\"currentColor\" stroke-width=\"1.33333\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_609_26588\">\n <rect width=\"14\" height=\"14\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </button>\n\n <!-- Duplicate Icon -->\n <button type=\"button\" (click)=\"onDuplicate(); $event.stopPropagation()\" title=\"Duplicate\" class=\"cqa-p-0 cqa-text-[#99A1Af] hover:cqa-text-[#1447E6]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M11.666 4.66663H5.83268C5.18835 4.66663 4.66602 5.18896 4.66602 5.83329V11.6666C4.66602 12.311 5.18835 12.8333 5.83268 12.8333H11.666C12.3103 12.8333 12.8327 12.311 12.8327 11.6666V5.83329C12.8327 5.18896 12.3103 4.66663 11.666 4.66663Z\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M2.33268 9.33329C1.69102 9.33329 1.16602 8.80829 1.16602 8.16663V2.33329C1.16602 1.69163 1.69102 1.16663 2.33268 1.16663H8.16602C8.80768 1.16663 9.33268 1.69163 9.33268 2.33329\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n </button>\n\n <!-- Delete Icon -->\n <button type=\"button\" (click)=\"onDelete(); $event.stopPropagation()\" title=\"Delete\" class=\"cqa-p-0 cqa-text-[#ff6467] hover:cqa-text-[#C63535]\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.75 3.5H12.25\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path\n d=\"M11.0827 3.5V11.6667C11.0827 12.25 10.4993 12.8333 9.91602 12.8333H4.08268C3.49935 12.8333 2.91602 12.25 2.91602 11.6667V3.5\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path\n d=\"M4.66602 3.49996V2.33329C4.66602 1.74996 5.24935 1.16663 5.83268 1.16663H8.16602C8.74935 1.16663 9.33268 1.74996 9.33268 2.33329V3.49996\"\n stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n <path d=\"M5.83398 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n <path d=\"M8.16602 6.41663V9.91663\" stroke=\"currentColor\" stroke-width=\"1.16667\" stroke-linecap=\"round\"\n stroke-linejoin=\"round\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Expanded Content with Nested Steps (renderer dispatches by step type, n-level nesting) -->\n <div *ngIf=\"expanded\" class=\"cqa-flex cqa-flex-col\">\n <!-- Loading Indicator -->\n <div *ngIf=\"loading\" class=\"cqa-flex cqa-items-center cqa-justify-center cqa-py-8 cqa-px-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-items-center cqa-gap-3\">\n <!-- Spinner -->\n <svg class=\"cqa-animate-spin cqa-h-6 cqa-w-6 cqa-text-[#3F43EE]\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle class=\"cqa-opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" stroke-width=\"4\"></circle>\n <path class=\"cqa-opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n <span class=\"cqa-text-[#6B7280] cqa-text-sm\">Loading steps...</span>\n </div>\n </div>\n \n <!-- Nested Steps Content (only show when not loading) -->\n <div *ngIf=\"!loading\" class=\"cqa-flex cqa-flex-col\">\n <div class=\"cqa-flex cqa-flex-col\" *ngIf=\"!isReorder\">\n <cqa-test-case-details-renderer\n *ngFor=\"let step of nestedSteps; let i = index\"\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n <div *ngIf=\"isReorder\" class=\"cqa-flex cqa-flex-col nested-step-drop-list\"\n [dndDropzone]=\"['step']\"\n dndEffectAllowed=\"move\"\n dndDragoverClass=\"dndDragover\"\n (dndDrop)=\"onDndDrop($event)\">\n <div dndPlaceholderRef class=\"step-drag-placeholder-nested cqa-my-1 cqa-min-h-[50px] cqa-border-2 cqa-border-dashed cqa-border-[#3F43EE] cqa-rounded cqa-bg-[rgba(63,67,238,0.08)] cqa-flex cqa-items-center cqa-justify-center cqa-text-[#3F43EE] cqa-text-xs\">Drop here</div>\n <div *ngFor=\"let step of nestedSteps; let i = index\" class=\"nested-step-drag-item\"\n [dndDraggable]=\"step\"\n dndEffectAllowed=\"move\"\n dndType=\"step\">\n <cqa-test-case-details-renderer\n [step]=\"step\"\n [index]=\"i\"\n [isNested]=\"true\"\n [isReorder]=\"isReorder\"\n (nestedStepChange)=\"onNestedStepChange($event.step, $event.index)\"\n (addStep)=\"onAddStep()\"\n (deleteStep)=\"onDeleteStep($event)\"\n (toggleExpanded)=\"onNestedToggleExpanded($event, step, i)\"\n (groupNameChange)=\"$any(step).groupName = $event; onNestedStepChange(step, i)\"\n (descriptionChange)=\"$any(step).description = $event; onNestedStepChange(step, i)\"\n (reusableChange)=\"$any(step).reusable = $event; onNestedStepChange(step, i)\"\n (openExternal)=\"onNestedStepChange(step, i)\"\n (edit)=\"onNestedStepChange(step, i)\"\n (link)=\"onNestedStepChange(step, i)\"\n (duplicate)=\"onNestedStepChange(step, i)\"\n (delete)=\"onDeleteStep(i)\"\n (conditionChange)=\"$any(step).condition = $event; onNestedStepChange(step, i)\"\n (branchStepChange)=\"onNestedStepChange(step, i)\"\n (addBranch)=\"onNestedConditionAddBranch($any(step), i)\"\n (deleteBranch)=\"onNestedConditionDeleteBranch($any(step), $event, i)\"\n (testDataProfileChange)=\"$any(step).testDataProfile = $event; onNestedStepChange(step, i)\"\n (startStepChange)=\"$any(step).startStep = $event; onNestedStepChange(step, i)\"\n (endStepChange)=\"$any(step).endStep = $event; onNestedStepChange(step, i)\"\n (maxIterationsChange)=\"$any(step).maxIterations = $event; onNestedStepChange(step, i)\"\n (eventTypeChange)=\"$any(step).eventType = $event; onNestedStepChange(step, i)\"\n (parameterChange)=\"onNestedStepChange(step, i)\"\n (selectionChange)=\"$any(step).selected = $event; onNestedStepChange(step, i)\"\n (dndDropInZone)=\"dndDropInZone.emit($event)\"\n >\n </cqa-test-case-details-renderer>\n </div>\n </div>\n\n <!-- END GROUP Marker -->\n <div [class]=\"'cqa-pl-8 cqa-py-2 cqa-border-t cqa-border-[#D1C4E9] cqa-bg-[#D1C4E9]'\">\n <span class=\"cqa-font-bold cqa-text-white cqa-text-sm cqa-uppercase\">\n END GROUP\n </span>\n </div>\n </div>\n </div>\n</div>" }]
|
|
@@ -20807,10 +20700,10 @@ class StepBuilderDatabaseComponent {
|
|
|
20807
20700
|
}
|
|
20808
20701
|
}
|
|
20809
20702
|
StepBuilderDatabaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderDatabaseComponent, deps: [{ token: i2$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
20810
|
-
StepBuilderDatabaseComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderDatabaseComponent, selector: "cqa-step-builder-database", inputs: { dbEnvironmentOptions: "dbEnvironmentOptions", queries: "queries", queryResults: "queryResults", isLoading: "isLoading" }, outputs: { createStep: "createStep", cancelled: "cancelled", runQuery: "runQuery", addQuery: "addQuery", deleteQuery: "deleteQuery" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create Database Test Step\n </h2>\n\n <!-- DB Environment Section -->\n <div class=\"cqa-flex cqa-items-start cqa-gap-4 cqa-mb-6\">\n <div class=\"cqa-flex-1\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block\">\n DB Environment <span class=\"cqa-text-red-500\">*</span>\n </label>\n <cqa-dynamic-select\n [form]=\"databaseForm\"\n [config]=\"getDbEnvironmentConfig()\">\n </cqa-dynamic-select>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Uses Database environments from Environments.\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-end cqa-mb-1\">\n <cqa-button\n variant=\"filled\"\n text=\"Run Query\"\n [customClass]=\"'cqa-whitespace-nowrap'\"\n (clicked)=\"onRunQuery()\"\n [disabled]=\"!databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Main Content: Two Column Layout -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Left Panel: Query List -->\n <div class=\"cqa-w-64 cqa-flex-shrink-0 cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Queries</h3>\n </div>\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-2\">\n <div *ngFor=\"let query of queries; let i = index\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-p-2 cqa-rounded cqa-cursor-pointer cqa-mb-1\"\n [class.cqa-bg-blue-50]=\"selectedQueryIndex === i\"\n [class.cqa-border]=\"selectedQueryIndex === i\"\n [class.cqa-border-blue-500]=\"selectedQueryIndex === i\"\n (click)=\"onSelectQuery(i)\">\n <span class=\"cqa-text-sm cqa-font-medium cqa-text-gray-900\">Query {{ i + 1 }}</span>\n <cqa-badge\n *ngIf=\"query.status\"\n [label]=\"query.status === 'passed' ? 'Passed' : query.status === 'failed' ? 'Failed' : 'Pending'\"\n [variant]=\"query.status === 'passed' ? 'success' : query.status === 'failed' ? 'error' : 'default'\"\n size=\"small\">\n </cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Right Panel: Query Editor -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Query & Store Response</h3>\n </div>\n \n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-flex cqa-flex-col cqa-gap-4\">\n <!-- SQL Query Textarea -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter your SQL query here...'\"\n [value]=\"getCurrentQueryFormGroup()?.get('query')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"8\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('query')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Variable Input -->\n <div class=\"cqa-flex cqa-gap-4\">\n <div class=\"cqa-flex-1\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block\">\n Variable\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable name'\"\n [value]=\"getCurrentQueryFormGroup()?.get('variable')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('variable')?.setValue($event)\">\n </cqa-custom-input>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Use letters, numbers, underscore. No spaces. Unique per step. Case sensitive.\n </p>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <cqa-button\n variant=\"outlined\"\n text=\"Add Query\"\n icon=\"add\"\n (clicked)=\"addNewQuery()\">\n </cqa-button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors cqa-border cqa-border-gray-300\"\n (click)=\"deleteQueryById(getCurrentQuery()?.id || '')\"\n [disabled]=\"queries.length <= 1\"\n [attr.aria-label]=\"'Delete query'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n <cqa-button\n variant=\"filled\"\n text=\"Run\"\n icon=\"play_arrow\"\n (clicked)=\"onRunQuery()\"\n [disabled]=\"!databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Results Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <!-- Tabs -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'output'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'output'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'output'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'output'\"\n (click)=\"onTabChange('output')\">\n Output\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'verification'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'verification'\"\n (click)=\"onTabChange('verification')\">\n Verification\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-p-4\">\n <!-- Output Tab -->\n <div *ngIf=\"selectedTab === 'output'\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-mb-3\">\n <h4 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Query Results</h4>\n <cqa-button\n variant=\"text\"\n text=\"Copy\"\n icon=\"content_copy\"\n [customClass]=\"'cqa-text-blue-600'\"\n (clicked)=\"onCopyResults()\">\n </cqa-button>\n </div>\n \n <!-- Results Table -->\n <div *ngIf=\"queryResults && queryResults.length > 0\" class=\"cqa-overflow-x-auto\">\n <table class=\"cqa-w-full cqa-border-collapse\">\n <thead>\n <tr class=\"cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <th *ngFor=\"let key of getTableColumns()\" \n class=\"cqa-px-4 cqa-py-2 cqa-text-left cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">\n {{ key }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of queryResults\" \n class=\"cqa-border-b cqa-border-gray-200 hover:cqa-bg-gray-50\">\n <td *ngFor=\"let key of getTableColumns()\" \n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-text-gray-900\">\n {{ row[key] }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n \n <div *ngIf=\"!queryResults || queryResults.length === 0\" \n class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-sm\">\n No results yet. Run a query to see results.\n </div>\n </div>\n\n <!-- Verification Tab -->\n <div *ngIf=\"selectedTab === 'verification'\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">Verification settings will be available here.</p>\n </div>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n text=\"Create Step\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n</div>\n\n", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle", "customClass"], outputs: ["valueChange", "blurred", "focused"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
20703
|
+
StepBuilderDatabaseComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderDatabaseComponent, selector: "cqa-step-builder-database", inputs: { dbEnvironmentOptions: "dbEnvironmentOptions", queries: "queries", queryResults: "queryResults", isLoading: "isLoading" }, outputs: { createStep: "createStep", cancelled: "cancelled", runQuery: "runQuery", addQuery: "addQuery", deleteQuery: "deleteQuery" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create Database Test Step\n </h2>\n\n <!-- DB Environment Section -->\n <div class=\"cqa-flex cqa-items-end cqa-justify-between cqa-mb-6\">\n <div class=\"cqa-flex-1\" style=\"max-width: 280px;\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block\">\n DB Environment <span class=\"cqa-text-red-500\">*</span>\n </label>\n <cqa-dynamic-select [form]=\"databaseForm\" [config]=\"getDbEnvironmentConfig()\">\n </cqa-dynamic-select>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Uses Database environments from Environments.\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-end cqa-mb-1\">\n <cqa-button variant=\"filled\" text=\"Run Query\" [customClass]=\"'cqa-whitespace-nowrap'\" (clicked)=\"onRunQuery()\"\n [disabled]=\"!databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Main Content: Two Column Layout -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Left Panel: Query List -->\n <div\n class=\"cqa-w-64 cqa-flex-shrink-0 cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden\"\n style=\"max-width: 174px;\">\n <!-- <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Queries</h3>\n </div> -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-2\">\n <div *ngFor=\"let query of queries; let i = index\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-p-2 cqa-rounded cqa-cursor-pointer cqa-mb-1\"\n [class.cqa-bg-blue-50]=\"selectedQueryIndex === i\" [class.cqa-border]=\"selectedQueryIndex === i\"\n [class.cqa-border-blue-500]=\"selectedQueryIndex === i\" (click)=\"onSelectQuery(i)\" style=\"height: 49px;\">\n <span class=\"cqa-text-sm cqa-font-medium cqa-text-gray-900\">Query {{ i + 1 }}</span>\n <cqa-badge *ngIf=\"query.status\"\n [label]=\"query.status === 'passed' ? 'Passed' : query.status === 'failed' ? 'Failed' : 'Pending'\"\n [variant]=\"query.status === 'passed' ? 'success' : query.status === 'failed' ? 'error' : 'default'\"\n size=\"small\">\n </cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Right Panel: Query Editor -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-overflow-auto\">\n <div class=\"cqa-flex-1 cqa-flex cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4\" style=\"width: 50%;\">\n <div class=\"\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900 cqa-text-[14px]\">Query & Store Response</h3>\n </div>\n\n <div class=\"cqa-flex cqa-justify-between\">\n <!-- SQL Query Textarea -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-custom-textarea [placeholder]=\"'Enter your SQL query here...'\"\n [value]=\"getCurrentQueryFormGroup()?.get('query')?.value || ''\" [fullWidth]=\"true\" [rows]=\"8\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('query')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-flex cqa-flex-col cqa-gap-4\">\n\n\n <!-- Variable Input -->\n <div class=\"cqa-flex cqa-gap-4\">\n <div class=\"cqa-flex-1\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block cqa-text-[14px] cqa-font-semibold\">\n Variable\n </label>\n <cqa-custom-input [placeholder]=\"'Variable name'\"\n [value]=\"getCurrentQueryFormGroup()?.get('variable')?.value || ''\" [fullWidth]=\"true\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('variable')?.setValue($event)\">\n </cqa-custom-input>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Use letters, numbers, underscore. No spaces. Unique per step. Case sensitive.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <cqa-button variant=\"outlined\" text=\"Add Query\" icon=\"add\" (clicked)=\"addNewQuery()\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors cqa-border cqa-border-gray-300\"\n (click)=\"deleteQueryById(getCurrentQuery()?.id || '')\" [disabled]=\"queries.length <= 1\"\n [attr.aria-label]=\"'Delete query'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button> -->\n <cqa-button variant=\"text\" icon=\"delete\" (clicked)=\"deleteQueryById(getCurrentQuery()?.id || '')\"\n [disabled]=\"queries.length <= 1\" [customClass]=\"'cqa-text-red-500'\" [attr.aria-label]=\"'Delete query'\">\n </cqa-button>\n <cqa-button variant=\"filled\" text=\"Run\" icon=\"play_arrow\" (clicked)=\"onRunQuery()\"\n [disabled]=\"!getCurrentQueryFormGroup()?.get('query')?.value || !databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n </div>\n <!-- Results Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-mb-6\">\n <!-- Tabs -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'output'\" [class.cqa-border-blue-600]=\"selectedTab === 'output'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'output'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'output'\" (click)=\"onTabChange('output')\">\n Output\n </button>\n <button type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'verification'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'verification'\" (click)=\"onTabChange('verification')\">\n Verification\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-p-4\">\n <!-- Output Tab -->\n <div *ngIf=\"selectedTab === 'output'\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-mb-3\">\n <h4 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Query Results</h4>\n <cqa-button variant=\"text\" text=\"Copy\" icon=\"content_copy\" [customClass]=\"'cqa-text-blue-600'\"\n (clicked)=\"onCopyResults()\">\n </cqa-button>\n </div>\n\n <!-- Results Table -->\n <div *ngIf=\"queryResults && queryResults.length > 0\" class=\"cqa-overflow-x-auto\">\n <table class=\"cqa-w-full cqa-border-collapse\">\n <thead>\n <tr class=\"cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <th *ngFor=\"let key of getTableColumns()\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-left cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">\n {{ key }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of queryResults\" class=\"cqa-border-b cqa-border-gray-200 hover:cqa-bg-gray-50\">\n <td *ngFor=\"let key of getTableColumns()\" class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-text-gray-900\">\n {{ row[key] }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <div *ngIf=\"!queryResults || queryResults.length === 0\"\n class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-sm\">\n No results yet. Run a query to see results.\n </div>\n </div>\n\n <!-- Verification Tab -->\n <div *ngIf=\"selectedTab === 'verification'\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">Verification settings will be available here.</p>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <cqa-button class=\"cqa-w-1/2\" variant=\"outlined\" text=\"Cancel\" [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <cqa-button class=\"cqa-w-1/2\" variant=\"filled\" text=\"Create Step\" [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n</div>", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: BadgeComponent, selector: "cqa-badge", inputs: ["type", "label", "icon", "iconLibrary", "variant", "size", "backgroundColor", "textColor", "borderColor", "iconBackgroundColor", "iconColor", "iconSize", "inlineStyles", "key", "value", "keyTextColor", "valueTextColor", "isLoading"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle", "customClass"], outputs: ["valueChange", "blurred", "focused"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
20811
20704
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderDatabaseComponent, decorators: [{
|
|
20812
20705
|
type: Component,
|
|
20813
|
-
args: [{ selector: 'cqa-step-builder-database', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create Database Test Step\n </h2>\n\n <!-- DB Environment Section -->\n <div class=\"cqa-flex cqa-items-
|
|
20706
|
+
args: [{ selector: 'cqa-step-builder-database', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create Database Test Step\n </h2>\n\n <!-- DB Environment Section -->\n <div class=\"cqa-flex cqa-items-end cqa-justify-between cqa-mb-6\">\n <div class=\"cqa-flex-1\" style=\"max-width: 280px;\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block\">\n DB Environment <span class=\"cqa-text-red-500\">*</span>\n </label>\n <cqa-dynamic-select [form]=\"databaseForm\" [config]=\"getDbEnvironmentConfig()\">\n </cqa-dynamic-select>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Uses Database environments from Environments.\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-end cqa-mb-1\">\n <cqa-button variant=\"filled\" text=\"Run Query\" [customClass]=\"'cqa-whitespace-nowrap'\" (clicked)=\"onRunQuery()\"\n [disabled]=\"!databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Main Content: Two Column Layout -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Left Panel: Query List -->\n <div\n class=\"cqa-w-64 cqa-flex-shrink-0 cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden\"\n style=\"max-width: 174px;\">\n <!-- <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Queries</h3>\n </div> -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-2\">\n <div *ngFor=\"let query of queries; let i = index\"\n class=\"cqa-flex cqa-items-center cqa-justify-between cqa-p-2 cqa-rounded cqa-cursor-pointer cqa-mb-1\"\n [class.cqa-bg-blue-50]=\"selectedQueryIndex === i\" [class.cqa-border]=\"selectedQueryIndex === i\"\n [class.cqa-border-blue-500]=\"selectedQueryIndex === i\" (click)=\"onSelectQuery(i)\" style=\"height: 49px;\">\n <span class=\"cqa-text-sm cqa-font-medium cqa-text-gray-900\">Query {{ i + 1 }}</span>\n <cqa-badge *ngIf=\"query.status\"\n [label]=\"query.status === 'passed' ? 'Passed' : query.status === 'failed' ? 'Failed' : 'Pending'\"\n [variant]=\"query.status === 'passed' ? 'success' : query.status === 'failed' ? 'error' : 'default'\"\n size=\"small\">\n </cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Right Panel: Query Editor -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-overflow-auto\">\n <div class=\"cqa-flex-1 cqa-flex cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-gap-4\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4\" style=\"width: 50%;\">\n <div class=\"\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900 cqa-text-[14px]\">Query & Store Response</h3>\n </div>\n\n <div class=\"cqa-flex cqa-justify-between\">\n <!-- SQL Query Textarea -->\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col\">\n <cqa-custom-textarea [placeholder]=\"'Enter your SQL query here...'\"\n [value]=\"getCurrentQueryFormGroup()?.get('query')?.value || ''\" [fullWidth]=\"true\" [rows]=\"8\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('query')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-flex cqa-flex-col cqa-gap-4\">\n\n\n <!-- Variable Input -->\n <div class=\"cqa-flex cqa-gap-4\">\n <div class=\"cqa-flex-1\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5 cqa-block cqa-text-[14px] cqa-font-semibold\">\n Variable\n </label>\n <cqa-custom-input [placeholder]=\"'Variable name'\"\n [value]=\"getCurrentQueryFormGroup()?.get('variable')?.value || ''\" [fullWidth]=\"true\"\n (valueChange)=\"getCurrentQueryFormGroup()?.get('variable')?.setValue($event)\">\n </cqa-custom-input>\n <p class=\"cqa-text-xs cqa-text-gray-500 cqa-mt-1\">\n Use letters, numbers, underscore. No spaces. Unique per step. Case sensitive.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <cqa-button variant=\"outlined\" text=\"Add Query\" icon=\"add\" (clicked)=\"addNewQuery()\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-10 cqa-h-10 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors cqa-border cqa-border-gray-300\"\n (click)=\"deleteQueryById(getCurrentQuery()?.id || '')\" [disabled]=\"queries.length <= 1\"\n [attr.aria-label]=\"'Delete query'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button> -->\n <cqa-button variant=\"text\" icon=\"delete\" (clicked)=\"deleteQueryById(getCurrentQuery()?.id || '')\"\n [disabled]=\"queries.length <= 1\" [customClass]=\"'cqa-text-red-500'\" [attr.aria-label]=\"'Delete query'\">\n </cqa-button>\n <cqa-button variant=\"filled\" text=\"Run\" icon=\"play_arrow\" (clicked)=\"onRunQuery()\"\n [disabled]=\"!getCurrentQueryFormGroup()?.get('query')?.value || !databaseForm.get('dbEnvironment')?.value || isLoading\">\n </cqa-button>\n </div>\n </div>\n </div>\n <!-- Results Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-mb-6\">\n <!-- Tabs -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'output'\" [class.cqa-border-blue-600]=\"selectedTab === 'output'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'output'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'output'\" (click)=\"onTabChange('output')\">\n Output\n </button>\n <button type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'verification'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'verification'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'verification'\" (click)=\"onTabChange('verification')\">\n Verification\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-p-4\">\n <!-- Output Tab -->\n <div *ngIf=\"selectedTab === 'output'\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-mb-3\">\n <h4 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Query Results</h4>\n <cqa-button variant=\"text\" text=\"Copy\" icon=\"content_copy\" [customClass]=\"'cqa-text-blue-600'\"\n (clicked)=\"onCopyResults()\">\n </cqa-button>\n </div>\n\n <!-- Results Table -->\n <div *ngIf=\"queryResults && queryResults.length > 0\" class=\"cqa-overflow-x-auto\">\n <table class=\"cqa-w-full cqa-border-collapse\">\n <thead>\n <tr class=\"cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <th *ngFor=\"let key of getTableColumns()\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-left cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">\n {{ key }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let row of queryResults\" class=\"cqa-border-b cqa-border-gray-200 hover:cqa-bg-gray-50\">\n <td *ngFor=\"let key of getTableColumns()\" class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-text-gray-900\">\n {{ row[key] }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <div *ngIf=\"!queryResults || queryResults.length === 0\"\n class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-sm\">\n No results yet. Run a query to see results.\n </div>\n </div>\n\n <!-- Verification Tab -->\n <div *ngIf=\"selectedTab === 'verification'\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">Verification settings will be available here.</p>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n\n\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <cqa-button class=\"cqa-w-1/2\" variant=\"outlined\" text=\"Cancel\" [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <cqa-button class=\"cqa-w-1/2\" variant=\"filled\" text=\"Create Step\" [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n</div>", styles: [] }]
|
|
20814
20707
|
}], ctorParameters: function () { return [{ type: i2$1.FormBuilder }]; }, propDecorators: { dbEnvironmentOptions: [{
|
|
20815
20708
|
type: Input
|
|
20816
20709
|
}], queries: [{
|
|
@@ -21552,6 +21445,7 @@ class StepBuilderApiComponent {
|
|
|
21552
21445
|
this.importCurl = new EventEmitter();
|
|
21553
21446
|
this.selectedTab = 'headers';
|
|
21554
21447
|
this.selectedProgressStep = 'request-details';
|
|
21448
|
+
this.formSubmitted = false;
|
|
21555
21449
|
// progressSteps: ProgressStep[] = ['request-details', 'store-response', 'validation'];
|
|
21556
21450
|
// Cache config objects to prevent infinite change detection loops
|
|
21557
21451
|
this.verificationTypeConfigCache = null;
|
|
@@ -21560,9 +21454,13 @@ class StepBuilderApiComponent {
|
|
|
21560
21454
|
this.headerNameConfigCache = null;
|
|
21561
21455
|
this.paramNameConfigCache = null;
|
|
21562
21456
|
this.hasLoadedInitialData = false;
|
|
21457
|
+
// Get first HTTP method option (default to 'GET' if options not available yet)
|
|
21458
|
+
const firstMethod = this.httpMethodOptions.length > 0
|
|
21459
|
+
? this.httpMethodOptions[0].value
|
|
21460
|
+
: 'GET';
|
|
21563
21461
|
this.apiForm = this.fb.group({
|
|
21564
|
-
method: [
|
|
21565
|
-
url: ['', Validators.required],
|
|
21462
|
+
method: [firstMethod, Validators.required],
|
|
21463
|
+
url: ['', [Validators.required, this.urlValidator()]],
|
|
21566
21464
|
headers: this.fb.array([]),
|
|
21567
21465
|
body: [''],
|
|
21568
21466
|
params: this.fb.array([]),
|
|
@@ -21571,11 +21469,49 @@ class StepBuilderApiComponent {
|
|
|
21571
21469
|
validation: this.fb.array([])
|
|
21572
21470
|
});
|
|
21573
21471
|
}
|
|
21472
|
+
urlValidator() {
|
|
21473
|
+
return (control) => {
|
|
21474
|
+
const url = control.value;
|
|
21475
|
+
if (!url) {
|
|
21476
|
+
return null; // Let required validator handle empty case
|
|
21477
|
+
}
|
|
21478
|
+
// Pattern for plain URLs only (no parameters)
|
|
21479
|
+
const urlPattern = /^(https?:\/\/)?([\w-]+(\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?$/;
|
|
21480
|
+
// Pattern to detect any parameter patterns: *|param|, $|param|, @|param|, or ${param}
|
|
21481
|
+
const parameterPattern = /(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})/;
|
|
21482
|
+
// Pattern for parameter-only values: *|param|, $|param|, @|param|, or ${param}
|
|
21483
|
+
const envPattern = /^\*\|[\w-]+\|(\*)?$|^\$\|[\w-]+\|(\*)?$|^@\|[\w-]+\|(\*)?$|^\$\{[^}]+\}$/;
|
|
21484
|
+
// Pattern to allow URLs with embedded parameters: *|param|, $|param|, @|param|, or ${param}
|
|
21485
|
+
const flexibleUrlPattern = /^[@]?(https?:\/\/)?([\w-]+(\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[\w.,@?^=%&:/~+#-]*)*$/;
|
|
21486
|
+
// Pattern that allows parameters anywhere after http:// or https://
|
|
21487
|
+
const protocolWithParamsPattern = /^https?:\/\/(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[^\s]*$|^https?:\/\/[^\s]*(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[^\s]*$/;
|
|
21488
|
+
// Check if URL contains parameters
|
|
21489
|
+
if (parameterPattern.test(url)) {
|
|
21490
|
+
// If it contains parameters, check if it matches allowed patterns
|
|
21491
|
+
const envCombined = new RegExp(`${urlPattern.source}|${flexibleUrlPattern.source}|${envPattern.source}|${protocolWithParamsPattern.source}`);
|
|
21492
|
+
if (!envCombined.test(url)) {
|
|
21493
|
+
return { hasParameter: true };
|
|
21494
|
+
}
|
|
21495
|
+
}
|
|
21496
|
+
else {
|
|
21497
|
+
// If no parameters, check if it's a valid plain URL
|
|
21498
|
+
if (!urlPattern.test(url)) {
|
|
21499
|
+
return { pattern: true };
|
|
21500
|
+
}
|
|
21501
|
+
}
|
|
21502
|
+
return null;
|
|
21503
|
+
};
|
|
21504
|
+
}
|
|
21574
21505
|
ngOnInit() {
|
|
21506
|
+
var _a, _b;
|
|
21575
21507
|
// Sync currentStep input with selectedProgressStep
|
|
21576
21508
|
if (this.currentStep) {
|
|
21577
21509
|
this.selectedProgressStep = this.currentStep;
|
|
21578
21510
|
}
|
|
21511
|
+
// Set method to first option if not already set
|
|
21512
|
+
if (!((_a = this.apiForm.get('method')) === null || _a === void 0 ? void 0 : _a.value) && this.httpMethodOptions.length > 0) {
|
|
21513
|
+
(_b = this.apiForm.get('method')) === null || _b === void 0 ? void 0 : _b.setValue(this.httpMethodOptions[0].value);
|
|
21514
|
+
}
|
|
21579
21515
|
// Load initial data if provided (edit mode)
|
|
21580
21516
|
if (this.initialData) {
|
|
21581
21517
|
this.loadInitialData(this.initialData);
|
|
@@ -21671,8 +21607,18 @@ class StepBuilderApiComponent {
|
|
|
21671
21607
|
return this.apiForm.get('validation');
|
|
21672
21608
|
}
|
|
21673
21609
|
addHeader() {
|
|
21610
|
+
// Get first header name option
|
|
21611
|
+
const headerOptions = this.headerNameOptions.length > 0
|
|
21612
|
+
? this.headerNameOptions
|
|
21613
|
+
: [
|
|
21614
|
+
{ id: 'string', value: 'string', name: 'string', label: 'string' },
|
|
21615
|
+
{ id: 'Content-Type', value: 'Content-Type', name: 'Content-Type', label: 'Content-Type' },
|
|
21616
|
+
{ id: 'Authorization', value: 'Authorization', name: 'Authorization', label: 'Authorization' },
|
|
21617
|
+
{ id: 'Accept', value: 'Accept', name: 'Accept', label: 'Accept' }
|
|
21618
|
+
];
|
|
21619
|
+
const firstHeaderName = headerOptions.length > 0 ? headerOptions[0].value : '';
|
|
21674
21620
|
const headerGroup = this.fb.group({
|
|
21675
|
-
name: [
|
|
21621
|
+
name: [firstHeaderName, Validators.required],
|
|
21676
21622
|
value: ['', Validators.required]
|
|
21677
21623
|
});
|
|
21678
21624
|
this.headersFormArray.push(headerGroup);
|
|
@@ -21694,9 +21640,25 @@ class StepBuilderApiComponent {
|
|
|
21694
21640
|
// Reset config caches when inputs change
|
|
21695
21641
|
if (changes['httpMethodOptions']) {
|
|
21696
21642
|
this.httpMethodConfigCache = null;
|
|
21643
|
+
// Set method to first option if not already set or if we're not in edit mode
|
|
21644
|
+
if (!this.hasLoadedInitialData && this.httpMethodOptions.length > 0) {
|
|
21645
|
+
const methodControl = this.apiForm.get('method');
|
|
21646
|
+
if (methodControl && !methodControl.value) {
|
|
21647
|
+
methodControl.setValue(this.httpMethodOptions[0].value);
|
|
21648
|
+
}
|
|
21649
|
+
}
|
|
21697
21650
|
}
|
|
21698
21651
|
if (changes['headerNameOptions']) {
|
|
21699
21652
|
this.headerNameConfigCache = null;
|
|
21653
|
+
// Update header names to first option for empty headers (only if not in edit mode)
|
|
21654
|
+
if (!this.hasLoadedInitialData && this.headerNameOptions.length > 0) {
|
|
21655
|
+
this.headersFormArray.controls.forEach((headerGroup) => {
|
|
21656
|
+
const nameControl = headerGroup.get('name');
|
|
21657
|
+
if (nameControl && !nameControl.value) {
|
|
21658
|
+
nameControl.setValue(this.headerNameOptions[0].value);
|
|
21659
|
+
}
|
|
21660
|
+
});
|
|
21661
|
+
}
|
|
21700
21662
|
}
|
|
21701
21663
|
// Load initial data if it's set after component initialization
|
|
21702
21664
|
if (changes['initialData'] && !changes['initialData'].firstChange && this.initialData && !this.hasLoadedInitialData) {
|
|
@@ -21756,6 +21718,10 @@ class StepBuilderApiComponent {
|
|
|
21756
21718
|
this.selectedTab = tab;
|
|
21757
21719
|
}
|
|
21758
21720
|
onSendRequest() {
|
|
21721
|
+
this.formSubmitted = true;
|
|
21722
|
+
this.markFormGroupTouched(this.apiForm);
|
|
21723
|
+
console.log('onSendRequest: apiForm', this.apiForm.value);
|
|
21724
|
+
console.log('onSendRequest: apiForm valid', this.apiForm);
|
|
21759
21725
|
if (this.apiForm.valid) {
|
|
21760
21726
|
const formValue = this.apiForm.value;
|
|
21761
21727
|
const headers = formValue.headers.map((h) => ({
|
|
@@ -21782,6 +21748,8 @@ class StepBuilderApiComponent {
|
|
|
21782
21748
|
this.cancelled.emit();
|
|
21783
21749
|
}
|
|
21784
21750
|
onCreateStep() {
|
|
21751
|
+
this.formSubmitted = true;
|
|
21752
|
+
this.markFormGroupTouched(this.apiForm);
|
|
21785
21753
|
if (this.apiForm.valid) {
|
|
21786
21754
|
const formValue = this.apiForm.value;
|
|
21787
21755
|
const stepData = {
|
|
@@ -21995,12 +21963,64 @@ class StepBuilderApiComponent {
|
|
|
21995
21963
|
this.removeValidationRule(index);
|
|
21996
21964
|
});
|
|
21997
21965
|
}
|
|
21966
|
+
markFormGroupTouched(formGroup) {
|
|
21967
|
+
Object.keys(formGroup.controls).forEach(key => {
|
|
21968
|
+
const control = formGroup.get(key);
|
|
21969
|
+
if (control) {
|
|
21970
|
+
control.markAsTouched();
|
|
21971
|
+
if (control instanceof FormGroup) {
|
|
21972
|
+
this.markFormGroupTouched(control);
|
|
21973
|
+
}
|
|
21974
|
+
else if (control instanceof FormArray) {
|
|
21975
|
+
control.controls.forEach((ctrl) => {
|
|
21976
|
+
if (ctrl instanceof FormGroup) {
|
|
21977
|
+
this.markFormGroupTouched(ctrl);
|
|
21978
|
+
}
|
|
21979
|
+
else {
|
|
21980
|
+
ctrl.markAsTouched();
|
|
21981
|
+
}
|
|
21982
|
+
});
|
|
21983
|
+
}
|
|
21984
|
+
}
|
|
21985
|
+
});
|
|
21986
|
+
}
|
|
21987
|
+
onUrlChange(value) {
|
|
21988
|
+
const urlControl = this.apiForm.get('url');
|
|
21989
|
+
if (urlControl) {
|
|
21990
|
+
urlControl.setValue(value);
|
|
21991
|
+
urlControl.updateValueAndValidity();
|
|
21992
|
+
}
|
|
21993
|
+
}
|
|
21994
|
+
onUrlBlur() {
|
|
21995
|
+
const urlControl = this.apiForm.get('url');
|
|
21996
|
+
if (urlControl) {
|
|
21997
|
+
urlControl.markAsTouched();
|
|
21998
|
+
}
|
|
21999
|
+
}
|
|
22000
|
+
getUrlErrors() {
|
|
22001
|
+
var _a, _b, _c;
|
|
22002
|
+
const urlControl = this.apiForm.get('url');
|
|
22003
|
+
if (!urlControl || (!this.formSubmitted && !urlControl.touched)) {
|
|
22004
|
+
return [];
|
|
22005
|
+
}
|
|
22006
|
+
const errors = [];
|
|
22007
|
+
if ((_a = urlControl.errors) === null || _a === void 0 ? void 0 : _a['required']) {
|
|
22008
|
+
errors.push('URL is required');
|
|
22009
|
+
}
|
|
22010
|
+
else if ((_b = urlControl.errors) === null || _b === void 0 ? void 0 : _b['pattern']) {
|
|
22011
|
+
errors.push('URL is not valid');
|
|
22012
|
+
}
|
|
22013
|
+
else if ((_c = urlControl.errors) === null || _c === void 0 ? void 0 : _c['hasParameter']) {
|
|
22014
|
+
errors.push('URL format is invalid. Please check the parameter format.');
|
|
22015
|
+
}
|
|
22016
|
+
return errors;
|
|
22017
|
+
}
|
|
21998
22018
|
}
|
|
21999
22019
|
StepBuilderApiComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderApiComponent, deps: [{ token: i2$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
22000
|
-
StepBuilderApiComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderApiComponent, selector: "cqa-step-builder-api", inputs: { httpMethodOptions: "httpMethodOptions", headerNameOptions: "headerNameOptions", currentStep: "currentStep", responsePreview: "responsePreview", isLoading: "isLoading", initialData: "initialData" }, outputs: { createStep: "createStep", cancelled: "cancelled", sendRequest: "sendRequest", importCurl: "importCurl" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div\n class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div>1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div>2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div>3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-6\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('url')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle", "customClass"], outputs: ["valueChange", "blurred", "focused"] }, { type: i3$3.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
22020
|
+
StepBuilderApiComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderApiComponent, selector: "cqa-step-builder-api", inputs: { httpMethodOptions: "httpMethodOptions", headerNameOptions: "headerNameOptions", currentStep: "currentStep", responsePreview: "responsePreview", isLoading: "isLoading", initialData: "initialData" }, outputs: { createStep: "createStep", cancelled: "cancelled", sendRequest: "sendRequest", importCurl: "importCurl" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div class=\"cqa-flex cqa-items-center cqa-w-full cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-mb-3\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n [errors]=\"getUrlErrors()\"\n (valueChange)=\"onUrlChange($event)\"\n (blurred)=\"onUrlBlur()\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name*</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value*</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", components: [{ type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle", "customClass"], outputs: ["valueChange", "blurred", "focused"] }, { type: i3$3.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
22001
22021
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderApiComponent, decorators: [{
|
|
22002
22022
|
type: Component,
|
|
22003
|
-
args: [{ selector: 'cqa-step-builder-api', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div\n class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div>1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div>2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div>3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2 cqa-mb-6\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('url')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", styles: [] }]
|
|
22023
|
+
args: [{ selector: 'cqa-step-builder-api', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div class=\"cqa-flex cqa-items-center cqa-w-full cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-mb-3\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n [errors]=\"getUrlErrors()\"\n (valueChange)=\"onUrlChange($event)\"\n (blurred)=\"onUrlBlur()\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name*</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value*</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", styles: [] }]
|
|
22004
22024
|
}], ctorParameters: function () { return [{ type: i2$1.FormBuilder }]; }, propDecorators: { httpMethodOptions: [{
|
|
22005
22025
|
type: Input
|
|
22006
22026
|
}], headerNameOptions: [{
|