@cqa-lib/cqa-ui 1.1.405 → 1.1.407

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.
@@ -16001,6 +16001,7 @@ class SimulatorComponent {
16001
16001
  this.selectedView = 'video';
16002
16002
  this.hideVideoTab = false;
16003
16003
  this.browserViewPort = null;
16004
+ this.browserDevice = '';
16004
16005
  this.videoTimeUpdate = new EventEmitter();
16005
16006
  this.videoPlay = new EventEmitter();
16006
16007
  this.videoPause = new EventEmitter();
@@ -16047,6 +16048,24 @@ class SimulatorComponent {
16047
16048
  description: 'The device you are trying to use is not supported.',
16048
16049
  actions: []
16049
16050
  };
16051
+ this.MOBILE_BROWSER_DEVICE_MAP = {
16052
+ 'iphone_11': 'iPhone 11',
16053
+ 'iphone_13': 'iPhone 13',
16054
+ 'iphone_15': 'iPhone 15',
16055
+ 'iphone_xr': 'iPhone XR',
16056
+ 'iphone_16': 'iPhone 16',
16057
+ 'iphone_16_pro': 'iPhone 16 Pro',
16058
+ 'iphone_17': 'iPhone 17',
16059
+ 'iphone_17_pro_max': 'iPhone 17 Pro Max',
16060
+ 'pixel_5': 'Pixel 5',
16061
+ 'pixel_8': 'Pixel 8',
16062
+ 'pixel_9': 'Pixel 9',
16063
+ 'pixel_10': 'Pixel 10',
16064
+ 'galaxy_s20_fe': 'Galaxy S20 FE',
16065
+ 'galaxy_s25': 'Galaxy S25',
16066
+ 'galaxy_s25_ultra': 'Galaxy S25 Ultra',
16067
+ 'galaxy_tab_a9+': 'Galaxy Tab A9+',
16068
+ };
16050
16069
  this.deviceFrameConfigs = {
16051
16070
  // Pixels
16052
16071
  'Pixel 5': {
@@ -16251,6 +16270,13 @@ class SimulatorComponent {
16251
16270
  get speedControlContainer() {
16252
16271
  return this._speedControlContainer;
16253
16272
  }
16273
+ get effectivePlatformType() {
16274
+ if (this.platformType === 'device')
16275
+ return 'device';
16276
+ if (this.resolveMobileBrowserDevice())
16277
+ return 'device';
16278
+ return 'browser';
16279
+ }
16254
16280
  get hasDeviceFrame() {
16255
16281
  return !!this.deviceFrameConfig;
16256
16282
  }
@@ -16266,7 +16292,7 @@ class SimulatorComponent {
16266
16292
  return Math.abs(windowAr - viewportAr) / viewportAr < tolerance;
16267
16293
  }
16268
16294
  get liveContentContainerStyle() {
16269
- if (typeof window === 'undefined' || !this.isLive || this.platformType !== 'browser') {
16295
+ if (typeof window === 'undefined' || !this.isLive || this.effectivePlatformType !== 'browser') {
16270
16296
  return {};
16271
16297
  }
16272
16298
  if (!this.isAspectRatioMatched) {
@@ -16289,26 +16315,27 @@ class SimulatorComponent {
16289
16315
  }
16290
16316
  return { width, height };
16291
16317
  }
16318
+ resolveMobileBrowserDevice() {
16319
+ if (!this.browserDevice)
16320
+ return null;
16321
+ const normalized = this.browserDevice.toLowerCase().replace(/-/g, '_');
16322
+ return this.MOBILE_BROWSER_DEVICE_MAP[normalized] || null;
16323
+ }
16292
16324
  onWindowResize() {
16293
16325
  this.cdr.markForCheck();
16294
16326
  }
16295
16327
  get deviceFrameConfig() {
16296
- if (this.platformType === 'browser') {
16297
- return this.deviceFrameConfigs['browser'] || null;
16298
- }
16299
16328
  if (this.platformType === 'device') {
16300
- // If we have a deviceName and its frame is available, return it
16301
- if (this.deviceName && this.deviceFrameConfigs[this.deviceName]) {
16302
- return this.deviceFrameConfigs[this.deviceName];
16329
+ const name = this.deviceName || this.resolveMobileBrowserDevice();
16330
+ return (name && this.deviceFrameConfigs[name]) ? this.deviceFrameConfigs[name] : null;
16331
+ }
16332
+ if (this.platformType === 'browser') {
16333
+ // Auto-detect mobile device emulation from the browser value
16334
+ const mobileName = this.resolveMobileBrowserDevice();
16335
+ if (mobileName && this.deviceFrameConfigs[mobileName]) {
16336
+ return this.deviceFrameConfigs[mobileName];
16303
16337
  }
16304
- // If no deviceName or deviceName's frame not available, use defaults based on platform
16305
- // if (this.platform === 'android') {
16306
- // return this.deviceFrameConfigs['Pixel 9'] || null;
16307
- // }
16308
- // if (this.platform === 'ios') {
16309
- // return this.deviceFrameConfigs['iPhone 15'] || null;
16310
- // }
16311
- return null;
16338
+ return this.deviceFrameConfigs['browser'] || null;
16312
16339
  }
16313
16340
  return null;
16314
16341
  }
@@ -17637,10 +17664,10 @@ class SimulatorComponent {
17637
17664
  }
17638
17665
  }
17639
17666
  SimulatorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, deps: [{ token: i1$2.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
17640
- SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause", markerHit: "markerHit", isVideoPlayingChange: "isVideoPlayingChange" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBarRef", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainerRef", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-overflow-hidden\"\n [ngClass]=\"{\n 'cqa-w-auto': hasDeviceFrame,\n 'cqa-w-full cqa-flex-col': !hasDeviceFrame,\n 'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser',\n 'cqa-max-h-full cqa-h-full': hasDeviceFrame && (platformType !== 'browser' || !isLive),\n 'cqa-min-w-max': hasDeviceFrame && platformType === 'device'\n }\"\n [ngStyle]=\"liveContentContainerStyle\">\n <img *ngIf=\"hasDeviceFrame\"\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div [ngClass]=\"{\n 'cqa-absolute cqa-flex cqa-flex-col': hasDeviceFrame,\n 'cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative': !hasDeviceFrame,\n 'cqa-z-20': hasDeviceFrame && platformType === 'browser',\n 'cqa-bg-white': hasDeviceFrame && platformType !== 'browser'\n }\"\n [ngStyle]=\"hasDeviceFrame ? deviceScreenStyle : {}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-max-h-[calc(100%-60px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame; else videoNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #videoNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <video\n #vplayer\n class=\"cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span\n class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-inline-block\"\n style=\"width: 40px; text-align: center;\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-mr-2\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame; else screenshotNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #screenshotNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i4$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
17667
+ SimulatorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: SimulatorComponent, selector: "cqa-simulator", inputs: { videoUrl: "videoUrl", videoUrls: "videoUrls", videoCurrentDuration: "videoCurrentDuration", stepMarkers: "stepMarkers", screenShotUrl: "screenShotUrl", traceViewUrl: "traceViewUrl", platformName: "platformName", platformType: "platformType", platform: "platform", deviceName: "deviceName", isLive: "isLive", liveStatus: "liveStatus", liveLoadingLabel: "liveLoadingLabel", isContentVideoLoading: "isContentVideoLoading", failedStatusMessage: "failedStatusMessage", isVNCSessionIntruppted: "isVNCSessionIntruppted", vncSessionIntupptedMessage: "vncSessionIntupptedMessage", selectedView: "selectedView", hideVideoTab: "hideVideoTab", browserViewPort: "browserViewPort", browserDevice: "browserDevice" }, outputs: { videoTimeUpdate: "videoTimeUpdate", videoPlay: "videoPlay", videoPause: "videoPause", markerHit: "markerHit", isVideoPlayingChange: "isVideoPlayingChange" }, host: { listeners: { "window:resize": "onWindowResize()" } }, viewQueries: [{ propertyName: "vplayerRef", first: true, predicate: ["vplayer"], descendants: true }, { propertyName: "timelineBarRef", first: true, predicate: ["timelineBar"], descendants: true }, { propertyName: "speedControlContainerRef", first: true, predicate: ["speedControlContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"effectivePlatformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"effectivePlatformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"effectivePlatformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-overflow-hidden\"\n [ngClass]=\"{\n 'cqa-w-auto': hasDeviceFrame,\n 'cqa-w-full cqa-flex-col': !hasDeviceFrame,\n 'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser',\n 'cqa-max-h-full cqa-h-full': hasDeviceFrame && (effectivePlatformType !== 'browser' || !isLive),\n 'cqa-min-w-max': hasDeviceFrame && effectivePlatformType === 'device'\n }\"\n [ngStyle]=\"liveContentContainerStyle\">\n <img *ngIf=\"hasDeviceFrame\"\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div [ngClass]=\"{\n 'cqa-absolute cqa-flex cqa-flex-col': hasDeviceFrame,\n 'cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative': !hasDeviceFrame,\n 'cqa-z-20': hasDeviceFrame && effectivePlatformType === 'browser',\n 'cqa-bg-white': hasDeviceFrame && effectivePlatformType !== 'browser'\n }\"\n [ngStyle]=\"hasDeviceFrame ? deviceScreenStyle : {}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-max-h-[calc(100%-60px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': effectivePlatformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame; else videoNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser', 'cqa-min-w-max': effectivePlatformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': effectivePlatformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': effectivePlatformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #videoNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <video\n #vplayer\n class=\"cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span\n class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-inline-block\"\n style=\"width: 40px; text-align: center;\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-mr-2\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame; else screenshotNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser', 'cqa-min-w-max': effectivePlatformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': effectivePlatformType === 'browser', 'cqa-max-h-full': effectivePlatformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': effectivePlatformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': effectivePlatformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #screenshotNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': effectivePlatformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", components: [{ type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }, { type: i4$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "diameter", "strokeWidth", "mode", "value"], exportAs: ["matProgressSpinner"] }], directives: [{ type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i6.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
17641
17668
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: SimulatorComponent, decorators: [{
17642
17669
  type: Component,
17643
- args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"platformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"platformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"platformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-overflow-hidden\"\n [ngClass]=\"{\n 'cqa-w-auto': hasDeviceFrame,\n 'cqa-w-full cqa-flex-col': !hasDeviceFrame,\n 'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser',\n 'cqa-max-h-full cqa-h-full': hasDeviceFrame && (platformType !== 'browser' || !isLive),\n 'cqa-min-w-max': hasDeviceFrame && platformType === 'device'\n }\"\n [ngStyle]=\"liveContentContainerStyle\">\n <img *ngIf=\"hasDeviceFrame\"\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div [ngClass]=\"{\n 'cqa-absolute cqa-flex cqa-flex-col': hasDeviceFrame,\n 'cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative': !hasDeviceFrame,\n 'cqa-z-20': hasDeviceFrame && platformType === 'browser',\n 'cqa-bg-white': hasDeviceFrame && platformType !== 'browser'\n }\"\n [ngStyle]=\"hasDeviceFrame ? deviceScreenStyle : {}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-max-h-[calc(100%-60px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame; else videoNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #videoNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <video\n #vplayer\n class=\"cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span\n class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-inline-block\"\n style=\"width: 40px; text-align: center;\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-mr-2\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame; else screenshotNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': platformType === 'browser', 'cqa-min-w-max': platformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': platformType === 'browser', 'cqa-max-h-full': platformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': platformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': platformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #screenshotNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': platformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
17670
+ args: [{ selector: 'cqa-simulator', template: "<div class=\"cqa-ui-root\" style=\"background-color: #F3F4F6; height: 100%; display: flex; flex-direction: column;\" [ngStyle]=\"{\n position: isFullScreen ? 'fixed' : null,\n inset: isFullScreen ? '1rem' : null,\n zIndex: isFullScreen ? '50' : null,\n boxShadow: isFullScreen ? '0px 13px 25px -12px rgba(0, 0, 0, 0.25)' : null,\n borderRadius: isFullScreen ? '.5rem' : null,\n border: isFullScreen ? '1px solid #E5E7EB' : null,\n width: isFullScreen ? 'calc(100% - 32px)' : null,\n height: isFullScreen ? 'calc(100% - 32px)' : '100%',\n overflow: isFullScreen ? 'hidden' : null\n}\">\n <div class=\"cqa-w-full cqa-py-1 cqa-px-2 cqa-bg-[#FFFFFF]\" style=\"border-bottom: 1px solid #E5E7EB;box-shadow: 0px 1px 2px 0px #0000000D;\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-justify-between cqa-flex-wrap\">\n <div class=\"cqa-flex cqa-items-center\">\n <div *ngIf=\"isLive\" class=\"cqa-h-[21px] cqa-inline-flex cqa-items-center cqa-gap-1.5 cqa-mr-2 cqa-px-[9px] cqa-py-[3px] cqa-bg-[#FCD9D9] cqa-rounded-[6px]\" style=\"border: 1px solid #F9BFBF;\">\n <span class=\"cqa-relative cqa-w-2 cqa-h-2 cqa-rounded-full cqa-bg-[#F47F7F]\" style=\"flex-shrink: 0;\">\n <span class=\"cqa-absolute cqa-inset-0 cqa-rounded-full cqa-bg-[#F47F7F] cqa-opacity-75 cqa-animate-ping\"></span>\n </span>\n <span class=\"cqa-text-[10px] cqa-font-medium cqa-text-[#C63535] cqa-leading-[15px]\">Live</span>\n </div>\n <mat-icon *ngIf=\"effectivePlatformType === 'browser'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <g clip-path=\"url(#clip0_935_15847)\">\n <path\n d=\"M0.625 5C0.625 6.16032 1.08594 7.27312 1.90641 8.09359C2.72688 8.91406 3.83968 9.375 5 9.375C6.16032 9.375 7.27312 8.91406 8.09359 8.09359C8.91406 7.27312 9.375 6.16032 9.375 5C9.375 3.83968 8.91406 2.72688 8.09359 1.90641C7.27312 1.08594 6.16032 0.625 5 0.625C3.83968 0.625 2.72688 1.08594 1.90641 1.90641C1.08594 2.72688 0.625 3.83968 0.625 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path\n d=\"M3.125 5C3.125 3.83968 3.32254 2.72688 3.67417 1.90641C4.02581 1.08594 4.50272 0.625 5 0.625C5.49728 0.625 5.97419 1.08594 6.32582 1.90641C6.67746 2.72688 6.875 3.83968 6.875 5C6.875 6.16032 6.67746 7.27312 6.32582 8.09359C5.97419 8.91406 5.49728 9.375 5 9.375C4.50272 9.375 4.02581 8.91406 3.67417 8.09359C3.32254 7.27312 3.125 6.16032 3.125 5Z\"\n stroke=\"#9CA3AF\" stroke-width=\"0.6\" stroke-linejoin=\"round\" />\n <path d=\"M0.9375 6.45866H9.0625M0.9375 3.54199H9.0625\" stroke=\"#9CA3AF\" stroke-width=\"0.6\"\n stroke-linecap=\"round\" />\n </g>\n <defs>\n <clipPath id=\"clip0_935_15847\">\n <rect width=\"10\" height=\"10\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n </mat-icon>\n <mat-icon *ngIf=\"effectivePlatformType === 'device'\" style=\"width: 10px; height: 10px;\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M7.08325 0.833008H2.91659C2.45635 0.833008 2.08325 1.2061 2.08325 1.66634V8.33301C2.08325 8.79324 2.45635 9.16634 2.91659 9.16634H7.08325C7.54349 9.16634 7.91658 8.79324 7.91658 8.33301V1.66634C7.91658 1.2061 7.54349 0.833008 7.08325 0.833008Z\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M5 7.5H5.00417\" stroke=\"#6B7280\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </mat-icon>\n <p class=\"cqa-text-sm !cqa-text-[10px] cqa-text-[#6B7280] cqa-ml-2\">\n {{ platformName }}\n <span\n *ngIf=\"effectivePlatformType === 'browser'\"\n class=\"cqa-ml-1\"\n [matTooltip]=\"'Screen size: ' + effectiveBrowserViewPort.width + 'x' + effectiveBrowserViewPort.height\"\n matTooltipPosition=\"below\"\n >\n \u00B7\n <span class=\"cqa-ml-1\">\n {{ effectiveBrowserViewPort.width }}x{{ effectiveBrowserViewPort.height }}\n </span>\n </span>\n </p>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div *ngIf=\"isLive\" [ngClass]=\"getStatusBadgeClass()\">\n <span [ngClass]=\"getStatusTextClass()\">{{ liveStatus }}</span>\n </div>\n\n <ng-container *ngIf=\"!isLive\">\n <cqa-segment-control \n [segments]=\"segments\" \n [value]=\"currentView\"\n (valueChange)=\"onSegmentChange($event)\">\n </cqa-segment-control>\n \n <div *ngIf=\"!isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Expand\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M6.25 1.25H8.75V3.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M8.74992 1.25L5.83325 4.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 8.74967L4.16667 5.83301\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M3.75 8.75H1.25V6.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div *ngIf=\"isFullScreen\" \n class=\"cqa-p-1 cqa-cursor-pointer hover:cqa-bg-gray-100 cqa-rounded-sm cqa-transition-colors\"\n (click)=\"toggleFullScreen()\"\n title=\"Exit full screen\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M8.75 6.25H6.25V8.75\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M6.25008 6.25L9.16675 9.16667\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M0.833252 0.833008L3.74992 3.74967\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M1.25 3.75H3.75V1.25\" stroke=\"#9CA3AF\" stroke-width=\"0.833333\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"cqa-w-full cqa-bg-[#F3F4F6] cqa-h-[calc(100%-41px)]\">\n <!-- Live Content View -->\n <div *ngIf=\"isLive\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center cqa-relative\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-overflow-hidden\"\n [ngClass]=\"{\n 'cqa-w-auto': hasDeviceFrame,\n 'cqa-w-full cqa-flex-col': !hasDeviceFrame,\n 'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser',\n 'cqa-max-h-full cqa-h-full': hasDeviceFrame && (effectivePlatformType !== 'browser' || !isLive),\n 'cqa-min-w-max': hasDeviceFrame && effectivePlatformType === 'device'\n }\"\n [ngStyle]=\"liveContentContainerStyle\">\n <img *ngIf=\"hasDeviceFrame\"\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div [ngClass]=\"{\n 'cqa-absolute cqa-flex cqa-flex-col': hasDeviceFrame,\n 'cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative': !hasDeviceFrame,\n 'cqa-z-20': hasDeviceFrame && effectivePlatformType === 'browser',\n 'cqa-bg-white': hasDeviceFrame && effectivePlatformType !== 'browser'\n }\"\n [ngStyle]=\"hasDeviceFrame ? deviceScreenStyle : {}\">\n <!-- Loading State -->\n <div *ngIf=\"isContentVideoLoading\" class=\"cqa-p-10 cqa-text-center cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center\">\n <div class=\"cqa-mb-4\">\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"40\"></mat-progress-spinner>\n </div>\n <p class=\"cqa-text-gray-400 cqa-text-sm\">{{ liveLoadingLabel }}</p>\n </div>\n\n <!-- Live Content (when not loading) -->\n <div *ngIf=\"!isContentVideoLoading\" class=\"cqa-w-full cqa-h-full cqa-flex cqa-flex-col cqa-items-center cqa-justify-center cqa-relative\">\n <div *ngIf=\"liveStatus === 'Failed' && failedStatusMessage\" class=\"cqa-p-6 cqa-text-center cqa-w-full\">\n <div class=\"cqa-inline-flex cqa-items-center cqa-gap-2 cqa-px-4 cqa-py-3 cqa-bg-[#FCD9D9] cqa-border cqa-border-[#F9BFBF] cqa-rounded-lg\">\n <mat-icon style=\"width: 18px; height: 18px; color: #C63535; font-size: 18px;\">error</mat-icon>\n <p class=\"cqa-text-[#C63535] cqa-text-sm cqa-font-medium cqa-m-0\">{{ failedStatusMessage }}</p>\n </div>\n </div>\n <ng-content *ngIf=\"liveStatus !== 'Failed' || !failedStatusMessage\"></ng-content>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Normal Video View (when not live) -->\n <div *ngIf=\"!isLive && currentView === 'video'\"\n class=\"cqa-h-full cqa-flex cqa-flex-col\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"Video playback\"\n (keydown)=\"onVideoKeydown($event)\">\n <div class=\"cqa-w-full cqa-flex cqa-items-center cqa-max-h-[calc(100%-60px)]\" *ngIf=\"currentVideoUrl\" [ngClass]=\"{'!cqa-h-full': effectivePlatformType === 'device', 'cqa-mt-auto': hasDeviceFrame}\">\n <ng-container *ngIf=\"hasDeviceFrame; else videoNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser', 'cqa-min-w-max': effectivePlatformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-max-h-full cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': effectivePlatformType !== 'browser'}\">\n <video\n #vplayer\n class=\"cqa-object-cover cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n [ngClass]=\"{'cqa-z-20': effectivePlatformType === 'browser'}\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #videoNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <video\n #vplayer\n class=\"cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n [src]=\"currentVideoUrl\"\n type=\"video/webm\"\n (loadedmetadata)=\"onVideoMetadataLoaded()\"\n (canplay)=\"onVideoCanPlay()\"\n (ended)=\"onVideoEnded()\"\n ></video>\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!currentVideoUrl\">\n <ng-container *ngIf=\"isVNCSessionIntruppted && vncSessionIntupptedMessage; else noVideoDefault\">\n <p class=\"cqa-text-sm cqa-text-gray-600\">\n {{ vncSessionIntupptedMessage }}\n </p>\n </ng-container>\n <ng-template #noVideoDefault>\n <span>No video recording found</span>\n </ng-template>\n </div>\n \n <div class=\"cqa-px-2 cqa-py-2 cqa-bg-white\" style=\"border-top: 1px solid #E5E7EB;\" [ngClass]=\"{'cqa-mt-auto': hasDeviceFrame}\" *ngIf=\"currentVideoUrl && !isLive\">\n <span class=\"cqa-text-[#6B7280] cqa-text-[12px] cqa-font-medium cqa-mb-2 cqa-whitespace-nowrap cqa-block\">\n Video {{ currentVideoIndex + 1 }} playing out of {{ videoUrls?.length || 0 }}\n </span>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"currentVideoIndex === 0\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\"\n (click)=\"prevVideo()\"\n matTooltip=\"Previous video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': currentVideoIndex === 0}\">skip_previous</mat-icon>\n </button>\n\n <div class=\"cqa-flex cqa-items-center cqa-justify-center\" style=\"width: 16px; height: 16px;\">\n <mat-progress-spinner\n *ngIf=\"isPlayerSwitching\"\n mode=\"indeterminate\"\n diameter=\"16\"\n class=\"cqa-inline-block\">\n </mat-progress-spinner>\n <button \n *ngIf=\"!isPlayerSwitching\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n (click)=\"togglePlay()\"\n matTooltip=\"{{ isPlaying ? 'Pause' : 'Play' }}\"\n matTooltipPosition=\"above\">\n <span *ngIf=\"!isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3 2L13 8L3 14V2Z\" fill=\"#374151\"/>\n </svg>\n </span>\n <span *ngIf=\"isPlaying\" class=\"cqa-flex cqa-items-center cqa-justify-center\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"3\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n <rect x=\"10\" y=\"2\" width=\"3\" height=\"12\" fill=\"#374151\"/>\n </svg>\n </span>\n </button>\n </div>\n\n <button \n *ngIf=\"hasMultipleVideos\"\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer !cqa-px-0 cqa-flex cqa-items-center cqa-justify-center hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none\"\n style=\"pointer-events: auto;\"\n [disabled]=\"videoUrls && (currentVideoIndex >= videoUrls.length - 1)\"\n [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\"\n (click)=\"nextVideo()\"\n matTooltip=\"Next video\"\n matTooltipPosition=\"above\">\n <mat-icon class=\"cqa-w-4 cqa-h-4 !cqa-text-[16px] cqa-text-[#374151]\" [ngClass]=\"{'cqa-opacity-50 cqa-cursor-not-allowed': videoUrls && (currentVideoIndex >= videoUrls.length - 1)}\">skip_next</mat-icon>\n </button>\n\n <span\n class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-inline-block\"\n style=\"width: 40px; text-align: center;\">\n {{ formatTime(vplayer?.nativeElement?.currentTime || 0) }}\n </span>\n\n <div #speedControlContainer class=\"cqa-relative cqa-mr-[8px] cqa-flex cqa-items-center cqa-justify-center\">\n <button\n type=\"button\"\n class=\"cqa-bg-transparent cqa-border-none cqa-cursor-pointer cqa-text-[#9CA3AF] cqa-text-[10px] cqa-leading-[15px] cqa-font-medium cqa-whitespace-nowrap cqa-select-none hover:cqa-opacity-70 cqa-transition-opacity cqa-outline-none cqa-px-1\"\n (click)=\"toggleSpeedControl()\"\n [matTooltip]=\"'Playback Speed'\"\n [matTooltipPosition]=\"'below'\">\n {{ currentSpeed }}\n </button>\n \n <div \n *ngIf=\"isSpeedControlOpen\"\n class=\"cqa-absolute cqa-bottom-full cqa-mb-2 cqa-right-0 cqa-bg-[#F0F0F1] cqa-rounded-lg cqa-overflow-hidden cqa-shadow-lg cqa-z-50\"\n style=\"min-width: max-content; left: 50%; bottom: 0%; transform: translate(-50%, -50%);\">\n <cqa-segment-control\n [segments]=\"speedSegments\"\n [value]=\"currentSpeed\"\n [containerBgColor]=\"'#F0F0F1'\"\n (valueChange)=\"onSpeedChange($event)\">\n </cqa-segment-control>\n </div>\n </div>\n \n <div class=\"cqa-flex-1 cqa-min-w-0\">\n <div \n #timelineBar\n class=\"cqa-relative cqa-h-1 cqa-bg-gray-200 cqa-rounded-full cqa-cursor-pointer cqa-w-full\"\n (click)=\"onTimelineClick($event)\">\n \n <div \n *ngFor=\"let marker of currentVideoMarkers\" \n class=\"cqa-absolute cqa-rounded-full\"\n [style.left.%]=\"getStepLeftPosition(marker)\"\n [style.width]=\"'8px'\"\n [style.height]=\"'8px'\"\n [style.background]=\"getGlobalMarkerColor(marker.level)\"\n [style.border]=\"'2px solid ' + getGlobalMarkerResultColor(marker.result)\"\n [style.box-sizing]=\"'border-box'\"\n [attr.title]=\"marker.title || ''\"\n style=\"pointer-events: auto; z-index: 50; cursor: pointer; transform: translate(-50%, -50%); top: 50%;\"\n (click)=\"onMarkerClick($event, marker)\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-left-0 cqa-top-0 cqa-h-full cqa-bg-blue-500 cqa-rounded-full\"\n [style.width.%]=\"progress\"\n [style.transition]=\"dragging ? 'none' : 'width 100ms'\"\n style=\"pointer-events: none; z-index: 2;\">\n </div>\n \n <div \n class=\"cqa-absolute cqa-top-1/2 cqa-w-3 cqa-h-3 cqa-bg-blue-600 cqa-rounded-full cqa-cursor-grab active:cqa-cursor-grabbing cqa-shadow-md\"\n [style.left.%]=\"progress\"\n style=\"transform: translate(-50%, -50%); z-index: 60;\"\n (mousedown)=\"startDrag($event)\">\n </div>\n </div>\n </div>\n\n <span class=\"cqa-text-[#9CA3AF] cqa-text-[9px] cqa-font-normal cqa-whitespace-nowrap cqa-select-none cqa-mr-2\">\n {{ formatTime(vplayer?.nativeElement?.duration || 0) }}\n </span>\n </div>\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'screenshots'\" class=\"cqa-h-full\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center\" *ngIf=\"screenShotUrl\">\n <ng-container *ngIf=\"hasDeviceFrame; else screenshotNoFrame\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <div class=\"cqa-relative cqa-h-full cqa-w-auto cqa-flex cqa-items-center cqa-justify-center cqa-max-h-full\" [ngClass]=\"{'cqa-rounded-md cqa-overflow-hidden': effectivePlatformType === 'browser', 'cqa-min-w-max': effectivePlatformType === 'device'}\">\n <img\n [src]=\"deviceMockupImage\"\n alt=\"Device mockup\"\n class=\"cqa-h-full cqa-w-auto cqa-object-contain cqa-block cqa-pointer-events-none cqa-z-10\"\n [ngClass]=\"{'cqa-max-h-[inherit]': effectivePlatformType === 'browser', 'cqa-max-h-full': effectivePlatformType !== 'browser'}\"\n />\n <div class=\"cqa-absolute cqa-flex cqa-flex-col\" [ngStyle]=\"deviceScreenStyle\" [ngClass]=\"{'cqa-bg-white': effectivePlatformType !== 'browser'}\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n [ngClass]=\"{'cqa-z-20': effectivePlatformType === 'browser'}\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </div>\n </div>\n </ng-container>\n <ng-template #screenshotNoFrame>\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-justify-center cqa-p-4\">\n <img\n [src]=\"screenShotUrl\"\n alt=\"Screenshot\"\n class=\"cqa-object-contain cqa-w-full cqa-h-full cqa-block cqa-bg-[##F2F2F2]\"\n />\n </div>\n </ng-template>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!screenShotUrl\">\n No screenshot available\n </div>\n </div>\n\n <div *ngIf=\"!isLive && currentView === 'trace'\" class=\"cqa-h-full cqa-flex cqa-flex-col cqa-justify-center\">\n <div class=\"cqa-w-full cqa-h-full cqa-flex cqa-items-center cqa-relative\" *ngIf=\"traceViewUrl\" [ngClass]=\"{'!cqa-h-full': effectivePlatformType === 'device'}\" style=\"padding-top: 48px; padding-bottom: 0px;\">\n <div class=\"cqa-w-full cqa-h-full cqa-overflow-hidden cqa-relative\">\n <iframe \n [src]=\"safeTraceUrl\" \n title=\"Trace Viewer\"\n class=\"cqa-object-contain cqa-w-full cqa-min-h-[250px] cqa-max-h-full cqa-block cqa-bg-[##F2F2F2]\"\n style=\"margin-top: -48px; height: calc(100% + 48px);\"\n frameborder=\"0\"\n allowfullscreen\n width=\"100%\"\n loading=\"lazy\"\n (load)=\"onTraceViewerLoad()\"\n (error)=\"onTraceViewerError()\">\n </iframe>\n </div>\n \n <div *ngIf=\"traceViewerLoading\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Loading trace viewer...\n </div>\n </div>\n \n <div *ngIf=\"traceViewerError\" class=\"cqa-absolute cqa-inset-0 cqa-bg-[#F3F4F6] cqa-flex cqa-items-center cqa-justify-center cqa-z-10\">\n <div class=\"cqa-text-center cqa-text-gray-400 cqa-text-sm\">\n Failed to load trace viewer\n </div>\n </div>\n </div>\n \n <div class=\"cqa-p-10 cqa-text-center cqa-text-gray-400 cqa-text-sm cqa-h-full cqa-flex cqa-items-center cqa-justify-center\" *ngIf=\"!traceViewUrl\">\n No trace available\n </div>\n </div> \n </div>\n</div>", styles: [] }]
17644
17671
  }], ctorParameters: function () { return [{ type: i1$2.DomSanitizer }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { videoUrl: [{
17645
17672
  type: Input
17646
17673
  }], videoUrls: [{
@@ -17681,6 +17708,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
17681
17708
  type: Input
17682
17709
  }], browserViewPort: [{
17683
17710
  type: Input
17711
+ }], browserDevice: [{
17712
+ type: Input
17684
17713
  }], videoTimeUpdate: [{
17685
17714
  type: Output
17686
17715
  }], videoPlay: [{
@@ -24696,6 +24725,15 @@ class TestCaseLoopStepComponent {
24696
24725
  if (this.templateVariablesForm && this.editSnapshot.conditionTemplateFormValue) {
24697
24726
  this.templateVariablesForm.patchValue(this.editSnapshot.conditionTemplateFormValue);
24698
24727
  }
24728
+ // Reset form controls so that getTestDataProfileFormValue / getLoopStartFormValue / getLoopEndFormValue
24729
+ // fall through to config on the next edit instead of returning the stale changed values.
24730
+ if (this.editForm) {
24731
+ this.editForm.patchValue({
24732
+ testDataProfile: null,
24733
+ startStep: null,
24734
+ endStep: null,
24735
+ }, { emitEvent: false });
24736
+ }
24699
24737
  this.isEditing = false;
24700
24738
  }
24701
24739
  onEditInDepth(templateOverride) {