@cqa-lib/cqa-ui 1.1.225 → 1.1.227
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/simulator/simulator.component.mjs +28 -45
- package/esm2020/lib/step-builder/step-builder-action/step-builder-action.component.mjs +267 -44
- package/esm2020/lib/step-builder/step-builder-condition/step-builder-condition.component.mjs +183 -41
- package/esm2020/lib/step-builder/step-builder-loop/step-builder-loop.component.mjs +44 -3
- package/esm2020/lib/step-builder/template-variables-form/template-variables-form.component.mjs +218 -57
- package/esm2020/lib/test-case-details/element-popup/element-form/element-form.component.mjs +277 -0
- package/esm2020/lib/test-case-details/element-popup/element-popup.component.mjs +32 -192
- package/esm2020/lib/ui-kit.module.mjs +6 -1
- package/esm2020/public-api.mjs +2 -1
- package/fesm2015/cqa-lib-cqa-ui.mjs +1118 -444
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +1103 -440
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/step-builder/step-builder-action/step-builder-action.component.d.ts +50 -4
- package/lib/step-builder/step-builder-condition/step-builder-condition.component.d.ts +39 -2
- package/lib/step-builder/step-builder-loop/step-builder-loop.component.d.ts +17 -1
- package/lib/step-builder/template-variables-form/template-variables-form.component.d.ts +56 -5
- package/lib/test-case-details/element-popup/element-form/element-form.component.d.ts +77 -0
- package/lib/test-case-details/element-popup/element-popup.component.d.ts +13 -32
- package/lib/ui-kit.module.d.ts +42 -41
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
- 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 i1$1 from '@angular/forms';
|
|
6
|
-
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, Validators, FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, Validators, FormBuilder, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
7
7
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|
8
8
|
import * as i1 from '@angular/material/icon';
|
|
9
9
|
import { MatIconModule } from '@angular/material/icon';
|
|
@@ -15003,12 +15003,11 @@ class SimulatorComponent {
|
|
|
15003
15003
|
this.playerState = 'paused';
|
|
15004
15004
|
this.videoPause.emit();
|
|
15005
15005
|
this.isVideoPlayingChange.emit(false);
|
|
15006
|
-
// Switch to next video and
|
|
15006
|
+
// Switch to next video and auto-play it
|
|
15007
15007
|
if (this.hasMultipleVideos && this.videoUrls && this.currentVideoIndex < this.videoUrls.length - 1) {
|
|
15008
|
-
this.currentVideoIndex
|
|
15008
|
+
const nextIndex = this.currentVideoIndex + 1;
|
|
15009
15009
|
this.enqueueOperation(async () => {
|
|
15010
|
-
await this.
|
|
15011
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
15010
|
+
await this.switchToVideoAndResetInternal(nextIndex);
|
|
15012
15011
|
if (this.vplayer?.nativeElement && this.currentVideoUrl) {
|
|
15013
15012
|
await this.playVideoInternal();
|
|
15014
15013
|
}
|
|
@@ -15518,31 +15517,23 @@ class SimulatorComponent {
|
|
|
15518
15517
|
this.playPromise = null;
|
|
15519
15518
|
this.videoPause.emit();
|
|
15520
15519
|
this.isVideoPlayingChange.emit(false);
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
if (resolved)
|
|
15520
|
+
const metadataLoaded = new Promise((resolve, reject) => {
|
|
15521
|
+
let settled = false;
|
|
15522
|
+
const settle = (fn) => {
|
|
15523
|
+
if (settled)
|
|
15526
15524
|
return;
|
|
15527
|
-
|
|
15525
|
+
settled = true;
|
|
15528
15526
|
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
15529
15527
|
video.removeEventListener('error', onError);
|
|
15528
|
+
fn();
|
|
15530
15529
|
};
|
|
15531
|
-
const onLoadedMetadata = () =>
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
};
|
|
15535
|
-
const onError = () => {
|
|
15536
|
-
cleanup();
|
|
15537
|
-
reject(new Error('Failed to load video'));
|
|
15538
|
-
};
|
|
15539
|
-
setTimeout(() => {
|
|
15540
|
-
if (resolved)
|
|
15541
|
-
return;
|
|
15542
|
-
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
15543
|
-
video.addEventListener('error', onError, { once: true });
|
|
15544
|
-
}, 100);
|
|
15530
|
+
const onLoadedMetadata = () => settle(resolve);
|
|
15531
|
+
const onError = () => settle(() => reject(new Error('Failed to load video')));
|
|
15532
|
+
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
15533
|
+
video.addEventListener('error', onError, { once: true });
|
|
15545
15534
|
});
|
|
15535
|
+
this.currentVideoIndex = targetVideoIndex;
|
|
15536
|
+
await metadataLoaded;
|
|
15546
15537
|
video.currentTime = 0;
|
|
15547
15538
|
this.progress = 0;
|
|
15548
15539
|
this.playPromise = null;
|
|
@@ -15590,31 +15581,23 @@ class SimulatorComponent {
|
|
|
15590
15581
|
this.playPromise = null;
|
|
15591
15582
|
this.videoPause.emit();
|
|
15592
15583
|
this.isVideoPlayingChange.emit(false);
|
|
15593
|
-
|
|
15594
|
-
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
if (resolved)
|
|
15584
|
+
const metadataLoaded = new Promise((resolve, reject) => {
|
|
15585
|
+
let settled = false;
|
|
15586
|
+
const settle = (fn) => {
|
|
15587
|
+
if (settled)
|
|
15598
15588
|
return;
|
|
15599
|
-
|
|
15589
|
+
settled = true;
|
|
15600
15590
|
video.removeEventListener('loadedmetadata', onLoadedMetadata);
|
|
15601
15591
|
video.removeEventListener('error', onError);
|
|
15592
|
+
fn();
|
|
15602
15593
|
};
|
|
15603
|
-
const onLoadedMetadata = () =>
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
};
|
|
15607
|
-
const onError = () => {
|
|
15608
|
-
cleanup();
|
|
15609
|
-
reject(new Error('Failed to load video'));
|
|
15610
|
-
};
|
|
15611
|
-
setTimeout(() => {
|
|
15612
|
-
if (resolved)
|
|
15613
|
-
return;
|
|
15614
|
-
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
15615
|
-
video.addEventListener('error', onError, { once: true });
|
|
15616
|
-
}, 100);
|
|
15594
|
+
const onLoadedMetadata = () => settle(resolve);
|
|
15595
|
+
const onError = () => settle(() => reject(new Error('Failed to load video')));
|
|
15596
|
+
video.addEventListener('loadedmetadata', onLoadedMetadata, { once: true });
|
|
15597
|
+
video.addEventListener('error', onError, { once: true });
|
|
15617
15598
|
});
|
|
15599
|
+
this.currentVideoIndex = targetVideoIndex;
|
|
15600
|
+
await metadataLoaded;
|
|
15618
15601
|
const seekSeconds = relativeTimestamp / 1000;
|
|
15619
15602
|
const targetTime = Math.max(0, Math.min(seekSeconds, video.duration || seekSeconds));
|
|
15620
15603
|
await new Promise((resolve) => {
|
|
@@ -18472,146 +18455,25 @@ class ElementPopupRef {
|
|
|
18472
18455
|
}
|
|
18473
18456
|
const CUSTOM_ELEMENT_POPUP_REF = new InjectionToken('CUSTOM_ELEMENT_POPUP_REF');
|
|
18474
18457
|
|
|
18475
|
-
class
|
|
18476
|
-
constructor() {
|
|
18477
|
-
/** Array of items to display */
|
|
18478
|
-
this.items = [];
|
|
18479
|
-
/** Key to access the title property from each item (default: 'title') */
|
|
18480
|
-
this.titleKey = 'title';
|
|
18481
|
-
/** Key to access the selector property from each item (default: 'selector') */
|
|
18482
|
-
this.selectorKey = 'selector';
|
|
18483
|
-
/** Key to access the labels array from each item (default: 'labels') */
|
|
18484
|
-
this.labelsKey = 'labels';
|
|
18485
|
-
/** Maximum height for the scrollable container (default: '200px') */
|
|
18486
|
-
this.maxHeight = '200px';
|
|
18487
|
-
/** Whether more items can be loaded */
|
|
18488
|
-
this.hasMore = false;
|
|
18489
|
-
/** Emitted when an item is clicked */
|
|
18490
|
-
this.itemClick = new EventEmitter();
|
|
18491
|
-
/** Emitted when user scrolls near the bottom and more items should be loaded */
|
|
18492
|
-
this.loadMore = new EventEmitter();
|
|
18493
|
-
/** Skip the first intersection callback (fires immediately when observe() is called) to prevent duplicate API calls on load */
|
|
18494
|
-
this.skipNextIntersection = false;
|
|
18495
|
-
}
|
|
18496
|
-
/**
|
|
18497
|
-
* Get the value from an item using the specified key
|
|
18498
|
-
*/
|
|
18499
|
-
getItemValue(item, key) {
|
|
18500
|
-
return item?.[key];
|
|
18501
|
-
}
|
|
18502
|
-
/**
|
|
18503
|
-
* Handle item click
|
|
18504
|
-
*/
|
|
18505
|
-
onItemClick(item) {
|
|
18506
|
-
this.itemClick.emit(item);
|
|
18507
|
-
}
|
|
18508
|
-
ngAfterViewInit() {
|
|
18509
|
-
if (this.hasMore) {
|
|
18510
|
-
setTimeout(() => this.setupScrollObserver(), 0);
|
|
18511
|
-
}
|
|
18512
|
-
}
|
|
18513
|
-
ngOnChanges(changes) {
|
|
18514
|
-
if (changes['hasMore'] && this.hasMore && this.scrollContainer) {
|
|
18515
|
-
setTimeout(() => this.setupScrollObserver(), 0);
|
|
18516
|
-
}
|
|
18517
|
-
}
|
|
18518
|
-
ngOnDestroy() {
|
|
18519
|
-
if (this.scrollObserver) {
|
|
18520
|
-
this.scrollObserver.disconnect();
|
|
18521
|
-
}
|
|
18522
|
-
}
|
|
18523
|
-
setupScrollObserver() {
|
|
18524
|
-
if (!this.hasMore || !this.scrollContainer) {
|
|
18525
|
-
return;
|
|
18526
|
-
}
|
|
18527
|
-
// Find the sentinel element (loading indicator)
|
|
18528
|
-
const sentinel = this.scrollContainer.nativeElement.querySelector('.load-more-sentinel');
|
|
18529
|
-
if (!sentinel) {
|
|
18530
|
-
return;
|
|
18531
|
-
}
|
|
18532
|
-
// Disconnect existing observer if any
|
|
18533
|
-
if (this.scrollObserver) {
|
|
18534
|
-
this.scrollObserver.disconnect();
|
|
18535
|
-
}
|
|
18536
|
-
// Skip the first intersection callback - it fires immediately when observe() is called
|
|
18537
|
-
// if the sentinel is already in view, causing duplicate API calls (page 0 + page 1) on load
|
|
18538
|
-
this.skipNextIntersection = true;
|
|
18539
|
-
// Create IntersectionObserver to detect when sentinel comes into view
|
|
18540
|
-
this.scrollObserver = new IntersectionObserver((entries) => {
|
|
18541
|
-
for (const entry of entries) {
|
|
18542
|
-
if (entry.isIntersecting && this.hasMore) {
|
|
18543
|
-
if (this.skipNextIntersection) {
|
|
18544
|
-
this.skipNextIntersection = false;
|
|
18545
|
-
return;
|
|
18546
|
-
}
|
|
18547
|
-
this.loadMore.emit();
|
|
18548
|
-
}
|
|
18549
|
-
}
|
|
18550
|
-
}, {
|
|
18551
|
-
root: this.scrollContainer.nativeElement,
|
|
18552
|
-
rootMargin: '50px',
|
|
18553
|
-
threshold: 0.1
|
|
18554
|
-
});
|
|
18555
|
-
this.scrollObserver.observe(sentinel);
|
|
18556
|
-
}
|
|
18557
|
-
}
|
|
18558
|
-
ElementListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18559
|
-
ElementListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ElementListComponent, selector: "cqa-element-list", inputs: { items: "items", titleKey: "titleKey", selectorKey: "selectorKey", labelsKey: "labelsKey", maxHeight: "maxHeight", hasMore: "hasMore" }, outputs: { itemClick: "itemClick", loadMore: "loadMore" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div \n #scrollContainer\n class=\"cqa-max-h-[200px] cqa-overflow-y-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB] cqa-flex cqa-flex-col cqa-gap-2\"\n [style.max-height]=\"maxHeight\">\n <div *ngFor=\"let item of items\" (click)=\"onItemClick(item)\">\n <div class=\"hover:cqa-bg-[#F5F5F5] cqa-flex cqa-items-center cqa-justify-between cqa-border cqa-border-[#FDE68A]\n cqa-rounded-lg cqa-p-3 cqa-cursor-pointer cqa-gap-1\" style=\"word-break: break-word;\">\n <div>\n <h6 class=\"cqa-text-[12px] cqa-leading-[100%] cqa-font-[400] cqa-text-[#171717]\">\n {{ getItemValue(item, titleKey) }}\n </h6>\n <span class=\"cqa-text-[10px] cqa-leading-[100%] cqa-text-[#6B7280]\">\n {{ getItemValue(item, selectorKey) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-gap-1\">\n <span \n *ngFor=\"let tag of getItemValue(item, labelsKey)\" \n class=\"cqa-text-[11px] cqa-text-[#4b74ec] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{ tag }}\n </span>\n </div>\n </div>\n </div>\n <!-- No elements found message -->\n <div *ngIf=\"items.length === 0 && !hasMore\" class=\"cqa-flex cqa-justify-center cqa-items-center cqa-py-4 cqa-text-[12px] cqa-text-[#6B7280]\">\n No elements found\n </div>\n <!-- Sentinel element for infinite scroll -->\n <div *ngIf=\"hasMore\" class=\"load-more-sentinel cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-2\">\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-[12px] cqa-text-[#6B7280]\">{{ items.length === 0 ? 'Loading...' : 'Loading more...' }}</span>\n </div>\n</div>\n\n", directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18560
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementListComponent, decorators: [{
|
|
18561
|
-
type: Component,
|
|
18562
|
-
args: [{ selector: 'cqa-element-list', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n #scrollContainer\n class=\"cqa-max-h-[200px] cqa-overflow-y-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB] cqa-flex cqa-flex-col cqa-gap-2\"\n [style.max-height]=\"maxHeight\">\n <div *ngFor=\"let item of items\" (click)=\"onItemClick(item)\">\n <div class=\"hover:cqa-bg-[#F5F5F5] cqa-flex cqa-items-center cqa-justify-between cqa-border cqa-border-[#FDE68A]\n cqa-rounded-lg cqa-p-3 cqa-cursor-pointer cqa-gap-1\" style=\"word-break: break-word;\">\n <div>\n <h6 class=\"cqa-text-[12px] cqa-leading-[100%] cqa-font-[400] cqa-text-[#171717]\">\n {{ getItemValue(item, titleKey) }}\n </h6>\n <span class=\"cqa-text-[10px] cqa-leading-[100%] cqa-text-[#6B7280]\">\n {{ getItemValue(item, selectorKey) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-gap-1\">\n <span \n *ngFor=\"let tag of getItemValue(item, labelsKey)\" \n class=\"cqa-text-[11px] cqa-text-[#4b74ec] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{ tag }}\n </span>\n </div>\n </div>\n </div>\n <!-- No elements found message -->\n <div *ngIf=\"items.length === 0 && !hasMore\" class=\"cqa-flex cqa-justify-center cqa-items-center cqa-py-4 cqa-text-[12px] cqa-text-[#6B7280]\">\n No elements found\n </div>\n <!-- Sentinel element for infinite scroll -->\n <div *ngIf=\"hasMore\" class=\"load-more-sentinel cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-2\">\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-[12px] cqa-text-[#6B7280]\">{{ items.length === 0 ? 'Loading...' : 'Loading more...' }}</span>\n </div>\n</div>\n\n" }]
|
|
18563
|
-
}], propDecorators: { scrollContainer: [{
|
|
18564
|
-
type: ViewChild,
|
|
18565
|
-
args: ['scrollContainer', { static: false }]
|
|
18566
|
-
}], items: [{
|
|
18567
|
-
type: Input
|
|
18568
|
-
}], titleKey: [{
|
|
18569
|
-
type: Input
|
|
18570
|
-
}], selectorKey: [{
|
|
18571
|
-
type: Input
|
|
18572
|
-
}], labelsKey: [{
|
|
18573
|
-
type: Input
|
|
18574
|
-
}], maxHeight: [{
|
|
18575
|
-
type: Input
|
|
18576
|
-
}], hasMore: [{
|
|
18577
|
-
type: Input
|
|
18578
|
-
}], itemClick: [{
|
|
18579
|
-
type: Output
|
|
18580
|
-
}], loadMore: [{
|
|
18581
|
-
type: Output
|
|
18582
|
-
}] } });
|
|
18583
|
-
|
|
18584
|
-
class ElementPopupComponent {
|
|
18585
|
-
constructor(ref, data, fb, cdr) {
|
|
18586
|
-
this.ref = ref;
|
|
18458
|
+
class ElementFormComponent {
|
|
18459
|
+
constructor(fb, cdr) {
|
|
18587
18460
|
this.cdr = cdr;
|
|
18588
|
-
|
|
18589
|
-
this.helpUrl = '';
|
|
18590
|
-
this.labels = [];
|
|
18461
|
+
/** Current element data (for edit mode) */
|
|
18591
18462
|
this.element = { title: '', selector: '', labels: [] };
|
|
18592
|
-
this.elements = [];
|
|
18593
|
-
this.enableForm = false;
|
|
18594
|
-
this.isOnRecord = false;
|
|
18595
|
-
this.hasMoreElements = false;
|
|
18596
18463
|
/** Screen name options for autocomplete (from API) */
|
|
18597
18464
|
this.screenNameOptions = [];
|
|
18598
18465
|
/** Whether more screen names are available for infinite scroll */
|
|
18599
18466
|
this.hasMoreScreenNames = false;
|
|
18600
18467
|
/** True while parent is loading screen names (search or load more) */
|
|
18601
18468
|
this.isLoadingScreenNames = false;
|
|
18602
|
-
/** Suggested tags from API for labels field */
|
|
18603
|
-
this.suggestedTags = [];
|
|
18604
18469
|
/** True while parent is fetching latest element data for edit (shows loading state) */
|
|
18605
18470
|
this.isElementLoading = false;
|
|
18606
|
-
/**
|
|
18607
|
-
this.
|
|
18608
|
-
|
|
18609
|
-
this.
|
|
18610
|
-
|
|
18611
|
-
this.
|
|
18612
|
-
/** Emitted when user clicks on a recent searched item */
|
|
18613
|
-
this.recentItemClick = new EventEmitter();
|
|
18614
|
-
this.loadMoreElements = new EventEmitter();
|
|
18471
|
+
/** Whether we're in edit mode */
|
|
18472
|
+
this.isEditMode = false;
|
|
18473
|
+
/** Whether we're in create mode */
|
|
18474
|
+
this.isCreateMode = false;
|
|
18475
|
+
/** Whether edit in depth is available */
|
|
18476
|
+
this.isEditInDepthAvailable = true;
|
|
18615
18477
|
/** Emitted when user creates a new element (parent should call API) */
|
|
18616
18478
|
this.createElement = new EventEmitter();
|
|
18617
18479
|
/** Emitted when user updates an element (parent should call API) */
|
|
@@ -18622,26 +18484,16 @@ class ElementPopupComponent {
|
|
|
18622
18484
|
this.searchScreenName = new EventEmitter();
|
|
18623
18485
|
/** Emitted when user scrolls to load more screen names (passes current search query) */
|
|
18624
18486
|
this.loadMoreScreenNames = new EventEmitter();
|
|
18625
|
-
/** Emitted when
|
|
18626
|
-
this.
|
|
18627
|
-
/** Emitted when user
|
|
18628
|
-
this.
|
|
18629
|
-
/** Emitted when user clicks Record - parent should check extension and call installPlugin or openSidePanelAndListSteps */
|
|
18630
|
-
this.toggleRecord = new EventEmitter();
|
|
18631
|
-
this.helpTooltipText = 'Not sure what to do? Click to go to our detailed step creation documentation';
|
|
18632
|
-
this.showHelpTooltip = false;
|
|
18633
|
-
this.isEditMode = false;
|
|
18634
|
-
/** Whether we're in create mode (no elementId) */
|
|
18635
|
-
this.isCreateMode = false;
|
|
18487
|
+
/** Emitted when user clicks "Select from Element list" or "Cancel" */
|
|
18488
|
+
this.cancel = new EventEmitter();
|
|
18489
|
+
/** Emitted when user clicks "Edit in depth" */
|
|
18490
|
+
this.editInDepth = new EventEmitter();
|
|
18636
18491
|
/** Labels (tags) as string array for multi-tag input */
|
|
18637
18492
|
this.formLabels = [];
|
|
18638
18493
|
/** Current tag input value */
|
|
18639
18494
|
this.tagInputValue = '';
|
|
18640
|
-
/** Current search input value (bound to search bar) */
|
|
18641
|
-
this.searchValue = '';
|
|
18642
18495
|
/** Whether we're saving (disable buttons) */
|
|
18643
18496
|
this.saving = false;
|
|
18644
|
-
this.injectedData = data;
|
|
18645
18497
|
this.fb = fb || new FormBuilder();
|
|
18646
18498
|
this.initializeForm();
|
|
18647
18499
|
}
|
|
@@ -18649,30 +18501,19 @@ class ElementPopupComponent {
|
|
|
18649
18501
|
if (changes['screenNameOptions'] || changes['hasMoreScreenNames'] || changes['isLoadingScreenNames']) {
|
|
18650
18502
|
this.updateScreenNameSelectConfig();
|
|
18651
18503
|
}
|
|
18652
|
-
if ((changes['element'] || changes['elementId']) && this.
|
|
18653
|
-
|
|
18654
|
-
|
|
18655
|
-
|
|
18656
|
-
|
|
18657
|
-
else {
|
|
18658
|
-
this.isCreateMode = true;
|
|
18659
|
-
this.isEditMode = false;
|
|
18660
|
-
}
|
|
18504
|
+
if ((changes['element'] || changes['elementId']) && this.elementId) {
|
|
18505
|
+
this.populateFormForEdit();
|
|
18506
|
+
}
|
|
18507
|
+
else if (changes['element'] && !this.elementId && this.isCreateMode) {
|
|
18508
|
+
this.populateFormForCreateWithElement();
|
|
18661
18509
|
}
|
|
18662
18510
|
}
|
|
18663
18511
|
ngOnInit() {
|
|
18664
|
-
if (this.
|
|
18665
|
-
|
|
18666
|
-
|
|
18667
|
-
|
|
18668
|
-
|
|
18669
|
-
if (this.labels.length === 0)
|
|
18670
|
-
this.labels = this.injectedData.labels ?? [];
|
|
18671
|
-
if (this.elements.length === 0)
|
|
18672
|
-
this.elements = this.injectedData.elements ?? [];
|
|
18673
|
-
if (!this.element || !this.element.title) {
|
|
18674
|
-
this.element = this.injectedData.element ?? { title: '', selector: '', labels: [] };
|
|
18675
|
-
}
|
|
18512
|
+
if (this.elementId) {
|
|
18513
|
+
this.populateFormForEdit();
|
|
18514
|
+
}
|
|
18515
|
+
else if (this.isCreateMode && this.element) {
|
|
18516
|
+
this.populateFormForCreateWithElement();
|
|
18676
18517
|
}
|
|
18677
18518
|
}
|
|
18678
18519
|
initializeForm() {
|
|
@@ -18755,18 +18596,6 @@ class ElementPopupComponent {
|
|
|
18755
18596
|
}
|
|
18756
18597
|
this.cdr?.markForCheck();
|
|
18757
18598
|
}
|
|
18758
|
-
resetForm() {
|
|
18759
|
-
this.isEditMode = false;
|
|
18760
|
-
this.isCreateMode = false;
|
|
18761
|
-
this.formLabels = [];
|
|
18762
|
-
this.tagInputValue = '';
|
|
18763
|
-
this.form.reset({
|
|
18764
|
-
name: '',
|
|
18765
|
-
screenNameId: null,
|
|
18766
|
-
value: '',
|
|
18767
|
-
});
|
|
18768
|
-
this.updateScreenNameSelectConfig();
|
|
18769
|
-
}
|
|
18770
18599
|
/** Called by parent when a new screen name was created (so we can set the selected value) */
|
|
18771
18600
|
setCreatedScreenName(opt) {
|
|
18772
18601
|
this.form.get('screenNameId')?.setValue(opt.id);
|
|
@@ -18808,60 +18637,349 @@ class ElementPopupComponent {
|
|
|
18808
18637
|
}
|
|
18809
18638
|
onCreateOrUpdateSuccess() {
|
|
18810
18639
|
this.saving = false;
|
|
18811
|
-
this.enableForm = false;
|
|
18812
|
-
this.resetForm();
|
|
18813
18640
|
this.cdr?.markForCheck();
|
|
18814
18641
|
}
|
|
18815
18642
|
onCreateOrUpdateError() {
|
|
18816
18643
|
this.saving = false;
|
|
18817
18644
|
this.cdr?.markForCheck();
|
|
18818
18645
|
}
|
|
18819
|
-
|
|
18820
|
-
|
|
18821
|
-
// If no elementId, go to create mode instead of edit mode
|
|
18822
|
-
if (!this.elementId) {
|
|
18823
|
-
this.isCreateMode = true;
|
|
18824
|
-
this.isEditMode = false;
|
|
18825
|
-
// Patch form with current element values when Edit clicked without elementId
|
|
18826
|
-
this.populateFormForCreateWithElement();
|
|
18827
|
-
this.formOpenRequest.emit({ mode: 'create' });
|
|
18828
|
-
}
|
|
18829
|
-
else {
|
|
18830
|
-
// Has elementId, go to edit mode
|
|
18831
|
-
this.isCreateMode = false;
|
|
18832
|
-
this.isEditMode = true;
|
|
18833
|
-
this.formOpenRequest.emit({ mode: 'edit', elementId: this.elementId });
|
|
18834
|
-
}
|
|
18835
|
-
}
|
|
18836
|
-
else {
|
|
18837
|
-
// Closing form - reset everything
|
|
18838
|
-
// If in create mode, reset labels when going back to element list
|
|
18839
|
-
if (this.isCreateMode) {
|
|
18840
|
-
this.labels = [];
|
|
18841
|
-
}
|
|
18842
|
-
this.resetForm();
|
|
18843
|
-
this.isCreateMode = false;
|
|
18844
|
-
}
|
|
18845
|
-
this.enableForm = !this.enableForm;
|
|
18846
|
-
this.cdr?.markForCheck();
|
|
18646
|
+
onCancel() {
|
|
18647
|
+
this.cancel.emit();
|
|
18847
18648
|
}
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
this.
|
|
18851
|
-
this.resetForm();
|
|
18852
|
-
this.enableForm = true;
|
|
18853
|
-
this.formOpenRequest.emit({ mode: 'create' });
|
|
18854
|
-
this.cdr?.markForCheck();
|
|
18649
|
+
onEditInDepth(event) {
|
|
18650
|
+
event.preventDefault();
|
|
18651
|
+
this.editInDepth.emit();
|
|
18855
18652
|
}
|
|
18856
|
-
|
|
18857
|
-
this.
|
|
18653
|
+
getFormControl(controlName) {
|
|
18654
|
+
return this.form.get(controlName);
|
|
18858
18655
|
}
|
|
18859
|
-
|
|
18860
|
-
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
|
|
18864
|
-
|
|
18656
|
+
getFormControlValue(controlName) {
|
|
18657
|
+
return this.form.get(controlName)?.value || '';
|
|
18658
|
+
}
|
|
18659
|
+
onFormControlChange(controlName, value) {
|
|
18660
|
+
this.form.patchValue({ [controlName]: value });
|
|
18661
|
+
this.cdr?.markForCheck();
|
|
18662
|
+
}
|
|
18663
|
+
/** Add a tag (label) */
|
|
18664
|
+
addTag(tag) {
|
|
18665
|
+
const t = (tag || this.tagInputValue || '').trim();
|
|
18666
|
+
if (t && !this.formLabels.includes(t)) {
|
|
18667
|
+
this.formLabels = [...this.formLabels, t];
|
|
18668
|
+
this.tagInputValue = '';
|
|
18669
|
+
this.cdr?.markForCheck();
|
|
18670
|
+
}
|
|
18671
|
+
}
|
|
18672
|
+
removeTag(tag) {
|
|
18673
|
+
this.formLabels = this.formLabels.filter((l) => l !== tag);
|
|
18674
|
+
this.cdr?.markForCheck();
|
|
18675
|
+
}
|
|
18676
|
+
onTagInputKeydown(event) {
|
|
18677
|
+
if (event.key === 'Enter' || event.key === ',') {
|
|
18678
|
+
event.preventDefault();
|
|
18679
|
+
this.addTag();
|
|
18680
|
+
}
|
|
18681
|
+
}
|
|
18682
|
+
}
|
|
18683
|
+
ElementFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementFormComponent, deps: [{ token: i1$1.FormBuilder, optional: true }, { token: i0.ChangeDetectorRef, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
18684
|
+
ElementFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ElementFormComponent, selector: "cqa-element-form", inputs: { elementId: "elementId", element: "element", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames", isElementLoading: "isElementLoading", isEditMode: "isEditMode", isCreateMode: "isCreateMode", isEditInDepthAvailable: "isEditInDepthAvailable" }, outputs: { createElement: "createElement", updateElement: "updateElement", createScreenNameRequest: "createScreenNameRequest", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", cancel: "cancel", editInDepth: "editInDepth" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n <div *ngIf=\"isElementLoading && isEditMode\" class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-8\">\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 element data...</span>\n </div>\n <div *ngIf=\"!isElementLoading\" class=\"cqa-flex cqa-gap-1.5\">\n <cqa-custom-input \n class=\"cqa-w-1/2\" \n label=\"Name\" \n placeholder=\"default-element\"\n [value]=\"getFormControlValue('name')\"\n [errors]=\"getFormControl('name')?.touched && getFormControl('name')?.invalid ? ['Name is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('name', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-1/2\">\n <cqa-dynamic-select [form]=\"form\" [config]=\"screenNameSelectConfig\"\n (addCustomValue)=\"createScreenNameRequest.emit($event.value)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n <div *ngIf=\"getFormControl('screenNameId')?.touched && getFormControl('screenNameId')?.invalid\" class=\"cqa-flex cqa-flex-col cqa-gap-1 cqa-mt-1.5\">\n <div class=\"cqa-flex cqa-items-start cqa-gap-1.5\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n class=\"cqa-flex-shrink-0 cqa-mt-0.5\">\n <path d=\"M7 1.75C4.1 1.75 1.75 4.1 1.75 7C1.75 9.9 4.1 12.25 7 12.25C9.9 12.25 12.25 9.9 12.25 7C12.25 4.1 9.9 1.75 7 1.75ZM7 9.625C6.65625 9.625 6.375 9.34375 6.375 9V7C6.375 6.65625 6.65625 6.375 7 6.375C7.34375 6.375 7.625 6.65625 7.625 7V9C7.625 9.34375 7.34375 9.625 7 9.625ZM7.625 5.25H6.375V4H7.625V5.25Z\" fill=\"#EF4444\"/>\n </svg>\n <span class=\"cqa-text-xs cqa-text-[#EF4444] cqa-font-medium cqa-leading-[18px]\">\n Screen Name is required\n </span>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"!isElementLoading\">\n <cqa-custom-input \n class=\"cqa-w-full\" \n label=\"Enter Value\" \n placeholder=\"#default_id or xpath\"\n [value]=\"getFormControlValue('value')\"\n [errors]=\"getFormControl('value')?.touched && getFormControl('value')?.invalid ? ['Value is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('value', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-full\">\n <label class=\"cqa-block cqa-text-[14px] cqa-font-medium cqa-text-[#374151] cqa-mb-1\">Labels (tags)</label>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2 cqa-p-2 cqa-border cqa-border-solid cqa-border-gray-200 cqa-rounded-md cqa-min-h-[42px]\">\n <span *ngFor=\"let tag of formLabels\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-2 cqa-py-1 cqa-bg-[#eff6ff] cqa-border cqa-border-[#c8e0ff] cqa-rounded-full cqa-text-[12px] cqa-text-[#3F43EE]\">\n {{ tag }}\n <button type=\"button\" (click)=\"removeTag(tag)\" class=\"cqa-p-0.5 hover:cqa-bg-[#c8e0ff] cqa-rounded cqa-cursor-pointer cqa-h-[16px] cqa-w-[16px]\">\n <mat-icon class=\"!cqa-w-3 !cqa-h-3 !cqa-text-[14px]\">close</mat-icon>\n </button>\n </span>\n <input type=\"text\"\n class=\"cqa-flex-1 cqa-min-w-[120px] cqa-px-2 cqa-py-1 cqa-text-sm cqa-border-0 cqa-outline-none cqa-bg-transparent\"\n placeholder=\"Type and press Enter to add\"\n [(ngModel)]=\"tagInputValue\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTag()\"\n [ngModelOptions]=\"{standalone: true}\">\n </div>\n </div>\n\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]=\"(elementId ? 'Cancel' : 'Select from Element list')\" [fullWidth]=\"true\" (clicked)=\"onCancel()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"saving ? 'Saving...' : (isEditMode ? 'Update' : 'Create')\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#3F43EE]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n </div>\n </div>\n <a href=\"#\" *ngIf=\"isEditInDepthAvailable\" (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 </ng-container>\n</div>\n\n\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", "addCustomValue"] }, { type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementFormComponent, decorators: [{
|
|
18686
|
+
type: Component,
|
|
18687
|
+
args: [{ selector: 'cqa-element-form', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n <div *ngIf=\"isElementLoading && isEditMode\" class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-8\">\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 element data...</span>\n </div>\n <div *ngIf=\"!isElementLoading\" class=\"cqa-flex cqa-gap-1.5\">\n <cqa-custom-input \n class=\"cqa-w-1/2\" \n label=\"Name\" \n placeholder=\"default-element\"\n [value]=\"getFormControlValue('name')\"\n [errors]=\"getFormControl('name')?.touched && getFormControl('name')?.invalid ? ['Name is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('name', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-1/2\">\n <cqa-dynamic-select [form]=\"form\" [config]=\"screenNameSelectConfig\"\n (addCustomValue)=\"createScreenNameRequest.emit($event.value)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n <div *ngIf=\"getFormControl('screenNameId')?.touched && getFormControl('screenNameId')?.invalid\" class=\"cqa-flex cqa-flex-col cqa-gap-1 cqa-mt-1.5\">\n <div class=\"cqa-flex cqa-items-start cqa-gap-1.5\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n class=\"cqa-flex-shrink-0 cqa-mt-0.5\">\n <path d=\"M7 1.75C4.1 1.75 1.75 4.1 1.75 7C1.75 9.9 4.1 12.25 7 12.25C9.9 12.25 12.25 9.9 12.25 7C12.25 4.1 9.9 1.75 7 1.75ZM7 9.625C6.65625 9.625 6.375 9.34375 6.375 9V7C6.375 6.65625 6.65625 6.375 7 6.375C7.34375 6.375 7.625 6.65625 7.625 7V9C7.625 9.34375 7.34375 9.625 7 9.625ZM7.625 5.25H6.375V4H7.625V5.25Z\" fill=\"#EF4444\"/>\n </svg>\n <span class=\"cqa-text-xs cqa-text-[#EF4444] cqa-font-medium cqa-leading-[18px]\">\n Screen Name is required\n </span>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"!isElementLoading\">\n <cqa-custom-input \n class=\"cqa-w-full\" \n label=\"Enter Value\" \n placeholder=\"#default_id or xpath\"\n [value]=\"getFormControlValue('value')\"\n [errors]=\"getFormControl('value')?.touched && getFormControl('value')?.invalid ? ['Value is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('value', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-full\">\n <label class=\"cqa-block cqa-text-[14px] cqa-font-medium cqa-text-[#374151] cqa-mb-1\">Labels (tags)</label>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2 cqa-p-2 cqa-border cqa-border-solid cqa-border-gray-200 cqa-rounded-md cqa-min-h-[42px]\">\n <span *ngFor=\"let tag of formLabels\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-2 cqa-py-1 cqa-bg-[#eff6ff] cqa-border cqa-border-[#c8e0ff] cqa-rounded-full cqa-text-[12px] cqa-text-[#3F43EE]\">\n {{ tag }}\n <button type=\"button\" (click)=\"removeTag(tag)\" class=\"cqa-p-0.5 hover:cqa-bg-[#c8e0ff] cqa-rounded cqa-cursor-pointer cqa-h-[16px] cqa-w-[16px]\">\n <mat-icon class=\"!cqa-w-3 !cqa-h-3 !cqa-text-[14px]\">close</mat-icon>\n </button>\n </span>\n <input type=\"text\"\n class=\"cqa-flex-1 cqa-min-w-[120px] cqa-px-2 cqa-py-1 cqa-text-sm cqa-border-0 cqa-outline-none cqa-bg-transparent\"\n placeholder=\"Type and press Enter to add\"\n [(ngModel)]=\"tagInputValue\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTag()\"\n [ngModelOptions]=\"{standalone: true}\">\n </div>\n </div>\n\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]=\"(elementId ? 'Cancel' : 'Select from Element list')\" [fullWidth]=\"true\" (clicked)=\"onCancel()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"saving ? 'Saving...' : (isEditMode ? 'Update' : 'Create')\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#3F43EE]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n </div>\n </div>\n <a href=\"#\" *ngIf=\"isEditInDepthAvailable\" (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 </ng-container>\n</div>\n\n\n" }]
|
|
18688
|
+
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder, decorators: [{
|
|
18689
|
+
type: Optional
|
|
18690
|
+
}] }, { type: i0.ChangeDetectorRef, decorators: [{
|
|
18691
|
+
type: Optional
|
|
18692
|
+
}] }]; }, propDecorators: { elementId: [{
|
|
18693
|
+
type: Input
|
|
18694
|
+
}], element: [{
|
|
18695
|
+
type: Input
|
|
18696
|
+
}], screenNameOptions: [{
|
|
18697
|
+
type: Input
|
|
18698
|
+
}], hasMoreScreenNames: [{
|
|
18699
|
+
type: Input
|
|
18700
|
+
}], isLoadingScreenNames: [{
|
|
18701
|
+
type: Input
|
|
18702
|
+
}], isElementLoading: [{
|
|
18703
|
+
type: Input
|
|
18704
|
+
}], isEditMode: [{
|
|
18705
|
+
type: Input
|
|
18706
|
+
}], isCreateMode: [{
|
|
18707
|
+
type: Input
|
|
18708
|
+
}], isEditInDepthAvailable: [{
|
|
18709
|
+
type: Input
|
|
18710
|
+
}], createElement: [{
|
|
18711
|
+
type: Output
|
|
18712
|
+
}], updateElement: [{
|
|
18713
|
+
type: Output
|
|
18714
|
+
}], createScreenNameRequest: [{
|
|
18715
|
+
type: Output
|
|
18716
|
+
}], searchScreenName: [{
|
|
18717
|
+
type: Output
|
|
18718
|
+
}], loadMoreScreenNames: [{
|
|
18719
|
+
type: Output
|
|
18720
|
+
}], cancel: [{
|
|
18721
|
+
type: Output
|
|
18722
|
+
}], editInDepth: [{
|
|
18723
|
+
type: Output
|
|
18724
|
+
}] } });
|
|
18725
|
+
|
|
18726
|
+
class ElementListComponent {
|
|
18727
|
+
constructor() {
|
|
18728
|
+
/** Array of items to display */
|
|
18729
|
+
this.items = [];
|
|
18730
|
+
/** Key to access the title property from each item (default: 'title') */
|
|
18731
|
+
this.titleKey = 'title';
|
|
18732
|
+
/** Key to access the selector property from each item (default: 'selector') */
|
|
18733
|
+
this.selectorKey = 'selector';
|
|
18734
|
+
/** Key to access the labels array from each item (default: 'labels') */
|
|
18735
|
+
this.labelsKey = 'labels';
|
|
18736
|
+
/** Maximum height for the scrollable container (default: '200px') */
|
|
18737
|
+
this.maxHeight = '200px';
|
|
18738
|
+
/** Whether more items can be loaded */
|
|
18739
|
+
this.hasMore = false;
|
|
18740
|
+
/** Emitted when an item is clicked */
|
|
18741
|
+
this.itemClick = new EventEmitter();
|
|
18742
|
+
/** Emitted when user scrolls near the bottom and more items should be loaded */
|
|
18743
|
+
this.loadMore = new EventEmitter();
|
|
18744
|
+
/** Skip the first intersection callback (fires immediately when observe() is called) to prevent duplicate API calls on load */
|
|
18745
|
+
this.skipNextIntersection = false;
|
|
18746
|
+
}
|
|
18747
|
+
/**
|
|
18748
|
+
* Get the value from an item using the specified key
|
|
18749
|
+
*/
|
|
18750
|
+
getItemValue(item, key) {
|
|
18751
|
+
return item?.[key];
|
|
18752
|
+
}
|
|
18753
|
+
/**
|
|
18754
|
+
* Handle item click
|
|
18755
|
+
*/
|
|
18756
|
+
onItemClick(item) {
|
|
18757
|
+
this.itemClick.emit(item);
|
|
18758
|
+
}
|
|
18759
|
+
ngAfterViewInit() {
|
|
18760
|
+
if (this.hasMore) {
|
|
18761
|
+
setTimeout(() => this.setupScrollObserver(), 0);
|
|
18762
|
+
}
|
|
18763
|
+
}
|
|
18764
|
+
ngOnChanges(changes) {
|
|
18765
|
+
if (changes['hasMore'] && this.hasMore && this.scrollContainer) {
|
|
18766
|
+
setTimeout(() => this.setupScrollObserver(), 0);
|
|
18767
|
+
}
|
|
18768
|
+
}
|
|
18769
|
+
ngOnDestroy() {
|
|
18770
|
+
if (this.scrollObserver) {
|
|
18771
|
+
this.scrollObserver.disconnect();
|
|
18772
|
+
}
|
|
18773
|
+
}
|
|
18774
|
+
setupScrollObserver() {
|
|
18775
|
+
if (!this.hasMore || !this.scrollContainer) {
|
|
18776
|
+
return;
|
|
18777
|
+
}
|
|
18778
|
+
// Find the sentinel element (loading indicator)
|
|
18779
|
+
const sentinel = this.scrollContainer.nativeElement.querySelector('.load-more-sentinel');
|
|
18780
|
+
if (!sentinel) {
|
|
18781
|
+
return;
|
|
18782
|
+
}
|
|
18783
|
+
// Disconnect existing observer if any
|
|
18784
|
+
if (this.scrollObserver) {
|
|
18785
|
+
this.scrollObserver.disconnect();
|
|
18786
|
+
}
|
|
18787
|
+
// Skip the first intersection callback - it fires immediately when observe() is called
|
|
18788
|
+
// if the sentinel is already in view, causing duplicate API calls (page 0 + page 1) on load
|
|
18789
|
+
this.skipNextIntersection = true;
|
|
18790
|
+
// Create IntersectionObserver to detect when sentinel comes into view
|
|
18791
|
+
this.scrollObserver = new IntersectionObserver((entries) => {
|
|
18792
|
+
for (const entry of entries) {
|
|
18793
|
+
if (entry.isIntersecting && this.hasMore) {
|
|
18794
|
+
if (this.skipNextIntersection) {
|
|
18795
|
+
this.skipNextIntersection = false;
|
|
18796
|
+
return;
|
|
18797
|
+
}
|
|
18798
|
+
this.loadMore.emit();
|
|
18799
|
+
}
|
|
18800
|
+
}
|
|
18801
|
+
}, {
|
|
18802
|
+
root: this.scrollContainer.nativeElement,
|
|
18803
|
+
rootMargin: '50px',
|
|
18804
|
+
threshold: 0.1
|
|
18805
|
+
});
|
|
18806
|
+
this.scrollObserver.observe(sentinel);
|
|
18807
|
+
}
|
|
18808
|
+
}
|
|
18809
|
+
ElementListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18810
|
+
ElementListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ElementListComponent, selector: "cqa-element-list", inputs: { items: "items", titleKey: "titleKey", selectorKey: "selectorKey", labelsKey: "labelsKey", maxHeight: "maxHeight", hasMore: "hasMore" }, outputs: { itemClick: "itemClick", loadMore: "loadMore" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div \n #scrollContainer\n class=\"cqa-max-h-[200px] cqa-overflow-y-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB] cqa-flex cqa-flex-col cqa-gap-2\"\n [style.max-height]=\"maxHeight\">\n <div *ngFor=\"let item of items\" (click)=\"onItemClick(item)\">\n <div class=\"hover:cqa-bg-[#F5F5F5] cqa-flex cqa-items-center cqa-justify-between cqa-border cqa-border-[#FDE68A]\n cqa-rounded-lg cqa-p-3 cqa-cursor-pointer cqa-gap-1\" style=\"word-break: break-word;\">\n <div>\n <h6 class=\"cqa-text-[12px] cqa-leading-[100%] cqa-font-[400] cqa-text-[#171717]\">\n {{ getItemValue(item, titleKey) }}\n </h6>\n <span class=\"cqa-text-[10px] cqa-leading-[100%] cqa-text-[#6B7280]\">\n {{ getItemValue(item, selectorKey) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-gap-1\">\n <span \n *ngFor=\"let tag of getItemValue(item, labelsKey)\" \n class=\"cqa-text-[11px] cqa-text-[#4b74ec] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{ tag }}\n </span>\n </div>\n </div>\n </div>\n <!-- No elements found message -->\n <div *ngIf=\"items.length === 0 && !hasMore\" class=\"cqa-flex cqa-justify-center cqa-items-center cqa-py-4 cqa-text-[12px] cqa-text-[#6B7280]\">\n No elements found\n </div>\n <!-- Sentinel element for infinite scroll -->\n <div *ngIf=\"hasMore\" class=\"load-more-sentinel cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-2\">\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-[12px] cqa-text-[#6B7280]\">{{ items.length === 0 ? 'Loading...' : 'Loading more...' }}</span>\n </div>\n</div>\n\n", directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18811
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementListComponent, decorators: [{
|
|
18812
|
+
type: Component,
|
|
18813
|
+
args: [{ selector: 'cqa-element-list', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n #scrollContainer\n class=\"cqa-max-h-[200px] cqa-overflow-y-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB] cqa-flex cqa-flex-col cqa-gap-2\"\n [style.max-height]=\"maxHeight\">\n <div *ngFor=\"let item of items\" (click)=\"onItemClick(item)\">\n <div class=\"hover:cqa-bg-[#F5F5F5] cqa-flex cqa-items-center cqa-justify-between cqa-border cqa-border-[#FDE68A]\n cqa-rounded-lg cqa-p-3 cqa-cursor-pointer cqa-gap-1\" style=\"word-break: break-word;\">\n <div>\n <h6 class=\"cqa-text-[12px] cqa-leading-[100%] cqa-font-[400] cqa-text-[#171717]\">\n {{ getItemValue(item, titleKey) }}\n </h6>\n <span class=\"cqa-text-[10px] cqa-leading-[100%] cqa-text-[#6B7280]\">\n {{ getItemValue(item, selectorKey) }}\n </span>\n </div>\n <div class=\"cqa-flex cqa-gap-1\">\n <span \n *ngFor=\"let tag of getItemValue(item, labelsKey)\" \n class=\"cqa-text-[11px] cqa-text-[#4b74ec] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{ tag }}\n </span>\n </div>\n </div>\n </div>\n <!-- No elements found message -->\n <div *ngIf=\"items.length === 0 && !hasMore\" class=\"cqa-flex cqa-justify-center cqa-items-center cqa-py-4 cqa-text-[12px] cqa-text-[#6B7280]\">\n No elements found\n </div>\n <!-- Sentinel element for infinite scroll -->\n <div *ngIf=\"hasMore\" class=\"load-more-sentinel cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-2\">\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-[12px] cqa-text-[#6B7280]\">{{ items.length === 0 ? 'Loading...' : 'Loading more...' }}</span>\n </div>\n</div>\n\n" }]
|
|
18814
|
+
}], propDecorators: { scrollContainer: [{
|
|
18815
|
+
type: ViewChild,
|
|
18816
|
+
args: ['scrollContainer', { static: false }]
|
|
18817
|
+
}], items: [{
|
|
18818
|
+
type: Input
|
|
18819
|
+
}], titleKey: [{
|
|
18820
|
+
type: Input
|
|
18821
|
+
}], selectorKey: [{
|
|
18822
|
+
type: Input
|
|
18823
|
+
}], labelsKey: [{
|
|
18824
|
+
type: Input
|
|
18825
|
+
}], maxHeight: [{
|
|
18826
|
+
type: Input
|
|
18827
|
+
}], hasMore: [{
|
|
18828
|
+
type: Input
|
|
18829
|
+
}], itemClick: [{
|
|
18830
|
+
type: Output
|
|
18831
|
+
}], loadMore: [{
|
|
18832
|
+
type: Output
|
|
18833
|
+
}] } });
|
|
18834
|
+
|
|
18835
|
+
class ElementPopupComponent {
|
|
18836
|
+
constructor(ref, data, cdr) {
|
|
18837
|
+
this.ref = ref;
|
|
18838
|
+
this.cdr = cdr;
|
|
18839
|
+
this.value = '';
|
|
18840
|
+
this.helpUrl = '';
|
|
18841
|
+
this.labels = [];
|
|
18842
|
+
this.element = { title: '', selector: '', labels: [] };
|
|
18843
|
+
this.elements = [];
|
|
18844
|
+
this.enableForm = false;
|
|
18845
|
+
this.isOnRecord = false;
|
|
18846
|
+
this.hasMoreElements = false;
|
|
18847
|
+
/** Screen name options for autocomplete (from API) */
|
|
18848
|
+
this.screenNameOptions = [];
|
|
18849
|
+
/** Whether more screen names are available for infinite scroll */
|
|
18850
|
+
this.hasMoreScreenNames = false;
|
|
18851
|
+
/** True while parent is loading screen names (search or load more) */
|
|
18852
|
+
this.isLoadingScreenNames = false;
|
|
18853
|
+
/** Suggested tags from API for labels field */
|
|
18854
|
+
this.suggestedTags = [];
|
|
18855
|
+
/** True while parent is fetching latest element data for edit (shows loading state) */
|
|
18856
|
+
this.isElementLoading = false;
|
|
18857
|
+
/** Recent searched items to display in Recent section */
|
|
18858
|
+
this.recentSearchedItems = [];
|
|
18859
|
+
this.apply = new EventEmitter();
|
|
18860
|
+
this.cancel = new EventEmitter();
|
|
18861
|
+
this.editInDepth = new EventEmitter();
|
|
18862
|
+
this.searchElement = new EventEmitter();
|
|
18863
|
+
/** Emitted when user clicks on a recent searched item */
|
|
18864
|
+
this.recentItemClick = new EventEmitter();
|
|
18865
|
+
this.loadMoreElements = new EventEmitter();
|
|
18866
|
+
/** Emitted when user creates a new element (parent should call API) */
|
|
18867
|
+
this.createElement = new EventEmitter();
|
|
18868
|
+
/** Emitted when user updates an element (parent should call API) */
|
|
18869
|
+
this.updateElement = new EventEmitter();
|
|
18870
|
+
/** Emitted when user requests to create a new screen name */
|
|
18871
|
+
this.createScreenNameRequest = new EventEmitter();
|
|
18872
|
+
/** Emitted when user searches screen names (server search) */
|
|
18873
|
+
this.searchScreenName = new EventEmitter();
|
|
18874
|
+
/** Emitted when user scrolls to load more screen names (passes current search query) */
|
|
18875
|
+
this.loadMoreScreenNames = new EventEmitter();
|
|
18876
|
+
/** Emitted when Create or Edit form is opened - parent should fetch screen names and (for edit) latest element */
|
|
18877
|
+
this.formOpenRequest = new EventEmitter();
|
|
18878
|
+
/** Emitted when user selects an element from the list - parent should set element and editingElementId for Edit flow */
|
|
18879
|
+
this.elementSelect = new EventEmitter();
|
|
18880
|
+
/** Emitted when user clicks Record - parent should check extension and call installPlugin or openSidePanelAndListSteps */
|
|
18881
|
+
this.toggleRecord = new EventEmitter();
|
|
18882
|
+
this.helpTooltipText = 'Not sure what to do? Click to go to our detailed step creation documentation';
|
|
18883
|
+
this.showHelpTooltip = false;
|
|
18884
|
+
this.isEditMode = false;
|
|
18885
|
+
/** Whether we're in create mode (no elementId) */
|
|
18886
|
+
this.isCreateMode = false;
|
|
18887
|
+
/** Current search input value (bound to search bar) */
|
|
18888
|
+
this.searchValue = '';
|
|
18889
|
+
this.injectedData = data;
|
|
18890
|
+
}
|
|
18891
|
+
ngOnChanges(changes) {
|
|
18892
|
+
if ((changes['element'] || changes['elementId']) && this.enableForm) {
|
|
18893
|
+
if (this.elementId) {
|
|
18894
|
+
this.isCreateMode = false;
|
|
18895
|
+
this.isEditMode = true;
|
|
18896
|
+
}
|
|
18897
|
+
else {
|
|
18898
|
+
this.isCreateMode = true;
|
|
18899
|
+
this.isEditMode = false;
|
|
18900
|
+
}
|
|
18901
|
+
}
|
|
18902
|
+
}
|
|
18903
|
+
ngOnInit() {
|
|
18904
|
+
if (this.injectedData) {
|
|
18905
|
+
if (!this.value)
|
|
18906
|
+
this.value = this.injectedData.description ?? '';
|
|
18907
|
+
if (!this.helpUrl)
|
|
18908
|
+
this.helpUrl = this.injectedData.helpUrl ?? '';
|
|
18909
|
+
if (this.labels.length === 0)
|
|
18910
|
+
this.labels = this.injectedData.labels ?? [];
|
|
18911
|
+
if (this.elements.length === 0)
|
|
18912
|
+
this.elements = this.injectedData.elements ?? [];
|
|
18913
|
+
if (!this.element || !this.element.title) {
|
|
18914
|
+
this.element = this.injectedData.element ?? { title: '', selector: '', labels: [] };
|
|
18915
|
+
}
|
|
18916
|
+
}
|
|
18917
|
+
}
|
|
18918
|
+
resetForm() {
|
|
18919
|
+
this.isEditMode = false;
|
|
18920
|
+
this.isCreateMode = false;
|
|
18921
|
+
}
|
|
18922
|
+
onElementFormCreate(payload) {
|
|
18923
|
+
this.createElement.emit(payload);
|
|
18924
|
+
}
|
|
18925
|
+
onElementFormUpdate(payload) {
|
|
18926
|
+
this.updateElement.emit(payload);
|
|
18927
|
+
}
|
|
18928
|
+
onElementFormCancel() {
|
|
18929
|
+
this.toggleForm();
|
|
18930
|
+
}
|
|
18931
|
+
onCreateOrUpdateSuccess() {
|
|
18932
|
+
this.enableForm = false;
|
|
18933
|
+
this.resetForm();
|
|
18934
|
+
this.cdr?.markForCheck();
|
|
18935
|
+
}
|
|
18936
|
+
onCreateOrUpdateError() {
|
|
18937
|
+
this.cdr?.markForCheck();
|
|
18938
|
+
}
|
|
18939
|
+
toggleForm() {
|
|
18940
|
+
if (!this.enableForm) {
|
|
18941
|
+
// If no elementId, go to create mode instead of edit mode
|
|
18942
|
+
if (!this.elementId) {
|
|
18943
|
+
this.isCreateMode = true;
|
|
18944
|
+
this.isEditMode = false;
|
|
18945
|
+
this.formOpenRequest.emit({ mode: 'create' });
|
|
18946
|
+
}
|
|
18947
|
+
else {
|
|
18948
|
+
// Has elementId, go to edit mode
|
|
18949
|
+
this.isCreateMode = false;
|
|
18950
|
+
this.isEditMode = true;
|
|
18951
|
+
this.formOpenRequest.emit({ mode: 'edit', elementId: this.elementId });
|
|
18952
|
+
}
|
|
18953
|
+
}
|
|
18954
|
+
else {
|
|
18955
|
+
// Closing form - reset everything
|
|
18956
|
+
// If in create mode, reset labels when going back to element list
|
|
18957
|
+
if (this.isCreateMode) {
|
|
18958
|
+
this.labels = [];
|
|
18959
|
+
}
|
|
18960
|
+
this.resetForm();
|
|
18961
|
+
this.isCreateMode = false;
|
|
18962
|
+
}
|
|
18963
|
+
this.enableForm = !this.enableForm;
|
|
18964
|
+
this.cdr?.markForCheck();
|
|
18965
|
+
}
|
|
18966
|
+
openCreateForm() {
|
|
18967
|
+
this.isCreateMode = true;
|
|
18968
|
+
this.isEditMode = false;
|
|
18969
|
+
this.resetForm();
|
|
18970
|
+
this.enableForm = true;
|
|
18971
|
+
this.formOpenRequest.emit({ mode: 'create' });
|
|
18972
|
+
this.cdr?.markForCheck();
|
|
18973
|
+
}
|
|
18974
|
+
onToggleRecordClick() {
|
|
18975
|
+
this.toggleRecord.emit();
|
|
18976
|
+
}
|
|
18977
|
+
onCancel() {
|
|
18978
|
+
if (this.enableForm) {
|
|
18979
|
+
// If in create mode, go back to element list and reset labels
|
|
18980
|
+
if (this.isCreateMode) {
|
|
18981
|
+
this.resetForm();
|
|
18982
|
+
this.enableForm = false;
|
|
18865
18983
|
this.isCreateMode = false;
|
|
18866
18984
|
// Reset labels when going back from create mode
|
|
18867
18985
|
this.labels = [];
|
|
@@ -18880,8 +18998,7 @@ class ElementPopupComponent {
|
|
|
18880
18998
|
onClose() {
|
|
18881
18999
|
this.onCancel();
|
|
18882
19000
|
}
|
|
18883
|
-
onEditInDepth(
|
|
18884
|
-
event.preventDefault();
|
|
19001
|
+
onEditInDepth() {
|
|
18885
19002
|
this.editInDepth.emit();
|
|
18886
19003
|
if (this.ref)
|
|
18887
19004
|
this.ref.close(ELEMENT_POPUP_EDIT_IN_DEPTH);
|
|
@@ -18898,35 +19015,6 @@ class ElementPopupComponent {
|
|
|
18898
19015
|
window.open(this.helpUrl, '_blank');
|
|
18899
19016
|
}
|
|
18900
19017
|
}
|
|
18901
|
-
getFormControl(controlName) {
|
|
18902
|
-
return this.form.get(controlName);
|
|
18903
|
-
}
|
|
18904
|
-
getFormControlValue(controlName) {
|
|
18905
|
-
return this.form.get(controlName)?.value || '';
|
|
18906
|
-
}
|
|
18907
|
-
onFormControlChange(controlName, value) {
|
|
18908
|
-
this.form.patchValue({ [controlName]: value });
|
|
18909
|
-
this.cdr?.markForCheck();
|
|
18910
|
-
}
|
|
18911
|
-
/** Add a tag (label) */
|
|
18912
|
-
addTag(tag) {
|
|
18913
|
-
const t = (tag || this.tagInputValue || '').trim();
|
|
18914
|
-
if (t && !this.formLabels.includes(t)) {
|
|
18915
|
-
this.formLabels = [...this.formLabels, t];
|
|
18916
|
-
this.tagInputValue = '';
|
|
18917
|
-
this.cdr?.markForCheck();
|
|
18918
|
-
}
|
|
18919
|
-
}
|
|
18920
|
-
removeTag(tag) {
|
|
18921
|
-
this.formLabels = this.formLabels.filter((l) => l !== tag);
|
|
18922
|
-
this.cdr?.markForCheck();
|
|
18923
|
-
}
|
|
18924
|
-
onTagInputKeydown(event) {
|
|
18925
|
-
if (event.key === 'Enter' || event.key === ',') {
|
|
18926
|
-
event.preventDefault();
|
|
18927
|
-
this.addTag();
|
|
18928
|
-
}
|
|
18929
|
-
}
|
|
18930
19018
|
onElementClick(element) {
|
|
18931
19019
|
this.element = element;
|
|
18932
19020
|
this.elementSelect.emit(element);
|
|
@@ -18948,12 +19036,16 @@ class ElementPopupComponent {
|
|
|
18948
19036
|
this.searchElement.emit(item);
|
|
18949
19037
|
this.cdr?.markForCheck();
|
|
18950
19038
|
}
|
|
19039
|
+
/** Called by parent when a new screen name was created (so we can set the selected value) */
|
|
19040
|
+
setCreatedScreenName(opt) {
|
|
19041
|
+
this.elementFormComponent?.setCreatedScreenName(opt);
|
|
19042
|
+
}
|
|
18951
19043
|
}
|
|
18952
|
-
ElementPopupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementPopupComponent, deps: [{ token: CUSTOM_ELEMENT_POPUP_REF, optional: true }, { token: ELEMENT_POPUP_DATA, optional: true }, { token:
|
|
18953
|
-
ElementPopupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ElementPopupComponent, selector: "cqa-element-popup", inputs: { value: "value", helpUrl: "helpUrl", labels: "labels", element: "element", elements: "elements", enableForm: "enableForm", isOnRecord: "isOnRecord", hasMoreElements: "hasMoreElements", elementId: "elementId", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames", suggestedTags: "suggestedTags", isElementLoading: "isElementLoading", recentSearchedItems: "recentSearchedItems" }, outputs: { apply: "apply", cancel: "cancel", editInDepth: "editInDepth", searchElement: "searchElement", recentItemClick: "recentItemClick", loadMoreElements: "loadMoreElements", createElement: "createElement", updateElement: "updateElement", createScreenNameRequest: "createScreenNameRequest", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", formOpenRequest: "formOpenRequest", elementSelect: "elementSelect", toggleRecord: "toggleRecord" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, 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\">\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 Element\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex\"\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 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(#help-icon-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=\"help-icon-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(#help-icon-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=\"help-icon-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\" class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100]\"\n style=\"top: -24px; left: -125px;\"\n role=\"tooltip\">\n <div class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap\"\n style=\"width: 306px; min-height: 20px; border-radius: 6px; opacity: 1; padding: 4px 8px; background-color: #0A0A0A; line-height: 20px; font-size: 8px;\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-p-1 cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px]\">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 <ng-container *ngIf=\"enableForm && !isOnRecord\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n <div *ngIf=\"isElementLoading && isEditMode\" class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-8\">\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 element data...</span>\n </div>\n <div *ngIf=\"!isElementLoading\" class=\"cqa-flex cqa-gap-1.5\">\n <cqa-custom-input \n class=\"cqa-w-1/2\" \n label=\"Name\" \n placeholder=\"default-element\"\n [value]=\"getFormControlValue('name')\"\n [errors]=\"getFormControl('name')?.touched && getFormControl('name')?.invalid ? ['Name is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('name', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-1/2\">\n <cqa-dynamic-select [form]=\"form\" [config]=\"screenNameSelectConfig\"\n (addCustomValue)=\"createScreenNameRequest.emit($event.value)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n <div *ngIf=\"getFormControl('screenNameId')?.touched && getFormControl('screenNameId')?.invalid\" class=\"cqa-flex cqa-flex-col cqa-gap-1 cqa-mt-1.5\">\n <div class=\"cqa-flex cqa-items-start cqa-gap-1.5\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n class=\"cqa-flex-shrink-0 cqa-mt-0.5\">\n <path d=\"M7 1.75C4.1 1.75 1.75 4.1 1.75 7C1.75 9.9 4.1 12.25 7 12.25C9.9 12.25 12.25 9.9 12.25 7C12.25 4.1 9.9 1.75 7 1.75ZM7 9.625C6.65625 9.625 6.375 9.34375 6.375 9V7C6.375 6.65625 6.65625 6.375 7 6.375C7.34375 6.375 7.625 6.65625 7.625 7V9C7.625 9.34375 7.34375 9.625 7 9.625ZM7.625 5.25H6.375V4H7.625V5.25Z\" fill=\"#EF4444\"/>\n </svg>\n <span class=\"cqa-text-xs cqa-text-[#EF4444] cqa-font-medium cqa-leading-[18px]\">\n Screen Name is required\n </span>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"!isElementLoading\">\n <cqa-custom-input \n class=\"cqa-w-full\" \n label=\"Enter Value\" \n placeholder=\"#default_id or xpath\"\n [value]=\"getFormControlValue('value')\"\n [errors]=\"getFormControl('value')?.touched && getFormControl('value')?.invalid ? ['Value is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('value', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-full\">\n <label class=\"cqa-block cqa-text-[14px] cqa-font-medium cqa-text-[#374151] cqa-mb-1\">Labels (tags)</label>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2 cqa-p-2 cqa-border cqa-border-solid cqa-border-gray-200 cqa-rounded-md cqa-min-h-[42px]\">\n <span *ngFor=\"let tag of formLabels\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-2 cqa-py-1 cqa-bg-[#eff6ff] cqa-border cqa-border-[#c8e0ff] cqa-rounded-full cqa-text-[12px] cqa-text-[#3F43EE]\">\n {{ tag }}\n <button type=\"button\" (click)=\"removeTag(tag)\" class=\"cqa-p-0.5 hover:cqa-bg-[#c8e0ff] cqa-rounded cqa-cursor-pointer cqa-h-[16px] cqa-w-[16px]\">\n <mat-icon class=\"!cqa-w-3 !cqa-h-3 !cqa-text-[14px]\">close</mat-icon>\n </button>\n </span>\n <input type=\"text\"\n class=\"cqa-flex-1 cqa-min-w-[120px] cqa-px-2 cqa-py-1 cqa-text-sm cqa-border-0 cqa-outline-none cqa-bg-transparent\"\n placeholder=\"Type and press Enter to add\"\n [(ngModel)]=\"tagInputValue\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTag()\"\n [ngModelOptions]=\"{standalone: true}\">\n </div>\n </div>\n\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]=\"(elementId ? 'Cancel' : 'Select from Element list')\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"saving ? 'Saving...' : (isEditMode ? 'Update' : 'Create')\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#3F43EE]'\" [disabled]=\"saving\"></cqa-button>\n </div>\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 </ng-container>\n </div>\n </ng-container>\n\n<ng-container *ngIf=\"isOnRecord && !enableForm\">\n <div\n class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-text-center cqa-gap-3 cqa-pt-10\">\n\n <!-- Video Icon -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-[64px] cqa-h-[64px] cqa-rounded-full cqa-bg-[#FEE2E2]\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.333 17.3333L28.297 21.9759C28.3974 22.0428 28.514 22.0811 28.6345 22.0868C28.7549 22.0926 28.8747 22.0656 28.981 22.0087C29.0873 21.9517 29.1762 21.8671 29.2382 21.7636C29.3002 21.6602 29.3329 21.5419 29.333 21.4213V10.4933C29.333 10.376 29.3021 10.2607 29.2434 10.1592C29.1846 10.0577 29.1001 9.97344 28.9984 9.91501C28.8967 9.85658 28.7814 9.82602 28.6641 9.82642C28.5468 9.82682 28.4317 9.85816 28.3303 9.91728L21.333 13.9999\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M18.667 8H5.33366C3.8609 8 2.66699 9.19391 2.66699 10.6667V21.3333C2.66699 22.8061 3.8609 24 5.33366 24H18.667C20.1398 24 21.3337 22.8061 21.3337 21.3333V10.6667C21.3337 9.19391 20.1398 8 18.667 8Z\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n \n </div>\n\n <!-- Title -->\n <h4 class=\"cqa-m-0 cqa-text-[16px] cqa-leading-[24px] cqa-font-[600] cqa-text-[#0A0A0A]\">\n Recording Mode Active\n </h4>\n\n <!-- Subtitle -->\n <p class=\"cqa-m-0 cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280]\">\n Click on any element in the browser to capture it\n </p>\n </div>\n\n <!-- Footer -->\n <div class=\"cqa-flex cqa-justify-center cqa-pb-4\">\n <cqa-button\n variant=\"outlined\"\n btnSize=\"lg\"\n [text]=\"'Cancel Recording'\"\n (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-px-16 cqa-py-[9px] cqa-border-[#414146]'\">\n </cqa-button>\n </div>\n</ng-container>\n\n\n <ng-container *ngIf=\"!enableForm && !isOnRecord\">\n<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n\n <!-- Selected -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Selected</span>\n\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between\n cqa-bg-[#FFFBEB] cqa-border cqa-border-[#fadfba]\n cqa-rounded-lg cqa-p-3 cqa-border-solid cqa-gap-3\">\n\n <div class=\"cqa-flex cqa-px-3 cqa-py-2 cqa-rounded-lg cqa-flex-col cqa-gap-0.5 cqa-bg-[#f5f5f5] cqa-flex-1\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2\">\n <span class=\"cqa-text-[14px] cqa-font-[600] cqa-text-[#111827]\">\n {{element.title}}\n </span>\n\n <div class=\"cqa-flex cqa-gap-2\">\n <span *ngFor=\"let l of element.labels\"\n class=\"cqa-text-[10px] cqa-px-1.5 cqa-py-0.5\n cqa-rounded cqa-bg-[#EEF2FF] cqa-text-[#3F43EE] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{l}}\n </span>\n </div>\n </div>\n\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">\n {{element.selector}}\n </span>\n </div>\n <cqa-button variant=\"outlined\" icon=\"edit\" btnSize=\"lg\" [text]=\"'Edit'\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n\n <!-- Recent -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\" *ngIf=\"recentSearchedItems.length > 0\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Recent</span>\n\n <div class=\"cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n\n <div *ngFor=\"let item of recentSearchedItems\" \n class=\"cqa-cursor-pointer cqa-inline-block\"\n (click)=\"onRecentItemClick(item)\">\n <cqa-badge \n class=\"cqa-element-badge cqa-mb-2 cqa-chip !cqa-bg-white !cqa-text-[12px] cqa-whitespace-nowrap\" \n [label]=\"item\"></cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Element Library -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Element Library</span>\n <cqa-search-bar [fullWidth]=\"true\" [value]=\"searchValue\" placeholder=\"Search library\" (valueChange)=\"search($event)\"></cqa-search-bar> \n </div>\n\n <cqa-element-list \n [items]=\"elements\"\n [titleKey]=\"'title'\"\n [selectorKey]=\"'selector'\"\n [labelsKey]=\"'labels'\"\n [maxHeight]=\"'200px'\"\n [hasMore]=\"hasMoreElements\"\n (itemClick)=\"onElementClick($event)\"\n (loadMore)=\"onLoadMoreElements()\">\n </cqa-element-list>\n</div>\n\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\" icon=\"radio_button_checked\" btnSize=\"lg\" [text]=\"'Record'\" [fullWidth]=\"true\" (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" icon=\"add\" btnSize=\"lg\" [text]=\"'Create New'\" [fullWidth]=\"true\" (clicked)=\"openCreateForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n </div>\n </ng-container>\n\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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", "addCustomValue"] }, { 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: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: ElementListComponent, selector: "cqa-element-list", inputs: ["items", "titleKey", "selectorKey", "labelsKey", "maxHeight", "hasMore"], outputs: ["itemClick", "loadMore"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
19044
|
+
ElementPopupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementPopupComponent, deps: [{ token: CUSTOM_ELEMENT_POPUP_REF, optional: true }, { token: ELEMENT_POPUP_DATA, optional: true }, { token: i0.ChangeDetectorRef, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
19045
|
+
ElementPopupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ElementPopupComponent, selector: "cqa-element-popup", inputs: { value: "value", helpUrl: "helpUrl", labels: "labels", element: "element", elements: "elements", enableForm: "enableForm", isOnRecord: "isOnRecord", hasMoreElements: "hasMoreElements", elementId: "elementId", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames", suggestedTags: "suggestedTags", isElementLoading: "isElementLoading", recentSearchedItems: "recentSearchedItems" }, outputs: { apply: "apply", cancel: "cancel", editInDepth: "editInDepth", searchElement: "searchElement", recentItemClick: "recentItemClick", loadMoreElements: "loadMoreElements", createElement: "createElement", updateElement: "updateElement", createScreenNameRequest: "createScreenNameRequest", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", formOpenRequest: "formOpenRequest", elementSelect: "elementSelect", toggleRecord: "toggleRecord" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "elementFormComponent", first: true, predicate: ElementFormComponent, descendants: true }], usesOnChanges: true, 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\">\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 Element\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex\"\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 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(#help-icon-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=\"help-icon-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(#help-icon-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=\"help-icon-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\" class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100]\"\n style=\"top: -24px; left: -125px;\"\n role=\"tooltip\">\n <div class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap\"\n style=\"width: 306px; min-height: 20px; border-radius: 6px; opacity: 1; padding: 4px 8px; background-color: #0A0A0A; line-height: 20px; font-size: 8px;\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-p-1 cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px]\">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 <ng-container *ngIf=\"enableForm && !isOnRecord\">\n <cqa-element-form\n #elementForm\n [elementId]=\"elementId\"\n [element]=\"element\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n [isElementLoading]=\"isElementLoading\"\n [isEditMode]=\"isEditMode\"\n [isCreateMode]=\"isCreateMode\"\n (createElement)=\"onElementFormCreate($event)\"\n (updateElement)=\"onElementFormUpdate($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (cancel)=\"onElementFormCancel()\"\n (editInDepth)=\"onEditInDepth()\">\n </cqa-element-form>\n </ng-container>\n\n<ng-container *ngIf=\"isOnRecord && !enableForm\">\n <div\n class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-text-center cqa-gap-3 cqa-pt-10\">\n\n <!-- Video Icon -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-[64px] cqa-h-[64px] cqa-rounded-full cqa-bg-[#FEE2E2]\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.333 17.3333L28.297 21.9759C28.3974 22.0428 28.514 22.0811 28.6345 22.0868C28.7549 22.0926 28.8747 22.0656 28.981 22.0087C29.0873 21.9517 29.1762 21.8671 29.2382 21.7636C29.3002 21.6602 29.3329 21.5419 29.333 21.4213V10.4933C29.333 10.376 29.3021 10.2607 29.2434 10.1592C29.1846 10.0577 29.1001 9.97344 28.9984 9.91501C28.8967 9.85658 28.7814 9.82602 28.6641 9.82642C28.5468 9.82682 28.4317 9.85816 28.3303 9.91728L21.333 13.9999\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M18.667 8H5.33366C3.8609 8 2.66699 9.19391 2.66699 10.6667V21.3333C2.66699 22.8061 3.8609 24 5.33366 24H18.667C20.1398 24 21.3337 22.8061 21.3337 21.3333V10.6667C21.3337 9.19391 20.1398 8 18.667 8Z\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n \n </div>\n\n <!-- Title -->\n <h4 class=\"cqa-m-0 cqa-text-[16px] cqa-leading-[24px] cqa-font-[600] cqa-text-[#0A0A0A]\">\n Recording Mode Active\n </h4>\n\n <!-- Subtitle -->\n <p class=\"cqa-m-0 cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280]\">\n Click on any element in the browser to capture it\n </p>\n </div>\n\n <!-- Footer -->\n <div class=\"cqa-flex cqa-justify-center cqa-pb-4\">\n <cqa-button\n variant=\"outlined\"\n btnSize=\"lg\"\n [text]=\"'Cancel Recording'\"\n (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-px-16 cqa-py-[9px] cqa-border-[#414146]'\">\n </cqa-button>\n </div>\n</ng-container>\n\n\n <ng-container *ngIf=\"!enableForm && !isOnRecord\">\n<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n\n <!-- Selected -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Selected</span>\n\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between\n cqa-bg-[#FFFBEB] cqa-border cqa-border-[#fadfba]\n cqa-rounded-lg cqa-p-3 cqa-border-solid cqa-gap-3\">\n\n <div class=\"cqa-flex cqa-px-3 cqa-py-2 cqa-rounded-lg cqa-flex-col cqa-gap-0.5 cqa-bg-[#f5f5f5] cqa-flex-1\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2\">\n <span class=\"cqa-text-[14px] cqa-font-[600] cqa-text-[#111827]\">\n {{element.title}}\n </span>\n\n <div class=\"cqa-flex cqa-gap-2\">\n <span *ngFor=\"let l of element.labels\"\n class=\"cqa-text-[10px] cqa-px-1.5 cqa-py-0.5\n cqa-rounded cqa-bg-[#EEF2FF] cqa-text-[#3F43EE] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{l}}\n </span>\n </div>\n </div>\n\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">\n {{element.selector}}\n </span>\n </div>\n <cqa-button variant=\"outlined\" icon=\"edit\" btnSize=\"lg\" [text]=\"'Edit'\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n\n <!-- Recent -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\" *ngIf=\"recentSearchedItems.length > 0\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Recent</span>\n\n <div class=\"cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n\n <div *ngFor=\"let item of recentSearchedItems\" \n class=\"cqa-cursor-pointer cqa-inline-block\"\n (click)=\"onRecentItemClick(item)\">\n <cqa-badge \n class=\"cqa-element-badge cqa-mb-2 cqa-chip !cqa-bg-white !cqa-text-[12px] cqa-whitespace-nowrap\" \n [label]=\"item\"></cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Element Library -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Element Library</span>\n <cqa-search-bar [fullWidth]=\"true\" [value]=\"searchValue\" placeholder=\"Search library\" (valueChange)=\"search($event)\"></cqa-search-bar> \n </div>\n\n <cqa-element-list \n [items]=\"elements\"\n [titleKey]=\"'title'\"\n [selectorKey]=\"'selector'\"\n [labelsKey]=\"'labels'\"\n [maxHeight]=\"'200px'\"\n [hasMore]=\"hasMoreElements\"\n (itemClick)=\"onElementClick($event)\"\n (loadMore)=\"onLoadMoreElements()\">\n </cqa-element-list>\n</div>\n\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\" icon=\"radio_button_checked\" btnSize=\"lg\" [text]=\"'Record'\" [fullWidth]=\"true\" (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" icon=\"add\" btnSize=\"lg\" [text]=\"'Create New'\" [fullWidth]=\"true\" (clicked)=\"openCreateForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n </div>\n </ng-container>\n\n</div>\n", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: ElementFormComponent, selector: "cqa-element-form", inputs: ["elementId", "element", "screenNameOptions", "hasMoreScreenNames", "isLoadingScreenNames", "isElementLoading", "isEditMode", "isCreateMode", "isEditInDepthAvailable"], outputs: ["createElement", "updateElement", "createScreenNameRequest", "searchScreenName", "loadMoreScreenNames", "cancel", "editInDepth"] }, { 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: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: ElementListComponent, selector: "cqa-element-list", inputs: ["items", "titleKey", "selectorKey", "labelsKey", "maxHeight", "hasMore"], outputs: ["itemClick", "loadMore"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
18954
19046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ElementPopupComponent, decorators: [{
|
|
18955
19047
|
type: Component,
|
|
18956
|
-
args: [{ selector: 'cqa-element-popup', 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\">\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 Element\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex\"\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 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(#help-icon-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=\"help-icon-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(#help-icon-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=\"help-icon-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\" class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100]\"\n style=\"top: -24px; left: -125px;\"\n role=\"tooltip\">\n <div class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap\"\n style=\"width: 306px; min-height: 20px; border-radius: 6px; opacity: 1; padding: 4px 8px; background-color: #0A0A0A; line-height: 20px; font-size: 8px;\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-p-1 cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px]\">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 <ng-container *ngIf=\"enableForm && !isOnRecord\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n <div *ngIf=\"isElementLoading && isEditMode\" class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-gap-3 cqa-py-8\">\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 element data...</span>\n </div>\n <div *ngIf=\"!isElementLoading\" class=\"cqa-flex cqa-gap-1.5\">\n <cqa-custom-input \n class=\"cqa-w-1/2\" \n label=\"Name\" \n placeholder=\"default-element\"\n [value]=\"getFormControlValue('name')\"\n [errors]=\"getFormControl('name')?.touched && getFormControl('name')?.invalid ? ['Name is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('name', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-1/2\">\n <cqa-dynamic-select [form]=\"form\" [config]=\"screenNameSelectConfig\"\n (addCustomValue)=\"createScreenNameRequest.emit($event.value)\"\n class=\"cqa-w-full\">\n </cqa-dynamic-select>\n <div *ngIf=\"getFormControl('screenNameId')?.touched && getFormControl('screenNameId')?.invalid\" class=\"cqa-flex cqa-flex-col cqa-gap-1 cqa-mt-1.5\">\n <div class=\"cqa-flex cqa-items-start cqa-gap-1.5\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n class=\"cqa-flex-shrink-0 cqa-mt-0.5\">\n <path d=\"M7 1.75C4.1 1.75 1.75 4.1 1.75 7C1.75 9.9 4.1 12.25 7 12.25C9.9 12.25 12.25 9.9 12.25 7C12.25 4.1 9.9 1.75 7 1.75ZM7 9.625C6.65625 9.625 6.375 9.34375 6.375 9V7C6.375 6.65625 6.65625 6.375 7 6.375C7.34375 6.375 7.625 6.65625 7.625 7V9C7.625 9.34375 7.34375 9.625 7 9.625ZM7.625 5.25H6.375V4H7.625V5.25Z\" fill=\"#EF4444\"/>\n </svg>\n <span class=\"cqa-text-xs cqa-text-[#EF4444] cqa-font-medium cqa-leading-[18px]\">\n Screen Name is required\n </span>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"!isElementLoading\">\n <cqa-custom-input \n class=\"cqa-w-full\" \n label=\"Enter Value\" \n placeholder=\"#default_id or xpath\"\n [value]=\"getFormControlValue('value')\"\n [errors]=\"getFormControl('value')?.touched && getFormControl('value')?.invalid ? ['Value is required'] : []\"\n [required]=\"true\"\n (valueChange)=\"onFormControlChange('value', $event)\">\n </cqa-custom-input>\n <div class=\"cqa-w-full\">\n <label class=\"cqa-block cqa-text-[14px] cqa-font-medium cqa-text-[#374151] cqa-mb-1\">Labels (tags)</label>\n <div class=\"cqa-flex cqa-flex-wrap cqa-gap-2 cqa-p-2 cqa-border cqa-border-solid cqa-border-gray-200 cqa-rounded-md cqa-min-h-[42px]\">\n <span *ngFor=\"let tag of formLabels\"\n class=\"cqa-inline-flex cqa-items-center cqa-gap-1 cqa-px-2 cqa-py-1 cqa-bg-[#eff6ff] cqa-border cqa-border-[#c8e0ff] cqa-rounded-full cqa-text-[12px] cqa-text-[#3F43EE]\">\n {{ tag }}\n <button type=\"button\" (click)=\"removeTag(tag)\" class=\"cqa-p-0.5 hover:cqa-bg-[#c8e0ff] cqa-rounded cqa-cursor-pointer cqa-h-[16px] cqa-w-[16px]\">\n <mat-icon class=\"!cqa-w-3 !cqa-h-3 !cqa-text-[14px]\">close</mat-icon>\n </button>\n </span>\n <input type=\"text\"\n class=\"cqa-flex-1 cqa-min-w-[120px] cqa-px-2 cqa-py-1 cqa-text-sm cqa-border-0 cqa-outline-none cqa-bg-transparent\"\n placeholder=\"Type and press Enter to add\"\n [(ngModel)]=\"tagInputValue\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTag()\"\n [ngModelOptions]=\"{standalone: true}\">\n </div>\n </div>\n\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]=\"(elementId ? 'Cancel' : 'Select from Element list')\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\" [disabled]=\"saving\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"filled\" btnSize=\"lg\" [text]=\"saving ? 'Saving...' : (isEditMode ? 'Update' : 'Create')\" [fullWidth]=\"true\" (clicked)=\"onApply()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#3F43EE]'\" [disabled]=\"saving\"></cqa-button>\n </div>\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 </ng-container>\n </div>\n </ng-container>\n\n<ng-container *ngIf=\"isOnRecord && !enableForm\">\n <div\n class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-text-center cqa-gap-3 cqa-pt-10\">\n\n <!-- Video Icon -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-[64px] cqa-h-[64px] cqa-rounded-full cqa-bg-[#FEE2E2]\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.333 17.3333L28.297 21.9759C28.3974 22.0428 28.514 22.0811 28.6345 22.0868C28.7549 22.0926 28.8747 22.0656 28.981 22.0087C29.0873 21.9517 29.1762 21.8671 29.2382 21.7636C29.3002 21.6602 29.3329 21.5419 29.333 21.4213V10.4933C29.333 10.376 29.3021 10.2607 29.2434 10.1592C29.1846 10.0577 29.1001 9.97344 28.9984 9.91501C28.8967 9.85658 28.7814 9.82602 28.6641 9.82642C28.5468 9.82682 28.4317 9.85816 28.3303 9.91728L21.333 13.9999\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M18.667 8H5.33366C3.8609 8 2.66699 9.19391 2.66699 10.6667V21.3333C2.66699 22.8061 3.8609 24 5.33366 24H18.667C20.1398 24 21.3337 22.8061 21.3337 21.3333V10.6667C21.3337 9.19391 20.1398 8 18.667 8Z\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n \n </div>\n\n <!-- Title -->\n <h4 class=\"cqa-m-0 cqa-text-[16px] cqa-leading-[24px] cqa-font-[600] cqa-text-[#0A0A0A]\">\n Recording Mode Active\n </h4>\n\n <!-- Subtitle -->\n <p class=\"cqa-m-0 cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280]\">\n Click on any element in the browser to capture it\n </p>\n </div>\n\n <!-- Footer -->\n <div class=\"cqa-flex cqa-justify-center cqa-pb-4\">\n <cqa-button\n variant=\"outlined\"\n btnSize=\"lg\"\n [text]=\"'Cancel Recording'\"\n (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-px-16 cqa-py-[9px] cqa-border-[#414146]'\">\n </cqa-button>\n </div>\n</ng-container>\n\n\n <ng-container *ngIf=\"!enableForm && !isOnRecord\">\n<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n\n <!-- Selected -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Selected</span>\n\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between\n cqa-bg-[#FFFBEB] cqa-border cqa-border-[#fadfba]\n cqa-rounded-lg cqa-p-3 cqa-border-solid cqa-gap-3\">\n\n <div class=\"cqa-flex cqa-px-3 cqa-py-2 cqa-rounded-lg cqa-flex-col cqa-gap-0.5 cqa-bg-[#f5f5f5] cqa-flex-1\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2\">\n <span class=\"cqa-text-[14px] cqa-font-[600] cqa-text-[#111827]\">\n {{element.title}}\n </span>\n\n <div class=\"cqa-flex cqa-gap-2\">\n <span *ngFor=\"let l of element.labels\"\n class=\"cqa-text-[10px] cqa-px-1.5 cqa-py-0.5\n cqa-rounded cqa-bg-[#EEF2FF] cqa-text-[#3F43EE] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{l}}\n </span>\n </div>\n </div>\n\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">\n {{element.selector}}\n </span>\n </div>\n <cqa-button variant=\"outlined\" icon=\"edit\" btnSize=\"lg\" [text]=\"'Edit'\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n\n <!-- Recent -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\" *ngIf=\"recentSearchedItems.length > 0\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Recent</span>\n\n <div class=\"cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n\n <div *ngFor=\"let item of recentSearchedItems\" \n class=\"cqa-cursor-pointer cqa-inline-block\"\n (click)=\"onRecentItemClick(item)\">\n <cqa-badge \n class=\"cqa-element-badge cqa-mb-2 cqa-chip !cqa-bg-white !cqa-text-[12px] cqa-whitespace-nowrap\" \n [label]=\"item\"></cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Element Library -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Element Library</span>\n <cqa-search-bar [fullWidth]=\"true\" [value]=\"searchValue\" placeholder=\"Search library\" (valueChange)=\"search($event)\"></cqa-search-bar> \n </div>\n\n <cqa-element-list \n [items]=\"elements\"\n [titleKey]=\"'title'\"\n [selectorKey]=\"'selector'\"\n [labelsKey]=\"'labels'\"\n [maxHeight]=\"'200px'\"\n [hasMore]=\"hasMoreElements\"\n (itemClick)=\"onElementClick($event)\"\n (loadMore)=\"onLoadMoreElements()\">\n </cqa-element-list>\n</div>\n\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\" icon=\"radio_button_checked\" btnSize=\"lg\" [text]=\"'Record'\" [fullWidth]=\"true\" (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" icon=\"add\" btnSize=\"lg\" [text]=\"'Create New'\" [fullWidth]=\"true\" (clicked)=\"openCreateForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n </div>\n </ng-container>\n\n</div>\n" }]
|
|
19048
|
+
args: [{ selector: 'cqa-element-popup', 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\">\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 Element\n </h2>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Need help? with custom tooltip (works inside overlay) -->\n <div class=\"cqa-relative cqa-inline-flex\"\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 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(#help-icon-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=\"help-icon-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(#help-icon-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=\"help-icon-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\" class=\"cqa-absolute cqa-pointer-events-none cqa-z-[100]\"\n style=\"top: -24px; left: -125px;\"\n role=\"tooltip\">\n <div class=\"cqa-text-white cqa-text-center cqa-whitespace-nowrap\"\n style=\"width: 306px; min-height: 20px; border-radius: 6px; opacity: 1; padding: 4px 8px; background-color: #0A0A0A; line-height: 20px; font-size: 8px;\">\n {{ helpTooltipText }}\n </div>\n </div>\n </div>\n <button type=\"button\" (click)=\"onClose()\"\n class=\"cqa-p-1 cqa-rounded cqa-text-[#6B7280] hover:cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center\"\n title=\"Close\" aria-label=\"Close\">\n <mat-icon class=\"!cqa-w-5 !cqa-h-5 !cqa-text-[20px]\">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 <ng-container *ngIf=\"enableForm && !isOnRecord\">\n <cqa-element-form\n #elementForm\n [elementId]=\"elementId\"\n [element]=\"element\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n [isElementLoading]=\"isElementLoading\"\n [isEditMode]=\"isEditMode\"\n [isCreateMode]=\"isCreateMode\"\n (createElement)=\"onElementFormCreate($event)\"\n (updateElement)=\"onElementFormUpdate($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (cancel)=\"onElementFormCancel()\"\n (editInDepth)=\"onEditInDepth()\">\n </cqa-element-form>\n </ng-container>\n\n<ng-container *ngIf=\"isOnRecord && !enableForm\">\n <div\n class=\"cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-text-center cqa-gap-3 cqa-pt-10\">\n\n <!-- Video Icon -->\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-[64px] cqa-h-[64px] cqa-rounded-full cqa-bg-[#FEE2E2]\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M21.333 17.3333L28.297 21.9759C28.3974 22.0428 28.514 22.0811 28.6345 22.0868C28.7549 22.0926 28.8747 22.0656 28.981 22.0087C29.0873 21.9517 29.1762 21.8671 29.2382 21.7636C29.3002 21.6602 29.3329 21.5419 29.333 21.4213V10.4933C29.333 10.376 29.3021 10.2607 29.2434 10.1592C29.1846 10.0577 29.1001 9.97344 28.9984 9.91501C28.8967 9.85658 28.7814 9.82602 28.6641 9.82642C28.5468 9.82682 28.4317 9.85816 28.3303 9.91728L21.333 13.9999\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M18.667 8H5.33366C3.8609 8 2.66699 9.19391 2.66699 10.6667V21.3333C2.66699 22.8061 3.8609 24 5.33366 24H18.667C20.1398 24 21.3337 22.8061 21.3337 21.3333V10.6667C21.3337 9.19391 20.1398 8 18.667 8Z\" stroke=\"#E7000B\" stroke-width=\"2.66667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n \n </div>\n\n <!-- Title -->\n <h4 class=\"cqa-m-0 cqa-text-[16px] cqa-leading-[24px] cqa-font-[600] cqa-text-[#0A0A0A]\">\n Recording Mode Active\n </h4>\n\n <!-- Subtitle -->\n <p class=\"cqa-m-0 cqa-text-[12px] cqa-leading-[18px] cqa-text-[#6B7280]\">\n Click on any element in the browser to capture it\n </p>\n </div>\n\n <!-- Footer -->\n <div class=\"cqa-flex cqa-justify-center cqa-pb-4\">\n <cqa-button\n variant=\"outlined\"\n btnSize=\"lg\"\n [text]=\"'Cancel Recording'\"\n (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-px-16 cqa-py-[9px] cqa-border-[#414146]'\">\n </cqa-button>\n </div>\n</ng-container>\n\n\n <ng-container *ngIf=\"!enableForm && !isOnRecord\">\n<div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-px-1 cqa-pt-3\">\n\n <!-- Selected -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Selected</span>\n\n <div\n class=\"cqa-flex cqa-items-center cqa-justify-between\n cqa-bg-[#FFFBEB] cqa-border cqa-border-[#fadfba]\n cqa-rounded-lg cqa-p-3 cqa-border-solid cqa-gap-3\">\n\n <div class=\"cqa-flex cqa-px-3 cqa-py-2 cqa-rounded-lg cqa-flex-col cqa-gap-0.5 cqa-bg-[#f5f5f5] cqa-flex-1\">\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-gap-2\">\n <span class=\"cqa-text-[14px] cqa-font-[600] cqa-text-[#111827]\">\n {{element.title}}\n </span>\n\n <div class=\"cqa-flex cqa-gap-2\">\n <span *ngFor=\"let l of element.labels\"\n class=\"cqa-text-[10px] cqa-px-1.5 cqa-py-0.5\n cqa-rounded cqa-bg-[#EEF2FF] cqa-text-[#3F43EE] cqa-rounded-full cqa-px-2 cqa-bg-[#eff6ff] cqa-border cqa-border-solid cqa-border-[#c8e0ff]\">\n {{l}}\n </span>\n </div>\n </div>\n\n <span class=\"cqa-text-[11px] cqa-text-[#6B7280]\">\n {{element.selector}}\n </span>\n </div>\n <cqa-button variant=\"outlined\" icon=\"edit\" btnSize=\"lg\" [text]=\"'Edit'\" [fullWidth]=\"true\" (clicked)=\"toggleForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n\n <!-- Recent -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\" *ngIf=\"recentSearchedItems.length > 0\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Recent</span>\n\n <div class=\"cqa-flex cqa-gap-2 cqa-overflow-x-auto cqa-scrollbar-thin cqa-scrollbar-track-transparent cqa-scrollbar-thumb-[#E5E7EB] cqa-scrollbar-thumb-rounded-full cqa-scrollbar-thumb-hover:cqa-bg-[#D1D5DB]\">\n\n <div *ngFor=\"let item of recentSearchedItems\" \n class=\"cqa-cursor-pointer cqa-inline-block\"\n (click)=\"onRecentItemClick(item)\">\n <cqa-badge \n class=\"cqa-element-badge cqa-mb-2 cqa-chip !cqa-bg-white !cqa-text-[12px] cqa-whitespace-nowrap\" \n [label]=\"item\"></cqa-badge>\n </div>\n </div>\n </div>\n\n <!-- Element Library -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <span class=\"cqa-text-[12px] cqa-text-[#6B7280]\">Element Library</span>\n <cqa-search-bar [fullWidth]=\"true\" [value]=\"searchValue\" placeholder=\"Search library\" (valueChange)=\"search($event)\"></cqa-search-bar> \n </div>\n\n <cqa-element-list \n [items]=\"elements\"\n [titleKey]=\"'title'\"\n [selectorKey]=\"'selector'\"\n [labelsKey]=\"'labels'\"\n [maxHeight]=\"'200px'\"\n [hasMore]=\"hasMoreElements\"\n (itemClick)=\"onElementClick($event)\"\n (loadMore)=\"onLoadMoreElements()\">\n </cqa-element-list>\n</div>\n\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\" icon=\"radio_button_checked\" btnSize=\"lg\" [text]=\"'Record'\" [fullWidth]=\"true\" (clicked)=\"onToggleRecordClick()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <cqa-button variant=\"outlined\" icon=\"add\" btnSize=\"lg\" [text]=\"'Create New'\" [fullWidth]=\"true\" (clicked)=\"openCreateForm()\"\n [customClass]=\"'cqa-text-[14px] cqa-py-[9px] cqa-border-[#414146]'\"></cqa-button>\n </div>\n </div>\n </div>\n </ng-container>\n\n</div>\n" }]
|
|
18957
19049
|
}], ctorParameters: function () { return [{ type: ElementPopupRef, decorators: [{
|
|
18958
19050
|
type: Optional
|
|
18959
19051
|
}, {
|
|
@@ -18964,8 +19056,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
18964
19056
|
}, {
|
|
18965
19057
|
type: Inject,
|
|
18966
19058
|
args: [ELEMENT_POPUP_DATA]
|
|
18967
|
-
}] }, { type: i1$1.FormBuilder, decorators: [{
|
|
18968
|
-
type: Optional
|
|
18969
19059
|
}] }, { type: i0.ChangeDetectorRef, decorators: [{
|
|
18970
19060
|
type: Optional
|
|
18971
19061
|
}] }]; }, propDecorators: { value: [{
|
|
@@ -19026,6 +19116,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
19026
19116
|
type: Output
|
|
19027
19117
|
}], toggleRecord: [{
|
|
19028
19118
|
type: Output
|
|
19119
|
+
}], elementFormComponent: [{
|
|
19120
|
+
type: ViewChild,
|
|
19121
|
+
args: [ElementFormComponent]
|
|
19029
19122
|
}] } });
|
|
19030
19123
|
|
|
19031
19124
|
class ElementPopupService {
|
|
@@ -25297,13 +25390,30 @@ class TemplateVariablesFormComponent {
|
|
|
25297
25390
|
constructor(cdr) {
|
|
25298
25391
|
this.cdr = cdr;
|
|
25299
25392
|
this.templateVariables = [];
|
|
25300
|
-
this.variablesForm = new
|
|
25393
|
+
this.variablesForm = new FormArray([]);
|
|
25301
25394
|
this.metadata = '';
|
|
25302
25395
|
this.description = '';
|
|
25396
|
+
this.elementOptions = []; // Element objects for element dropdown
|
|
25397
|
+
this.hasMoreElements = false; // Whether more elements are available
|
|
25398
|
+
this.isLoadingElements = false; // Loading state for elements
|
|
25399
|
+
/** Screen name options for element form autocomplete (from API) */
|
|
25400
|
+
this.screenNameOptions = [];
|
|
25401
|
+
/** Whether more screen names are available for infinite scroll */
|
|
25402
|
+
this.hasMoreScreenNames = false;
|
|
25403
|
+
/** True while parent is loading screen names (search or load more) */
|
|
25404
|
+
this.isLoadingScreenNames = false;
|
|
25303
25405
|
this.variableValueChange = new EventEmitter();
|
|
25304
25406
|
this.variableBooleanChange = new EventEmitter();
|
|
25305
25407
|
this.metadataChange = new EventEmitter();
|
|
25306
25408
|
this.descriptionChange = new EventEmitter();
|
|
25409
|
+
this.loadMoreElements = new EventEmitter(); // Emit when load more is requested
|
|
25410
|
+
this.searchElements = new EventEmitter(); // Emit when user searches for elements
|
|
25411
|
+
this.createElement = new EventEmitter(); // Emit when element is created with payload
|
|
25412
|
+
this.searchScreenName = new EventEmitter(); // Emit when user searches screen names
|
|
25413
|
+
this.loadMoreScreenNames = new EventEmitter(); // Emit when user scrolls to load more screen names
|
|
25414
|
+
this.createScreenNameRequest = new EventEmitter(); // Emit when user requests to create a new screen name
|
|
25415
|
+
this.cancelElementForm = new EventEmitter(); // Emit when element form is cancelled
|
|
25416
|
+
this.elementFormVisibilityChange = new EventEmitter(); // Emit when element form visibility changes
|
|
25307
25417
|
// Cache for select configs to avoid recalculating on every change detection
|
|
25308
25418
|
this.selectConfigCache = new Map();
|
|
25309
25419
|
// Cache for data type select configs
|
|
@@ -25322,9 +25432,29 @@ class TemplateVariablesFormComponent {
|
|
|
25322
25432
|
{ id: 'runtime', value: 'runtime', name: '$|Runtime|', label: '$|Runtime|' },
|
|
25323
25433
|
{ id: 'environment', value: 'environment', name: '*|Environment|', label: '*|Environment|' }
|
|
25324
25434
|
];
|
|
25435
|
+
this.createElementVisible = false;
|
|
25436
|
+
}
|
|
25437
|
+
onCreateElement(payload) {
|
|
25438
|
+
console.log('onCreateElement', payload);
|
|
25439
|
+
this.createElement.emit(payload);
|
|
25440
|
+
this.createElementVisible = false;
|
|
25441
|
+
this.elementFormVisibilityChange.emit(false);
|
|
25442
|
+
this.cdr.markForCheck();
|
|
25443
|
+
}
|
|
25444
|
+
onCancelElementForm() {
|
|
25445
|
+
this.createElementVisible = false;
|
|
25446
|
+
this.elementFormVisibilityChange.emit(false);
|
|
25447
|
+
this.cancelElementForm.emit();
|
|
25448
|
+
this.cdr.markForCheck();
|
|
25449
|
+
}
|
|
25450
|
+
onShowElementForm() {
|
|
25451
|
+
this.createElementVisible = true;
|
|
25452
|
+
this.elementFormVisibilityChange.emit(true);
|
|
25453
|
+
this.cdr.markForCheck();
|
|
25325
25454
|
}
|
|
25326
25455
|
ngOnChanges(changes) {
|
|
25327
|
-
if (changes['templateVariables'] || changes['variablesForm']
|
|
25456
|
+
if (changes['templateVariables'] || changes['variablesForm'] || changes['elementOptions'] ||
|
|
25457
|
+
changes['hasMoreElements'] || changes['isLoadingElements']) {
|
|
25328
25458
|
// Clear all caches when inputs change
|
|
25329
25459
|
this.selectConfigCache.clear();
|
|
25330
25460
|
this.dataTypeSelectConfigCache.clear();
|
|
@@ -25341,34 +25471,51 @@ class TemplateVariablesFormComponent {
|
|
|
25341
25471
|
}
|
|
25342
25472
|
}
|
|
25343
25473
|
initializeTestDataVariables() {
|
|
25344
|
-
this.templateVariables.forEach(variable => {
|
|
25474
|
+
this.templateVariables.forEach((variable, index) => {
|
|
25345
25475
|
if (this.needsDataTypeDropdown(variable)) {
|
|
25346
25476
|
const { dataType, rawValue } = this.parseTestDataValue(variable.value || '');
|
|
25347
25477
|
this.variableDataTypes.set(variable.name, dataType);
|
|
25348
25478
|
this.variableRawValues.set(variable.name, rawValue);
|
|
25349
|
-
// Ensure form control exists for data type
|
|
25350
|
-
const
|
|
25351
|
-
if (
|
|
25352
|
-
|
|
25353
|
-
|
|
25354
|
-
|
|
25355
|
-
|
|
25479
|
+
// Ensure form control exists for data type in the FormArray
|
|
25480
|
+
const variableGroup = this.getVariableFormGroup(variable.name);
|
|
25481
|
+
if (variableGroup) {
|
|
25482
|
+
if (!variableGroup.get('dataType')) {
|
|
25483
|
+
variableGroup.addControl('dataType', new FormControl(dataType));
|
|
25484
|
+
}
|
|
25485
|
+
else {
|
|
25486
|
+
variableGroup.get('dataType')?.setValue(dataType, { emitEvent: false });
|
|
25487
|
+
}
|
|
25356
25488
|
}
|
|
25357
25489
|
}
|
|
25358
25490
|
});
|
|
25359
25491
|
}
|
|
25492
|
+
/** Get form group for a variable by name from FormArray */
|
|
25493
|
+
getVariableFormGroup(variableName) {
|
|
25494
|
+
const variableIndex = this.variablesForm.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
25495
|
+
if (variableIndex !== -1) {
|
|
25496
|
+
return this.variablesForm.at(variableIndex);
|
|
25497
|
+
}
|
|
25498
|
+
return null;
|
|
25499
|
+
}
|
|
25500
|
+
/** Get form group at a specific index from FormArray (for template use) */
|
|
25501
|
+
getFormGroupAt(index) {
|
|
25502
|
+
if (index >= 0 && index < this.variablesForm.length) {
|
|
25503
|
+
return this.variablesForm.at(index);
|
|
25504
|
+
}
|
|
25505
|
+
return null;
|
|
25506
|
+
}
|
|
25360
25507
|
precomputeConfigs() {
|
|
25361
25508
|
if (!this.templateVariables)
|
|
25362
25509
|
return;
|
|
25363
25510
|
// Pre-compute all select configs
|
|
25364
|
-
this.templateVariables.forEach(variable => {
|
|
25511
|
+
this.templateVariables.forEach((variable, index) => {
|
|
25365
25512
|
// Pre-compute regular select configs
|
|
25366
25513
|
if (this.shouldShowDropdown(variable)) {
|
|
25367
|
-
this.getSelectConfig(variable);
|
|
25514
|
+
this.getSelectConfig(variable, index);
|
|
25368
25515
|
}
|
|
25369
25516
|
// Pre-compute data type select configs
|
|
25370
25517
|
if (this.needsDataTypeDropdown(variable)) {
|
|
25371
|
-
this.getDataTypeSelectConfig(variable);
|
|
25518
|
+
this.getDataTypeSelectConfig(variable, index);
|
|
25372
25519
|
}
|
|
25373
25520
|
});
|
|
25374
25521
|
}
|
|
@@ -25412,32 +25559,70 @@ class TemplateVariablesFormComponent {
|
|
|
25412
25559
|
trackByVariable(index, variable) {
|
|
25413
25560
|
return variable.name || index;
|
|
25414
25561
|
}
|
|
25415
|
-
getSelectConfig(variable) {
|
|
25562
|
+
getSelectConfig(variable, index) {
|
|
25416
25563
|
// Use cache to avoid recalculating on every change detection
|
|
25417
|
-
|
|
25564
|
+
// For element variables, include elementOptions, hasMoreElements, and isLoadingElements in cache key
|
|
25565
|
+
const optionsKey = variable.dataKey === 'element' || variable.dataKey === 'label'
|
|
25566
|
+
? this.elementOptions.map(el => String(el.name || '')).join(',')
|
|
25567
|
+
: (variable.options?.join(',') || '');
|
|
25568
|
+
// Include hasMoreElements and isLoadingElements in cache key for selector variables
|
|
25569
|
+
const cacheKey = variable.dataKey === 'element' || variable.dataKey === 'label'
|
|
25570
|
+
? `${variable.name}_${optionsKey}_${this.hasMoreElements}_${this.isLoadingElements}`
|
|
25571
|
+
: `${variable.name}_${optionsKey}`;
|
|
25418
25572
|
if (this.selectConfigCache.has(cacheKey)) {
|
|
25419
25573
|
return this.selectConfigCache.get(cacheKey);
|
|
25420
25574
|
}
|
|
25421
|
-
|
|
25422
|
-
|
|
25423
|
-
|
|
25424
|
-
|
|
25425
|
-
|
|
25426
|
-
|
|
25575
|
+
// Use elementOptions if variable name is 'selector', otherwise use variable.options
|
|
25576
|
+
// Extract element names from Element objects
|
|
25577
|
+
let optionsArray = [];
|
|
25578
|
+
if (variable.dataKey === 'element' || variable.dataKey === 'label') {
|
|
25579
|
+
// For element options, use locatorValue as both id and value so the component returns locatorValue
|
|
25580
|
+
// This ensures the selected value is the locatorValue (not the element id)
|
|
25581
|
+
optionsArray = this.elementOptions
|
|
25582
|
+
.map(el => {
|
|
25583
|
+
const locatorValue = el.locatorValue || '';
|
|
25584
|
+
return {
|
|
25585
|
+
id: locatorValue,
|
|
25586
|
+
elementId: el.id?.toString() || '',
|
|
25587
|
+
value: locatorValue,
|
|
25588
|
+
name: el.name,
|
|
25589
|
+
label: el.name
|
|
25590
|
+
};
|
|
25591
|
+
});
|
|
25592
|
+
}
|
|
25593
|
+
else {
|
|
25594
|
+
optionsArray = variable.options?.map(opt => { return { id: opt, value: opt, name: opt, label: opt }; }) || [];
|
|
25595
|
+
}
|
|
25596
|
+
console.log('optionsArray', optionsArray);
|
|
25427
25597
|
const config = {
|
|
25428
|
-
key:
|
|
25598
|
+
key: 'value',
|
|
25429
25599
|
placeholder: `Select ${variable.label}`,
|
|
25430
25600
|
multiple: false,
|
|
25431
25601
|
searchable: false,
|
|
25432
|
-
options:
|
|
25602
|
+
options: optionsArray,
|
|
25433
25603
|
onChange: (value) => {
|
|
25434
25604
|
this.onVariableValueChange(variable.name, value);
|
|
25435
25605
|
}
|
|
25436
25606
|
};
|
|
25607
|
+
// Add load more and search support for selector variables
|
|
25608
|
+
if (variable.dataKey === 'element' || variable.dataKey === 'label') {
|
|
25609
|
+
config.searchable = true; // Enable search for selector dropdown
|
|
25610
|
+
config.serverSearch = true; // Enable server-side search
|
|
25611
|
+
config.hasMore = this.hasMoreElements;
|
|
25612
|
+
config.isLoading = this.isLoadingElements;
|
|
25613
|
+
config.onLoadMore = () => {
|
|
25614
|
+
this.loadMoreElements.emit();
|
|
25615
|
+
};
|
|
25616
|
+
config.onSearch = (query) => {
|
|
25617
|
+
// Emit search event when user types in the search box
|
|
25618
|
+
this.searchElements.emit(query);
|
|
25619
|
+
};
|
|
25620
|
+
}
|
|
25437
25621
|
this.selectConfigCache.set(cacheKey, config);
|
|
25438
25622
|
return config;
|
|
25439
25623
|
}
|
|
25440
25624
|
onVariableValueChange(variableName, value) {
|
|
25625
|
+
console.log("onVariableValueChange", variableName, value);
|
|
25441
25626
|
const variable = this.templateVariables.find(v => v.name === variableName);
|
|
25442
25627
|
if (!variable)
|
|
25443
25628
|
return;
|
|
@@ -25446,17 +25631,18 @@ class TemplateVariablesFormComponent {
|
|
|
25446
25631
|
const { dataType, rawValue } = this.parseTestDataValue(value || '');
|
|
25447
25632
|
this.variableDataTypes.set(variableName, dataType);
|
|
25448
25633
|
this.variableRawValues.set(variableName, rawValue);
|
|
25449
|
-
// Update data type form control
|
|
25450
|
-
const
|
|
25451
|
-
if (
|
|
25452
|
-
|
|
25634
|
+
// Update data type form control in FormArray
|
|
25635
|
+
const variableGroup = this.getVariableFormGroup(variableName);
|
|
25636
|
+
if (variableGroup && variableGroup.get('dataType')) {
|
|
25637
|
+
variableGroup.get('dataType')?.setValue(dataType, { emitEvent: false });
|
|
25453
25638
|
}
|
|
25454
25639
|
}
|
|
25455
25640
|
// Update the variable in templateVariables array
|
|
25456
25641
|
variable.value = value;
|
|
25457
|
-
// Also update form control (use emitEvent: false to prevent triggering valueChanges)
|
|
25458
|
-
|
|
25459
|
-
|
|
25642
|
+
// Also update form control in FormArray (use emitEvent: false to prevent triggering valueChanges)
|
|
25643
|
+
const variableGroup = this.getVariableFormGroup(variableName);
|
|
25644
|
+
if (variableGroup && variableGroup.get('value')) {
|
|
25645
|
+
variableGroup.get('value')?.setValue(value, { emitEvent: false });
|
|
25460
25646
|
}
|
|
25461
25647
|
// Mark for check since we're using OnPush
|
|
25462
25648
|
this.cdr.markForCheck();
|
|
@@ -25469,14 +25655,12 @@ class TemplateVariablesFormComponent {
|
|
|
25469
25655
|
if (variable) {
|
|
25470
25656
|
variable.value = value;
|
|
25471
25657
|
}
|
|
25472
|
-
// Also update form control (use emitEvent: false to prevent triggering valueChanges)
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
else {
|
|
25477
|
-
// Create form control if it doesn't exist
|
|
25478
|
-
this.variablesForm.addControl(variableName, new FormControl(value));
|
|
25658
|
+
// Also update form control in FormArray (use emitEvent: false to prevent triggering valueChanges)
|
|
25659
|
+
const variableGroup = this.getVariableFormGroup(variableName);
|
|
25660
|
+
if (variableGroup && variableGroup.get('value')) {
|
|
25661
|
+
variableGroup.get('value')?.setValue(value, { emitEvent: false });
|
|
25479
25662
|
}
|
|
25663
|
+
// Note: If variable doesn't exist in FormArray, it should be added by parent component
|
|
25480
25664
|
// Mark for check since we're using OnPush
|
|
25481
25665
|
this.cdr.markForCheck();
|
|
25482
25666
|
// Emit the change event
|
|
@@ -25487,7 +25671,7 @@ class TemplateVariablesFormComponent {
|
|
|
25487
25671
|
if (this.shouldShowDropdownCache.has(variable.name)) {
|
|
25488
25672
|
return this.shouldShowDropdownCache.get(variable.name);
|
|
25489
25673
|
}
|
|
25490
|
-
const result = variable.name === 'type' || variable.name === 'scrollTo';
|
|
25674
|
+
const result = variable.name === 'type' || variable.name === 'scrollTo' || variable.dataKey === 'element' || variable.dataKey === 'label';
|
|
25491
25675
|
this.shouldShowDropdownCache.set(variable.name, result);
|
|
25492
25676
|
return result;
|
|
25493
25677
|
}
|
|
@@ -25496,8 +25680,8 @@ class TemplateVariablesFormComponent {
|
|
|
25496
25680
|
if (this.needsDataTypeDropdownCache.has(variable.name)) {
|
|
25497
25681
|
return this.needsDataTypeDropdownCache.get(variable.name);
|
|
25498
25682
|
}
|
|
25499
|
-
const
|
|
25500
|
-
const result =
|
|
25683
|
+
const dataKey = variable.dataKey?.toLowerCase() || '';
|
|
25684
|
+
const result = dataKey === 'test-data' || dataKey === 'source_value' || dataKey === 'target_value';
|
|
25501
25685
|
this.needsDataTypeDropdownCache.set(variable.name, result);
|
|
25502
25686
|
return result;
|
|
25503
25687
|
}
|
|
@@ -25505,20 +25689,20 @@ class TemplateVariablesFormComponent {
|
|
|
25505
25689
|
// Return cached static array
|
|
25506
25690
|
return this.dataTypeOptions;
|
|
25507
25691
|
}
|
|
25508
|
-
getDataTypeSelectConfig(variable) {
|
|
25692
|
+
getDataTypeSelectConfig(variable, index) {
|
|
25509
25693
|
// Use cache to avoid recalculating on every change detection
|
|
25510
25694
|
const cacheKey = `${variable.name}_dataType`;
|
|
25511
25695
|
if (this.dataTypeSelectConfigCache.has(cacheKey)) {
|
|
25512
25696
|
return this.dataTypeSelectConfigCache.get(cacheKey);
|
|
25513
25697
|
}
|
|
25514
|
-
|
|
25515
|
-
|
|
25516
|
-
if (!
|
|
25698
|
+
// Ensure form control exists in FormArray
|
|
25699
|
+
const variableGroup = this.getVariableFormGroup(variable.name);
|
|
25700
|
+
if (variableGroup && !variableGroup.get('dataType')) {
|
|
25517
25701
|
const currentDataType = this.variableDataTypes.get(variable.name) || 'plain-text';
|
|
25518
|
-
|
|
25702
|
+
variableGroup.addControl('dataType', new FormControl(currentDataType));
|
|
25519
25703
|
}
|
|
25520
25704
|
const config = {
|
|
25521
|
-
key:
|
|
25705
|
+
key: 'dataType',
|
|
25522
25706
|
placeholder: 'Select Type',
|
|
25523
25707
|
multiple: false,
|
|
25524
25708
|
searchable: false,
|
|
@@ -25538,6 +25722,38 @@ class TemplateVariablesFormComponent {
|
|
|
25538
25722
|
// Simple getter - already cached in Map, no computation needed
|
|
25539
25723
|
return this.variableRawValues.get(variable.name) || '';
|
|
25540
25724
|
}
|
|
25725
|
+
/**
|
|
25726
|
+
* Check if selector variable is available in templateVariables
|
|
25727
|
+
*/
|
|
25728
|
+
get selectorVariableAvailable() {
|
|
25729
|
+
return this.templateVariables.some(v => v.dataKey === 'element' || v.dataKey === 'label');
|
|
25730
|
+
}
|
|
25731
|
+
/**
|
|
25732
|
+
* Check if parameter variable is available (testData with parameter type)
|
|
25733
|
+
*/
|
|
25734
|
+
get parameterVariableAvailable() {
|
|
25735
|
+
return this.templateVariables.some(v => {
|
|
25736
|
+
const dataKey = v.dataKey?.toLowerCase() || '';
|
|
25737
|
+
if (dataKey === 'test-data' || dataKey === 'source_value' || dataKey === 'target_value') {
|
|
25738
|
+
const dataType = this.variableDataTypes.get(v.name) || 'plain-text';
|
|
25739
|
+
return dataType === 'parameter';
|
|
25740
|
+
}
|
|
25741
|
+
return false;
|
|
25742
|
+
});
|
|
25743
|
+
}
|
|
25744
|
+
/**
|
|
25745
|
+
* Check if environment variable is available (testData with environment type)
|
|
25746
|
+
*/
|
|
25747
|
+
get environmentVariableAvailable() {
|
|
25748
|
+
return this.templateVariables.some(v => {
|
|
25749
|
+
const dataKey = v.name?.toLowerCase() || '';
|
|
25750
|
+
if (dataKey === 'test-data' || dataKey === 'source_value' || dataKey === 'target_value') {
|
|
25751
|
+
const dataType = this.variableDataTypes.get(v.name) || 'plain-text';
|
|
25752
|
+
return dataType === 'environment';
|
|
25753
|
+
}
|
|
25754
|
+
return false;
|
|
25755
|
+
});
|
|
25756
|
+
}
|
|
25541
25757
|
onDataTypeChange(variableName, dataType) {
|
|
25542
25758
|
// Update stored data type
|
|
25543
25759
|
this.variableDataTypes.set(variableName, dataType);
|
|
@@ -25550,9 +25766,10 @@ class TemplateVariablesFormComponent {
|
|
|
25550
25766
|
if (variable) {
|
|
25551
25767
|
variable.value = formattedValue;
|
|
25552
25768
|
}
|
|
25553
|
-
// Update form control
|
|
25554
|
-
|
|
25555
|
-
|
|
25769
|
+
// Update form control in FormArray
|
|
25770
|
+
const variableGroup = this.getVariableFormGroup(variableName);
|
|
25771
|
+
if (variableGroup && variableGroup.get('value')) {
|
|
25772
|
+
variableGroup.get('value')?.setValue(formattedValue, { emitEvent: false });
|
|
25556
25773
|
}
|
|
25557
25774
|
// Mark for check since we're using OnPush
|
|
25558
25775
|
this.cdr.markForCheck();
|
|
@@ -25560,6 +25777,12 @@ class TemplateVariablesFormComponent {
|
|
|
25560
25777
|
// Emit the change event
|
|
25561
25778
|
this.variableValueChange.emit({ name: variableName, value: formattedValue });
|
|
25562
25779
|
}
|
|
25780
|
+
onElementSearch(event) {
|
|
25781
|
+
// Only handle search for selector variables
|
|
25782
|
+
// The key will be 'value' since that's what we set in the config
|
|
25783
|
+
// Emit the search query to parent component
|
|
25784
|
+
this.searchElements.emit(event.query);
|
|
25785
|
+
}
|
|
25563
25786
|
onTestDataValueChange(variableName, rawValue) {
|
|
25564
25787
|
// Update stored raw value
|
|
25565
25788
|
this.variableRawValues.set(variableName, rawValue);
|
|
@@ -25572,9 +25795,10 @@ class TemplateVariablesFormComponent {
|
|
|
25572
25795
|
if (variable) {
|
|
25573
25796
|
variable.value = formattedValue;
|
|
25574
25797
|
}
|
|
25575
|
-
// Update form control
|
|
25576
|
-
|
|
25577
|
-
|
|
25798
|
+
// Update form control in FormArray
|
|
25799
|
+
const variableGroup = this.getVariableFormGroup(variableName);
|
|
25800
|
+
if (variableGroup && variableGroup.get('value')) {
|
|
25801
|
+
variableGroup.get('value')?.setValue(formattedValue, { emitEvent: false });
|
|
25578
25802
|
}
|
|
25579
25803
|
// Mark for check since we're using OnPush
|
|
25580
25804
|
this.cdr.markForCheck();
|
|
@@ -25583,10 +25807,10 @@ class TemplateVariablesFormComponent {
|
|
|
25583
25807
|
}
|
|
25584
25808
|
}
|
|
25585
25809
|
TemplateVariablesFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TemplateVariablesFormComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
25586
|
-
TemplateVariablesFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TemplateVariablesFormComponent, selector: "cqa-template-variables-form", inputs: { templateVariables: "templateVariables", variablesForm: "variablesForm", metadata: "metadata", description: "description" }, outputs: { variableValueChange: "variableValueChange", variableBooleanChange: "variableBooleanChange", metadataChange: "metadataChange", descriptionChange: "descriptionChange" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-gap-x-6 cqa-flex-wrap\">\n <ng-container *ngFor=\"let variable of templateVariables; trackBy: trackByVariable\">\n <!-- Boolean variables with mat-slide-toggle -->\n <ng-container *ngIf=\"variable.type === 'boolean'\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">\n {{ variable.label }}\n </label>\n <mat-slide-toggle
|
|
25810
|
+
TemplateVariablesFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: TemplateVariablesFormComponent, selector: "cqa-template-variables-form", inputs: { templateVariables: "templateVariables", variablesForm: "variablesForm", metadata: "metadata", description: "description", elementOptions: "elementOptions", hasMoreElements: "hasMoreElements", isLoadingElements: "isLoadingElements", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames" }, outputs: { variableValueChange: "variableValueChange", variableBooleanChange: "variableBooleanChange", metadataChange: "metadataChange", descriptionChange: "descriptionChange", loadMoreElements: "loadMoreElements", searchElements: "searchElements", createElement: "createElement", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", createScreenNameRequest: "createScreenNameRequest", cancelElementForm: "cancelElementForm", elementFormVisibilityChange: "elementFormVisibilityChange" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-gap-x-6 cqa-gap-y-4 cqa-flex-wrap\" *ngIf=\"!createElementVisible\">\n <ng-container *ngFor=\"let variable of templateVariables; let i = index; trackBy: trackByVariable\">\n <!-- Boolean variables with mat-slide-toggle -->\n <ng-container *ngIf=\"variable.type === 'boolean'\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">\n {{ variable.label }}\n </label>\n <mat-slide-toggle [checked]=\"variablesForm.at(i)?.get('value')?.value || variable.value || false\"\n (change)=\"onVariableBooleanChange(variable.name, $event.checked)\" color=\"primary\">\n </mat-slide-toggle>\n </div>\n </ng-container>\n\n <!-- Non-boolean, non-custom_code variables -->\n <ng-container *ngIf=\"variable.name !== 'custom_code' && variable.type !== 'boolean'\">\n <ng-container *ngIf=\"shouldShowDropdown(variable); else defaultInput\">\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-dynamic-select [form]=\"getFormGroupAt(i)!\" [config]=\"getSelectConfig(variable, i)\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-template #defaultInput>\n <!-- Test-data, source-value, or target-value with data type dropdown -->\n <ng-container *ngIf=\"needsDataTypeDropdown(variable); else regularInput\">\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }} Type\n </label>\n <cqa-dynamic-select [form]=\"getFormGroupAt(i)!\" [config]=\"getDataTypeSelectConfig(variable, i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"getRawValue(variable)\" [fullWidth]=\"true\"\n (valueChange)=\"onTestDataValueChange(variable.name, $event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n <ng-template #regularInput>\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"variable.value\" [fullWidth]=\"true\"\n (valueChange)=\"onVariableValueChange(variable.name, $event)\">\n </cqa-custom-input>\n </div>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-container>\n\n <!-- Metadata -->\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n Metadata\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"metadata\" [fullWidth]=\"true\"\n (valueChange)=\"metadataChange.emit($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Description -->\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n Description\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"description\" [fullWidth]=\"true\"\n (valueChange)=\"descriptionChange.emit($event)\">\n </cqa-custom-input>\n </div>\n</div>\n\n<div *ngIf=\"createElementVisible\">\n <cqa-element-form\n [isCreateMode]=\"true\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n [isEditInDepthAvailable]=\"false\"\n (createElement)=\"onCreateElement($event)\"\n (cancel)=\"onCancelElementForm()\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\">\n </cqa-element-form>\n</div>\n<div class=\"cqa-flex cqa-justify-end cqa-pt-2\" *ngIf=\"!createElementVisible\">\n <cqa-button \n *ngIf=\"selectorVariableAvailable\"\n variant=\"text\" \n size=\"sm\"\n text=\"Create Element\"\n (clicked)=\"onShowElementForm()\">\n </cqa-button>\n <!-- <cqa-button \n *ngIf=\"parameterVariableAvailable\"\n variant=\"filled\" \n text=\"Create Parameter\"\n (clicked)=\"onCreateParameter()\">\n </cqa-button>\n <cqa-button \n *ngIf=\"environmentVariableAvailable\"\n variant=\"filled\" \n text=\"Create Environment\"\n (clicked)=\"onCreateEnvironment()\">\n </cqa-button> -->\n</div>", components: [{ type: i5$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex", "name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "checked"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { 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: ElementFormComponent, selector: "cqa-element-form", inputs: ["elementId", "element", "screenNameOptions", "hasMoreScreenNames", "isLoadingScreenNames", "isElementLoading", "isEditMode", "isCreateMode", "isEditInDepthAvailable"], outputs: ["createElement", "updateElement", "createScreenNameRequest", "searchScreenName", "loadMoreScreenNames", "cancel", "editInDepth"] }, { 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 });
|
|
25587
25811
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: TemplateVariablesFormComponent, decorators: [{
|
|
25588
25812
|
type: Component,
|
|
25589
|
-
args: [{ selector: 'cqa-template-variables-form', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-flex cqa-gap-x-6 cqa-flex-wrap\">\n <ng-container *ngFor=\"let variable of templateVariables; trackBy: trackByVariable\">\n <!-- Boolean variables with mat-slide-toggle -->\n <ng-container *ngIf=\"variable.type === 'boolean'\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">\n {{ variable.label }}\n </label>\n <mat-slide-toggle
|
|
25813
|
+
args: [{ selector: 'cqa-template-variables-form', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"cqa-flex cqa-gap-x-6 cqa-gap-y-4 cqa-flex-wrap\" *ngIf=\"!createElementVisible\">\n <ng-container *ngFor=\"let variable of templateVariables; let i = index; trackBy: trackByVariable\">\n <!-- Boolean variables with mat-slide-toggle -->\n <ng-container *ngIf=\"variable.type === 'boolean'\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700\">\n {{ variable.label }}\n </label>\n <mat-slide-toggle [checked]=\"variablesForm.at(i)?.get('value')?.value || variable.value || false\"\n (change)=\"onVariableBooleanChange(variable.name, $event.checked)\" color=\"primary\">\n </mat-slide-toggle>\n </div>\n </ng-container>\n\n <!-- Non-boolean, non-custom_code variables -->\n <ng-container *ngIf=\"variable.name !== 'custom_code' && variable.type !== 'boolean'\">\n <ng-container *ngIf=\"shouldShowDropdown(variable); else defaultInput\">\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-dynamic-select [form]=\"getFormGroupAt(i)!\" [config]=\"getSelectConfig(variable, i)\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-template #defaultInput>\n <!-- Test-data, source-value, or target-value with data type dropdown -->\n <ng-container *ngIf=\"needsDataTypeDropdown(variable); else regularInput\">\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }} Type\n </label>\n <cqa-dynamic-select [form]=\"getFormGroupAt(i)!\" [config]=\"getDataTypeSelectConfig(variable, i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"getRawValue(variable)\" [fullWidth]=\"true\"\n (valueChange)=\"onTestDataValueChange(variable.name, $event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n <ng-template #regularInput>\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n {{ variable.label }}\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"variable.value\" [fullWidth]=\"true\"\n (valueChange)=\"onVariableValueChange(variable.name, $event)\">\n </cqa-custom-input>\n </div>\n </ng-template>\n </ng-template>\n </ng-container>\n </ng-container>\n\n <!-- Metadata -->\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n Metadata\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"metadata\" [fullWidth]=\"true\"\n (valueChange)=\"metadataChange.emit($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Description -->\n <div class=\"cqa-flex cqa-flex-col\" style=\"width: calc(50% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1\">\n Description\n </label>\n <cqa-custom-input [placeholder]=\"'Text Input'\" [value]=\"description\" [fullWidth]=\"true\"\n (valueChange)=\"descriptionChange.emit($event)\">\n </cqa-custom-input>\n </div>\n</div>\n\n<div *ngIf=\"createElementVisible\">\n <cqa-element-form\n [isCreateMode]=\"true\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n [isEditInDepthAvailable]=\"false\"\n (createElement)=\"onCreateElement($event)\"\n (cancel)=\"onCancelElementForm()\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\">\n </cqa-element-form>\n</div>\n<div class=\"cqa-flex cqa-justify-end cqa-pt-2\" *ngIf=\"!createElementVisible\">\n <cqa-button \n *ngIf=\"selectorVariableAvailable\"\n variant=\"text\" \n size=\"sm\"\n text=\"Create Element\"\n (clicked)=\"onShowElementForm()\">\n </cqa-button>\n <!-- <cqa-button \n *ngIf=\"parameterVariableAvailable\"\n variant=\"filled\" \n text=\"Create Parameter\"\n (clicked)=\"onCreateParameter()\">\n </cqa-button>\n <cqa-button \n *ngIf=\"environmentVariableAvailable\"\n variant=\"filled\" \n text=\"Create Environment\"\n (clicked)=\"onCreateEnvironment()\">\n </cqa-button> -->\n</div>", styles: [] }]
|
|
25590
25814
|
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { templateVariables: [{
|
|
25591
25815
|
type: Input
|
|
25592
25816
|
}], variablesForm: [{
|
|
@@ -25595,6 +25819,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
25595
25819
|
type: Input
|
|
25596
25820
|
}], description: [{
|
|
25597
25821
|
type: Input
|
|
25822
|
+
}], elementOptions: [{
|
|
25823
|
+
type: Input
|
|
25824
|
+
}], hasMoreElements: [{
|
|
25825
|
+
type: Input
|
|
25826
|
+
}], isLoadingElements: [{
|
|
25827
|
+
type: Input
|
|
25828
|
+
}], screenNameOptions: [{
|
|
25829
|
+
type: Input
|
|
25830
|
+
}], hasMoreScreenNames: [{
|
|
25831
|
+
type: Input
|
|
25832
|
+
}], isLoadingScreenNames: [{
|
|
25833
|
+
type: Input
|
|
25598
25834
|
}], variableValueChange: [{
|
|
25599
25835
|
type: Output
|
|
25600
25836
|
}], variableBooleanChange: [{
|
|
@@ -25603,6 +25839,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
25603
25839
|
type: Output
|
|
25604
25840
|
}], descriptionChange: [{
|
|
25605
25841
|
type: Output
|
|
25842
|
+
}], loadMoreElements: [{
|
|
25843
|
+
type: Output
|
|
25844
|
+
}], searchElements: [{
|
|
25845
|
+
type: Output
|
|
25846
|
+
}], createElement: [{
|
|
25847
|
+
type: Output
|
|
25848
|
+
}], searchScreenName: [{
|
|
25849
|
+
type: Output
|
|
25850
|
+
}], loadMoreScreenNames: [{
|
|
25851
|
+
type: Output
|
|
25852
|
+
}], createScreenNameRequest: [{
|
|
25853
|
+
type: Output
|
|
25854
|
+
}], cancelElementForm: [{
|
|
25855
|
+
type: Output
|
|
25856
|
+
}], elementFormVisibilityChange: [{
|
|
25857
|
+
type: Output
|
|
25606
25858
|
}] } });
|
|
25607
25859
|
|
|
25608
25860
|
class StepBuilderActionComponent {
|
|
@@ -25616,7 +25868,22 @@ class StepBuilderActionComponent {
|
|
|
25616
25868
|
/** Function to handle variable processing or custom logic. Can be passed from parent component. */
|
|
25617
25869
|
this.setTemplateVariables = () => { return []; };
|
|
25618
25870
|
this.preventSelectTemplate = ['databaseverification'];
|
|
25871
|
+
this.elementOptions = []; // Element objects for element dropdown
|
|
25872
|
+
this.hasMoreElements = false; // Whether more elements are available
|
|
25873
|
+
this.isLoadingElements = false; // Loading state for elements
|
|
25874
|
+
/** Screen name options for element form autocomplete (from API) */
|
|
25875
|
+
this.screenNameOptions = [];
|
|
25876
|
+
/** Whether more screen names are available for infinite scroll */
|
|
25877
|
+
this.hasMoreScreenNames = false;
|
|
25878
|
+
/** True while parent is loading screen names (search or load more) */
|
|
25879
|
+
this.isLoadingScreenNames = false;
|
|
25619
25880
|
this.templateChanged = new EventEmitter();
|
|
25881
|
+
this.loadMoreElements = new EventEmitter(); // Emit when load more is requested
|
|
25882
|
+
this.searchElements = new EventEmitter(); // Emit when user searches for elements
|
|
25883
|
+
this.createElement = new EventEmitter(); // Emit when element is created
|
|
25884
|
+
this.searchScreenName = new EventEmitter(); // Emit when user searches screen names
|
|
25885
|
+
this.loadMoreScreenNames = new EventEmitter(); // Emit when user scrolls to load more screen names
|
|
25886
|
+
this.createScreenNameRequest = new EventEmitter(); // Emit when user requests to create a new screen name
|
|
25620
25887
|
/** Emit when step is created */
|
|
25621
25888
|
this.createStep = new EventEmitter();
|
|
25622
25889
|
/** Emit when cancelled */
|
|
@@ -25628,12 +25895,21 @@ class StepBuilderActionComponent {
|
|
|
25628
25895
|
this.description = '';
|
|
25629
25896
|
this.advancedExpanded = false;
|
|
25630
25897
|
this.templateVariables = [];
|
|
25898
|
+
this.updatedHtmlGrammar = ''; // Updated HTML grammar with variable values
|
|
25899
|
+
// Track element form visibility
|
|
25900
|
+
this.isElementFormVisible = false;
|
|
25631
25901
|
// Cache for select configs to avoid recalculating on every change detection
|
|
25632
25902
|
this.selectConfigCache = new Map();
|
|
25633
25903
|
this.formValidCache = false;
|
|
25634
25904
|
this.lastFormValidationTime = 0;
|
|
25635
25905
|
this.FORM_VALIDATION_CACHE_MS = 100; // Cache for 100ms
|
|
25636
|
-
this.variablesForm = this.fb.
|
|
25906
|
+
this.variablesForm = this.fb.array([]);
|
|
25907
|
+
}
|
|
25908
|
+
/**
|
|
25909
|
+
* Handle element form visibility change
|
|
25910
|
+
*/
|
|
25911
|
+
onElementFormVisibilityChange(visible) {
|
|
25912
|
+
this.isElementFormVisible = visible;
|
|
25637
25913
|
}
|
|
25638
25914
|
ngOnInit() {
|
|
25639
25915
|
this.filteredTemplates = [...this.templates];
|
|
@@ -25663,14 +25939,38 @@ class StepBuilderActionComponent {
|
|
|
25663
25939
|
const searchTerm = this.searchValue.toLowerCase().trim();
|
|
25664
25940
|
this.filteredTemplates = this.templates.filter(template => {
|
|
25665
25941
|
const naturalText = template.naturalText?.toLowerCase() || '';
|
|
25666
|
-
|
|
25942
|
+
// Strip HTML tags from htmlGrammar for searching (only search text content, not HTML markup)
|
|
25943
|
+
const htmlGrammarText = this.stripHtmlTags(template.htmlGrammar || '').toLowerCase();
|
|
25667
25944
|
const searchableGrammar = template.searchableGrammar?.toLowerCase() || '';
|
|
25668
25945
|
return naturalText.includes(searchTerm) ||
|
|
25669
|
-
|
|
25946
|
+
htmlGrammarText.includes(searchTerm) ||
|
|
25670
25947
|
searchableGrammar.includes(searchTerm);
|
|
25671
25948
|
});
|
|
25672
25949
|
console.log("filteredTemplates", this.filteredTemplates);
|
|
25673
25950
|
}
|
|
25951
|
+
/**
|
|
25952
|
+
* Strip HTML tags from a string, returning only the text content
|
|
25953
|
+
* @param htmlString - HTML string to strip tags from
|
|
25954
|
+
* @returns Plain text without HTML tags
|
|
25955
|
+
*/
|
|
25956
|
+
stripHtmlTags(htmlString) {
|
|
25957
|
+
if (!htmlString)
|
|
25958
|
+
return '';
|
|
25959
|
+
// Use browser's DOMParser if available
|
|
25960
|
+
if (typeof document !== 'undefined' && document.createElement) {
|
|
25961
|
+
try {
|
|
25962
|
+
const tempDiv = document.createElement('div');
|
|
25963
|
+
tempDiv.innerHTML = htmlString;
|
|
25964
|
+
return tempDiv.textContent || tempDiv.innerText || '';
|
|
25965
|
+
}
|
|
25966
|
+
catch (error) {
|
|
25967
|
+
// Fallback to regex if DOM parsing fails
|
|
25968
|
+
return htmlString.replace(/<[^>]*>/g, '');
|
|
25969
|
+
}
|
|
25970
|
+
}
|
|
25971
|
+
// Fallback: regex-based tag removal for server-side rendering
|
|
25972
|
+
return htmlString.replace(/<[^>]*>/g, '');
|
|
25973
|
+
}
|
|
25674
25974
|
selectTemplate(template) {
|
|
25675
25975
|
if (this.preventSelectTemplate.includes(template.displayName || '')) {
|
|
25676
25976
|
this.templateChanged.emit(template);
|
|
@@ -25687,20 +25987,26 @@ class StepBuilderActionComponent {
|
|
|
25687
25987
|
setTimeout(() => {
|
|
25688
25988
|
try {
|
|
25689
25989
|
this.templateVariables = this.setTemplateVariables(template);
|
|
25990
|
+
console.log("templateVariables", this.templateVariables);
|
|
25690
25991
|
this.buildVariablesForm();
|
|
25992
|
+
// Initialize updated HTML grammar
|
|
25993
|
+
this.updateHtmlGrammar();
|
|
25691
25994
|
}
|
|
25692
25995
|
catch (error) {
|
|
25693
25996
|
console.error('Error processing template variables:', error);
|
|
25694
25997
|
}
|
|
25695
25998
|
}, 0);
|
|
25696
25999
|
}
|
|
26000
|
+
else {
|
|
26001
|
+
// Initialize with template's HTML grammar if no variables
|
|
26002
|
+
this.updatedHtmlGrammar = template.htmlGrammar || template.naturalText || '';
|
|
26003
|
+
}
|
|
25697
26004
|
}
|
|
25698
26005
|
buildVariablesForm() {
|
|
25699
|
-
// Clear existing form
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
});
|
|
26006
|
+
// Clear existing form array
|
|
26007
|
+
while (this.variablesForm.length !== 0) {
|
|
26008
|
+
this.variablesForm.removeAt(0);
|
|
26009
|
+
}
|
|
25704
26010
|
// Clear cache when form is rebuilt
|
|
25705
26011
|
this.selectConfigCache.clear();
|
|
25706
26012
|
this.formValidCache = false;
|
|
@@ -25708,13 +26014,39 @@ class StepBuilderActionComponent {
|
|
|
25708
26014
|
if (this.formValueChangesSubscription) {
|
|
25709
26015
|
this.formValueChangesSubscription.unsubscribe();
|
|
25710
26016
|
}
|
|
25711
|
-
// Add form
|
|
26017
|
+
// Add form groups for each variable
|
|
25712
26018
|
this.templateVariables.forEach(variable => {
|
|
25713
26019
|
// Handle boolean variables - use boolean value, others use string
|
|
25714
26020
|
const defaultValue = variable.type === 'boolean'
|
|
25715
26021
|
? (variable.value === true || variable.value === 'true' || variable.value === 1)
|
|
25716
26022
|
: (variable.value || '');
|
|
25717
|
-
|
|
26023
|
+
// Create a FormGroup for each variable with name and value
|
|
26024
|
+
const variableGroup = this.fb.group({
|
|
26025
|
+
name: [variable.name],
|
|
26026
|
+
value: [defaultValue],
|
|
26027
|
+
type: [variable.type || 'string'],
|
|
26028
|
+
label: [variable.label || ''],
|
|
26029
|
+
options: [variable.options || []]
|
|
26030
|
+
});
|
|
26031
|
+
// Add dataType control for test-data variables if needed
|
|
26032
|
+
const label = variable.label?.toLowerCase() || '';
|
|
26033
|
+
if (label === 'test-data' || label === 'source-value' || label === 'target-value' ||
|
|
26034
|
+
label === 'source_value' || label === 'target_value') {
|
|
26035
|
+
// Parse the value to determine data type
|
|
26036
|
+
const valueStr = String(defaultValue || '');
|
|
26037
|
+
let dataType = 'plain-text';
|
|
26038
|
+
if (valueStr.startsWith('@|') && valueStr.endsWith('|')) {
|
|
26039
|
+
dataType = 'parameter';
|
|
26040
|
+
}
|
|
26041
|
+
else if (valueStr.startsWith('$|') && valueStr.endsWith('|')) {
|
|
26042
|
+
dataType = 'runtime';
|
|
26043
|
+
}
|
|
26044
|
+
else if (valueStr.startsWith('*|') && valueStr.endsWith('|')) {
|
|
26045
|
+
dataType = 'environment';
|
|
26046
|
+
}
|
|
26047
|
+
variableGroup.addControl('dataType', new FormControl(dataType));
|
|
26048
|
+
}
|
|
26049
|
+
this.variablesForm.push(variableGroup);
|
|
25718
26050
|
});
|
|
25719
26051
|
// Subscribe to form value changes to invalidate cache (only when user actually changes values)
|
|
25720
26052
|
// Note: We use emitEvent: false when programmatically setting values, so this won't fire unnecessarily
|
|
@@ -25728,7 +26060,7 @@ class StepBuilderActionComponent {
|
|
|
25728
26060
|
this.formValueChangesSubscription.unsubscribe();
|
|
25729
26061
|
}
|
|
25730
26062
|
}
|
|
25731
|
-
getSelectConfig(variable) {
|
|
26063
|
+
getSelectConfig(variable, index) {
|
|
25732
26064
|
// Use cache to avoid recalculating on every change detection
|
|
25733
26065
|
const cacheKey = `${variable.name}_${variable.options?.join(',') || ''}`;
|
|
25734
26066
|
if (this.selectConfigCache.has(cacheKey)) {
|
|
@@ -25741,7 +26073,7 @@ class StepBuilderActionComponent {
|
|
|
25741
26073
|
label: opt
|
|
25742
26074
|
}));
|
|
25743
26075
|
const config = {
|
|
25744
|
-
key:
|
|
26076
|
+
key: `value`,
|
|
25745
26077
|
placeholder: `Select ${variable.label}`,
|
|
25746
26078
|
multiple: false,
|
|
25747
26079
|
searchable: false,
|
|
@@ -25753,18 +26085,62 @@ class StepBuilderActionComponent {
|
|
|
25753
26085
|
this.selectConfigCache.set(cacheKey, config);
|
|
25754
26086
|
return config;
|
|
25755
26087
|
}
|
|
26088
|
+
/** Get form group for a variable by name */
|
|
26089
|
+
getVariableFormGroup(variableName) {
|
|
26090
|
+
const variableIndex = this.variablesForm.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
26091
|
+
if (variableIndex !== -1) {
|
|
26092
|
+
return this.variablesForm.at(variableIndex);
|
|
26093
|
+
}
|
|
26094
|
+
return null;
|
|
26095
|
+
}
|
|
26096
|
+
/** Add a new variable to the form array dynamically */
|
|
26097
|
+
addVariable(variable) {
|
|
26098
|
+
const defaultValue = variable.type === 'boolean'
|
|
26099
|
+
? (variable.value === true || variable.value === 'true' || variable.value === 1)
|
|
26100
|
+
: (variable.value || '');
|
|
26101
|
+
const variableGroup = this.fb.group({
|
|
26102
|
+
name: [variable.name],
|
|
26103
|
+
value: [defaultValue],
|
|
26104
|
+
type: [variable.type || 'string'],
|
|
26105
|
+
label: [variable.label || ''],
|
|
26106
|
+
options: [variable.options || []]
|
|
26107
|
+
});
|
|
26108
|
+
// Add dataType control for test-data variables if needed
|
|
26109
|
+
const label = variable.label?.toLowerCase() || '';
|
|
26110
|
+
if (label === 'test-data' || label === 'source-value' || label === 'target-value' ||
|
|
26111
|
+
label === 'source_value' || label === 'target_value') {
|
|
26112
|
+
const valueStr = String(defaultValue || '');
|
|
26113
|
+
let dataType = 'plain-text';
|
|
26114
|
+
if (valueStr.startsWith('@|') && valueStr.endsWith('|')) {
|
|
26115
|
+
dataType = 'parameter';
|
|
26116
|
+
}
|
|
26117
|
+
else if (valueStr.startsWith('$|') && valueStr.endsWith('|')) {
|
|
26118
|
+
dataType = 'runtime';
|
|
26119
|
+
}
|
|
26120
|
+
else if (valueStr.startsWith('*|') && valueStr.endsWith('|')) {
|
|
26121
|
+
dataType = 'environment';
|
|
26122
|
+
}
|
|
26123
|
+
variableGroup.addControl('dataType', new FormControl(dataType));
|
|
26124
|
+
}
|
|
26125
|
+
this.variablesForm.push(variableGroup);
|
|
26126
|
+
this.formValidCache = false;
|
|
26127
|
+
}
|
|
25756
26128
|
onVariableValueChange(variableName, value) {
|
|
26129
|
+
console.log("onVariableValueChange", variableName, value);
|
|
25757
26130
|
// Update the variable in templateVariables array
|
|
25758
26131
|
const variable = this.templateVariables.find(v => v.name === variableName);
|
|
25759
26132
|
if (variable) {
|
|
25760
26133
|
variable.value = value;
|
|
25761
26134
|
}
|
|
25762
|
-
// Also update form
|
|
25763
|
-
|
|
25764
|
-
|
|
26135
|
+
// Also update form array (use emitEvent: false to prevent triggering valueChanges)
|
|
26136
|
+
const variableIndex = this.variablesForm.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
26137
|
+
if (variableIndex !== -1) {
|
|
26138
|
+
this.variablesForm.at(variableIndex).get('value')?.setValue(value, { emitEvent: false });
|
|
25765
26139
|
}
|
|
25766
26140
|
// Invalidate form validation cache
|
|
25767
26141
|
this.formValidCache = false;
|
|
26142
|
+
// Update HTML grammar with new value
|
|
26143
|
+
this.updateHtmlGrammar();
|
|
25768
26144
|
}
|
|
25769
26145
|
onVariableBooleanChange(variableName, value) {
|
|
25770
26146
|
// Update the variable in templateVariables array
|
|
@@ -25772,16 +26148,26 @@ class StepBuilderActionComponent {
|
|
|
25772
26148
|
if (variable) {
|
|
25773
26149
|
variable.value = value;
|
|
25774
26150
|
}
|
|
25775
|
-
// Also update form
|
|
25776
|
-
|
|
25777
|
-
|
|
26151
|
+
// Also update form array (use emitEvent: false to prevent triggering valueChanges)
|
|
26152
|
+
const variableIndex = this.variablesForm.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
26153
|
+
if (variableIndex !== -1) {
|
|
26154
|
+
this.variablesForm.at(variableIndex).get('value')?.setValue(value, { emitEvent: false });
|
|
25778
26155
|
}
|
|
25779
26156
|
else {
|
|
25780
|
-
// Create form
|
|
25781
|
-
this.
|
|
26157
|
+
// Create new form group if it doesn't exist
|
|
26158
|
+
const variableGroup = this.fb.group({
|
|
26159
|
+
name: [variableName],
|
|
26160
|
+
value: [value],
|
|
26161
|
+
type: ['boolean'],
|
|
26162
|
+
label: [variable?.label || ''],
|
|
26163
|
+
options: [variable?.options || []]
|
|
26164
|
+
});
|
|
26165
|
+
this.variablesForm.push(variableGroup);
|
|
25782
26166
|
}
|
|
25783
26167
|
// Invalidate form validation cache
|
|
25784
26168
|
this.formValidCache = false;
|
|
26169
|
+
// Update HTML grammar with new value
|
|
26170
|
+
this.updateHtmlGrammar();
|
|
25785
26171
|
}
|
|
25786
26172
|
onBack() {
|
|
25787
26173
|
this.selectedTemplate = null;
|
|
@@ -25789,10 +26175,11 @@ class StepBuilderActionComponent {
|
|
|
25789
26175
|
this.description = '';
|
|
25790
26176
|
this.advancedExpanded = false;
|
|
25791
26177
|
this.templateVariables = [];
|
|
25792
|
-
|
|
25793
|
-
|
|
25794
|
-
|
|
25795
|
-
|
|
26178
|
+
this.updatedHtmlGrammar = '';
|
|
26179
|
+
// Clear form array
|
|
26180
|
+
while (this.variablesForm.length !== 0) {
|
|
26181
|
+
this.variablesForm.removeAt(0);
|
|
26182
|
+
}
|
|
25796
26183
|
// Reapply filter to maintain search state
|
|
25797
26184
|
this.applyFilter();
|
|
25798
26185
|
}
|
|
@@ -25810,22 +26197,22 @@ class StepBuilderActionComponent {
|
|
|
25810
26197
|
return this.formValidCache;
|
|
25811
26198
|
}
|
|
25812
26199
|
// Check if all required variables are filled
|
|
25813
|
-
let isValid = true;
|
|
25814
|
-
if (this.templateVariables && this.templateVariables.length > 0) {
|
|
25815
|
-
|
|
25816
|
-
|
|
25817
|
-
|
|
25818
|
-
|
|
25819
|
-
|
|
25820
|
-
|
|
25821
|
-
|
|
25822
|
-
|
|
25823
|
-
|
|
25824
|
-
}
|
|
26200
|
+
// let isValid = true;
|
|
26201
|
+
// if (this.templateVariables && this.templateVariables.length > 0) {
|
|
26202
|
+
// isValid = this.templateVariables.every(variable => {
|
|
26203
|
+
// // Boolean variables are always valid (they have a default value)
|
|
26204
|
+
// if (variable.type === 'boolean') {
|
|
26205
|
+
// return true;
|
|
26206
|
+
// }
|
|
26207
|
+
// // Check if variable has a value
|
|
26208
|
+
// const value = variable.value;
|
|
26209
|
+
// return value !== null && value !== undefined && value !== '';
|
|
26210
|
+
// });
|
|
26211
|
+
// }
|
|
25825
26212
|
// Cache the result
|
|
25826
|
-
this.formValidCache =
|
|
26213
|
+
this.formValidCache = this.variablesForm.valid;
|
|
25827
26214
|
this.lastFormValidationTime = now;
|
|
25828
|
-
return
|
|
26215
|
+
return this.variablesForm.valid;
|
|
25829
26216
|
}
|
|
25830
26217
|
trackByTemplate(index, template) {
|
|
25831
26218
|
return template.id || template.displayName || index;
|
|
@@ -25843,6 +26230,8 @@ class StepBuilderActionComponent {
|
|
|
25843
26230
|
description: this.description,
|
|
25844
26231
|
templateVariables: this.templateVariables
|
|
25845
26232
|
};
|
|
26233
|
+
console.log("stepData", stepData);
|
|
26234
|
+
console.log("variablesForm", this.variablesForm.value);
|
|
25846
26235
|
this.createStep.emit(stepData);
|
|
25847
26236
|
}
|
|
25848
26237
|
toggleAdvanced() {
|
|
@@ -25858,12 +26247,75 @@ class StepBuilderActionComponent {
|
|
|
25858
26247
|
onTestDataValueChange(key, value) {
|
|
25859
26248
|
console.log(key, value);
|
|
25860
26249
|
}
|
|
26250
|
+
/**
|
|
26251
|
+
* Update HTML grammar by replacing placeholder spans with actual variable values
|
|
26252
|
+
*/
|
|
26253
|
+
updateHtmlGrammar() {
|
|
26254
|
+
if (!this.selectedTemplate) {
|
|
26255
|
+
this.updatedHtmlGrammar = '';
|
|
26256
|
+
return;
|
|
26257
|
+
}
|
|
26258
|
+
const htmlGrammar = this.selectedTemplate.htmlGrammar || this.selectedTemplate.naturalText || '';
|
|
26259
|
+
if (!htmlGrammar) {
|
|
26260
|
+
this.updatedHtmlGrammar = '';
|
|
26261
|
+
return;
|
|
26262
|
+
}
|
|
26263
|
+
// Create a map of variable values by name for quick lookup
|
|
26264
|
+
const valueMap = new Map();
|
|
26265
|
+
if (this.templateVariables && Array.isArray(this.templateVariables)) {
|
|
26266
|
+
this.templateVariables.forEach((variable) => {
|
|
26267
|
+
if (variable.name && variable.value !== undefined && variable.value !== null) {
|
|
26268
|
+
// Convert value to string, handling boolean values
|
|
26269
|
+
const valueStr = typeof variable.value === 'boolean'
|
|
26270
|
+
? (variable.value ? 'true' : 'false')
|
|
26271
|
+
: String(variable.value || '');
|
|
26272
|
+
valueMap.set(variable.name, valueStr);
|
|
26273
|
+
}
|
|
26274
|
+
});
|
|
26275
|
+
}
|
|
26276
|
+
// Use browser's DOMParser if available, otherwise fallback to string replacement
|
|
26277
|
+
if (typeof document !== 'undefined' && document.createElement) {
|
|
26278
|
+
try {
|
|
26279
|
+
const tempDiv = document.createElement('div');
|
|
26280
|
+
tempDiv.innerHTML = String(htmlGrammar);
|
|
26281
|
+
// Find all spans with data-event-key attribute
|
|
26282
|
+
const spans = tempDiv.querySelectorAll('span[data-event-key]');
|
|
26283
|
+
spans.forEach((span) => {
|
|
26284
|
+
const eventKey = span.getAttribute('data-event-key');
|
|
26285
|
+
if (eventKey && valueMap.has(eventKey)) {
|
|
26286
|
+
const value = valueMap.get(eventKey);
|
|
26287
|
+
// Preserve the span structure but update the content
|
|
26288
|
+
span.innerHTML = value || '';
|
|
26289
|
+
}
|
|
26290
|
+
});
|
|
26291
|
+
this.updatedHtmlGrammar = tempDiv.innerHTML;
|
|
26292
|
+
}
|
|
26293
|
+
catch (error) {
|
|
26294
|
+
console.error('Error updating HTML grammar:', error);
|
|
26295
|
+
// Fallback to original HTML grammar
|
|
26296
|
+
this.updatedHtmlGrammar = String(htmlGrammar);
|
|
26297
|
+
}
|
|
26298
|
+
}
|
|
26299
|
+
else {
|
|
26300
|
+
// Fallback: simple string replacement for server-side rendering
|
|
26301
|
+
let updatedHtml = String(htmlGrammar);
|
|
26302
|
+
valueMap.forEach((value, key) => {
|
|
26303
|
+
// Replace spans with data-event-key matching the variable name
|
|
26304
|
+
const regex = new RegExp(`<span[^>]*data-event-key="${key}"[^>]*>.*?</span>`, 'gi');
|
|
26305
|
+
updatedHtml = updatedHtml.replace(regex, (match) => {
|
|
26306
|
+
// Replace the content inside the span
|
|
26307
|
+
return match.replace(/>.*?</, `>${value}<`);
|
|
26308
|
+
});
|
|
26309
|
+
});
|
|
26310
|
+
this.updatedHtmlGrammar = updatedHtml;
|
|
26311
|
+
}
|
|
26312
|
+
}
|
|
25861
26313
|
}
|
|
25862
26314
|
StepBuilderActionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderActionComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
25863
|
-
StepBuilderActionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderActionComponent, selector: "cqa-step-builder-action", inputs: { showHeader: "showHeader", templates: "templates", searchPlaceholder: "searchPlaceholder", setTemplateVariables: "setTemplateVariables", preventSelectTemplate: "preventSelectTemplate" }, outputs: { templateChanged: "templateChanged", createStep: "createStep", cancelled: "cancelled" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white\" [ngClass]=\"{'cqa-px-4 cqa-py-2': showHeader}\">\n <!-- Header -->\n <h2 *ngIf=\"showHeader\" class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-1\">\n Create an action step\n </h2>\n <div *ngIf=\"!selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-h-full cqa-flex-1\"\n [ngClass]=\"{'cqa-px-3': showHeader}\">\n\n <!-- Search Bar -->\n <div class=\"cqa-pb-1\">\n <div class=\"cqa-pb-1\" *ngIf=\"showHeader\">\n <p class=\"cqa-text-[12px] cqa-text-gray-500\">\n Template library\n </p>\n </div>\n <cqa-search-bar [placeholder]=\"searchPlaceholder\" [fullWidth]=\"true\" [value]=\"searchValue\"\n (valueChange)=\"onSearchChange($event)\" (search)=\"onSearchSubmit($event)\" (cleared)=\"onSearchCleared()\">\n </cqa-search-bar>\n </div>\n\n <!-- Template List -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-px-2\">\n <div class=\"cqa-py-2\">\n <div *ngFor=\"let template of filteredTemplates; trackBy: trackByTemplate\"\n class=\"cqa-action-format cqa-bg-white cqa-cursor-pointer cqa-transition-all hover:cqa-border-blue-500 hover:cqa-shadow-sm mb-6\"\n (click)=\"selectTemplate(template)\">\n <div class=\"cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"template.htmlGrammar || template.naturalText || ''\">\n </div>\n </div>\n\n <div *ngIf=\"filteredTemplates.length === 0\" class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-[12px]\">\n No templates found\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-
|
|
26315
|
+
StepBuilderActionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderActionComponent, selector: "cqa-step-builder-action", inputs: { showHeader: "showHeader", templates: "templates", searchPlaceholder: "searchPlaceholder", setTemplateVariables: "setTemplateVariables", preventSelectTemplate: "preventSelectTemplate", elementOptions: "elementOptions", hasMoreElements: "hasMoreElements", isLoadingElements: "isLoadingElements", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames" }, outputs: { templateChanged: "templateChanged", loadMoreElements: "loadMoreElements", searchElements: "searchElements", createElement: "createElement", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", createScreenNameRequest: "createScreenNameRequest", createStep: "createStep", cancelled: "cancelled" }, host: { styleAttribute: "display: block;height: 100%;width: 100%;", classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white\" [ngClass]=\"{'cqa-px-4': showHeader, 'cqa-py-2': showHeader && !selectedTemplate}\">\n <!-- Header -->\n <h2 *ngIf=\"showHeader\" class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-1\">\n Create an action step\n </h2>\n <div *ngIf=\"!selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-h-full cqa-flex-1\"\n [ngClass]=\"{'cqa-px-3': showHeader}\">\n\n <!-- Search Bar -->\n <div class=\"cqa-pb-1\">\n <div class=\"cqa-pb-1\" *ngIf=\"showHeader\">\n <p class=\"cqa-text-[12px] cqa-text-gray-500\">\n Template library\n </p>\n </div>\n <cqa-search-bar [placeholder]=\"searchPlaceholder\" [fullWidth]=\"true\" [value]=\"searchValue\"\n (valueChange)=\"onSearchChange($event)\" (search)=\"onSearchSubmit($event)\" (cleared)=\"onSearchCleared()\">\n </cqa-search-bar>\n </div>\n\n <!-- Template List -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-px-2\">\n <div class=\"cqa-py-2\">\n <div *ngFor=\"let template of filteredTemplates; trackBy: trackByTemplate\"\n class=\"cqa-action-format cqa-bg-white cqa-cursor-pointer cqa-transition-all hover:cqa-border-blue-500 hover:cqa-shadow-sm mb-6\"\n (click)=\"selectTemplate(template)\">\n <div class=\"cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"template.htmlGrammar || template.naturalText || ''\">\n </div>\n </div>\n\n <div *ngIf=\"filteredTemplates.length === 0\" class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-[12px]\">\n No templates found\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-overflow-y-auto\" style=\"flex: 1 1 0 !important;\">\n <!-- Instruction Text with Element Buttons -->\n <div class=\"cqa-mb-4 cqa-flex cqa-items-center cqa-flex-wrap cqa-gap-1 cqa-text-sm cqa-text-gray-700\">\n <div class=\"cqa-action-format cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"updatedHtmlGrammar || selectedTemplate.htmlGrammar || selectedTemplate.naturalText || ''\">\n </div>\n </div>\n\n <!-- Form Fields in Two Columns -->\n <div class=\"cqa-flex cqa-overflow-y-auto cqa-flex-1 cqa-pb-2\">\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-gap-1\">\n <div class=\"cqa-flex cqa-gap-x-6 cqa-flex-wrap cqa-pb-4\">\n <!-- Template Variables Form Component -->\n <cqa-template-variables-form\n style=\"width: 100%;\"\n [templateVariables]=\"templateVariables\"\n [variablesForm]=\"variablesForm\"\n [metadata]=\"metadata\"\n [description]=\"description\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (variableValueChange)=\"onVariableValueChange($event.name, $event.value)\"\n (variableBooleanChange)=\"onVariableBooleanChange($event.name, $event.value)\"\n (metadataChange)=\"metadata = $event\"\n (descriptionChange)=\"description = $event\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (elementFormVisibilityChange)=\"onElementFormVisibilityChange($event)\">\n </cqa-template-variables-form>\n </div>\n\n <!-- Advanced (Expandable) -->\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-w-full\">\n <button type=\"button\"\n class=\"cqa-flex cqa-w-full cqa-items-center cqa-justify-between cqa-gap-2 cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-p-0 cqa-mb-1.5\"\n (click)=\"toggleAdvanced()\">\n <span class=\"cqa-text-[10px]\">Advanced</span>\n <mat-icon class=\"cqa-text-base\" [class.cqa-rotate-180]=\"advancedExpanded\">\n expand_more\n </mat-icon>\n </button>\n <div *ngIf=\"advancedExpanded\" class=\"cqa-mt-2\">\n </div>\n </div> -->\n <div>\n \n </div>\n </div>\n\n\n </div>\n\n <!-- Action Buttons -->\n <div *ngIf=\"!isElementFormVisible\" class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-border-t cqa-border-gray-200 cqa-pb-2\">\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 [disabled]=\"!isFormValid()\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n </div>\n</div>", components: [{ type: SearchBarComponent, selector: "cqa-search-bar", inputs: ["placeholder", "value", "disabled", "showClear", "ariaLabel", "autoFocus", "size", "fullWidth"], outputs: ["valueChange", "search", "cleared"] }, { type: TemplateVariablesFormComponent, selector: "cqa-template-variables-form", inputs: ["templateVariables", "variablesForm", "metadata", "description", "elementOptions", "hasMoreElements", "isLoadingElements", "screenNameOptions", "hasMoreScreenNames", "isLoadingScreenNames"], outputs: ["variableValueChange", "variableBooleanChange", "metadataChange", "descriptionChange", "loadMoreElements", "searchElements", "createElement", "searchScreenName", "loadMoreScreenNames", "createScreenNameRequest", "cancelElementForm", "elementFormVisibilityChange"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }], 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"] }] });
|
|
25864
26316
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderActionComponent, decorators: [{
|
|
25865
26317
|
type: Component,
|
|
25866
|
-
args: [{ selector: 'cqa-step-builder-action', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white\" [ngClass]=\"{'cqa-px-4 cqa-py-2': showHeader}\">\n <!-- Header -->\n <h2 *ngIf=\"showHeader\" class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-1\">\n Create an action step\n </h2>\n <div *ngIf=\"!selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-h-full cqa-flex-1\"\n [ngClass]=\"{'cqa-px-3': showHeader}\">\n\n <!-- Search Bar -->\n <div class=\"cqa-pb-1\">\n <div class=\"cqa-pb-1\" *ngIf=\"showHeader\">\n <p class=\"cqa-text-[12px] cqa-text-gray-500\">\n Template library\n </p>\n </div>\n <cqa-search-bar [placeholder]=\"searchPlaceholder\" [fullWidth]=\"true\" [value]=\"searchValue\"\n (valueChange)=\"onSearchChange($event)\" (search)=\"onSearchSubmit($event)\" (cleared)=\"onSearchCleared()\">\n </cqa-search-bar>\n </div>\n\n <!-- Template List -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-px-2\">\n <div class=\"cqa-py-2\">\n <div *ngFor=\"let template of filteredTemplates; trackBy: trackByTemplate\"\n class=\"cqa-action-format cqa-bg-white cqa-cursor-pointer cqa-transition-all hover:cqa-border-blue-500 hover:cqa-shadow-sm mb-6\"\n (click)=\"selectTemplate(template)\">\n <div class=\"cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"template.htmlGrammar || template.naturalText || ''\">\n </div>\n </div>\n\n <div *ngIf=\"filteredTemplates.length === 0\" class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-[12px]\">\n No templates found\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-
|
|
26318
|
+
args: [{ selector: 'cqa-step-builder-action', host: { class: 'cqa-ui-root', style: 'display: block;height: 100%;width: 100%;' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white\" [ngClass]=\"{'cqa-px-4': showHeader, 'cqa-py-2': showHeader && !selectedTemplate}\">\n <!-- Header -->\n <h2 *ngIf=\"showHeader\" class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-1\">\n Create an action step\n </h2>\n <div *ngIf=\"!selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-h-full cqa-flex-1\"\n [ngClass]=\"{'cqa-px-3': showHeader}\">\n\n <!-- Search Bar -->\n <div class=\"cqa-pb-1\">\n <div class=\"cqa-pb-1\" *ngIf=\"showHeader\">\n <p class=\"cqa-text-[12px] cqa-text-gray-500\">\n Template library\n </p>\n </div>\n <cqa-search-bar [placeholder]=\"searchPlaceholder\" [fullWidth]=\"true\" [value]=\"searchValue\"\n (valueChange)=\"onSearchChange($event)\" (search)=\"onSearchSubmit($event)\" (cleared)=\"onSearchCleared()\">\n </cqa-search-bar>\n </div>\n\n <!-- Template List -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-px-2\">\n <div class=\"cqa-py-2\">\n <div *ngFor=\"let template of filteredTemplates; trackBy: trackByTemplate\"\n class=\"cqa-action-format cqa-bg-white cqa-cursor-pointer cqa-transition-all hover:cqa-border-blue-500 hover:cqa-shadow-sm mb-6\"\n (click)=\"selectTemplate(template)\">\n <div class=\"cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"template.htmlGrammar || template.naturalText || ''\">\n </div>\n </div>\n\n <div *ngIf=\"filteredTemplates.length === 0\" class=\"cqa-text-center cqa-py-8 cqa-text-gray-400 cqa-text-[12px]\">\n No templates found\n </div>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"selectedTemplate\" class=\"cqa-flex cqa-flex-col cqa-overflow-y-auto\" style=\"flex: 1 1 0 !important;\">\n <!-- Instruction Text with Element Buttons -->\n <div class=\"cqa-mb-4 cqa-flex cqa-items-center cqa-flex-wrap cqa-gap-1 cqa-text-sm cqa-text-gray-700\">\n <div class=\"cqa-action-format cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"updatedHtmlGrammar || selectedTemplate.htmlGrammar || selectedTemplate.naturalText || ''\">\n </div>\n </div>\n\n <!-- Form Fields in Two Columns -->\n <div class=\"cqa-flex cqa-overflow-y-auto cqa-flex-1 cqa-pb-2\">\n <div class=\"cqa-flex-1 cqa-flex cqa-flex-col cqa-gap-1\">\n <div class=\"cqa-flex cqa-gap-x-6 cqa-flex-wrap cqa-pb-4\">\n <!-- Template Variables Form Component -->\n <cqa-template-variables-form\n style=\"width: 100%;\"\n [templateVariables]=\"templateVariables\"\n [variablesForm]=\"variablesForm\"\n [metadata]=\"metadata\"\n [description]=\"description\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (variableValueChange)=\"onVariableValueChange($event.name, $event.value)\"\n (variableBooleanChange)=\"onVariableBooleanChange($event.name, $event.value)\"\n (metadataChange)=\"metadata = $event\"\n (descriptionChange)=\"description = $event\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (elementFormVisibilityChange)=\"onElementFormVisibilityChange($event)\">\n </cqa-template-variables-form>\n </div>\n\n <!-- Advanced (Expandable) -->\n <!-- <div class=\"cqa-flex cqa-flex-col cqa-w-full\">\n <button type=\"button\"\n class=\"cqa-flex cqa-w-full cqa-items-center cqa-justify-between cqa-gap-2 cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-p-0 cqa-mb-1.5\"\n (click)=\"toggleAdvanced()\">\n <span class=\"cqa-text-[10px]\">Advanced</span>\n <mat-icon class=\"cqa-text-base\" [class.cqa-rotate-180]=\"advancedExpanded\">\n expand_more\n </mat-icon>\n </button>\n <div *ngIf=\"advancedExpanded\" class=\"cqa-mt-2\">\n </div>\n </div> -->\n <div>\n \n </div>\n </div>\n\n\n </div>\n\n <!-- Action Buttons -->\n <div *ngIf=\"!isElementFormVisible\" class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-border-t cqa-border-gray-200 cqa-pb-2\">\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 [disabled]=\"!isFormValid()\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n </div>\n</div>", styles: [] }]
|
|
25867
26319
|
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }]; }, propDecorators: { showHeader: [{
|
|
25868
26320
|
type: Input
|
|
25869
26321
|
}], templates: [{
|
|
@@ -25874,8 +26326,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
25874
26326
|
type: Input
|
|
25875
26327
|
}], preventSelectTemplate: [{
|
|
25876
26328
|
type: Input
|
|
26329
|
+
}], elementOptions: [{
|
|
26330
|
+
type: Input
|
|
26331
|
+
}], hasMoreElements: [{
|
|
26332
|
+
type: Input
|
|
26333
|
+
}], isLoadingElements: [{
|
|
26334
|
+
type: Input
|
|
26335
|
+
}], screenNameOptions: [{
|
|
26336
|
+
type: Input
|
|
26337
|
+
}], hasMoreScreenNames: [{
|
|
26338
|
+
type: Input
|
|
26339
|
+
}], isLoadingScreenNames: [{
|
|
26340
|
+
type: Input
|
|
25877
26341
|
}], templateChanged: [{
|
|
25878
26342
|
type: Output
|
|
26343
|
+
}], loadMoreElements: [{
|
|
26344
|
+
type: Output
|
|
26345
|
+
}], searchElements: [{
|
|
26346
|
+
type: Output
|
|
26347
|
+
}], createElement: [{
|
|
26348
|
+
type: Output
|
|
26349
|
+
}], searchScreenName: [{
|
|
26350
|
+
type: Output
|
|
26351
|
+
}], loadMoreScreenNames: [{
|
|
26352
|
+
type: Output
|
|
26353
|
+
}], createScreenNameRequest: [{
|
|
26354
|
+
type: Output
|
|
25879
26355
|
}], createStep: [{
|
|
25880
26356
|
type: Output
|
|
25881
26357
|
}], cancelled: [{
|
|
@@ -25912,6 +26388,21 @@ class StepBuilderLoopComponent {
|
|
|
25912
26388
|
this.whileTemplates = [];
|
|
25913
26389
|
this.whileSearchPlaceholder = 'Search While';
|
|
25914
26390
|
this.whileSearchValue = '';
|
|
26391
|
+
// Element fetching properties
|
|
26392
|
+
this.elementOptions = [];
|
|
26393
|
+
this.hasMoreElements = false;
|
|
26394
|
+
this.isLoadingElements = false;
|
|
26395
|
+
// Screen name fetching properties
|
|
26396
|
+
this.screenNameOptions = [];
|
|
26397
|
+
this.hasMoreScreenNames = false;
|
|
26398
|
+
this.isLoadingScreenNames = false;
|
|
26399
|
+
this.loadMoreElements = new EventEmitter();
|
|
26400
|
+
this.searchElements = new EventEmitter();
|
|
26401
|
+
this.createElement = new EventEmitter();
|
|
26402
|
+
this.searchScreenName = new EventEmitter();
|
|
26403
|
+
this.loadMoreScreenNames = new EventEmitter();
|
|
26404
|
+
this.createScreenNameRequest = new EventEmitter();
|
|
26405
|
+
this.cancelElementForm = new EventEmitter();
|
|
25915
26406
|
this.selectedWhileTemplate = null;
|
|
25916
26407
|
this.selectedLoopType = 'for';
|
|
25917
26408
|
// Internal state for managing loop indices
|
|
@@ -26255,10 +26746,10 @@ class StepBuilderLoopComponent {
|
|
|
26255
26746
|
}
|
|
26256
26747
|
}
|
|
26257
26748
|
StepBuilderLoopComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderLoopComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
26258
|
-
StepBuilderLoopComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderLoopComponent, selector: "cqa-step-builder-loop", inputs: { loopType: "loopType", selectOptions: "selectOptions", dataProfileOptions: "dataProfileOptions", hasMoreDataProfiles: "hasMoreDataProfiles", isLoadingDataProfiles: "isLoadingDataProfiles", setWhileTemplateVariables: "setWhileTemplateVariables", whileTemplates: "whileTemplates", whileSearchPlaceholder: "whileSearchPlaceholder", whileSearchValue: "whileSearchValue" }, outputs: { createStep: "createStep", cancelled: "cancelled", loopTypeChange: "loopTypeChange", loadMoreDataProfiles: "loadMoreDataProfiles", searchDataProfiles: "searchDataProfiles" }, 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 Loop Test Step\n </h2>\n\n <!-- Loop Type Selection -->\n <div class=\"cqa-mb-4 cqa-w-full\">\n <div class=\"cqa-w-full cqa-inline-flex cqa-items-center cqa-bg-gray-100 cqa-rounded-lg cqa-p-1 cqa-gap-0\" style=\"height: 30px; background-color: #F3F4F6;\">\n <!-- For Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'for' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'for' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('for')\">\n For\n </button>\n <!-- While Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'while' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'while' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('while')\">\n While\n </button>\n </div>\n </div>\n\n <!-- Form Fields -->\n <ng-container *ngIf=\"selectedLoopType === 'for'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Dropdown Fields Row -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-wrap\">\n <!-- Select Option -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Select Option\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"selectOptionConfig\">\n </cqa-dynamic-select>\n </div>\n\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'dataProfile'\">\n <!-- Data Profile -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Data Profile\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"dataProfileConfig\"\n (searchChange)=\"onSearchDataProfiles($event.query)\"\n (loadMore)=\"onLoadMoreDataProfiles($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop Start -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop Start\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopStartConfig\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop End -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop End\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopEndConfig\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'runTime'\">\n <!-- Run Time Input Field -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Run Time\n </label>\n <cqa-custom-input\n [placeholder]=\"'Enter Run Time'\"\n [value]=\"loopForm.get('runTime')?.value\"\n [fullWidth]=\"true\"\n (valueChange)=\"loopForm.get('runTime')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-container>\n <ng-container *ngIf=\"selectedLoopType === 'while'\">\n <cqa-step-builder-action [showHeader]=\"false\" [templates]=\"whileTemplates\" [setTemplateVariables]=\"setWhileTemplateVariables\" [searchPlaceholder]=\"whileSearchPlaceholder\"
|
|
26749
|
+
StepBuilderLoopComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderLoopComponent, selector: "cqa-step-builder-loop", inputs: { loopType: "loopType", selectOptions: "selectOptions", dataProfileOptions: "dataProfileOptions", hasMoreDataProfiles: "hasMoreDataProfiles", isLoadingDataProfiles: "isLoadingDataProfiles", setWhileTemplateVariables: "setWhileTemplateVariables", whileTemplates: "whileTemplates", whileSearchPlaceholder: "whileSearchPlaceholder", whileSearchValue: "whileSearchValue", elementOptions: "elementOptions", hasMoreElements: "hasMoreElements", isLoadingElements: "isLoadingElements", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames" }, outputs: { createStep: "createStep", cancelled: "cancelled", loopTypeChange: "loopTypeChange", loadMoreDataProfiles: "loadMoreDataProfiles", searchDataProfiles: "searchDataProfiles", loadMoreElements: "loadMoreElements", searchElements: "searchElements", createElement: "createElement", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", createScreenNameRequest: "createScreenNameRequest", cancelElementForm: "cancelElementForm" }, 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 Loop Test Step\n </h2>\n\n <!-- Loop Type Selection -->\n <div class=\"cqa-mb-4 cqa-w-full\">\n <div class=\"cqa-w-full cqa-inline-flex cqa-items-center cqa-bg-gray-100 cqa-rounded-lg cqa-p-1 cqa-gap-0\" style=\"height: 30px; background-color: #F3F4F6;\">\n <!-- For Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'for' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'for' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('for')\">\n For\n </button>\n <!-- While Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'while' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'while' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('while')\">\n While\n </button>\n </div>\n </div>\n\n <!-- Form Fields -->\n <ng-container *ngIf=\"selectedLoopType === 'for'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Dropdown Fields Row -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-wrap\">\n <!-- Select Option -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Select Option\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"selectOptionConfig\">\n </cqa-dynamic-select>\n </div>\n\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'dataProfile'\">\n <!-- Data Profile -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Data Profile\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"dataProfileConfig\"\n (searchChange)=\"onSearchDataProfiles($event.query)\"\n (loadMore)=\"onLoadMoreDataProfiles($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop Start -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop Start\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopStartConfig\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop End -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop End\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopEndConfig\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'runTime'\">\n <!-- Run Time Input Field -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Run Time\n </label>\n <cqa-custom-input\n [placeholder]=\"'Enter Run Time'\"\n [value]=\"loopForm.get('runTime')?.value\"\n [fullWidth]=\"true\"\n (valueChange)=\"loopForm.get('runTime')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-container>\n <ng-container *ngIf=\"selectedLoopType === 'while'\">\n <cqa-step-builder-action \n [showHeader]=\"false\" \n [templates]=\"whileTemplates\" \n [setTemplateVariables]=\"setWhileTemplateVariables\" \n [searchPlaceholder]=\"whileSearchPlaceholder\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (templateChanged)=\"selectWhileTemplate($event)\" \n (createStep)=\"createWhileStep($event)\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (cancelElementForm)=\"cancelElementForm.emit()\">\n </cqa-step-builder-action>\n </ng-container>\n\n <!-- Action Buttons -->\n <div *ngIf=\"selectedLoopType === 'for'\" class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-6 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 [disabled]=\"!isFormValid()\"\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", "addCustomValue"] }, { 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: StepBuilderActionComponent, selector: "cqa-step-builder-action", inputs: ["showHeader", "templates", "searchPlaceholder", "setTemplateVariables", "preventSelectTemplate", "elementOptions", "hasMoreElements", "isLoadingElements", "screenNameOptions", "hasMoreScreenNames", "isLoadingScreenNames"], outputs: ["templateChanged", "loadMoreElements", "searchElements", "createElement", "searchScreenName", "loadMoreScreenNames", "createScreenNameRequest", "createStep", "cancelled"] }, { 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"] }] });
|
|
26259
26750
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderLoopComponent, decorators: [{
|
|
26260
26751
|
type: Component,
|
|
26261
|
-
args: [{ selector: 'cqa-step-builder-loop', 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 Loop Test Step\n </h2>\n\n <!-- Loop Type Selection -->\n <div class=\"cqa-mb-4 cqa-w-full\">\n <div class=\"cqa-w-full cqa-inline-flex cqa-items-center cqa-bg-gray-100 cqa-rounded-lg cqa-p-1 cqa-gap-0\" style=\"height: 30px; background-color: #F3F4F6;\">\n <!-- For Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'for' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'for' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('for')\">\n For\n </button>\n <!-- While Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'while' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'while' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('while')\">\n While\n </button>\n </div>\n </div>\n\n <!-- Form Fields -->\n <ng-container *ngIf=\"selectedLoopType === 'for'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Dropdown Fields Row -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-wrap\">\n <!-- Select Option -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Select Option\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"selectOptionConfig\">\n </cqa-dynamic-select>\n </div>\n\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'dataProfile'\">\n <!-- Data Profile -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Data Profile\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"dataProfileConfig\"\n (searchChange)=\"onSearchDataProfiles($event.query)\"\n (loadMore)=\"onLoadMoreDataProfiles($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop Start -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop Start\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopStartConfig\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop End -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop End\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopEndConfig\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'runTime'\">\n <!-- Run Time Input Field -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Run Time\n </label>\n <cqa-custom-input\n [placeholder]=\"'Enter Run Time'\"\n [value]=\"loopForm.get('runTime')?.value\"\n [fullWidth]=\"true\"\n (valueChange)=\"loopForm.get('runTime')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-container>\n <ng-container *ngIf=\"selectedLoopType === 'while'\">\n <cqa-step-builder-action [showHeader]=\"false\" [templates]=\"whileTemplates\" [setTemplateVariables]=\"setWhileTemplateVariables\" [searchPlaceholder]=\"whileSearchPlaceholder\"
|
|
26752
|
+
args: [{ selector: 'cqa-step-builder-loop', 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 Loop Test Step\n </h2>\n\n <!-- Loop Type Selection -->\n <div class=\"cqa-mb-4 cqa-w-full\">\n <div class=\"cqa-w-full cqa-inline-flex cqa-items-center cqa-bg-gray-100 cqa-rounded-lg cqa-p-1 cqa-gap-0\" style=\"height: 30px; background-color: #F3F4F6;\">\n <!-- For Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'for' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'for' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('for')\">\n For\n </button>\n <!-- While Button -->\n <button\n type=\"button\"\n class=\"cqa-w-1/2 cqa-text-[12px] cqa-rounded-md cqa-font-medium cqa-transition-all cqa-duration-200 cqa-ease-in-out cqa-min-w-[80px] cqa-text-center cqa-cursor-pointer\"\n [style.background-color]=\"selectedLoopType === 'while' ? '#3F43EE' : 'transparent'\"\n [style.color]=\"selectedLoopType === 'while' ? '#FFFFFF' : '#6B7280'\"\n [style.border-radius]=\"'8px'\"\n [style.height]=\"'22px'\"\n (click)=\"onLoopTypeChange('while')\">\n While\n </button>\n </div>\n </div>\n\n <!-- Form Fields -->\n <ng-container *ngIf=\"selectedLoopType === 'for'\">\n <div class=\"cqa-flex cqa-flex-col cqa-gap-4 cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Dropdown Fields Row -->\n <div class=\"cqa-flex cqa-gap-4 cqa-flex-wrap\">\n <!-- Select Option -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Select Option\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"selectOptionConfig\">\n </cqa-dynamic-select>\n </div>\n\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'dataProfile'\">\n <!-- Data Profile -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Data Profile\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"dataProfileConfig\"\n (searchChange)=\"onSearchDataProfiles($event.query)\"\n (loadMore)=\"onLoadMoreDataProfiles($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop Start -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop Start\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopStartConfig\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Loop End -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Loop End\n </label>\n <cqa-dynamic-select\n [form]=\"loopForm\"\n [config]=\"loopEndConfig\">\n </cqa-dynamic-select>\n </div>\n </ng-container>\n <ng-container *ngIf=\"loopForm.get('selectOption')?.value === 'runTime'\">\n <!-- Run Time Input Field -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1\" style=\"min-width: calc(25% - 12px);\">\n <label class=\"cqa-text-sm cqa-font-medium cqa-text-gray-700 cqa-mb-1.5\">\n Run Time\n </label>\n <cqa-custom-input\n [placeholder]=\"'Enter Run Time'\"\n [value]=\"loopForm.get('runTime')?.value\"\n [fullWidth]=\"true\"\n (valueChange)=\"loopForm.get('runTime')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </ng-container>\n </div>\n </div>\n</ng-container>\n <ng-container *ngIf=\"selectedLoopType === 'while'\">\n <cqa-step-builder-action \n [showHeader]=\"false\" \n [templates]=\"whileTemplates\" \n [setTemplateVariables]=\"setWhileTemplateVariables\" \n [searchPlaceholder]=\"whileSearchPlaceholder\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (templateChanged)=\"selectWhileTemplate($event)\" \n (createStep)=\"createWhileStep($event)\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\"\n (cancelElementForm)=\"cancelElementForm.emit()\">\n </cqa-step-builder-action>\n </ng-container>\n\n <!-- Action Buttons -->\n <div *ngIf=\"selectedLoopType === 'for'\" class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-6 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 [disabled]=\"!isFormValid()\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n</div>\n\n", styles: [] }]
|
|
26262
26753
|
}], ctorParameters: function () { return []; }, propDecorators: { loopType: [{
|
|
26263
26754
|
type: Input
|
|
26264
26755
|
}], selectOptions: [{
|
|
@@ -26287,6 +26778,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
26287
26778
|
type: Input
|
|
26288
26779
|
}], whileSearchValue: [{
|
|
26289
26780
|
type: Input
|
|
26781
|
+
}], elementOptions: [{
|
|
26782
|
+
type: Input
|
|
26783
|
+
}], hasMoreElements: [{
|
|
26784
|
+
type: Input
|
|
26785
|
+
}], isLoadingElements: [{
|
|
26786
|
+
type: Input
|
|
26787
|
+
}], screenNameOptions: [{
|
|
26788
|
+
type: Input
|
|
26789
|
+
}], hasMoreScreenNames: [{
|
|
26790
|
+
type: Input
|
|
26791
|
+
}], isLoadingScreenNames: [{
|
|
26792
|
+
type: Input
|
|
26793
|
+
}], loadMoreElements: [{
|
|
26794
|
+
type: Output
|
|
26795
|
+
}], searchElements: [{
|
|
26796
|
+
type: Output
|
|
26797
|
+
}], createElement: [{
|
|
26798
|
+
type: Output
|
|
26799
|
+
}], searchScreenName: [{
|
|
26800
|
+
type: Output
|
|
26801
|
+
}], loadMoreScreenNames: [{
|
|
26802
|
+
type: Output
|
|
26803
|
+
}], createScreenNameRequest: [{
|
|
26804
|
+
type: Output
|
|
26805
|
+
}], cancelElementForm: [{
|
|
26806
|
+
type: Output
|
|
26290
26807
|
}] } });
|
|
26291
26808
|
|
|
26292
26809
|
class StepBuilderConditionComponent {
|
|
@@ -26306,10 +26823,25 @@ class StepBuilderConditionComponent {
|
|
|
26306
26823
|
this.conditionTemplates = [];
|
|
26307
26824
|
/** Function to handle variable processing or custom logic. Can be passed from parent component. */
|
|
26308
26825
|
this.setConditionTemplateVariables = () => { return []; };
|
|
26826
|
+
this.elementOptions = []; // Element objects for element dropdown
|
|
26827
|
+
this.hasMoreElements = false; // Whether more elements are available
|
|
26828
|
+
this.isLoadingElements = false; // Loading state for elements
|
|
26829
|
+
/** Screen name options for element form autocomplete (from API) */
|
|
26830
|
+
this.screenNameOptions = [];
|
|
26831
|
+
/** Whether more screen names are available for infinite scroll */
|
|
26832
|
+
this.hasMoreScreenNames = false;
|
|
26833
|
+
/** True while parent is loading screen names (search or load more) */
|
|
26834
|
+
this.isLoadingScreenNames = false;
|
|
26309
26835
|
/** Emit when step is created */
|
|
26310
26836
|
this.createStep = new EventEmitter();
|
|
26311
26837
|
/** Emit when cancelled */
|
|
26312
26838
|
this.cancelled = new EventEmitter();
|
|
26839
|
+
this.loadMoreElements = new EventEmitter(); // Emit when load more is requested
|
|
26840
|
+
this.searchElements = new EventEmitter(); // Emit when user searches for elements
|
|
26841
|
+
this.createElement = new EventEmitter(); // Emit when element is created
|
|
26842
|
+
this.searchScreenName = new EventEmitter(); // Emit when user searches screen names
|
|
26843
|
+
this.loadMoreScreenNames = new EventEmitter(); // Emit when user scrolls to load more screen names
|
|
26844
|
+
this.createScreenNameRequest = new EventEmitter(); // Emit when user requests to create a new screen name
|
|
26313
26845
|
this.includeElse = false;
|
|
26314
26846
|
// Cache for value configs to avoid recreating on every change detection
|
|
26315
26847
|
this.valueConfigCache = null;
|
|
@@ -26321,6 +26853,7 @@ class StepBuilderConditionComponent {
|
|
|
26321
26853
|
this.selectedTemplates = new Map();
|
|
26322
26854
|
this.conditionTemplateVariables = new Map();
|
|
26323
26855
|
this.conditionVariablesForms = new Map();
|
|
26856
|
+
this.conditionUpdatedHtmlGrammar = new Map(); // Updated HTML grammar per condition
|
|
26324
26857
|
// Cache for condition form groups to avoid repeated lookups
|
|
26325
26858
|
this.conditionFormGroupCache = new Map();
|
|
26326
26859
|
this.conditionForm = this.fb.group({
|
|
@@ -26369,8 +26902,8 @@ class StepBuilderConditionComponent {
|
|
|
26369
26902
|
});
|
|
26370
26903
|
const index = this.conditionsFormArray.length;
|
|
26371
26904
|
this.conditionsFormArray.push(conditionGroup);
|
|
26372
|
-
// Initialize variables form for this condition
|
|
26373
|
-
this.conditionVariablesForms.set(index, this.fb.
|
|
26905
|
+
// Initialize variables form for this condition (FormArray)
|
|
26906
|
+
this.conditionVariablesForms.set(index, this.fb.array([]));
|
|
26374
26907
|
// Cache the form group
|
|
26375
26908
|
this.conditionFormGroupCache.set(index, conditionGroup);
|
|
26376
26909
|
// Mark for check since we're using OnPush
|
|
@@ -26398,6 +26931,7 @@ class StepBuilderConditionComponent {
|
|
|
26398
26931
|
const newVariablesForms = new Map();
|
|
26399
26932
|
const newFormGroupCache = new Map();
|
|
26400
26933
|
const newValueConfigs = new Map();
|
|
26934
|
+
const newUpdatedHtmlGrammar = new Map();
|
|
26401
26935
|
this.selectedTemplates.forEach((template, oldIndex) => {
|
|
26402
26936
|
if (oldIndex < removedIndex) {
|
|
26403
26937
|
newSelectedTemplates.set(oldIndex, template);
|
|
@@ -26445,11 +26979,20 @@ class StepBuilderConditionComponent {
|
|
|
26445
26979
|
newValueConfigs.set(oldIndex - 1, newConfig);
|
|
26446
26980
|
}
|
|
26447
26981
|
});
|
|
26982
|
+
this.conditionUpdatedHtmlGrammar.forEach((grammar, oldIndex) => {
|
|
26983
|
+
if (oldIndex < removedIndex) {
|
|
26984
|
+
newUpdatedHtmlGrammar.set(oldIndex, grammar);
|
|
26985
|
+
}
|
|
26986
|
+
else if (oldIndex > removedIndex) {
|
|
26987
|
+
newUpdatedHtmlGrammar.set(oldIndex - 1, grammar);
|
|
26988
|
+
}
|
|
26989
|
+
});
|
|
26448
26990
|
this.selectedTemplates = newSelectedTemplates;
|
|
26449
26991
|
this.conditionTemplateVariables = newTemplateVariables;
|
|
26450
26992
|
this.conditionVariablesForms = newVariablesForms;
|
|
26451
26993
|
this.conditionFormGroupCache = newFormGroupCache;
|
|
26452
26994
|
this.valueConfigsWithHandlers = newValueConfigs;
|
|
26995
|
+
this.conditionUpdatedHtmlGrammar = newUpdatedHtmlGrammar;
|
|
26453
26996
|
}
|
|
26454
26997
|
getOperatorConfig(index) {
|
|
26455
26998
|
// Return cached config (static, same for all conditions)
|
|
@@ -26505,54 +27048,98 @@ class StepBuilderConditionComponent {
|
|
|
26505
27048
|
this.conditionTemplateVariables.set(index, variables);
|
|
26506
27049
|
// Build form for template variables
|
|
26507
27050
|
this.buildConditionVariablesForm(index, variables);
|
|
27051
|
+
// Initialize updated HTML grammar
|
|
27052
|
+
this.updateConditionHtmlGrammar(index);
|
|
26508
27053
|
}
|
|
26509
27054
|
else {
|
|
26510
27055
|
// Clear template and variables if no template selected
|
|
26511
27056
|
this.selectedTemplates.delete(index);
|
|
26512
27057
|
this.conditionTemplateVariables.delete(index);
|
|
26513
|
-
|
|
26514
|
-
|
|
26515
|
-
|
|
26516
|
-
|
|
26517
|
-
|
|
27058
|
+
this.conditionUpdatedHtmlGrammar.delete(index);
|
|
27059
|
+
const formArray = this.conditionVariablesForms.get(index);
|
|
27060
|
+
if (formArray) {
|
|
27061
|
+
while (formArray.length !== 0) {
|
|
27062
|
+
formArray.removeAt(0);
|
|
27063
|
+
}
|
|
26518
27064
|
}
|
|
26519
27065
|
}
|
|
26520
27066
|
// Mark for check since we're using OnPush
|
|
26521
27067
|
this.cdr.markForCheck();
|
|
26522
27068
|
}
|
|
26523
27069
|
buildConditionVariablesForm(index, variables) {
|
|
26524
|
-
let
|
|
26525
|
-
if (!
|
|
26526
|
-
|
|
26527
|
-
this.conditionVariablesForms.set(index,
|
|
27070
|
+
let formArray = this.conditionVariablesForms.get(index);
|
|
27071
|
+
if (!formArray) {
|
|
27072
|
+
formArray = this.fb.array([]);
|
|
27073
|
+
this.conditionVariablesForms.set(index, formArray);
|
|
26528
27074
|
}
|
|
26529
|
-
// Ensure
|
|
26530
|
-
if (!
|
|
27075
|
+
// Ensure formArray is not undefined (TypeScript guard)
|
|
27076
|
+
if (!formArray) {
|
|
26531
27077
|
return;
|
|
26532
27078
|
}
|
|
26533
|
-
//
|
|
26534
|
-
|
|
26535
|
-
|
|
26536
|
-
|
|
26537
|
-
|
|
27079
|
+
// Store reference to avoid TypeScript issues in forEach callback
|
|
27080
|
+
// TypeScript knows formArray is defined here due to the early return above
|
|
27081
|
+
const formArrayRef = formArray;
|
|
27082
|
+
// Clear existing form array
|
|
27083
|
+
while (formArrayRef.length !== 0) {
|
|
27084
|
+
formArrayRef.removeAt(0);
|
|
27085
|
+
}
|
|
27086
|
+
// Add form groups for each variable
|
|
26538
27087
|
variables.forEach(variable => {
|
|
26539
27088
|
// Handle boolean variables - use boolean value, others use string
|
|
26540
27089
|
const defaultValue = variable.type === 'boolean'
|
|
26541
27090
|
? (variable.value === true || variable.value === 'true' || variable.value === 1)
|
|
26542
27091
|
: (variable.value || '');
|
|
26543
|
-
|
|
27092
|
+
// Create a FormGroup for each variable with name and value
|
|
27093
|
+
const variableGroup = this.fb.group({
|
|
27094
|
+
name: [variable.name],
|
|
27095
|
+
value: [defaultValue],
|
|
27096
|
+
type: [variable.type || 'string'],
|
|
27097
|
+
label: [variable.label || ''],
|
|
27098
|
+
options: [variable.options || []]
|
|
27099
|
+
});
|
|
27100
|
+
// Add dataType control for test-data variables if needed
|
|
27101
|
+
const label = variable.label?.toLowerCase() || '';
|
|
27102
|
+
if (label === 'test-data' || label === 'source-value' || label === 'target-value' ||
|
|
27103
|
+
label === 'source_value' || label === 'target_value') {
|
|
27104
|
+
// Parse the value to determine data type
|
|
27105
|
+
const valueStr = String(defaultValue || '');
|
|
27106
|
+
let dataType = 'plain-text';
|
|
27107
|
+
if (valueStr.startsWith('@|') && valueStr.endsWith('|')) {
|
|
27108
|
+
dataType = 'parameter';
|
|
27109
|
+
}
|
|
27110
|
+
else if (valueStr.startsWith('$|') && valueStr.endsWith('|')) {
|
|
27111
|
+
dataType = 'runtime';
|
|
27112
|
+
}
|
|
27113
|
+
else if (valueStr.startsWith('*|') && valueStr.endsWith('|')) {
|
|
27114
|
+
dataType = 'environment';
|
|
27115
|
+
}
|
|
27116
|
+
variableGroup.addControl('dataType', new FormControl(dataType));
|
|
27117
|
+
}
|
|
27118
|
+
formArrayRef.push(variableGroup);
|
|
26544
27119
|
});
|
|
27120
|
+
// Initialize updated HTML grammar for this condition
|
|
27121
|
+
this.updateConditionHtmlGrammar(index);
|
|
26545
27122
|
}
|
|
26546
27123
|
getConditionTemplateVariables(index) {
|
|
26547
27124
|
return this.conditionTemplateVariables.get(index) || [];
|
|
26548
27125
|
}
|
|
26549
27126
|
getConditionVariablesForm(index) {
|
|
26550
|
-
let
|
|
26551
|
-
if (!
|
|
26552
|
-
|
|
26553
|
-
this.conditionVariablesForms.set(index,
|
|
27127
|
+
let formArray = this.conditionVariablesForms.get(index);
|
|
27128
|
+
if (!formArray) {
|
|
27129
|
+
formArray = this.fb.array([]);
|
|
27130
|
+
this.conditionVariablesForms.set(index, formArray);
|
|
26554
27131
|
}
|
|
26555
|
-
return
|
|
27132
|
+
return formArray;
|
|
27133
|
+
}
|
|
27134
|
+
getConditionFormGroupAt(index, variableIndex) {
|
|
27135
|
+
const formArray = this.getConditionVariablesForm(index);
|
|
27136
|
+
return formArray.at(variableIndex);
|
|
27137
|
+
}
|
|
27138
|
+
getConditionUpdatedHtmlGrammar(index) {
|
|
27139
|
+
const template = this.selectedTemplates.get(index);
|
|
27140
|
+
if (!template)
|
|
27141
|
+
return '';
|
|
27142
|
+
return this.conditionUpdatedHtmlGrammar.get(index) || template.htmlGrammar || template.naturalText || '';
|
|
26556
27143
|
}
|
|
26557
27144
|
getSelectedTemplate(index) {
|
|
26558
27145
|
return this.selectedTemplates.get(index) || null;
|
|
@@ -26582,11 +27169,16 @@ class StepBuilderConditionComponent {
|
|
|
26582
27169
|
if (variable) {
|
|
26583
27170
|
variable.value = value;
|
|
26584
27171
|
}
|
|
26585
|
-
// Also update form
|
|
26586
|
-
const
|
|
26587
|
-
if (
|
|
26588
|
-
|
|
27172
|
+
// Also update form array
|
|
27173
|
+
const formArray = this.conditionVariablesForms.get(conditionIndex);
|
|
27174
|
+
if (formArray) {
|
|
27175
|
+
const variableIndex = formArray.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
27176
|
+
if (variableIndex !== -1) {
|
|
27177
|
+
formArray.at(variableIndex).get('value')?.setValue(value, { emitEvent: false });
|
|
27178
|
+
}
|
|
26589
27179
|
}
|
|
27180
|
+
// Update HTML grammar for this condition
|
|
27181
|
+
this.updateConditionHtmlGrammar(conditionIndex);
|
|
26590
27182
|
// Mark for check since we're using OnPush
|
|
26591
27183
|
this.cdr.markForCheck();
|
|
26592
27184
|
}
|
|
@@ -26610,20 +27202,63 @@ class StepBuilderConditionComponent {
|
|
|
26610
27202
|
if (variable) {
|
|
26611
27203
|
variable.value = value;
|
|
26612
27204
|
}
|
|
26613
|
-
// Also update form
|
|
26614
|
-
const
|
|
26615
|
-
if (
|
|
26616
|
-
|
|
26617
|
-
|
|
26618
|
-
|
|
26619
|
-
|
|
26620
|
-
|
|
26621
|
-
form.addControl(variableName, new FormControl(value));
|
|
26622
|
-
}
|
|
27205
|
+
// Also update form array
|
|
27206
|
+
const formArray = this.conditionVariablesForms.get(conditionIndex);
|
|
27207
|
+
if (!formArray) {
|
|
27208
|
+
return;
|
|
27209
|
+
}
|
|
27210
|
+
const variableIndex = formArray.controls.findIndex(control => control.get('name')?.value === variableName);
|
|
27211
|
+
if (variableIndex !== -1) {
|
|
27212
|
+
formArray.at(variableIndex).get('value')?.setValue(value, { emitEvent: false });
|
|
26623
27213
|
}
|
|
27214
|
+
else {
|
|
27215
|
+
// Create new form group if it doesn't exist
|
|
27216
|
+
const variableGroup = this.fb.group({
|
|
27217
|
+
name: [variableName],
|
|
27218
|
+
value: [value],
|
|
27219
|
+
type: ['boolean'],
|
|
27220
|
+
label: [variable?.label || ''],
|
|
27221
|
+
options: [variable?.options || []]
|
|
27222
|
+
});
|
|
27223
|
+
// formArray is guaranteed to be defined here due to the early return above
|
|
27224
|
+
formArray.push(variableGroup);
|
|
27225
|
+
}
|
|
27226
|
+
// Update HTML grammar for this condition
|
|
27227
|
+
this.updateConditionHtmlGrammar(conditionIndex);
|
|
26624
27228
|
// Mark for check since we're using OnPush
|
|
26625
27229
|
this.cdr.markForCheck();
|
|
26626
27230
|
}
|
|
27231
|
+
/**
|
|
27232
|
+
* Strip HTML tags from a string for search functionality
|
|
27233
|
+
*/
|
|
27234
|
+
stripHtmlTags(htmlString) {
|
|
27235
|
+
if (!htmlString)
|
|
27236
|
+
return '';
|
|
27237
|
+
// Create a temporary div element to parse HTML
|
|
27238
|
+
const tmp = document.createElement('DIV');
|
|
27239
|
+
tmp.innerHTML = htmlString;
|
|
27240
|
+
return tmp.textContent || tmp.innerText || '';
|
|
27241
|
+
}
|
|
27242
|
+
/**
|
|
27243
|
+
* Update HTML grammar for a specific condition with actual variable values
|
|
27244
|
+
*/
|
|
27245
|
+
updateConditionHtmlGrammar(conditionIndex) {
|
|
27246
|
+
const template = this.selectedTemplates.get(conditionIndex);
|
|
27247
|
+
if (!template || !template.htmlGrammar) {
|
|
27248
|
+
return;
|
|
27249
|
+
}
|
|
27250
|
+
let updatedGrammar = template.htmlGrammar;
|
|
27251
|
+
const variables = this.conditionTemplateVariables.get(conditionIndex) || [];
|
|
27252
|
+
// Replace placeholders with actual values
|
|
27253
|
+
variables.forEach(variable => {
|
|
27254
|
+
const placeholder = new RegExp(`<span[^>]*data-event-key="${variable.name}"[^>]*>.*?</span>`, 'gi');
|
|
27255
|
+
const value = variable.value || '';
|
|
27256
|
+
// Escape HTML in value to prevent XSS
|
|
27257
|
+
const escapedValue = String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
27258
|
+
updatedGrammar = updatedGrammar.replace(placeholder, escapedValue);
|
|
27259
|
+
});
|
|
27260
|
+
this.conditionUpdatedHtmlGrammar.set(conditionIndex, updatedGrammar);
|
|
27261
|
+
}
|
|
26627
27262
|
getConditionFormGroup(index) {
|
|
26628
27263
|
// Use cache to avoid repeated lookups
|
|
26629
27264
|
if (this.conditionFormGroupCache.has(index)) {
|
|
@@ -26692,20 +27327,44 @@ class StepBuilderConditionComponent {
|
|
|
26692
27327
|
}
|
|
26693
27328
|
}
|
|
26694
27329
|
StepBuilderConditionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderConditionComponent, deps: [{ token: i1$1.FormBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
26695
|
-
StepBuilderConditionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderConditionComponent, selector: "cqa-step-builder-condition", inputs: { operatorOptions: "operatorOptions", conditionTemplates: "conditionTemplates", setConditionTemplateVariables: "setConditionTemplateVariables" }, outputs: { createStep: "createStep", cancelled: "cancelled" }, 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 Condition Step\n </h2>\n\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Condition Builder Section -->\n <div class=\"cqa-mb-6\">\n <h3 class=\"cqa-text-sm cqa-text-[12px] cqa-font-semibold cqa-text-gray-900 cqa-mb-3\">\n Condition Builder\n </h3>\n\n <!-- Condition Rows -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-mb-3\">\n <ng-container *ngFor=\"let condition of conditionsFormArray.controls; let i = index; trackBy: trackByConditionIndex\">\n <div\n *ngIf=\"isConditionIf(i) || isConditionElseIf(i)\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <!-- Condition Row -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Condition Label -->\n <div class=\"cqa-text-[12px] cqa-font-semibold\">\n {{ getConditionLabel(i) }}\n </div>\n\n <!-- Operator Dropdown -->\n <!-- <div class=\"cqa-flex-1 cqa-max-w-[100px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getOperatorConfig(i)\">\n </cqa-dynamic-select>\n </div> -->\n\n <!-- Value Template Dropdown -->\n <div class=\"cqa-flex-1 cqa-min-w-[150px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getValueConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Remove Button -->\n <cqa-button\n *ngIf=\"i >= 1\"\n variant=\"text\"\n icon=\"close\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"'Remove condition'\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors\"\n (click)=\"removeCondition(i)\" *ngIf=\"i >= 1\"\n [attr.aria-label]=\"'Remove condition'\">\n <mat-icon class=\"cqa-text-lg cqa-text-[24px]\">close</mat-icon>\n </button> -->\n </div>\n\n <!-- Template Variables Section (shown when template is selected) -->\n <div *ngIf=\"getSelectedTemplate(i)\">\n <!-- Template Grammar Display -->\n
|
|
27330
|
+
StepBuilderConditionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderConditionComponent, selector: "cqa-step-builder-condition", inputs: { operatorOptions: "operatorOptions", conditionTemplates: "conditionTemplates", setConditionTemplateVariables: "setConditionTemplateVariables", elementOptions: "elementOptions", hasMoreElements: "hasMoreElements", isLoadingElements: "isLoadingElements", screenNameOptions: "screenNameOptions", hasMoreScreenNames: "hasMoreScreenNames", isLoadingScreenNames: "isLoadingScreenNames" }, outputs: { createStep: "createStep", cancelled: "cancelled", loadMoreElements: "loadMoreElements", searchElements: "searchElements", createElement: "createElement", searchScreenName: "searchScreenName", loadMoreScreenNames: "loadMoreScreenNames", createScreenNameRequest: "createScreenNameRequest" }, 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 Condition Step\n </h2>\n\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Condition Builder Section -->\n <div class=\"cqa-mb-6\">\n <h3 class=\"cqa-text-sm cqa-text-[12px] cqa-font-semibold cqa-text-gray-900 cqa-mb-3\">\n Condition Builder\n </h3>\n\n <!-- Condition Rows -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-mb-3\">\n <ng-container *ngFor=\"let condition of conditionsFormArray.controls; let i = index; trackBy: trackByConditionIndex\">\n <div\n *ngIf=\"isConditionIf(i) || isConditionElseIf(i)\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <!-- Condition Row -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Condition Label -->\n <div class=\"cqa-text-[12px] cqa-font-semibold\">\n {{ getConditionLabel(i) }}\n </div>\n\n <!-- Operator Dropdown -->\n <!-- <div class=\"cqa-flex-1 cqa-max-w-[100px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getOperatorConfig(i)\">\n </cqa-dynamic-select>\n </div> -->\n\n <!-- Value Template Dropdown -->\n <div class=\"cqa-flex-1 cqa-min-w-[150px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getValueConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Remove Button -->\n <cqa-button\n *ngIf=\"i >= 1\"\n variant=\"text\"\n icon=\"close\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"'Remove condition'\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors\"\n (click)=\"removeCondition(i)\" *ngIf=\"i >= 1\"\n [attr.aria-label]=\"'Remove condition'\">\n <mat-icon class=\"cqa-text-lg cqa-text-[24px]\">close</mat-icon>\n </button> -->\n </div>\n\n <!-- Template Variables Section (shown when template is selected) -->\n <div *ngIf=\"getSelectedTemplate(i)\" class=\"cqa-mt-2\">\n <!-- Template Grammar Display -->\n <div class=\"cqa-mb-4 cqa-flex cqa-items-center cqa-flex-wrap cqa-gap-1 cqa-text-sm cqa-text-gray-700\">\n <div class=\"cqa-action-format cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"getConditionUpdatedHtmlGrammar(i) || getSelectedTemplate(i)?.htmlGrammar || getSelectedTemplate(i)?.naturalText || ''\">\n </div>\n </div>\n \n <!-- Template Variables Form Component (includes Description and Metadata) -->\n <cqa-template-variables-form\n style=\"width: 100%;\"\n [templateVariables]=\"getConditionTemplateVariables(i)\"\n [variablesForm]=\"getConditionVariablesForm(i)\"\n [metadata]=\"getConditionFormGroup(i).get('metadata')?.value || ''\"\n [description]=\"getConditionFormGroup(i).get('description')?.value || ''\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (variableValueChange)=\"onConditionVariableValueChange(i, $event.name, $event.value)\"\n (variableBooleanChange)=\"onConditionVariableBooleanChange(i, $event.name, $event.value)\"\n (metadataChange)=\"getConditionFormGroup(i).get('metadata')?.setValue($event)\"\n (descriptionChange)=\"getConditionFormGroup(i).get('description')?.setValue($event)\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\">\n </cqa-template-variables-form>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Add Condition Button -->\n <div class=\"cqa-border-2 cqa-border-dashed cqa-border-gray-300 cqa-rounded-lg cqa-p-1 cqa-mt-3\">\n <cqa-button\n variant=\"text\"\n icon=\"add\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n [text]=\"'Add Condition'\"\n (clicked)=\"addCondition('CONDITION_ELSE_IF')\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Include ELSE Branch Section -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-mb-6 cqa-p-3 cqa-bg-gray-50 cqa-rounded-lg\">\n <div class=\"cqa-flex cqa-flex-col\">\n <h3 class=\"cqa-text-[14px] cqa-font-semibold cqa-text-gray-900 cqa-mb-1\">\n Include ELSE branch\n </h3>\n <p class=\"cqa-text-[12px] cqa-text-gray-600\">\n Execute alternative steps when condition is not met.\n </p>\n </div>\n <mat-slide-toggle [checked]=\"includeElse\" (change)=\"onIncludeElseChange($event.checked)\" color=\"primary\">\n </mat-slide-toggle>\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 <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 [disabled]=\"!conditionForm.valid\"\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", "addCustomValue"] }, { type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: TemplateVariablesFormComponent, selector: "cqa-template-variables-form", inputs: ["templateVariables", "variablesForm", "metadata", "description", "elementOptions", "hasMoreElements", "isLoadingElements", "screenNameOptions", "hasMoreScreenNames", "isLoadingScreenNames"], outputs: ["variableValueChange", "variableBooleanChange", "metadataChange", "descriptionChange", "loadMoreElements", "searchElements", "createElement", "searchScreenName", "loadMoreScreenNames", "createScreenNameRequest", "cancelElementForm", "elementFormVisibilityChange"] }, { type: i5$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex", "name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "checked"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
26696
27331
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderConditionComponent, decorators: [{
|
|
26697
27332
|
type: Component,
|
|
26698
|
-
args: [{ selector: 'cqa-step-builder-condition', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, 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 Condition Step\n </h2>\n\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Condition Builder Section -->\n <div class=\"cqa-mb-6\">\n <h3 class=\"cqa-text-sm cqa-text-[12px] cqa-font-semibold cqa-text-gray-900 cqa-mb-3\">\n Condition Builder\n </h3>\n\n <!-- Condition Rows -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-mb-3\">\n <ng-container *ngFor=\"let condition of conditionsFormArray.controls; let i = index; trackBy: trackByConditionIndex\">\n <div\n *ngIf=\"isConditionIf(i) || isConditionElseIf(i)\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <!-- Condition Row -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Condition Label -->\n <div class=\"cqa-text-[12px] cqa-font-semibold\">\n {{ getConditionLabel(i) }}\n </div>\n\n <!-- Operator Dropdown -->\n <!-- <div class=\"cqa-flex-1 cqa-max-w-[100px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getOperatorConfig(i)\">\n </cqa-dynamic-select>\n </div> -->\n\n <!-- Value Template Dropdown -->\n <div class=\"cqa-flex-1 cqa-min-w-[150px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getValueConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Remove Button -->\n <cqa-button\n *ngIf=\"i >= 1\"\n variant=\"text\"\n icon=\"close\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"'Remove condition'\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors\"\n (click)=\"removeCondition(i)\" *ngIf=\"i >= 1\"\n [attr.aria-label]=\"'Remove condition'\">\n <mat-icon class=\"cqa-text-lg cqa-text-[24px]\">close</mat-icon>\n </button> -->\n </div>\n\n <!-- Template Variables Section (shown when template is selected) -->\n <div *ngIf=\"getSelectedTemplate(i)\">\n <!-- Template Grammar Display -->\n
|
|
27333
|
+
args: [{ selector: 'cqa-step-builder-condition', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.OnPush, 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 Condition Step\n </h2>\n\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-y-auto\">\n <!-- Condition Builder Section -->\n <div class=\"cqa-mb-6\">\n <h3 class=\"cqa-text-sm cqa-text-[12px] cqa-font-semibold cqa-text-gray-900 cqa-mb-3\">\n Condition Builder\n </h3>\n\n <!-- Condition Rows -->\n <div class=\"cqa-flex cqa-flex-col cqa-gap-3 cqa-mb-3\">\n <ng-container *ngFor=\"let condition of conditionsFormArray.controls; let i = index; trackBy: trackByConditionIndex\">\n <div\n *ngIf=\"isConditionIf(i) || isConditionElseIf(i)\"\n class=\"cqa-flex cqa-flex-col cqa-gap-2\">\n <!-- Condition Row -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <!-- Condition Label -->\n <div class=\"cqa-text-[12px] cqa-font-semibold\">\n {{ getConditionLabel(i) }}\n </div>\n\n <!-- Operator Dropdown -->\n <!-- <div class=\"cqa-flex-1 cqa-max-w-[100px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getOperatorConfig(i)\">\n </cqa-dynamic-select>\n </div> -->\n\n <!-- Value Template Dropdown -->\n <div class=\"cqa-flex-1 cqa-min-w-[150px] cqa-text-[10px]\">\n <cqa-dynamic-select [form]=\"getConditionFormGroup(i)\" [config]=\"getValueConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Remove Button -->\n <cqa-button\n *ngIf=\"i >= 1\"\n variant=\"text\"\n icon=\"close\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n (click)=\"removeCondition(i)\"\n [attr.aria-label]=\"'Remove condition'\">\n </cqa-button>\n <!-- <button type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-gray-500 hover:cqa-text-gray-700 hover:cqa-bg-gray-100 cqa-transition-colors\"\n (click)=\"removeCondition(i)\" *ngIf=\"i >= 1\"\n [attr.aria-label]=\"'Remove condition'\">\n <mat-icon class=\"cqa-text-lg cqa-text-[24px]\">close</mat-icon>\n </button> -->\n </div>\n\n <!-- Template Variables Section (shown when template is selected) -->\n <div *ngIf=\"getSelectedTemplate(i)\" class=\"cqa-mt-2\">\n <!-- Template Grammar Display -->\n <div class=\"cqa-mb-4 cqa-flex cqa-items-center cqa-flex-wrap cqa-gap-1 cqa-text-sm cqa-text-gray-700\">\n <div class=\"cqa-action-format cqa-text-[12px] cqa-leading-[23px] cqa-text-black-100\"\n [innerHTML]=\"getConditionUpdatedHtmlGrammar(i) || getSelectedTemplate(i)?.htmlGrammar || getSelectedTemplate(i)?.naturalText || ''\">\n </div>\n </div>\n \n <!-- Template Variables Form Component (includes Description and Metadata) -->\n <cqa-template-variables-form\n style=\"width: 100%;\"\n [templateVariables]=\"getConditionTemplateVariables(i)\"\n [variablesForm]=\"getConditionVariablesForm(i)\"\n [metadata]=\"getConditionFormGroup(i).get('metadata')?.value || ''\"\n [description]=\"getConditionFormGroup(i).get('description')?.value || ''\"\n [elementOptions]=\"elementOptions\"\n [hasMoreElements]=\"hasMoreElements\"\n [isLoadingElements]=\"isLoadingElements\"\n [screenNameOptions]=\"screenNameOptions\"\n [hasMoreScreenNames]=\"hasMoreScreenNames\"\n [isLoadingScreenNames]=\"isLoadingScreenNames\"\n (variableValueChange)=\"onConditionVariableValueChange(i, $event.name, $event.value)\"\n (variableBooleanChange)=\"onConditionVariableBooleanChange(i, $event.name, $event.value)\"\n (metadataChange)=\"getConditionFormGroup(i).get('metadata')?.setValue($event)\"\n (descriptionChange)=\"getConditionFormGroup(i).get('description')?.setValue($event)\"\n (loadMoreElements)=\"loadMoreElements.emit()\"\n (searchElements)=\"searchElements.emit($event)\"\n (createElement)=\"createElement.emit($event)\"\n (searchScreenName)=\"searchScreenName.emit($event)\"\n (loadMoreScreenNames)=\"loadMoreScreenNames.emit($event)\"\n (createScreenNameRequest)=\"createScreenNameRequest.emit($event)\">\n </cqa-template-variables-form>\n </div>\n </div>\n </ng-container>\n </div>\n\n <!-- Add Condition Button -->\n <div class=\"cqa-border-2 cqa-border-dashed cqa-border-gray-300 cqa-rounded-lg cqa-p-1 cqa-mt-3\">\n <cqa-button\n variant=\"text\"\n icon=\"add\"\n iconPosition=\"start\"\n [customClass]=\"'cqa-w-full cqa-flex cqa-items-center cqa-justify-center'\"\n [text]=\"'Add Condition'\"\n (clicked)=\"addCondition('CONDITION_ELSE_IF')\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Include ELSE Branch Section -->\n <div class=\"cqa-flex cqa-items-center cqa-justify-between cqa-mb-6 cqa-p-3 cqa-bg-gray-50 cqa-rounded-lg\">\n <div class=\"cqa-flex cqa-flex-col\">\n <h3 class=\"cqa-text-[14px] cqa-font-semibold cqa-text-gray-900 cqa-mb-1\">\n Include ELSE branch\n </h3>\n <p class=\"cqa-text-[12px] cqa-text-gray-600\">\n Execute alternative steps when condition is not met.\n </p>\n </div>\n <mat-slide-toggle [checked]=\"includeElse\" (change)=\"onIncludeElseChange($event.checked)\" color=\"primary\">\n </mat-slide-toggle>\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 <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 [disabled]=\"!conditionForm.valid\"\n (clicked)=\"onCreateStep()\">\n </cqa-button>\n </div>\n</div>", styles: [] }]
|
|
26699
27334
|
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { operatorOptions: [{
|
|
26700
27335
|
type: Input
|
|
26701
27336
|
}], conditionTemplates: [{
|
|
26702
27337
|
type: Input
|
|
26703
27338
|
}], setConditionTemplateVariables: [{
|
|
26704
27339
|
type: Input
|
|
27340
|
+
}], elementOptions: [{
|
|
27341
|
+
type: Input
|
|
27342
|
+
}], hasMoreElements: [{
|
|
27343
|
+
type: Input
|
|
27344
|
+
}], isLoadingElements: [{
|
|
27345
|
+
type: Input
|
|
27346
|
+
}], screenNameOptions: [{
|
|
27347
|
+
type: Input
|
|
27348
|
+
}], hasMoreScreenNames: [{
|
|
27349
|
+
type: Input
|
|
27350
|
+
}], isLoadingScreenNames: [{
|
|
27351
|
+
type: Input
|
|
26705
27352
|
}], createStep: [{
|
|
26706
27353
|
type: Output
|
|
26707
27354
|
}], cancelled: [{
|
|
26708
27355
|
type: Output
|
|
27356
|
+
}], loadMoreElements: [{
|
|
27357
|
+
type: Output
|
|
27358
|
+
}], searchElements: [{
|
|
27359
|
+
type: Output
|
|
27360
|
+
}], createElement: [{
|
|
27361
|
+
type: Output
|
|
27362
|
+
}], searchScreenName: [{
|
|
27363
|
+
type: Output
|
|
27364
|
+
}], loadMoreScreenNames: [{
|
|
27365
|
+
type: Output
|
|
27366
|
+
}], createScreenNameRequest: [{
|
|
27367
|
+
type: Output
|
|
26709
27368
|
}] } });
|
|
26710
27369
|
|
|
26711
27370
|
class StepBuilderDatabaseComponent {
|
|
@@ -30407,6 +31066,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
30407
31066
|
StepBuilderActionComponent,
|
|
30408
31067
|
StepBuilderLoopComponent,
|
|
30409
31068
|
ElementPopupComponent,
|
|
31069
|
+
ElementFormComponent,
|
|
30410
31070
|
StepBuilderConditionComponent,
|
|
30411
31071
|
StepBuilderDatabaseComponent,
|
|
30412
31072
|
StepBuilderAiAgentComponent,
|
|
@@ -30550,6 +31210,7 @@ UiKitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "1
|
|
|
30550
31210
|
StepBuilderActionComponent,
|
|
30551
31211
|
StepBuilderLoopComponent,
|
|
30552
31212
|
ElementPopupComponent,
|
|
31213
|
+
ElementFormComponent,
|
|
30553
31214
|
StepBuilderConditionComponent,
|
|
30554
31215
|
StepBuilderDatabaseComponent,
|
|
30555
31216
|
StepBuilderAiAgentComponent,
|
|
@@ -30742,6 +31403,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
30742
31403
|
StepBuilderActionComponent,
|
|
30743
31404
|
StepBuilderLoopComponent,
|
|
30744
31405
|
ElementPopupComponent,
|
|
31406
|
+
ElementFormComponent,
|
|
30745
31407
|
StepBuilderConditionComponent,
|
|
30746
31408
|
StepBuilderDatabaseComponent,
|
|
30747
31409
|
StepBuilderAiAgentComponent,
|
|
@@ -30891,6 +31553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
30891
31553
|
StepBuilderActionComponent,
|
|
30892
31554
|
StepBuilderLoopComponent,
|
|
30893
31555
|
ElementPopupComponent,
|
|
31556
|
+
ElementFormComponent,
|
|
30894
31557
|
StepBuilderConditionComponent,
|
|
30895
31558
|
StepBuilderDatabaseComponent,
|
|
30896
31559
|
StepBuilderAiAgentComponent,
|
|
@@ -31580,5 +32243,5 @@ function buildTestCaseDetailsFromApi(data, options) {
|
|
|
31580
32243
|
* Generated bundle index. Do not edit.
|
|
31581
32244
|
*/
|
|
31582
32245
|
|
|
31583
|
-
export { ADVANCED_SUBFIELDS_BY_TYPE, ADVANCED_TOGGLE_KEYS, AIActionStepComponent, AIAgentStepComponent, API_EDIT_STEP_LABELS, ActionMenuButtonComponent, AddPrerequisiteCasesSectionComponent, AiDebugAlertComponent, AiLogsWithReasoningComponent, AiReasoningComponent, ApiEditStepComponent, ApiStepComponent, AutocompleteComponent, BadgeComponent, BasicStepComponent, BreakpointsModalComponent, ButtonComponent, CUSTOM_EDIT_STEP_DATA, CUSTOM_EDIT_STEP_EDIT_IN_DEPTH, CUSTOM_EDIT_STEP_REF, CUSTOM_ELEMENT_POPUP_REF, ChartCardComponent, ColumnVisibilityComponent, CompareRunsComponent, ConditionStepComponent, ConfigurationCardComponent, ConsoleAlertComponent, CoverageModuleCardComponent, CreateStepGroupComponent, CustomEditStepComponent, CustomEditStepRef, CustomEditStepService, CustomInputComponent, CustomTextareaComponent, CustomToggleComponent, DEFAULT_METADATA_COLOR, DEFAULT_PRIORITY_COLOR_CONFIG, DEFAULT_STATUS_COLOR_CONFIG, DIALOG_DATA, DIALOG_REF, DashboardHeaderComponent, DaterangepickerComponent, DaterangepickerDirective, DbQueryExecutionItemComponent, DbVerificationStepComponent, DeleteStepsComponent, DetailDrawerComponent, DetailDrawerTabComponent, DetailDrawerTabContentDirective, DetailSidePanelComponent, DialogComponent, DialogRef, DialogService, DocumentVerificationStepComponent, DropdownButtonComponent, DynamicCellContainerDirective, DynamicCellTemplateDirective, DynamicFilterComponent, DynamicHeaderTemplateDirective, DynamicSelectFieldComponent, DynamicTableComponent, ELEMENT_POPUP_DATA, ELEMENT_POPUP_EDIT_IN_DEPTH, EMPTY_STATE_IMAGES, EMPTY_STATE_PRESETS, ElementListComponent, ElementPopupComponent, ElementPopupRef, ElementPopupService, EmptyStateComponent, ErrorModalComponent, ExecutionResultModalComponent, ExportCodeModalComponent, FailedStepCardComponent, FailedStepComponent, FailedTestCasesCardComponent, FileDownloadStepComponent, FileUploadComponent, FullTableLoaderComponent, HeatErrorMapCellComponent, InsightCardComponent, ItemListComponent, IterationsLoopComponent, JumpToStepModalComponent, LiveConversationComponent, LiveExecutionStepComponent, LoopStepComponent, MainStepCollapseComponent, MetricsCardComponent, NetworkRequestComponent, OtherButtonComponent, PRIORITY_COLORS, PaginationComponent, ProgressIndicatorComponent, ProgressTextCardComponent, RESULT_COLORS, RunHistoryCardComponent, STATUS_COLORS, STEP_DETAILS_DRAWER_DATA, STEP_DETAILS_DRAWER_REF, STEP_DETAILS_FIELDS_BY_TYPE, STEP_DETAILS_FIELD_META, SearchBarComponent, SegmentControlComponent, SelectedFiltersComponent, SelfHealAnalysisComponent, SessionChangesModalComponent, SimulatorComponent, StepBuilderActionComponent, StepBuilderAiAgentComponent, StepBuilderConditionComponent, StepBuilderCustomCodeComponent, StepBuilderDatabaseComponent, StepBuilderDocumentComponent, StepBuilderDocumentGenerationTemplateStepComponent, StepBuilderGroupComponent, StepBuilderLoopComponent, StepBuilderRecordStepComponent, StepDetailsDrawerComponent, StepDetailsDrawerRef, StepDetailsDrawerService, StepGroupComponent, StepProgressCardComponent, StepRendererComponent, StepStatusCardComponent, StepTypes, TEST_CASE_DETAILS_FIELD_MAP, TEST_CASE_DETAILS_SELECT_KEYS, TEST_DATA_MODAL_DATA, TEST_DATA_MODAL_EDIT_IN_DEPTH, TEST_DATA_MODAL_REF, TableActionToolbarComponent, TableDataLoaderComponent, TableTemplateComponent, TailwindOverlayContainer, TemplateVariablesFormComponent, TestCaseAiAgentStepComponent, TestCaseAiVerifyStepComponent, TestCaseApiStepComponent, TestCaseConditionStepComponent, TestCaseCustomCodeStepComponent, TestCaseDatabaseStepComponent, TestCaseDetailsComponent, TestCaseDetailsEditComponent, TestCaseDetailsRendererComponent, TestCaseLoopStepComponent, TestCaseNormalStepComponent, TestCaseRestoreSessionStepComponent, TestCaseScreenshotStepComponent, TestCaseScrollStepComponent, TestCaseStepGroupComponent, TestCaseUploadStepComponent, TestCaseVerifyUrlStepComponent, TestDataModalComponent, TestDataModalRef, TestDataModalService, TestDistributionCardComponent, UiKitModule, UpdatedFailedStepComponent, ViewMoreFailedStepButtonComponent, VisualComparisonComponent, VisualDifferenceModalComponent, buildTestCaseDetailsFromApi, getDynamicFieldsFromLegacyConfig, getEmptyStatePreset, getMetadataColor, getMetadataValueStyle, getStepDetailsStepType, humanizeVariableKey, isAiAgentStepConfig, isAiVerifyStepConfig, isApiStepConfig, isConditionStepConfig, isCustomCodeStepConfig, isDatabaseStepConfig, isLoopStepConfig, isNormalStepConfig, isRestoreSessionStepConfig, isScreenshotStepConfig, isScrollStepConfig, isStepGroupConfig, isUploadStepConfig, isVerifyUrlStepConfig, mapApiVariablesToDynamicFields };
|
|
32246
|
+
export { ADVANCED_SUBFIELDS_BY_TYPE, ADVANCED_TOGGLE_KEYS, AIActionStepComponent, AIAgentStepComponent, API_EDIT_STEP_LABELS, ActionMenuButtonComponent, AddPrerequisiteCasesSectionComponent, AiDebugAlertComponent, AiLogsWithReasoningComponent, AiReasoningComponent, ApiEditStepComponent, ApiStepComponent, AutocompleteComponent, BadgeComponent, BasicStepComponent, BreakpointsModalComponent, ButtonComponent, CUSTOM_EDIT_STEP_DATA, CUSTOM_EDIT_STEP_EDIT_IN_DEPTH, CUSTOM_EDIT_STEP_REF, CUSTOM_ELEMENT_POPUP_REF, ChartCardComponent, ColumnVisibilityComponent, CompareRunsComponent, ConditionStepComponent, ConfigurationCardComponent, ConsoleAlertComponent, CoverageModuleCardComponent, CreateStepGroupComponent, CustomEditStepComponent, CustomEditStepRef, CustomEditStepService, CustomInputComponent, CustomTextareaComponent, CustomToggleComponent, DEFAULT_METADATA_COLOR, DEFAULT_PRIORITY_COLOR_CONFIG, DEFAULT_STATUS_COLOR_CONFIG, DIALOG_DATA, DIALOG_REF, DashboardHeaderComponent, DaterangepickerComponent, DaterangepickerDirective, DbQueryExecutionItemComponent, DbVerificationStepComponent, DeleteStepsComponent, DetailDrawerComponent, DetailDrawerTabComponent, DetailDrawerTabContentDirective, DetailSidePanelComponent, DialogComponent, DialogRef, DialogService, DocumentVerificationStepComponent, DropdownButtonComponent, DynamicCellContainerDirective, DynamicCellTemplateDirective, DynamicFilterComponent, DynamicHeaderTemplateDirective, DynamicSelectFieldComponent, DynamicTableComponent, ELEMENT_POPUP_DATA, ELEMENT_POPUP_EDIT_IN_DEPTH, EMPTY_STATE_IMAGES, EMPTY_STATE_PRESETS, ElementFormComponent, ElementListComponent, ElementPopupComponent, ElementPopupRef, ElementPopupService, EmptyStateComponent, ErrorModalComponent, ExecutionResultModalComponent, ExportCodeModalComponent, FailedStepCardComponent, FailedStepComponent, FailedTestCasesCardComponent, FileDownloadStepComponent, FileUploadComponent, FullTableLoaderComponent, HeatErrorMapCellComponent, InsightCardComponent, ItemListComponent, IterationsLoopComponent, JumpToStepModalComponent, LiveConversationComponent, LiveExecutionStepComponent, LoopStepComponent, MainStepCollapseComponent, MetricsCardComponent, NetworkRequestComponent, OtherButtonComponent, PRIORITY_COLORS, PaginationComponent, ProgressIndicatorComponent, ProgressTextCardComponent, RESULT_COLORS, RunHistoryCardComponent, STATUS_COLORS, STEP_DETAILS_DRAWER_DATA, STEP_DETAILS_DRAWER_REF, STEP_DETAILS_FIELDS_BY_TYPE, STEP_DETAILS_FIELD_META, SearchBarComponent, SegmentControlComponent, SelectedFiltersComponent, SelfHealAnalysisComponent, SessionChangesModalComponent, SimulatorComponent, StepBuilderActionComponent, StepBuilderAiAgentComponent, StepBuilderConditionComponent, StepBuilderCustomCodeComponent, StepBuilderDatabaseComponent, StepBuilderDocumentComponent, StepBuilderDocumentGenerationTemplateStepComponent, StepBuilderGroupComponent, StepBuilderLoopComponent, StepBuilderRecordStepComponent, StepDetailsDrawerComponent, StepDetailsDrawerRef, StepDetailsDrawerService, StepGroupComponent, StepProgressCardComponent, StepRendererComponent, StepStatusCardComponent, StepTypes, TEST_CASE_DETAILS_FIELD_MAP, TEST_CASE_DETAILS_SELECT_KEYS, TEST_DATA_MODAL_DATA, TEST_DATA_MODAL_EDIT_IN_DEPTH, TEST_DATA_MODAL_REF, TableActionToolbarComponent, TableDataLoaderComponent, TableTemplateComponent, TailwindOverlayContainer, TemplateVariablesFormComponent, TestCaseAiAgentStepComponent, TestCaseAiVerifyStepComponent, TestCaseApiStepComponent, TestCaseConditionStepComponent, TestCaseCustomCodeStepComponent, TestCaseDatabaseStepComponent, TestCaseDetailsComponent, TestCaseDetailsEditComponent, TestCaseDetailsRendererComponent, TestCaseLoopStepComponent, TestCaseNormalStepComponent, TestCaseRestoreSessionStepComponent, TestCaseScreenshotStepComponent, TestCaseScrollStepComponent, TestCaseStepGroupComponent, TestCaseUploadStepComponent, TestCaseVerifyUrlStepComponent, TestDataModalComponent, TestDataModalRef, TestDataModalService, TestDistributionCardComponent, UiKitModule, UpdatedFailedStepComponent, ViewMoreFailedStepButtonComponent, VisualComparisonComponent, VisualDifferenceModalComponent, buildTestCaseDetailsFromApi, getDynamicFieldsFromLegacyConfig, getEmptyStatePreset, getMetadataColor, getMetadataValueStyle, getStepDetailsStepType, humanizeVariableKey, isAiAgentStepConfig, isAiVerifyStepConfig, isApiStepConfig, isConditionStepConfig, isCustomCodeStepConfig, isDatabaseStepConfig, isLoopStepConfig, isNormalStepConfig, isRestoreSessionStepConfig, isScreenshotStepConfig, isScrollStepConfig, isStepGroupConfig, isUploadStepConfig, isVerifyUrlStepConfig, mapApiVariablesToDynamicFields };
|
|
31584
32247
|
//# sourceMappingURL=cqa-lib-cqa-ui.mjs.map
|