angular-debug-recorder 1.0.3 → 1.1.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"angular-debug-recorder.mjs","sources":["../../../projects/debug-recorder/src/lib/services/recorder.service.ts","../../../projects/debug-recorder/src/lib/services/ai-generator.service.ts","../../../projects/debug-recorder/src/lib/services/rrweb-recorder.service.ts","../../../projects/debug-recorder/src/lib/action-list/action-list.component.ts","../../../projects/debug-recorder/src/lib/test-preview/test-preview.component.ts","../../../projects/debug-recorder/src/lib/settings-dialog/settings-dialog.component.ts","../../../projects/debug-recorder/src/lib/session-replay/session-replay.component.ts","../../../projects/debug-recorder/src/lib/debug-panel/debug-panel.component.ts","../../../projects/debug-recorder/src/public-api.ts","../../../projects/debug-recorder/src/angular-debug-recorder.ts"],"sourcesContent":["import { Injectable, NgZone, signal, computed } from '@angular/core';\r\nimport { ActionType, ElementInfo, RecordedAction, RecordingSession } from '../models/recorded-action.model';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class RecorderService {\r\n private _isRecording = signal(false);\r\n private _currentSession = signal<RecordingSession | null>(null);\r\n private _sessions = signal<RecordingSession[]>([]);\r\n private _isPaused = signal(false);\r\n\r\n isRecording = computed(() => this._isRecording());\r\n isPaused = computed(() => this._isPaused());\r\n currentSession = computed(() => this._currentSession());\r\n sessions = computed(() => this._sessions());\r\n actionCount = computed(() => this._currentSession()?.actions.length ?? 0);\r\n\r\n private listeners: Array<{ type: string; fn: EventListener }> = [];\r\n private mutationObserver?: MutationObserver;\r\n\r\n constructor(private zone: NgZone) {}\r\n\r\n startRecording(name?: string, description?: string): void {\r\n const session: RecordingSession = {\r\n id: this.generateId(),\r\n name: name || `Session ${new Date().toLocaleTimeString()}`,\r\n description,\r\n startTime: Date.now(),\r\n startUrl: window.location.href,\r\n actions: [],\r\n tags: [],\r\n };\r\n\r\n this._currentSession.set(session);\r\n this._isRecording.set(true);\r\n this._isPaused.set(false);\r\n this.attachListeners();\r\n this.recordNavigation('navigation', window.location.href);\r\n }\r\n\r\n stopRecording(): RecordingSession | null {\r\n const session = this._currentSession();\r\n if (!session) return null;\r\n\r\n const completed = { ...session, endTime: Date.now() };\r\n this._sessions.update(s => [...s, completed]);\r\n this._currentSession.set(null);\r\n this._isRecording.set(false);\r\n this._isPaused.set(false);\r\n this.detachListeners();\r\n return completed;\r\n }\r\n\r\n pauseRecording(): void {\r\n if (this._isRecording()) {\r\n this._isPaused.set(!this._isPaused());\r\n }\r\n }\r\n\r\n clearCurrentSession(): void {\r\n this._currentSession.update(s => s ? { ...s, actions: [] } : null);\r\n }\r\n\r\n removeAction(actionId: string): void {\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: s.actions.filter(a => a.id !== actionId) } : null\r\n );\r\n }\r\n\r\n addNote(actionId: string, note: string): void {\r\n this._currentSession.update(s =>\r\n s ? {\r\n ...s,\r\n actions: s.actions.map(a => a.id === actionId ? { ...a, note } : a)\r\n } : null\r\n );\r\n }\r\n\r\n deleteSession(sessionId: string): void {\r\n this._sessions.update(s => s.filter(x => x.id !== sessionId));\r\n }\r\n\r\n loadSession(session: RecordingSession): void {\r\n this._currentSession.set(session);\r\n }\r\n\r\n // ─── Event Listeners ──────────────────────────────────────────────────────\r\n\r\n private attachListeners(): void {\r\n const opts = { capture: true, passive: true };\r\n\r\n const onClick = (e: MouseEvent) => this.zone.run(() => this.handleClick(e));\r\n const onDblClick = (e: MouseEvent) => this.zone.run(() => this.handleDblClick(e));\r\n const onInput = (e: Event) => this.zone.run(() => this.handleInput(e));\r\n const onChange = (e: Event) => this.zone.run(() => this.handleChange(e));\r\n const onSubmit = (e: SubmitEvent) => this.zone.run(() => this.handleSubmit(e));\r\n const onKeydown = (e: KeyboardEvent) => this.zone.run(() => this.handleKeydown(e));\r\n const onScroll = (e: Event) => this.zone.run(() => this.handleScroll(e));\r\n\r\n document.addEventListener('click', onClick, opts);\r\n document.addEventListener('dblclick', onDblClick, opts);\r\n document.addEventListener('input', onInput, opts);\r\n document.addEventListener('change', onChange, opts);\r\n document.addEventListener('submit', onSubmit, opts);\r\n document.addEventListener('keydown', onKeydown, opts);\r\n document.addEventListener('scroll', onScroll, { capture: true, passive: true });\r\n\r\n this.listeners = [\r\n { type: 'click', fn: onClick as EventListener },\r\n { type: 'dblclick', fn: onDblClick as EventListener },\r\n { type: 'input', fn: onInput as EventListener },\r\n { type: 'change', fn: onChange as EventListener },\r\n { type: 'submit', fn: onSubmit as EventListener },\r\n { type: 'keydown', fn: onKeydown as EventListener },\r\n { type: 'scroll', fn: onScroll as EventListener },\r\n ];\r\n }\r\n\r\n private detachListeners(): void {\r\n this.listeners.forEach(({ type, fn }) =>\r\n document.removeEventListener(type, fn, true)\r\n );\r\n this.listeners = [];\r\n this.mutationObserver?.disconnect();\r\n }\r\n\r\n // ─── Handlers ─────────────────────────────────────────────────────────────\r\n\r\n private handleClick(e: MouseEvent): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const el = e.target as HTMLElement;\r\n const info = this.getElementInfo(el);\r\n const selector = this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'click',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n description: `Click on ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleDblClick(e: MouseEvent): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const el = e.target as HTMLElement;\r\n const info = this.getElementInfo(el);\r\n const selector = this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'dblclick',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n description: `Double-click on ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleInput(e: Event): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const el = e.target as HTMLInputElement | HTMLTextAreaElement;\r\n if (['checkbox', 'radio'].includes(el.type)) return; // handled by change\r\n const info = this.getElementInfo(el);\r\n const selector = this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'input',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: el.value,\r\n description: `Type \"${el.value}\" in ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleChange(e: Event): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const el = e.target as HTMLSelectElement | HTMLInputElement;\r\n const info = this.getElementInfo(el);\r\n const selector = this.buildSelector(el);\r\n\r\n if (el.tagName === 'SELECT') {\r\n this.addAction({\r\n type: 'select',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: el.value,\r\n description: `Select \"${el.value}\" in ${this.describeElement(info)}`,\r\n });\r\n } else if ((el as HTMLInputElement).type === 'checkbox') {\r\n this.addAction({\r\n type: 'click',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: String((el as HTMLInputElement).checked),\r\n description: `${(el as HTMLInputElement).checked ? 'Check' : 'Uncheck'} ${this.describeElement(info)}`,\r\n });\r\n }\r\n }\r\n\r\n private handleSubmit(e: SubmitEvent): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const form = e.target as HTMLFormElement;\r\n const info = this.getElementInfo(form);\r\n const selector = this.buildSelector(form);\r\n\r\n this.addAction({\r\n type: 'submit',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(form),\r\n element: info,\r\n description: `Submit form ${info.id ? '#' + info.id : info.name ? info.name : ''}`.trim(),\r\n });\r\n }\r\n\r\n private lastScrollTime = 0;\r\n private handleScroll(e: Event): void {\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n const now = Date.now();\r\n if (now - this.lastScrollTime < 1000) return; // debounce 1s\r\n this.lastScrollTime = now;\r\n\r\n const el = e.target as HTMLElement;\r\n const isDoc = !el.tagName || el.tagName === 'HTML';\r\n const scrollY = isDoc ? window.scrollY : el.scrollTop;\r\n const scrollX = isDoc ? window.scrollX : el.scrollLeft;\r\n\r\n const selector = el.tagName === 'HTML' || el.tagName === 'BODY'\r\n ? 'window'\r\n : this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'scroll',\r\n selector,\r\n selectorStrategy: 'combined',\r\n value: `${scrollX},${scrollY}`,\r\n description: `Scroll to (${scrollX}, ${scrollY})`,\r\n });\r\n }\r\n\r\n private handleKeydown(e: KeyboardEvent): void {\r\n const specialKeys = ['Enter', 'Escape', 'Tab', 'F5', 'F12'];\r\n if (!specialKeys.includes(e.key)) return;\r\n if (!this.shouldRecord(e.target as Element)) return;\r\n\r\n const el = e.target as HTMLElement;\r\n const selector = this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'keypress',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n value: e.key,\r\n description: `Press \"${e.key}\" on ${el.tagName.toLowerCase()}`,\r\n });\r\n }\r\n\r\n private recordNavigation(type: ActionType, navUrl: string): void {\r\n const action: RecordedAction = {\r\n id: this.generateId(),\r\n timestamp: Date.now(),\r\n url: navUrl,\r\n type,\r\n selector: 'window',\r\n selectorStrategy: 'combined',\r\n description: `Navigate to ${navUrl}`,\r\n };\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: [...s.actions, action] } : s\r\n );\r\n }\r\n\r\n // ─── Selector Building ────────────────────────────────────────────────────\r\n\r\n private buildSelector(el: HTMLElement): string {\r\n // Priority: data-testid > data-cy > id > name > aria-label > combined\r\n const testId = el.getAttribute('data-testid');\r\n if (testId) return `[data-testid=\"${testId}\"]`;\r\n\r\n const cy = el.getAttribute('data-cy');\r\n if (cy) return `[data-cy=\"${cy}\"]`;\r\n\r\n if (el.id && !el.id.includes(':')) return `#${el.id}`;\r\n\r\n const name = el.getAttribute('name');\r\n if (name) return `${el.tagName.toLowerCase()}[name=\"${name}\"]`;\r\n\r\n const ariaLabel = el.getAttribute('aria-label');\r\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\r\n\r\n // Class-based fallback\r\n const relevantClasses = Array.from(el.classList)\r\n .filter(c => !c.startsWith('ng-') && !c.startsWith('cdk-') && c.length > 0)\r\n .slice(0, 3);\r\n if (relevantClasses.length > 0) {\r\n return `${el.tagName.toLowerCase()}.${relevantClasses.join('.')}`;\r\n }\r\n\r\n // Text content for buttons/links\r\n if (['BUTTON', 'A'].includes(el.tagName)) {\r\n const text = el.textContent?.trim().slice(0, 30);\r\n if (text) return `${el.tagName.toLowerCase()}:contains(\"${text}\")`;\r\n }\r\n\r\n return el.tagName.toLowerCase();\r\n }\r\n\r\n private getSelectorStrategy(el: HTMLElement): RecordedAction['selectorStrategy'] {\r\n if (el.getAttribute('data-testid')) return 'data-testid';\r\n if (el.getAttribute('data-cy')) return 'data-cy';\r\n if (el.id) return 'id';\r\n if (el.getAttribute('name')) return 'name';\r\n return 'class';\r\n }\r\n\r\n private getElementInfo(el: HTMLElement): ElementInfo {\r\n return {\r\n tagName: el.tagName.toLowerCase(),\r\n id: el.id || undefined,\r\n classes: Array.from(el.classList).filter(c => !c.startsWith('ng-')),\r\n dataTestId: el.getAttribute('data-testid') || undefined,\r\n dataCy: el.getAttribute('data-cy') || undefined,\r\n name: el.getAttribute('name') || undefined,\r\n type: el.getAttribute('type') || undefined,\r\n placeholder: el.getAttribute('placeholder') || undefined,\r\n text: el.textContent?.trim().slice(0, 50) || undefined,\r\n href: (el as HTMLAnchorElement).href || undefined,\r\n ariaLabel: el.getAttribute('aria-label') || undefined,\r\n };\r\n }\r\n\r\n private describeElement(info: ElementInfo): string {\r\n if (info.dataTestId) return `[data-testid=\"${info.dataTestId}\"]`;\r\n if (info.dataCy) return `[data-cy=\"${info.dataCy}\"]`;\r\n if (info.id) return `#${info.id}`;\r\n if (info.ariaLabel) return `\"${info.ariaLabel}\"`;\r\n if (info.placeholder) return `\"${info.placeholder}\" input`;\r\n if (info.text) return `\"${info.text}\"`;\r\n return info.tagName;\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────────\r\n\r\n private shouldRecord(target: Element | null): boolean {\r\n if (!this._isRecording() || this._isPaused()) return false;\r\n if (!target) return false;\r\n // Ignore the debug panel itself\r\n if (target.closest('[data-debug-panel]')) return false;\r\n return true;\r\n }\r\n\r\n private addAction(partial: Omit<RecordedAction, 'id' | 'timestamp' | 'url'>): void {\r\n const action: RecordedAction = {\r\n id: this.generateId(),\r\n timestamp: Date.now(),\r\n url: window.location.href,\r\n ...partial,\r\n };\r\n\r\n // Deduplicate consecutive identical inputs (keep only latest value)\r\n if (action.type === 'input') {\r\n this._currentSession.update(s => {\r\n if (!s) return s;\r\n const last = s.actions[s.actions.length - 1];\r\n if (last?.type === 'input' && last.selector === action.selector) {\r\n return { ...s, actions: [...s.actions.slice(0, -1), action] };\r\n }\r\n return { ...s, actions: [...s.actions, action] };\r\n });\r\n return;\r\n }\r\n\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: [...s.actions, action] } : s\r\n );\r\n }\r\n\r\n private generateId(): string {\r\n return Math.random().toString(36).slice(2, 11);\r\n }\r\n}\r\n","import { Injectable, signal } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { GeneratedTest, RecordingSession } from '../models/recorded-action.model';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class AiGeneratorService {\r\n private _webhookUrl = signal(localStorage.getItem('debugRecorder_webhookUrl') ?? '');\r\n private _isGenerating = signal(false);\r\n private _error = signal<string | null>(null);\r\n private _lastTest = signal<GeneratedTest | null>(null);\r\n\r\n webhookUrl = this._webhookUrl.asReadonly();\r\n isGenerating = this._isGenerating.asReadonly();\r\n error = this._error.asReadonly();\r\n lastTest = this._lastTest.asReadonly();\r\n\r\n constructor(private http: HttpClient) {}\r\n\r\n setWebhookUrl(url: string): void {\r\n this._webhookUrl.set(url);\r\n localStorage.setItem('debugRecorder_webhookUrl', url);\r\n }\r\n\r\n async generateCypressTest(session: RecordingSession): Promise<GeneratedTest> {\r\n const url = this._webhookUrl();\r\n if (!url) throw new Error('Keine Webhook-URL konfiguriert');\r\n\r\n this._isGenerating.set(true);\r\n this._error.set(null);\r\n\r\n try {\r\n const code = await this.postSession(url, session);\r\n const test: GeneratedTest = {\r\n code,\r\n generatedAt: Date.now(),\r\n model: url,\r\n sessionId: session.id,\r\n };\r\n this._lastTest.set(test);\r\n return test;\r\n } catch (err: any) {\r\n const msg = err?.error?.message || err?.message || 'Fehler beim Senden';\r\n this._error.set(msg);\r\n throw err;\r\n } finally {\r\n this._isGenerating.set(false);\r\n }\r\n }\r\n\r\n private postSession(url: string, session: RecordingSession): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n this.http.post(url, session, { responseType: 'text' }).subscribe({\r\n next: (res) => resolve(res),\r\n error: reject,\r\n });\r\n });\r\n }\r\n}\r\n","import { Injectable, NgZone, signal } from '@angular/core';\r\nimport type { eventWithTime } from '@rrweb/types';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class RrwebRecorderService {\r\n // Plain array — cheap push, no O(n) spread on every event\r\n private _eventsArray: eventWithTime[] = [];\r\n // Signal only for reactive count display in templates\r\n private _eventCount = signal(0);\r\n private _isRecording = signal(false);\r\n private stopFn?: () => void;\r\n private replayer?: any;\r\n\r\n eventCount = this._eventCount.asReadonly();\r\n isRecording = this._isRecording.asReadonly();\r\n\r\n constructor(private zone: NgZone) {}\r\n\r\n hasEvents(): boolean {\r\n return this._eventsArray.length > 0;\r\n }\r\n\r\n getEvents(): eventWithTime[] {\r\n return this._eventsArray;\r\n }\r\n\r\n async startRecording(): Promise<void> {\r\n const { record } = await import('rrweb');\r\n this._eventsArray = [];\r\n this._eventCount.set(0);\r\n this._isRecording.set(true);\r\n\r\n this.stopFn = record({\r\n emit: (event: eventWithTime) => {\r\n // Push outside Angular zone — no change detection per event\r\n this.zone.runOutsideAngular(() => {\r\n this._eventsArray.push(event);\r\n });\r\n // Update count signal only every 10 events to keep UI responsive\r\n const len = this._eventsArray.length;\r\n if (len === 1 || len % 10 === 0) {\r\n this.zone.run(() => this._eventCount.set(len));\r\n }\r\n },\r\n // Note: blockSelector omitted — rrweb 2.0.0-alpha.4 calls node.matches()\r\n // on TextNodes/CommentNodes which crash the recorder.\r\n maskTextSelector: 'input[type=\"password\"]',\r\n checkoutEveryNth: 200,\r\n });\r\n }\r\n\r\n stopRecording(): eventWithTime[] {\r\n if (this.stopFn) {\r\n this.stopFn();\r\n this.stopFn = undefined;\r\n }\r\n this._isRecording.set(false);\r\n this._eventCount.set(this._eventsArray.length);\r\n return this._eventsArray;\r\n }\r\n\r\n clearEvents(): void {\r\n this._eventsArray = [];\r\n this._eventCount.set(0);\r\n }\r\n\r\n // ─── Replay ──────────────────────────────────────────────────────────────\r\n\r\n async startReplay(container: HTMLElement, events?: eventWithTime[]): Promise<void> {\r\n const { Replayer } = await import('rrweb');\r\n const eventsToReplay = events ?? this._eventsArray;\r\n\r\n if (eventsToReplay.length === 0) return;\r\n\r\n this.destroyReplayer();\r\n\r\n this.replayer = new Replayer(eventsToReplay, {\r\n root: container,\r\n skipInactive: true,\r\n showWarning: false,\r\n showDebug: false,\r\n blockClass: 'debug-panel',\r\n });\r\n\r\n this.replayer.play();\r\n }\r\n\r\n pauseReplay(): void {\r\n this.replayer?.pause();\r\n }\r\n\r\n resumeReplay(): void {\r\n this.replayer?.play();\r\n }\r\n\r\n destroyReplayer(): void {\r\n if (this.replayer) {\r\n try { this.replayer.pause(); } catch {}\r\n this.replayer = undefined;\r\n }\r\n }\r\n\r\n // ─── Export ───────────────────────────────────────────────────────────────\r\n\r\n exportEvents(): string {\r\n return JSON.stringify(this._eventsArray, null, 2);\r\n }\r\n\r\n downloadEvents(filename = 'rrweb-session.json'): void {\r\n const blob = new Blob([this.exportEvents()], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = filename;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n importEvents(json: string): eventWithTime[] {\r\n try {\r\n const events = JSON.parse(json) as eventWithTime[];\r\n this._eventsArray = events;\r\n this._eventCount.set(events.length);\r\n return events;\r\n } catch {\r\n console.error('Invalid rrweb events JSON');\r\n return [];\r\n }\r\n }\r\n}\r\n","import { Component, Input, Output, EventEmitter, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { RecordedAction, RecordingSession } from '../models/recorded-action.model';\r\n\r\n@Component({\r\n selector: 'app-action-list',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <div class=\"action-list\" data-debug-panel>\r\n @if (!session || session.actions.length === 0) {\r\n <div class=\"empty-state\">\r\n <div class=\"empty-icon\">🎬</div>\r\n <p>Noch keine Aktionen aufgezeichnet.</p>\r\n <p class=\"hint\">Starte die Aufnahme und interagiere mit der App.</p>\r\n <div class=\"shortcuts-hint\">\r\n <kbd>Ctrl+Shift+D</kbd> Panel &nbsp;\r\n <kbd>Ctrl+Shift+R</kbd> Record\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"list-header\">\r\n <span class=\"list-count\">{{ session.actions.length }} Aktionen</span>\r\n <span class=\"list-duration\">\r\n @if (session.endTime) {\r\n {{ formatDuration(session.startTime, session.endTime) }}\r\n } @else {\r\n Live\r\n }\r\n </span>\r\n </div>\r\n\r\n @for (action of session.actions; track action.id; let i = $index) {\r\n <div class=\"action-item\" [class.expanded]=\"expandedId() === action.id\">\r\n <div class=\"action-row\" (click)=\"toggleExpand(action.id)\">\r\n <span class=\"action-index\">{{ i + 1 }}</span>\r\n <span class=\"action-type-badge\" [class]=\"'type-' + action.type\">\r\n {{ getActionIcon(action.type) }}\r\n </span>\r\n <div class=\"action-info\">\r\n <span class=\"action-desc\">{{ action.description }}</span>\r\n <span class=\"action-selector\">{{ action.selector }}</span>\r\n </div>\r\n <span class=\"action-time\">{{ formatTime(action.timestamp) }}</span>\r\n <button\r\n class=\"remove-btn\"\r\n data-debug-panel\r\n title=\"Aktion entfernen\"\r\n (click)=\"onRemove(action.id, $event)\"\r\n >✕</button>\r\n </div>\r\n\r\n @if (expandedId() === action.id) {\r\n <div class=\"action-detail\" data-debug-panel>\r\n <div class=\"detail-grid\">\r\n <span class=\"detail-label\">Selector</span>\r\n <code class=\"detail-value\">{{ action.selector }}</code>\r\n @if (action.value) {\r\n <span class=\"detail-label\">Wert</span>\r\n <code class=\"detail-value\">{{ action.value }}</code>\r\n }\r\n @if (action.element?.tagName) {\r\n <span class=\"detail-label\">Element</span>\r\n <code class=\"detail-value\">&lt;{{ action.element?.tagName }}&gt;</code>\r\n }\r\n <span class=\"detail-label\">Strategie</span>\r\n <span class=\"detail-value strategy-badge\" [class]=\"'strat-' + action.selectorStrategy\">\r\n {{ action.selectorStrategy }}\r\n </span>\r\n <span class=\"detail-label\">URL</span>\r\n <code class=\"detail-value url-val\">{{ action.url }}</code>\r\n </div>\r\n <div class=\"note-area\">\r\n <textarea\r\n data-debug-panel\r\n class=\"note-input\"\r\n [(ngModel)]=\"noteMap[action.id]\"\r\n placeholder=\"Notiz zu dieser Aktion...\"\r\n rows=\"2\"\r\n (blur)=\"onAddNote(action.id)\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n .action-list { padding: 0; }\r\n\r\n .empty-state {\r\n text-align: center;\r\n padding: 32px 20px;\r\n color: #64748b;\r\n }\r\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\r\n .empty-state p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n .shortcuts-hint {\r\n margin-top: 12px;\r\n font-size: 11px;\r\n color: #475569;\r\n }\r\n kbd {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #94a3b8;\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n font-size: 10px;\r\n }\r\n\r\n .list-header {\r\n display: flex;\r\n justify-content: space-between;\r\n padding: 8px 14px;\r\n font-size: 11px;\r\n color: #64748b;\r\n background: #0f172a;\r\n border-bottom: 1px solid #1e293b;\r\n position: sticky;\r\n top: 0;\r\n }\r\n\r\n .action-item {\r\n border-bottom: 1px solid #1e293b;\r\n transition: background 0.1s;\r\n }\r\n .action-item:hover { background: rgba(30,41,59,0.5); }\r\n .action-item.expanded { background: #1e293b; }\r\n\r\n .action-row {\r\n display: flex;\r\n align-items: center;\r\n padding: 8px 10px;\r\n gap: 8px;\r\n cursor: pointer;\r\n }\r\n .action-index {\r\n color: #475569;\r\n font-size: 10px;\r\n min-width: 18px;\r\n text-align: right;\r\n }\r\n .action-type-badge {\r\n font-size: 14px;\r\n min-width: 20px;\r\n text-align: center;\r\n }\r\n .action-info {\r\n flex: 1;\r\n min-width: 0;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 1px;\r\n }\r\n .action-desc {\r\n font-size: 12px;\r\n color: #cbd5e1;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n .action-selector {\r\n font-size: 10px;\r\n color: #64748b;\r\n font-family: 'Cascadia Code', 'Consolas', monospace;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n .action-time {\r\n font-size: 10px;\r\n color: #475569;\r\n white-space: nowrap;\r\n }\r\n .remove-btn {\r\n background: none;\r\n border: none;\r\n color: #475569;\r\n cursor: pointer;\r\n font-size: 12px;\r\n padding: 2px 5px;\r\n border-radius: 3px;\r\n opacity: 0;\r\n transition: opacity 0.15s, color 0.15s;\r\n }\r\n .action-row:hover .remove-btn { opacity: 1; }\r\n .remove-btn:hover { color: #f87171; }\r\n\r\n .action-detail {\r\n padding: 10px 14px;\r\n background: rgba(15,23,42,0.7);\r\n border-top: 1px solid #1e293b;\r\n }\r\n .detail-grid {\r\n display: grid;\r\n grid-template-columns: auto 1fr;\r\n gap: 4px 10px;\r\n margin-bottom: 8px;\r\n align-items: start;\r\n }\r\n .detail-label { font-size: 10px; color: #64748b; padding-top: 2px; white-space: nowrap; }\r\n .detail-value {\r\n font-size: 11px;\r\n color: #93c5fd;\r\n font-family: 'Cascadia Code', 'Consolas', monospace;\r\n word-break: break-all;\r\n }\r\n .url-val { color: #6ee7b7; }\r\n .strategy-badge {\r\n font-size: 10px;\r\n padding: 1px 6px;\r\n border-radius: 3px;\r\n font-family: monospace;\r\n }\r\n .strat-data-testid { background: #064e3b; color: #34d399; }\r\n .strat-data-cy { background: #064e3b; color: #34d399; }\r\n .strat-id { background: #1e3a8a; color: #93c5fd; }\r\n .strat-name { background: #44337a; color: #c4b5fd; }\r\n .strat-class { background: #374151; color: #9ca3af; }\r\n .strat-combined { background: #292524; color: #d6d3d1; }\r\n\r\n .note-area { margin-top: 6px; }\r\n .note-input {\r\n width: 100%;\r\n box-sizing: border-box;\r\n background: #0f172a;\r\n border: 1px solid #334155;\r\n color: #e2e8f0;\r\n border-radius: 5px;\r\n padding: 6px 8px;\r\n font-size: 11px;\r\n resize: vertical;\r\n }\r\n .note-input:focus { outline: none; border-color: #3b82f6; }\r\n `],\r\n})\r\nexport class ActionListComponent {\r\n @Input() session: RecordingSession | null = null;\r\n @Output() removeAction = new EventEmitter<string>();\r\n @Output() addNote = new EventEmitter<{ id: string; note: string }>();\r\n\r\n expandedId = signal<string | null>(null);\r\n noteMap: Record<string, string> = {};\r\n\r\n toggleExpand(id: string): void {\r\n this.expandedId.update(v => v === id ? null : id);\r\n }\r\n\r\n onRemove(id: string, e: Event): void {\r\n e.stopPropagation();\r\n this.removeAction.emit(id);\r\n }\r\n\r\n onAddNote(id: string): void {\r\n this.addNote.emit({ id, note: this.noteMap[id] ?? '' });\r\n }\r\n\r\n getActionIcon(type: string): string {\r\n const icons: Record<string, string> = {\r\n click: '👆',\r\n dblclick: '👆👆',\r\n input: '⌨️',\r\n select: '📋',\r\n submit: '📤',\r\n navigation: '🔗',\r\n keypress: '⌨️',\r\n scroll: '↕️',\r\n hover: '🖱️',\r\n assertion: '✅',\r\n screenshot: '📸',\r\n };\r\n return icons[type] ?? '•';\r\n }\r\n\r\n formatTime(ts: number): string {\r\n return new Date(ts).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\r\n }\r\n\r\n formatDuration(start: number, end: number): string {\r\n const s = Math.round((end - start) / 1000);\r\n return s < 60 ? `${s}s` : `${Math.floor(s/60)}m ${s%60}s`;\r\n }\r\n}\r\n","import { Component, Input, signal, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { GeneratedTest } from '../models/recorded-action.model';\r\n\r\n@Component({\r\n selector: 'app-test-preview',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"test-preview\" data-debug-panel>\r\n @if (!test) {\r\n <div class=\"empty-state\">\r\n <div class=\"empty-icon\">🤖</div>\r\n <p>Noch kein Test generiert.</p>\r\n <p class=\"hint\">Zeichne Aktionen auf und klicke „🤖 → Cypress Test\".</p>\r\n </div>\r\n } @else {\r\n <div class=\"test-toolbar\" data-debug-panel>\r\n <div class=\"test-meta\">\r\n <span class=\"model-tag\">{{ test.model }}</span>\r\n <span class=\"gen-time\">{{ formatDate(test.generatedAt) }}</span>\r\n </div>\r\n <div class=\"test-actions\">\r\n <button class=\"action-btn\" title=\"Kopieren\" (click)=\"copyCode()\">\r\n {{ copied() ? '✅ Kopiert!' : '📋 Kopieren' }}\r\n </button>\r\n <button class=\"action-btn\" title=\"Herunterladen\" (click)=\"downloadCode()\">\r\n 💾 Download\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"code-container\">\r\n <pre class=\"code-block\"><code [innerHTML]=\"highlightedCode()\"></code></pre>\r\n </div>\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n .test-preview { height: 100%; display: flex; flex-direction: column; }\r\n\r\n .empty-state {\r\n text-align: center;\r\n padding: 32px 20px;\r\n color: #64748b;\r\n }\r\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\r\n .empty-state p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n\r\n .test-toolbar {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 8px 12px;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n flex-shrink: 0;\r\n gap: 8px;\r\n }\r\n .test-meta { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\r\n .model-tag {\r\n background: #312e81;\r\n color: #a5b4fc;\r\n font-size: 10px;\r\n padding: 2px 7px;\r\n border-radius: 4px;\r\n font-weight: 600;\r\n white-space: nowrap;\r\n }\r\n .gen-time { font-size: 10px; color: #64748b; white-space: nowrap; }\r\n .test-actions { display: flex; gap: 6px; flex-shrink: 0; }\r\n .action-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 4px 10px;\r\n border-radius: 5px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n white-space: nowrap;\r\n transition: background 0.15s;\r\n }\r\n .action-btn:hover { background: #475569; }\r\n\r\n .code-container {\r\n flex: 1;\r\n overflow: auto;\r\n }\r\n .code-container::-webkit-scrollbar { width: 5px; height: 5px; }\r\n .code-container::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\r\n\r\n .code-block {\r\n margin: 0;\r\n padding: 14px;\r\n font-family: 'Cascadia Code', 'Consolas', 'Fira Code', monospace;\r\n font-size: 11px;\r\n line-height: 1.7;\r\n color: #e2e8f0;\r\n white-space: pre;\r\n tab-size: 2;\r\n }\r\n\r\n /* Syntax Highlighting */\r\n :global(.kw) { color: #c084fc; }\r\n :global(.str) { color: #86efac; }\r\n :global(.fn) { color: #67e8f9; }\r\n :global(.cm) { color: #64748b; font-style: italic; }\r\n :global(.num) { color: #fb923c; }\r\n :global(.cy) { color: #fbbf24; font-weight: 600; }\r\n `],\r\n})\r\nexport class TestPreviewComponent {\r\n @Input() test: GeneratedTest | null = null;\r\n\r\n copied = signal(false);\r\n\r\n highlightedCode = computed(() => {\r\n if (!this.test) return '';\r\n return this.syntaxHighlight(this.test.code);\r\n });\r\n\r\n private syntaxHighlight(code: string): string {\r\n return code\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n // Comments\r\n .replace(/(\\/\\/[^\\n]*)/g, '<span class=\"cm\">$1</span>')\r\n // cy. commands\r\n .replace(/\\b(cy)\\b/g, '<span class=\"cy\">$1</span>')\r\n // Keywords\r\n .replace(/\\b(describe|it|beforeEach|afterEach|before|after|context|specify|const|let|var|function|return|import|export|from|async|await|new)\\b/g, '<span class=\"kw\">$1</span>')\r\n // Strings\r\n .replace(/('[^']*'|\"[^\"]*\"|`[^`]*`)/g, '<span class=\"str\">$1</span>')\r\n // Numbers\r\n .replace(/\\b(\\d+)\\b/g, '<span class=\"num\">$1</span>');\r\n }\r\n\r\n async copyCode(): Promise<void> {\r\n if (!this.test) return;\r\n await navigator.clipboard.writeText(this.test.code);\r\n this.copied.set(true);\r\n setTimeout(() => this.copied.set(false), 2000);\r\n }\r\n\r\n downloadCode(): void {\r\n if (!this.test) return;\r\n const blob = new Blob([this.test.code], { type: 'text/typescript' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = `cypress-test-${new Date().toISOString().slice(0, 10)}.cy.ts`;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n formatDate(ts: number): string {\r\n return new Date(ts).toLocaleString('de-DE', {\r\n day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit',\r\n });\r\n }\r\n}\r\n","import { Component, Output, EventEmitter, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { AiGeneratorService } from '../services/ai-generator.service';\r\n\r\n@Component({\r\n selector: 'app-settings-dialog',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <div class=\"overlay\" data-debug-panel (click)=\"onOverlayClick($event)\">\r\n <div class=\"dialog\" data-debug-panel>\r\n <div class=\"dialog-header\">\r\n <h2>⚙️ Einstellungen</h2>\r\n <button class=\"close-btn\" (click)=\"close.emit()\">✕</button>\r\n </div>\r\n\r\n <div class=\"dialog-body\">\r\n <div class=\"field-group\">\r\n <label>KI Webhook-URL</label>\r\n <input\r\n data-debug-panel\r\n class=\"field-input\"\r\n type=\"url\"\r\n [(ngModel)]=\"localUrl\"\r\n placeholder=\"https://deine-ki-api.de/generate\"\r\n />\r\n <p class=\"field-hint\">\r\n Die aufgezeichnete Session wird als JSON per POST an diese URL gesendet.\r\n Die Antwort wird als Cypress-Test angezeigt.\r\n </p>\r\n </div>\r\n\r\n <div class=\"info-box\">\r\n <p>📦 POST-Body: Die Session als JSON (<code>actions</code>, <code>startUrl</code>, ...)</p>\r\n <p>📄 Erwartete Antwort: Cypress-Test-Code als Plain-Text</p>\r\n <p>⌨️ Shortcuts: <kbd>Ctrl+Shift+D</kbd> Panel &nbsp; <kbd>Ctrl+Shift+R</kbd> Aufnahme</p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"dialog-footer\">\r\n <button class=\"btn-cancel\" (click)=\"close.emit()\">Abbrechen</button>\r\n <button class=\"btn-save\" (click)=\"save()\">💾 Speichern</button>\r\n </div>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n .overlay {\r\n position: fixed; inset: 0; background: rgba(0,0,0,0.7);\r\n z-index: 100000; display: flex; align-items: center; justify-content: center;\r\n backdrop-filter: blur(4px);\r\n }\r\n .dialog {\r\n background: #0f172a; border: 1px solid #1e3a5f; border-radius: 12px;\r\n width: 440px; max-width: 95vw; display: flex; flex-direction: column;\r\n box-shadow: 0 25px 60px rgba(0,0,0,0.6); overflow: hidden;\r\n }\r\n .dialog-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 18px; background: #1e293b; border-bottom: 1px solid #334155;\r\n }\r\n .dialog-header h2 { margin: 0; font-size: 15px; color: #f1f5f9; font-weight: 600; }\r\n .close-btn {\r\n background: none; border: none; color: #94a3b8;\r\n cursor: pointer; font-size: 16px; padding: 4px; border-radius: 4px;\r\n }\r\n .close-btn:hover { color: #f1f5f9; background: #334155; }\r\n .dialog-body { padding: 18px; display: flex; flex-direction: column; gap: 16px; }\r\n .field-group { display: flex; flex-direction: column; gap: 6px; }\r\n label {\r\n font-size: 12px; font-weight: 600; color: #94a3b8;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .field-input {\r\n background: #1e293b; border: 1px solid #334155; color: #e2e8f0;\r\n border-radius: 6px; padding: 10px 12px; font-size: 13px;\r\n width: 100%; box-sizing: border-box;\r\n }\r\n .field-input:focus { outline: none; border-color: #3b82f6; }\r\n .field-hint { font-size: 11px; color: #64748b; margin: 0; line-height: 1.5; }\r\n .info-box {\r\n background: rgba(30,41,59,0.5); border: 1px solid #1e3a5f;\r\n border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 6px;\r\n }\r\n .info-box p { margin: 0; font-size: 11px; color: #64748b; }\r\n .info-box code {\r\n background: #1e293b; color: #34d399; padding: 1px 4px;\r\n border-radius: 3px; font-family: monospace;\r\n }\r\n kbd {\r\n background: #1e293b; border: 1px solid #334155; color: #94a3b8;\r\n padding: 1px 5px; border-radius: 3px; font-size: 10px;\r\n }\r\n .dialog-footer {\r\n display: flex; gap: 8px; justify-content: flex-end;\r\n padding: 14px 18px; background: #1e293b; border-top: 1px solid #334155;\r\n }\r\n .btn-cancel, .btn-save {\r\n padding: 8px 20px; border-radius: 6px; font-size: 13px;\r\n font-weight: 600; cursor: pointer; border: none; transition: filter 0.15s;\r\n }\r\n .btn-cancel { background: #334155; color: #94a3b8; }\r\n .btn-cancel:hover { filter: brightness(1.2); }\r\n .btn-save { background: #2563eb; color: #fff; }\r\n .btn-save:hover { filter: brightness(1.1); }\r\n `],\r\n})\r\nexport class SettingsDialogComponent {\r\n @Output() close = new EventEmitter<void>();\r\n private ai = inject(AiGeneratorService);\r\n localUrl = this.ai.webhookUrl();\r\n\r\n save(): void {\r\n this.ai.setWebhookUrl(this.localUrl.trim());\r\n this.close.emit();\r\n }\r\n\r\n onOverlayClick(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).classList.contains('overlay')) {\r\n this.close.emit();\r\n }\r\n }\r\n}\r\n","import {\r\n Component, ElementRef, ViewChild, OnDestroy, inject, signal,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\r\n\r\n@Component({\r\n selector: 'app-session-replay',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"replay-panel\" data-debug-panel>\r\n @if (!rrweb.hasEvents()) {\r\n <div class=\"replay-empty\">\r\n <div class=\"replay-icon\">📽️</div>\r\n <p>Kein Replay verfügbar.</p>\r\n <p class=\"hint\">Starte eine Aufnahme — rrweb zeichnet den DOM parallel mit.</p>\r\n </div>\r\n } @else {\r\n <div class=\"replay-info\">\r\n <span class=\"event-count\">{{ rrweb.eventCount() }} Events aufgezeichnet</span>\r\n </div>\r\n <div class=\"replay-actions\">\r\n <button class=\"replay-btn primary\" (click)=\"openOverlay()\">\r\n ▶ Replay abspielen\r\n </button>\r\n <button class=\"replay-btn\" (click)=\"exportSession()\">\r\n 💾 JSON exportieren\r\n </button>\r\n </div>\r\n <p class=\"replay-hint\">\r\n Der Replay öffnet sich als Vollbild-Overlay über der aktuellen Seite.\r\n </p>\r\n }\r\n </div>\r\n\r\n <!-- Fullscreen Replay Overlay -->\r\n @if (overlayOpen()) {\r\n <div class=\"replay-overlay\" data-debug-panel>\r\n <div class=\"overlay-header\" data-debug-panel>\r\n <span class=\"overlay-title\">📽️ Session Replay</span>\r\n <div class=\"overlay-controls\" data-debug-panel>\r\n <button class=\"ovl-btn\" (click)=\"pauseResume()\">\r\n {{ isPlaying() ? '⏸ Pause' : '▶ Play' }}\r\n </button>\r\n <button class=\"ovl-btn\" (click)=\"restart()\">⟳ Neustart</button>\r\n <button class=\"ovl-btn close-ovl\" (click)=\"closeOverlay()\">✕ Schließen</button>\r\n </div>\r\n </div>\r\n <div #replayContainer class=\"overlay-stage\" data-debug-panel></div>\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .replay-panel {\r\n padding: 20px 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n }\r\n\r\n .replay-empty {\r\n text-align: center;\r\n padding: 20px 0;\r\n color: #64748b;\r\n }\r\n .replay-icon { font-size: 36px; margin-bottom: 8px; }\r\n .replay-empty p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n\r\n .replay-info {\r\n background: #1e293b;\r\n border-radius: 6px;\r\n padding: 8px 12px;\r\n }\r\n .event-count { font-size: 12px; color: #6ee7b7; font-weight: 600; }\r\n\r\n .replay-actions { display: flex; gap: 8px; }\r\n .replay-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 8px 14px;\r\n border-radius: 6px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .replay-btn:hover { background: #475569; }\r\n .replay-btn.primary { background: #1d4ed8; color: #fff; }\r\n .replay-btn.primary:hover { background: #2563eb; }\r\n\r\n .replay-hint { font-size: 11px; color: #475569; margin: 0; }\r\n\r\n /* ── Fullscreen Overlay ── */\r\n .replay-overlay {\r\n position: fixed;\r\n inset: 0;\r\n z-index: 99997;\r\n background: #000;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n .overlay-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 16px;\r\n background: #0f172a;\r\n border-bottom: 1px solid #1e293b;\r\n flex-shrink: 0;\r\n }\r\n .overlay-title { font-size: 14px; font-weight: 600; color: #f1f5f9; }\r\n .overlay-controls { display: flex; gap: 8px; }\r\n .ovl-btn {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #cbd5e1;\r\n padding: 5px 12px;\r\n border-radius: 5px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .ovl-btn:hover { background: #334155; }\r\n .close-ovl { color: #fca5a5; }\r\n .close-ovl:hover { background: rgba(220,38,38,0.2); }\r\n\r\n .overlay-stage {\r\n flex: 1;\r\n overflow: hidden;\r\n position: relative;\r\n background: #f8fafc;\r\n }\r\n\r\n /* Scale the rrweb iframe to fill available space */\r\n :host ::ng-deep .replayer-wrapper {\r\n position: absolute !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n transform-origin: top left !important;\r\n }\r\n :host ::ng-deep .replayer-wrapper iframe {\r\n pointer-events: none;\r\n }\r\n `],\r\n})\r\nexport class SessionReplayComponent implements OnDestroy {\r\n @ViewChild('replayContainer') replayContainer?: ElementRef<HTMLDivElement>;\r\n\r\n rrweb = inject(RrwebRecorderService);\r\n overlayOpen = signal(false);\r\n isPlaying = signal(false);\r\n\r\n async openOverlay(): Promise<void> {\r\n this.overlayOpen.set(true);\r\n this.isPlaying.set(false);\r\n // Wait for the DOM to render the overlay\r\n await new Promise(r => setTimeout(r, 50));\r\n await this.startPlay();\r\n }\r\n\r\n closeOverlay(): void {\r\n this.rrweb.destroyReplayer();\r\n this.overlayOpen.set(false);\r\n this.isPlaying.set(false);\r\n }\r\n\r\n async pauseResume(): Promise<void> {\r\n if (this.isPlaying()) {\r\n this.rrweb.pauseReplay();\r\n this.isPlaying.set(false);\r\n } else {\r\n this.rrweb.resumeReplay();\r\n this.isPlaying.set(true);\r\n }\r\n }\r\n\r\n async restart(): Promise<void> {\r\n this.rrweb.destroyReplayer();\r\n await new Promise(r => setTimeout(r, 50));\r\n await this.startPlay();\r\n }\r\n\r\n exportSession(): void {\r\n this.rrweb.downloadEvents();\r\n }\r\n\r\n private async startPlay(): Promise<void> {\r\n if (!this.replayContainer) return;\r\n const container = this.replayContainer.nativeElement;\r\n\r\n await this.rrweb.startReplay(container);\r\n\r\n // Scale iframe to fill the stage container\r\n this.scaleReplayer(container);\r\n this.isPlaying.set(true);\r\n }\r\n\r\n private scaleReplayer(container: HTMLElement): void {\r\n // rrweb injects .replayer-wrapper with an iframe sized to the recorded viewport\r\n setTimeout(() => {\r\n const wrapper = container.querySelector('.replayer-wrapper') as HTMLElement;\r\n if (!wrapper) return;\r\n\r\n const iframe = wrapper.querySelector('iframe') as HTMLIFrameElement;\r\n const wrapW = iframe?.offsetWidth || wrapper.offsetWidth || 1280;\r\n const wrapH = iframe?.offsetHeight || wrapper.offsetHeight || 720;\r\n const stageW = container.offsetWidth;\r\n const stageH = container.offsetHeight;\r\n\r\n if (!stageW || !stageH || !wrapW || !wrapH) return;\r\n\r\n const scale = Math.min(stageW / wrapW, stageH / wrapH);\r\n const offsetX = (stageW - wrapW * scale) / 2;\r\n const offsetY = (stageH - wrapH * scale) / 2;\r\n\r\n wrapper.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n }, 300);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.rrweb.destroyReplayer();\r\n }\r\n}\r\n","import {\r\n Component, signal, computed, inject, OnInit, OnDestroy,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { RecorderService } from '../services/recorder.service';\r\nimport { AiGeneratorService } from '../services/ai-generator.service';\r\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\r\nimport { RecordingSession } from '../models/recorded-action.model';\r\nimport { ActionListComponent } from '../action-list/action-list.component';\r\nimport { TestPreviewComponent } from '../test-preview/test-preview.component';\r\nimport { SettingsDialogComponent } from '../settings-dialog/settings-dialog.component';\r\nimport { SessionReplayComponent } from '../session-replay/session-replay.component';\r\n\r\ntype PanelTab = 'actions' | 'test' | 'sessions' | 'replay';\r\ntype PanelPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n\r\n@Component({\r\n selector: 'app-debug-panel',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, ActionListComponent, TestPreviewComponent, SettingsDialogComponent, SessionReplayComponent],\r\n template: `\r\n <!-- Toggle FAB -->\r\n <button\r\n data-debug-panel\r\n class=\"debug-fab\"\r\n [class.recording]=\"recorder.isRecording()\"\r\n [class.pulse]=\"recorder.isRecording() && !recorder.isPaused()\"\r\n (click)=\"togglePanel()\"\r\n [title]=\"panelOpen() ? 'Debug Panel schließen' : 'Debug Panel öffnen'\"\r\n >\r\n <span class=\"fab-icon\">{{ recorder.isRecording() ? '⏺' : '🐛' }}</span>\r\n @if (recorder.isRecording() && recorder.actionCount() > 0) {\r\n <span class=\"fab-badge\">{{ recorder.actionCount() }}</span>\r\n }\r\n </button>\r\n\r\n <!-- Main Panel -->\r\n @if (panelOpen()) {\r\n <div\r\n data-debug-panel\r\n class=\"debug-panel\"\r\n [class]=\"'pos-' + position()\"\r\n [style.width.px]=\"panelWidth()\"\r\n >\r\n <!-- Header -->\r\n <div class=\"panel-header\" (mousedown)=\"startDrag($event)\">\r\n <div class=\"header-left\">\r\n <span class=\"panel-icon\">🐛</span>\r\n <span class=\"panel-title\">Debug Recorder</span>\r\n @if (recorder.isRecording()) {\r\n <span class=\"rec-indicator\" [class.paused]=\"recorder.isPaused()\">\r\n {{ recorder.isPaused() ? '⏸ PAUSED' : '⏺ REC' }}\r\n </span>\r\n }\r\n </div>\r\n <div class=\"header-actions\">\r\n <button class=\"icon-btn\" title=\"Einstellungen\" (click)=\"showSettings.set(true)\">⚙️</button>\r\n <button class=\"icon-btn\" title=\"Position wechseln\" (click)=\"cyclePosition()\">📌</button>\r\n <button class=\"icon-btn\" title=\"Schließen\" (click)=\"togglePanel()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Session Name Input (only when not recording) -->\r\n @if (!recorder.isRecording()) {\r\n <div class=\"session-setup\">\r\n <input\r\n data-debug-panel\r\n class=\"session-input\"\r\n type=\"text\"\r\n [(ngModel)]=\"sessionName\"\r\n placeholder=\"Session-Name (optional)\"\r\n />\r\n <textarea\r\n data-debug-panel\r\n class=\"session-desc\"\r\n [(ngModel)]=\"sessionDesc\"\r\n placeholder=\"Fehlerbeschreibung...\"\r\n rows=\"2\"\r\n ></textarea>\r\n </div>\r\n }\r\n\r\n <!-- Recording Controls -->\r\n <div class=\"recording-controls\" data-debug-panel>\r\n @if (!recorder.isRecording()) {\r\n <button class=\"ctrl-btn start\" (click)=\"startRecording()\">\r\n ▶ Aufnahme starten\r\n </button>\r\n } @else {\r\n <button class=\"ctrl-btn pause\" (click)=\"recorder.pauseRecording()\">\r\n {{ recorder.isPaused() ? '▶ Fortsetzen' : '⏸ Pause' }}\r\n </button>\r\n <button class=\"ctrl-btn stop\" (click)=\"stopRecording()\">\r\n ⏹ Stoppen\r\n </button>\r\n <button class=\"ctrl-btn clear\" title=\"Aktionen löschen\" (click)=\"recorder.clearCurrentSession()\">\r\n 🗑\r\n </button>\r\n }\r\n\r\n @if (hasActions()) {\r\n <button\r\n class=\"ctrl-btn generate\"\r\n [disabled]=\"aiService.isGenerating() || !aiService.webhookUrl()\"\r\n [title]=\"!aiService.webhookUrl() ? 'Webhook-URL in Einstellungen eintragen' : 'Cypress Test generieren'\"\r\n (click)=\"generateTest()\"\r\n >\r\n @if (aiService.isGenerating()) {\r\n <span class=\"spinner\">⟳</span> Generiere...\r\n } @else {\r\n 🤖 → Cypress Test\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Error Banner -->\r\n @if (aiService.error()) {\r\n <div class=\"error-banner\" data-debug-panel>\r\n ⚠️ {{ aiService.error() }}\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <div class=\"tab-bar\" data-debug-panel>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Aktionen\r\n @if (recorder.actionCount() > 0) {\r\n <span class=\"tab-badge\">{{ recorder.actionCount() }}</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'replay'\"\r\n (click)=\"activeTab.set('replay')\"\r\n title=\"rrweb Session Replay\"\r\n >\r\n 📽️ Replay\r\n @if (rrweb.eventCount() > 0) {\r\n <span class=\"tab-badge\">{{ rrweb.eventCount() }}</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'test'\"\r\n [disabled]=\"!aiService.lastTest()\"\r\n (click)=\"activeTab.set('test')\"\r\n >\r\n 🤖 Test\r\n @if (aiService.lastTest()) {\r\n <span class=\"tab-badge new\">NEU</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'sessions'\"\r\n [disabled]=\"recorder.sessions().length === 0\"\r\n (click)=\"activeTab.set('sessions')\"\r\n >\r\n Sessions ({{ recorder.sessions().length }})\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Content -->\r\n <div class=\"tab-content\">\r\n @if (activeTab() === 'actions') {\r\n <app-action-list\r\n [session]=\"recorder.currentSession()\"\r\n (removeAction)=\"recorder.removeAction($event)\"\r\n (addNote)=\"recorder.addNote($event.id, $event.note)\"\r\n />\r\n }\r\n\r\n @if (activeTab() === 'replay') {\r\n <app-session-replay />\r\n }\r\n\r\n @if (activeTab() === 'test') {\r\n <app-test-preview [test]=\"aiService.lastTest()\" />\r\n }\r\n\r\n @if (activeTab() === 'sessions') {\r\n <div class=\"sessions-list\">\r\n @for (session of recorder.sessions(); track session.id) {\r\n <div class=\"session-card\">\r\n <div class=\"session-card-header\">\r\n <span class=\"session-name\">{{ session.name }}</span>\r\n <span class=\"session-meta\">{{ session.actions.length }} Aktionen</span>\r\n </div>\r\n <div class=\"session-card-actions\">\r\n <button class=\"sm-btn\" (click)=\"loadAndGenerate(session)\">🤖 Neu generieren</button>\r\n <button class=\"sm-btn danger\" (click)=\"recorder.deleteSession(session.id)\">🗑</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Resize Handle -->\r\n <div class=\"resize-handle\" (mousedown)=\"startResize($event)\">⠿</div>\r\n </div>\r\n }\r\n\r\n <!-- Settings Dialog -->\r\n @if (showSettings()) {\r\n <app-settings-dialog (close)=\"showSettings.set(false)\" />\r\n }\r\n `,\r\n styles: [`\r\n .debug-fab {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: 99999;\r\n width: 52px;\r\n height: 52px;\r\n border-radius: 50%;\r\n border: none;\r\n background: #1e293b;\r\n color: white;\r\n font-size: 22px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\r\n transition: transform 0.2s, background 0.2s;\r\n position: fixed;\r\n }\r\n .debug-fab:hover { transform: scale(1.1); background: #334155; }\r\n .debug-fab.recording { background: #dc2626; }\r\n .debug-fab.pulse { animation: fabPulse 1.5s ease-in-out infinite; }\r\n @keyframes fabPulse {\r\n 0%, 100% { box-shadow: 0 4px 20px rgba(220,38,38,0.4); }\r\n 50% { box-shadow: 0 4px 30px rgba(220,38,38,0.9), 0 0 0 8px rgba(220,38,38,0.15); }\r\n }\r\n .fab-badge {\r\n position: absolute;\r\n top: -4px;\r\n right: -4px;\r\n background: #f59e0b;\r\n color: #000;\r\n font-size: 10px;\r\n font-weight: 700;\r\n min-width: 18px;\r\n height: 18px;\r\n border-radius: 9px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 0 4px;\r\n }\r\n\r\n .debug-panel {\r\n position: fixed;\r\n z-index: 99998;\r\n width: 420px;\r\n max-height: 80vh;\r\n background: #0f172a;\r\n color: #e2e8f0;\r\n border-radius: 12px;\r\n border: 1px solid #1e3a5f;\r\n box-shadow: 0 25px 60px rgba(0,0,0,0.6);\r\n display: flex;\r\n flex-direction: column;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n font-size: 13px;\r\n overflow: hidden;\r\n }\r\n .pos-bottom-right { bottom: 88px; right: 24px; }\r\n .pos-bottom-left { bottom: 88px; left: 24px; }\r\n .pos-top-right { top: 24px; right: 24px; }\r\n .pos-top-left { top: 24px; left: 24px; }\r\n\r\n .panel-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 14px;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: move;\r\n user-select: none;\r\n flex-shrink: 0;\r\n }\r\n .header-left { display: flex; align-items: center; gap: 8px; }\r\n .panel-icon { font-size: 16px; }\r\n .panel-title { font-weight: 600; font-size: 14px; color: #f1f5f9; }\r\n .rec-indicator {\r\n font-size: 10px;\r\n font-weight: 700;\r\n color: #ef4444;\r\n background: rgba(239,68,68,0.15);\r\n padding: 2px 7px;\r\n border-radius: 4px;\r\n animation: blink 1s step-end infinite;\r\n }\r\n .rec-indicator.paused { color: #f59e0b; background: rgba(245,158,11,0.15); animation: none; }\r\n @keyframes blink { 50% { opacity: 0.4; } }\r\n .header-actions { display: flex; gap: 4px; }\r\n .icon-btn {\r\n background: none;\r\n border: none;\r\n color: #94a3b8;\r\n cursor: pointer;\r\n padding: 4px;\r\n border-radius: 4px;\r\n font-size: 14px;\r\n line-height: 1;\r\n transition: color 0.15s, background 0.15s;\r\n }\r\n .icon-btn:hover { color: #f1f5f9; background: #334155; }\r\n\r\n .session-setup {\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #1e293b;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n flex-shrink: 0;\r\n }\r\n .session-input, .session-desc {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #e2e8f0;\r\n border-radius: 6px;\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n width: 100%;\r\n box-sizing: border-box;\r\n resize: vertical;\r\n }\r\n .session-input:focus, .session-desc:focus {\r\n outline: none;\r\n border-color: #3b82f6;\r\n }\r\n\r\n .recording-controls {\r\n display: flex;\r\n gap: 6px;\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #1e293b;\r\n flex-wrap: wrap;\r\n flex-shrink: 0;\r\n }\r\n .ctrl-btn {\r\n border: none;\r\n border-radius: 6px;\r\n padding: 6px 14px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: filter 0.15s, transform 0.1s;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n }\r\n .ctrl-btn:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); }\r\n .ctrl-btn:active:not(:disabled) { transform: translateY(0); }\r\n .ctrl-btn:disabled { opacity: 0.5; cursor: not-allowed; }\r\n .ctrl-btn.start { background: #16a34a; color: #fff; }\r\n .ctrl-btn.stop { background: #dc2626; color: #fff; }\r\n .ctrl-btn.pause { background: #d97706; color: #fff; }\r\n .ctrl-btn.generate { background: #7c3aed; color: #fff; flex: 1; justify-content: center; }\r\n .ctrl-btn.clear { background: #374151; color: #9ca3af; padding: 6px 10px; }\r\n .spinner { display: inline-block; animation: spin 0.8s linear infinite; }\r\n @keyframes spin { to { transform: rotate(360deg); } }\r\n\r\n .error-banner {\r\n background: rgba(220,38,38,0.15);\r\n border-left: 3px solid #dc2626;\r\n color: #fca5a5;\r\n padding: 8px 14px;\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n\r\n .tab-bar {\r\n display: flex;\r\n border-bottom: 1px solid #1e293b;\r\n flex-shrink: 0;\r\n }\r\n .tab-btn {\r\n flex: 1;\r\n background: none;\r\n border: none;\r\n color: #64748b;\r\n padding: 8px 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n border-bottom: 2px solid transparent;\r\n transition: color 0.15s;\r\n }\r\n .tab-btn:hover:not(:disabled) { color: #cbd5e1; }\r\n .tab-btn.active { color: #60a5fa; border-bottom-color: #3b82f6; }\r\n .tab-btn:disabled { opacity: 0.4; cursor: not-allowed; }\r\n .tab-badge {\r\n background: #334155;\r\n color: #94a3b8;\r\n font-size: 10px;\r\n padding: 1px 5px;\r\n border-radius: 3px;\r\n }\r\n .tab-badge.new { background: #7c3aed; color: #e9d5ff; }\r\n\r\n .tab-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n min-height: 0;\r\n }\r\n .tab-content::-webkit-scrollbar { width: 5px; }\r\n .tab-content::-webkit-scrollbar-track { background: transparent; }\r\n .tab-content::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\r\n\r\n .sessions-list { padding: 10px 14px; display: flex; flex-direction: column; gap: 8px; }\r\n .session-card {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n border-radius: 8px;\r\n padding: 10px;\r\n }\r\n .session-card-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 8px;\r\n }\r\n .session-name { font-weight: 600; color: #f1f5f9; font-size: 13px; }\r\n .session-meta { font-size: 11px; color: #64748b; }\r\n .session-card-actions { display: flex; gap: 6px; }\r\n .sm-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 4px 10px;\r\n border-radius: 5px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .sm-btn:hover { background: #475569; }\r\n .sm-btn.danger { color: #fca5a5; }\r\n .sm-btn.danger:hover { background: rgba(220,38,38,0.2); }\r\n\r\n .resize-handle {\r\n text-align: center;\r\n color: #334155;\r\n cursor: ns-resize;\r\n font-size: 16px;\r\n padding: 2px;\r\n flex-shrink: 0;\r\n background: #0f172a;\r\n user-select: none;\r\n }\r\n .resize-handle:hover { color: #64748b; }\r\n `],\r\n})\r\nexport class DebugPanelComponent implements OnInit, OnDestroy {\r\n recorder = inject(RecorderService);\r\n aiService = inject(AiGeneratorService);\r\n rrweb = inject(RrwebRecorderService);\r\n\r\n panelOpen = signal(false);\r\n activeTab = signal<PanelTab>('actions');\r\n position = signal<PanelPosition>('bottom-right');\r\n panelWidth = signal(420);\r\n showSettings = signal(false);\r\n sessionName = '';\r\n sessionDesc = '';\r\n\r\n hasActions = computed(\r\n () => (this.recorder.currentSession()?.actions.length ?? 0) > 0 ||\r\n (this.recorder.sessions().length > 0)\r\n );\r\n\r\n private resizing = false;\r\n private resizeStartY = 0;\r\n private resizeStartH = 0;\r\n\r\n ngOnInit(): void {\r\n // Keyboard shortcut: Ctrl+Shift+D\r\n document.addEventListener('keydown', this.handleHotkey);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n document.removeEventListener('keydown', this.handleHotkey);\r\n }\r\n\r\n private handleHotkey = (e: KeyboardEvent) => {\r\n if (e.ctrlKey && e.shiftKey && e.key === 'D') {\r\n e.preventDefault();\r\n this.togglePanel();\r\n }\r\n if (e.ctrlKey && e.shiftKey && e.key === 'R') {\r\n e.preventDefault();\r\n if (this.recorder.isRecording()) {\r\n this.stopRecording();\r\n } else {\r\n this.startRecording();\r\n }\r\n }\r\n };\r\n\r\n togglePanel(): void {\r\n this.panelOpen.update(v => !v);\r\n if (this.panelOpen() && !this.recorder.currentSession()) {\r\n this.activeTab.set('actions');\r\n }\r\n }\r\n\r\n cyclePosition(): void {\r\n const positions: PanelPosition[] = ['bottom-right', 'bottom-left', 'top-right', 'top-left'];\r\n const idx = positions.indexOf(this.position());\r\n this.position.set(positions[(idx + 1) % positions.length]);\r\n }\r\n\r\n startRecording(): void {\r\n this.recorder.startRecording(\r\n this.sessionName || undefined,\r\n this.sessionDesc || undefined\r\n );\r\n // Start rrweb in parallel for visual replay\r\n this.rrweb.startRecording();\r\n this.activeTab.set('actions');\r\n }\r\n\r\n stopRecording(): void {\r\n const session = this.recorder.stopRecording();\r\n this.rrweb.stopRecording();\r\n if (session) {\r\n this.activeTab.set('actions');\r\n }\r\n }\r\n\r\n async generateTest(): Promise<void> {\r\n const session = this.recorder.currentSession() ?? this.recorder.sessions().at(-1);\r\n if (!session) return;\r\n await this.aiService.generateCypressTest(session);\r\n this.activeTab.set('test');\r\n }\r\n\r\n async loadAndGenerate(session: RecordingSession): Promise<void> {\r\n await this.aiService.generateCypressTest(session);\r\n this.activeTab.set('test');\r\n }\r\n\r\n // Drag to reposition\r\n startDrag(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).closest('button')) return;\r\n const panel = (e.currentTarget as HTMLElement).parentElement!;\r\n const startX = e.clientX - panel.getBoundingClientRect().left;\r\n const startY = e.clientY - panel.getBoundingClientRect().top;\r\n\r\n const onMove = (ev: MouseEvent) => {\r\n panel.style.left = `${ev.clientX - startX}px`;\r\n panel.style.top = `${ev.clientY - startY}px`;\r\n panel.style.right = 'auto';\r\n panel.style.bottom = 'auto';\r\n };\r\n const onUp = () => {\r\n document.removeEventListener('mousemove', onMove);\r\n document.removeEventListener('mouseup', onUp);\r\n };\r\n document.addEventListener('mousemove', onMove);\r\n document.addEventListener('mouseup', onUp);\r\n }\r\n\r\n // Resize height\r\n startResize(e: MouseEvent): void {\r\n const panel = (e.currentTarget as HTMLElement).parentElement!;\r\n this.resizeStartY = e.clientY;\r\n this.resizeStartH = panel.getBoundingClientRect().height;\r\n\r\n const onMove = (ev: MouseEvent) => {\r\n const newH = Math.max(250, this.resizeStartH + (ev.clientY - this.resizeStartY));\r\n panel.style.maxHeight = `${newH}px`;\r\n };\r\n const onUp = () => {\r\n document.removeEventListener('mousemove', onMove);\r\n document.removeEventListener('mouseup', onUp);\r\n };\r\n document.addEventListener('mousemove', onMove);\r\n document.addEventListener('mouseup', onUp);\r\n e.preventDefault();\r\n }\r\n}\r\n","/*\r\n * Public API Surface of debug-recorder\r\n */\r\n\r\n// Main entry component — add this to your Angular app\r\nexport * from './lib/debug-panel/debug-panel.component';\r\n\r\n// Sub-components (if you need them individually)\r\nexport * from './lib/action-list/action-list.component';\r\nexport * from './lib/test-preview/test-preview.component';\r\nexport * from './lib/session-replay/session-replay.component';\r\nexport * from './lib/settings-dialog/settings-dialog.component';\r\n\r\n// Services\r\nexport * from './lib/services/recorder.service';\r\nexport * from './lib/services/ai-generator.service';\r\nexport * from './lib/services/rrweb-recorder.service';\r\n\r\n// Models / interfaces\r\nexport * from './lib/models/recorded-action.model';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}
1
+ {"version":3,"file":"angular-debug-recorder.mjs","sources":["../../../src/lib/services/recorder.service.ts","../../../src/lib/services/ai-generator.service.ts","../../../src/lib/services/rrweb-recorder.service.ts","../../../src/lib/action-list/action-list.component.ts","../../../src/lib/test-preview/test-preview.component.ts","../../../src/lib/settings-dialog/settings-dialog.component.ts","../../../src/lib/session-replay/session-replay.component.ts","../../../src/lib/debug-panel/debug-panel.component.ts","../../../src/public-api.ts","../../../src/angular-debug-recorder.ts"],"sourcesContent":["import { Injectable, NgZone, signal, computed } from '@angular/core';\r\nimport { ActionType, ElementInfo, RecordedAction, RecordingSession } from '../models/recorded-action.model';\r\n\r\n/**\r\n * Performance notes\r\n * ─────────────────\r\n * All DOM event listeners are registered **outside Angular's NgZone**\r\n * (zone.runOutsideAngular). This means a click, input, or scroll never\r\n * triggers Angular Change Detection by itself.\r\n *\r\n * Recorded actions are batched in a plain array and flushed once per\r\n * animation frame via requestAnimationFrame. Only the RAF callback runs\r\n * inside zone.run() → at most one CD cycle per frame, regardless of how\r\n * many events fired.\r\n *\r\n * Why this matters for OnPush host apps\r\n * ──────────────────────────────────────\r\n * When this recorder is embedded in a library used inside an OnPush app,\r\n * the old zone.run()-per-event approach caused the host app's CD to run\r\n * on every user interaction. With this implementation the host app is\r\n * completely unaffected — only the recorder's own signals trigger CD.\r\n *\r\n * F5 / page-reload survival\r\n * ─────────────────────────\r\n * The active recording session is written to sessionStorage on\r\n * beforeunload and restored in the constructor. If the user accidentally\r\n * refreshes mid-recording, no actions are lost.\r\n */\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class RecorderService {\r\n\r\n // ─── Reactive state ───────────────────────────────────────────────────\r\n\r\n private _isRecording = signal(false);\r\n private _currentSession = signal<RecordingSession | null>(null);\r\n private _sessions = signal<RecordingSession[]>([]);\r\n private _isPaused = signal(false);\r\n\r\n isRecording = computed(() => this._isRecording());\r\n isPaused = computed(() => this._isPaused());\r\n currentSession = computed(() => this._currentSession());\r\n sessions = computed(() => this._sessions());\r\n actionCount = computed(() => this._currentSession()?.actions.length ?? 0);\r\n\r\n // ─── RAF batch buffer ─────────────────────────────────────────────────\r\n\r\n private pendingActions: RecordedAction[] = [];\r\n private rafId?: number;\r\n\r\n // ─── Listener registry ────────────────────────────────────────────────\r\n\r\n private listeners: Array<{ type: string; fn: EventListener }> = [];\r\n private lastScrollTime = 0;\r\n\r\n // ─── SessionStorage keys ──────────────────────────────────────────────\r\n\r\n private static readonly SESSION_KEY = 'dr_active_session';\r\n private static readonly SESSIONS_KEY = 'dr_sessions';\r\n\r\n constructor(private zone: NgZone) {\r\n this.restoreFromStorage();\r\n // Register outside Angular zone — zone.js intercepts beforeunload\r\n // inside the zone and may suppress it (dialog-return handling).\r\n this.zone.runOutsideAngular(() => {\r\n window.addEventListener('beforeunload', () => this.persistToStorage());\r\n });\r\n }\r\n\r\n // ─── Public API ───────────────────────────────────────────────────────\r\n\r\n startRecording(name?: string, description?: string): void {\r\n const session: RecordingSession = {\r\n id: this.generateId(),\r\n name: name || `Session ${new Date().toLocaleTimeString()}`,\r\n description,\r\n startTime: Date.now(),\r\n startUrl: window.location.href,\r\n actions: [],\r\n tags: [],\r\n };\r\n\r\n this._currentSession.set(session);\r\n this._isRecording.set(true);\r\n this._isPaused.set(false);\r\n this.attachListeners();\r\n this.recordNavigation(window.location.href);\r\n }\r\n\r\n stopRecording(): RecordingSession | null {\r\n // Flush pending actions synchronously before tearing down\r\n if (this.rafId !== undefined) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = undefined;\r\n }\r\n this.flushPending();\r\n\r\n const session = this._currentSession();\r\n if (!session) return null;\r\n\r\n const completed = { ...session, endTime: Date.now() };\r\n this._sessions.update(s => [...s, completed]);\r\n this._currentSession.set(null);\r\n this._isRecording.set(false);\r\n this._isPaused.set(false);\r\n this.detachListeners();\r\n this.persistToStorage();\r\n return completed;\r\n }\r\n\r\n pauseRecording(): void {\r\n if (this._isRecording()) {\r\n this._isPaused.set(!this._isPaused());\r\n }\r\n }\r\n\r\n clearCurrentSession(): void {\r\n this._currentSession.update(s => s ? { ...s, actions: [] } : null);\r\n }\r\n\r\n removeAction(actionId: string): void {\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: s.actions.filter(a => a.id !== actionId) } : null\r\n );\r\n }\r\n\r\n addNote(actionId: string, note: string): void {\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: s.actions.map(a => a.id === actionId ? { ...a, note } : a) } : null\r\n );\r\n }\r\n\r\n deleteSession(sessionId: string): void {\r\n this._sessions.update(s => s.filter(x => x.id !== sessionId));\r\n }\r\n\r\n loadSession(session: RecordingSession): void {\r\n this._currentSession.set(session);\r\n }\r\n\r\n // ─── RAF batch flush ──────────────────────────────────────────────────\r\n\r\n /**\r\n * Schedule one signal update at the next animation frame.\r\n * Multiple events within a single frame are coalesced → one CD cycle.\r\n */\r\n private scheduleFlush(): void {\r\n if (this.rafId !== undefined) return;\r\n this.rafId = requestAnimationFrame(() => {\r\n this.rafId = undefined;\r\n this.flushPending();\r\n });\r\n }\r\n\r\n private flushPending(): void {\r\n if (!this.pendingActions.length) return;\r\n const batch = this.pendingActions.splice(0);\r\n\r\n this.zone.run(() => {\r\n this._currentSession.update(s => {\r\n if (!s) return s;\r\n let actions = [...s.actions];\r\n for (const action of batch) {\r\n // Deduplicate consecutive inputs: keep only the latest value\r\n if (action.type === 'input') {\r\n const last = actions[actions.length - 1];\r\n if (last?.type === 'input' && last.selector === action.selector) {\r\n actions[actions.length - 1] = action;\r\n continue;\r\n }\r\n }\r\n actions.push(action);\r\n }\r\n return { ...s, actions };\r\n });\r\n });\r\n }\r\n\r\n // ─── Event listeners (registered outside NgZone) ──────────────────────\r\n\r\n private attachListeners(): void {\r\n const opts = { capture: true, passive: true };\r\n\r\n // Handlers run completely outside Angular Zone — zero CD impact per event.\r\n // Only the RAF flush (above) re-enters the zone.\r\n const onClick = (e: MouseEvent) => { if (this.shouldRecord(e.target as Element)) this.handleClick(e); };\r\n const onDblClick = (e: MouseEvent) => { if (this.shouldRecord(e.target as Element)) this.handleDblClick(e); };\r\n const onInput = (e: Event) => { if (this.shouldRecord(e.target as Element)) this.handleInput(e); };\r\n const onChange = (e: Event) => { if (this.shouldRecord(e.target as Element)) this.handleChange(e); };\r\n const onSubmit = (e: Event) => { if (this.shouldRecord(e.target as Element)) this.handleSubmit(e); };\r\n const onKeydown = (e: KeyboardEvent) => { if (this.shouldRecord(e.target as Element)) this.handleKeydown(e); };\r\n const onScroll = (e: Event) => { if (this.shouldRecord(e.target as Element)) this.handleScroll(e); };\r\n\r\n this.zone.runOutsideAngular(() => {\r\n document.addEventListener('click', onClick as EventListener, opts);\r\n document.addEventListener('dblclick',onDblClick as EventListener, opts);\r\n document.addEventListener('input', onInput, opts);\r\n document.addEventListener('change', onChange, opts);\r\n document.addEventListener('submit', onSubmit, opts);\r\n document.addEventListener('keydown', onKeydown as EventListener, opts);\r\n document.addEventListener('scroll', onScroll, { capture: true, passive: true });\r\n });\r\n\r\n this.listeners = [\r\n { type: 'click', fn: onClick as EventListener },\r\n { type: 'dblclick', fn: onDblClick as EventListener },\r\n { type: 'input', fn: onInput as EventListener },\r\n { type: 'change', fn: onChange as EventListener },\r\n { type: 'submit', fn: onSubmit as EventListener },\r\n { type: 'keydown', fn: onKeydown as EventListener },\r\n { type: 'scroll', fn: onScroll as EventListener },\r\n ];\r\n }\r\n\r\n private detachListeners(): void {\r\n this.listeners.forEach(({ type, fn }) =>\r\n document.removeEventListener(type, fn, true)\r\n );\r\n this.listeners = [];\r\n }\r\n\r\n // ─── Handlers (run outside NgZone, call addAction which batches) ──────\r\n\r\n private handleClick(e: MouseEvent): void {\r\n const el = e.target as HTMLElement;\r\n const info = this.getElementInfo(el);\r\n this.addAction({\r\n type: 'click',\r\n selector: this.buildSelector(el),\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n description: `Click on ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleDblClick(e: MouseEvent): void {\r\n const el = e.target as HTMLElement;\r\n const info = this.getElementInfo(el);\r\n this.addAction({\r\n type: 'dblclick',\r\n selector: this.buildSelector(el),\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n description: `Double-click on ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleInput(e: Event): void {\r\n const el = e.target as HTMLInputElement | HTMLTextAreaElement;\r\n if (['checkbox', 'radio'].includes(el.type)) return; // handled by change\r\n const info = this.getElementInfo(el);\r\n this.addAction({\r\n type: 'input',\r\n selector: this.buildSelector(el),\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: el.value,\r\n description: `Type \"${el.value}\" in ${this.describeElement(info)}`,\r\n });\r\n }\r\n\r\n private handleChange(e: Event): void {\r\n const el = e.target as HTMLSelectElement | HTMLInputElement;\r\n const info = this.getElementInfo(el);\r\n const selector = this.buildSelector(el);\r\n\r\n if (el.tagName === 'SELECT') {\r\n this.addAction({\r\n type: 'select',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: el.value,\r\n description: `Select \"${el.value}\" in ${this.describeElement(info)}`,\r\n });\r\n } else if ((el as HTMLInputElement).type === 'checkbox') {\r\n this.addAction({\r\n type: 'click',\r\n selector,\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n element: info,\r\n value: String((el as HTMLInputElement).checked),\r\n description: `${(el as HTMLInputElement).checked ? 'Check' : 'Uncheck'} ${this.describeElement(info)}`,\r\n });\r\n }\r\n }\r\n\r\n private handleSubmit(e: Event): void {\r\n const form = e.target as HTMLFormElement;\r\n const info = this.getElementInfo(form);\r\n this.addAction({\r\n type: 'submit',\r\n selector: this.buildSelector(form),\r\n selectorStrategy: this.getSelectorStrategy(form),\r\n element: info,\r\n description: `Submit form ${info.id ? '#' + info.id : info.name ?? ''}`.trim(),\r\n });\r\n }\r\n\r\n private handleScroll(e: Event): void {\r\n const now = Date.now();\r\n if (now - this.lastScrollTime < 1000) return; // debounce 1 s\r\n this.lastScrollTime = now;\r\n\r\n const el = e.target as HTMLElement;\r\n const isDoc = !el.tagName || el.tagName === 'HTML';\r\n const scrollY = isDoc ? window.scrollY : el.scrollTop;\r\n const scrollX = isDoc ? window.scrollX : el.scrollLeft;\r\n const selector = (el.tagName === 'HTML' || el.tagName === 'BODY')\r\n ? 'window'\r\n : this.buildSelector(el);\r\n\r\n this.addAction({\r\n type: 'scroll',\r\n selector,\r\n selectorStrategy: 'combined',\r\n value: `${scrollX},${scrollY}`,\r\n description: `Scroll to (${scrollX}, ${scrollY})`,\r\n });\r\n }\r\n\r\n private handleKeydown(e: KeyboardEvent): void {\r\n const specialKeys = ['Enter', 'Escape', 'Tab', 'F5', 'F12'];\r\n if (!specialKeys.includes(e.key)) return;\r\n\r\n const el = e.target as HTMLElement;\r\n this.addAction({\r\n type: 'keypress',\r\n selector: this.buildSelector(el),\r\n selectorStrategy: this.getSelectorStrategy(el),\r\n value: e.key,\r\n description: `Press \"${e.key}\" on ${el.tagName.toLowerCase()}`,\r\n });\r\n }\r\n\r\n private recordNavigation(navUrl: string): void {\r\n // Navigation is always added synchronously (no pending batch needed)\r\n const action: RecordedAction = {\r\n id: this.generateId(),\r\n timestamp: Date.now(),\r\n url: navUrl,\r\n type: 'navigation',\r\n selector: 'window',\r\n selectorStrategy: 'combined',\r\n description: `Navigate to ${navUrl}`,\r\n };\r\n this._currentSession.update(s =>\r\n s ? { ...s, actions: [...s.actions, action] } : s\r\n );\r\n }\r\n\r\n // ─── Selector building ────────────────────────────────────────────────\r\n\r\n private buildSelector(el: HTMLElement): string {\r\n const testId = el.getAttribute('data-testid');\r\n if (testId) return `[data-testid=\"${testId}\"]`;\r\n\r\n const cy = el.getAttribute('data-cy');\r\n if (cy) return `[data-cy=\"${cy}\"]`;\r\n\r\n if (el.id && !el.id.includes(':')) return `#${el.id}`;\r\n\r\n const name = el.getAttribute('name');\r\n if (name) return `${el.tagName.toLowerCase()}[name=\"${name}\"]`;\r\n\r\n const ariaLabel = el.getAttribute('aria-label');\r\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\r\n\r\n const relevantClasses = Array.from(el.classList)\r\n .filter(c => !c.startsWith('ng-') && !c.startsWith('cdk-') && c.length > 0)\r\n .slice(0, 3);\r\n if (relevantClasses.length > 0) {\r\n return `${el.tagName.toLowerCase()}.${relevantClasses.join('.')}`;\r\n }\r\n\r\n if (['BUTTON', 'A'].includes(el.tagName)) {\r\n const text = el.textContent?.trim().slice(0, 30);\r\n if (text) return `${el.tagName.toLowerCase()}:contains(\"${text}\")`;\r\n }\r\n\r\n return el.tagName.toLowerCase();\r\n }\r\n\r\n private getSelectorStrategy(el: HTMLElement): RecordedAction['selectorStrategy'] {\r\n if (el.getAttribute('data-testid')) return 'data-testid';\r\n if (el.getAttribute('data-cy')) return 'data-cy';\r\n if (el.id) return 'id';\r\n if (el.getAttribute('name')) return 'name';\r\n return 'class';\r\n }\r\n\r\n private getElementInfo(el: HTMLElement): ElementInfo {\r\n return {\r\n tagName: el.tagName.toLowerCase(),\r\n id: el.id || undefined,\r\n classes: Array.from(el.classList).filter(c => !c.startsWith('ng-')),\r\n dataTestId: el.getAttribute('data-testid') || undefined,\r\n dataCy: el.getAttribute('data-cy') || undefined,\r\n name: el.getAttribute('name') || undefined,\r\n type: el.getAttribute('type') || undefined,\r\n placeholder: el.getAttribute('placeholder') || undefined,\r\n text: el.textContent?.trim().slice(0, 50) || undefined,\r\n href: (el as HTMLAnchorElement).href || undefined,\r\n ariaLabel: el.getAttribute('aria-label') || undefined,\r\n };\r\n }\r\n\r\n private describeElement(info: ElementInfo): string {\r\n if (info.dataTestId) return `[data-testid=\"${info.dataTestId}\"]`;\r\n if (info.dataCy) return `[data-cy=\"${info.dataCy}\"]`;\r\n if (info.id) return `#${info.id}`;\r\n if (info.ariaLabel) return `\"${info.ariaLabel}\"`;\r\n if (info.placeholder) return `\"${info.placeholder}\" input`;\r\n if (info.text) return `\"${info.text}\"`;\r\n return info.tagName;\r\n }\r\n\r\n // ─── Guard ────────────────────────────────────────────────────────────\r\n\r\n private shouldRecord(target: Element | null): boolean {\r\n if (!this._isRecording() || this._isPaused()) return false;\r\n if (!target) return false;\r\n if (target.closest('[data-debug-panel]')) return false;\r\n return true;\r\n }\r\n\r\n // ─── Batch buffer ─────────────────────────────────────────────────────\r\n\r\n private addAction(partial: Omit<RecordedAction, 'id' | 'timestamp' | 'url'>): void {\r\n const action: RecordedAction = {\r\n id: this.generateId(),\r\n timestamp: Date.now(),\r\n url: window.location.href,\r\n ...partial,\r\n };\r\n this.pendingActions.push(action);\r\n this.scheduleFlush();\r\n }\r\n\r\n // ─── SessionStorage (F5 survival) ─────────────────────────────────────\r\n\r\n private persistToStorage(): void {\r\n try {\r\n const session = this._currentSession();\r\n if (session && this._isRecording()) {\r\n sessionStorage.setItem(\r\n RecorderService.SESSION_KEY,\r\n JSON.stringify({ session, isPaused: this._isPaused() })\r\n );\r\n } else {\r\n sessionStorage.removeItem(RecorderService.SESSION_KEY);\r\n }\r\n const sessions = this._sessions();\r\n if (sessions.length > 0) {\r\n sessionStorage.setItem(RecorderService.SESSIONS_KEY, JSON.stringify(sessions));\r\n }\r\n } catch { /* storage quota exceeded or private browsing */ }\r\n }\r\n\r\n private restoreFromStorage(): void {\r\n try {\r\n const savedSessions = sessionStorage.getItem(RecorderService.SESSIONS_KEY);\r\n if (savedSessions) this._sessions.set(JSON.parse(savedSessions));\r\n\r\n const savedActive = sessionStorage.getItem(RecorderService.SESSION_KEY);\r\n if (savedActive) {\r\n const { session, isPaused } = JSON.parse(savedActive) as {\r\n session: RecordingSession;\r\n isPaused: boolean;\r\n };\r\n this._currentSession.set(session);\r\n this._isRecording.set(true);\r\n this._isPaused.set(isPaused);\r\n this.attachListeners(); // resume recording after reload\r\n }\r\n } catch { /* corrupt or missing storage */ }\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────\r\n\r\n private generateId(): string {\r\n return Math.random().toString(36).slice(2, 11);\r\n }\r\n}\r\n","import { Injectable, signal } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { GeneratedTest, RecordingSession } from '../models/recorded-action.model';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class AiGeneratorService {\r\n private _webhookUrl = signal(localStorage.getItem('debugRecorder_webhookUrl') ?? '');\r\n private _isGenerating = signal(false);\r\n private _error = signal<string | null>(null);\r\n private _lastTest = signal<GeneratedTest | null>(null);\r\n\r\n webhookUrl = this._webhookUrl.asReadonly();\r\n isGenerating = this._isGenerating.asReadonly();\r\n error = this._error.asReadonly();\r\n lastTest = this._lastTest.asReadonly();\r\n\r\n constructor(private http: HttpClient) {}\r\n\r\n setWebhookUrl(url: string): void {\r\n this._webhookUrl.set(url);\r\n localStorage.setItem('debugRecorder_webhookUrl', url);\r\n }\r\n\r\n async generateCypressTest(session: RecordingSession): Promise<GeneratedTest> {\r\n const url = this._webhookUrl();\r\n if (!url) throw new Error('Keine Webhook-URL konfiguriert');\r\n\r\n this._isGenerating.set(true);\r\n this._error.set(null);\r\n\r\n try {\r\n const code = await this.postSession(url, session);\r\n const test: GeneratedTest = {\r\n code,\r\n generatedAt: Date.now(),\r\n model: url,\r\n sessionId: session.id,\r\n };\r\n this._lastTest.set(test);\r\n return test;\r\n } catch (err: any) {\r\n const msg = err?.error?.message || err?.message || 'Fehler beim Senden';\r\n this._error.set(msg);\r\n throw err;\r\n } finally {\r\n this._isGenerating.set(false);\r\n }\r\n }\r\n\r\n private postSession(url: string, session: RecordingSession): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n this.http.post(url, session, { responseType: 'text' }).subscribe({\r\n next: (res) => resolve(res),\r\n error: reject,\r\n });\r\n });\r\n }\r\n}\r\n","import { Injectable, NgZone, signal } from '@angular/core';\r\nimport type { eventWithTime } from '@rrweb/types';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class RrwebRecorderService {\r\n // Plain array — cheap push, no O(n) spread on every event\r\n private _eventsArray: eventWithTime[] = [];\r\n // Signal only for reactive count display in templates\r\n private _eventCount = signal(0);\r\n private _isRecording = signal(false);\r\n private stopFn?: () => void;\r\n private replayer?: any;\r\n\r\n eventCount = this._eventCount.asReadonly();\r\n isRecording = this._isRecording.asReadonly();\r\n\r\n constructor(private zone: NgZone) {}\r\n\r\n hasEvents(): boolean {\r\n return this._eventsArray.length > 0;\r\n }\r\n\r\n getEvents(): eventWithTime[] {\r\n return this._eventsArray;\r\n }\r\n\r\n async startRecording(): Promise<void> {\r\n const { record } = await import('rrweb');\r\n this._eventsArray = [];\r\n this._eventCount.set(0);\r\n this._isRecording.set(true);\r\n\r\n this.stopFn = record({\r\n emit: (event: eventWithTime) => {\r\n // Push outside Angular zone — no change detection per event\r\n this.zone.runOutsideAngular(() => {\r\n this._eventsArray.push(event);\r\n });\r\n // Update count signal only every 10 events to keep UI responsive\r\n const len = this._eventsArray.length;\r\n if (len === 1 || len % 10 === 0) {\r\n this.zone.run(() => this._eventCount.set(len));\r\n }\r\n },\r\n // Note: blockSelector omitted — rrweb 2.0.0-alpha.4 calls node.matches()\r\n // on TextNodes/CommentNodes which crash the recorder.\r\n maskTextSelector: 'input[type=\"password\"]',\r\n checkoutEveryNth: 200,\r\n });\r\n }\r\n\r\n stopRecording(): eventWithTime[] {\r\n if (this.stopFn) {\r\n this.stopFn();\r\n this.stopFn = undefined;\r\n }\r\n this._isRecording.set(false);\r\n this._eventCount.set(this._eventsArray.length);\r\n return this._eventsArray;\r\n }\r\n\r\n clearEvents(): void {\r\n this._eventsArray = [];\r\n this._eventCount.set(0);\r\n }\r\n\r\n // ─── Replay ──────────────────────────────────────────────────────────────\r\n\r\n async startReplay(container: HTMLElement, events?: eventWithTime[]): Promise<void> {\r\n const { Replayer } = await import('rrweb');\r\n const eventsToReplay = events ?? this._eventsArray;\r\n\r\n if (eventsToReplay.length === 0) return;\r\n\r\n this.destroyReplayer();\r\n\r\n this.replayer = new Replayer(eventsToReplay, {\r\n root: container,\r\n skipInactive: true,\r\n showWarning: false,\r\n showDebug: false,\r\n blockClass: 'debug-panel',\r\n });\r\n\r\n this.replayer.play();\r\n }\r\n\r\n pauseReplay(): void {\r\n this.replayer?.pause();\r\n }\r\n\r\n resumeReplay(): void {\r\n this.replayer?.play();\r\n }\r\n\r\n destroyReplayer(): void {\r\n if (this.replayer) {\r\n try { this.replayer.pause(); } catch {}\r\n this.replayer = undefined;\r\n }\r\n }\r\n\r\n // ─── Export ───────────────────────────────────────────────────────────────\r\n\r\n exportEvents(): string {\r\n return JSON.stringify(this._eventsArray, null, 2);\r\n }\r\n\r\n downloadEvents(filename = 'rrweb-session.json'): void {\r\n const blob = new Blob([this.exportEvents()], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = filename;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n importEvents(json: string): eventWithTime[] {\r\n try {\r\n const events = JSON.parse(json) as eventWithTime[];\r\n this._eventsArray = events;\r\n this._eventCount.set(events.length);\r\n return events;\r\n } catch {\r\n console.error('Invalid rrweb events JSON');\r\n return [];\r\n }\r\n }\r\n}\r\n","import { Component, Input, Output, EventEmitter, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { RecordedAction, RecordingSession } from '../models/recorded-action.model';\r\n\r\n@Component({\r\n selector: 'app-action-list',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <div class=\"action-list\" data-debug-panel>\r\n @if (!session || session.actions.length === 0) {\r\n <div class=\"empty-state\">\r\n <div class=\"empty-icon\">🎬</div>\r\n <p>Noch keine Aktionen aufgezeichnet.</p>\r\n <p class=\"hint\">Starte die Aufnahme und interagiere mit der App.</p>\r\n <div class=\"shortcuts-hint\">\r\n <kbd>Ctrl+Shift+D</kbd> Panel &nbsp;\r\n <kbd>Ctrl+Shift+R</kbd> Record\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"list-header\">\r\n <span class=\"list-count\">{{ session.actions.length }} Aktionen</span>\r\n <span class=\"list-duration\">\r\n @if (session.endTime) {\r\n {{ formatDuration(session.startTime, session.endTime) }}\r\n } @else {\r\n Live\r\n }\r\n </span>\r\n </div>\r\n\r\n @for (action of session.actions; track action.id; let i = $index) {\r\n <div class=\"action-item\" [class.expanded]=\"expandedId() === action.id\">\r\n <div class=\"action-row\" (click)=\"toggleExpand(action.id)\">\r\n <span class=\"action-index\">{{ i + 1 }}</span>\r\n <span class=\"action-type-badge\" [class]=\"'type-' + action.type\">\r\n {{ getActionIcon(action.type) }}\r\n </span>\r\n <div class=\"action-info\">\r\n <span class=\"action-desc\">{{ action.description }}</span>\r\n <span class=\"action-selector\">{{ action.selector }}</span>\r\n </div>\r\n <span class=\"action-time\">{{ formatTime(action.timestamp) }}</span>\r\n <button\r\n class=\"remove-btn\"\r\n data-debug-panel\r\n title=\"Aktion entfernen\"\r\n (click)=\"onRemove(action.id, $event)\"\r\n >✕</button>\r\n </div>\r\n\r\n @if (expandedId() === action.id) {\r\n <div class=\"action-detail\" data-debug-panel>\r\n <div class=\"detail-grid\">\r\n <span class=\"detail-label\">Selector</span>\r\n <code class=\"detail-value\">{{ action.selector }}</code>\r\n @if (action.value) {\r\n <span class=\"detail-label\">Wert</span>\r\n <code class=\"detail-value\">{{ action.value }}</code>\r\n }\r\n @if (action.element?.tagName) {\r\n <span class=\"detail-label\">Element</span>\r\n <code class=\"detail-value\">&lt;{{ action.element?.tagName }}&gt;</code>\r\n }\r\n <span class=\"detail-label\">Strategie</span>\r\n <span class=\"detail-value strategy-badge\" [class]=\"'strat-' + action.selectorStrategy\">\r\n {{ action.selectorStrategy }}\r\n </span>\r\n <span class=\"detail-label\">URL</span>\r\n <code class=\"detail-value url-val\">{{ action.url }}</code>\r\n </div>\r\n <div class=\"note-area\">\r\n <textarea\r\n data-debug-panel\r\n class=\"note-input\"\r\n [(ngModel)]=\"noteMap[action.id]\"\r\n placeholder=\"Notiz zu dieser Aktion...\"\r\n rows=\"2\"\r\n (blur)=\"onAddNote(action.id)\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n .action-list { padding: 0; }\r\n\r\n .empty-state {\r\n text-align: center;\r\n padding: 32px 20px;\r\n color: #64748b;\r\n }\r\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\r\n .empty-state p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n .shortcuts-hint {\r\n margin-top: 12px;\r\n font-size: 11px;\r\n color: #475569;\r\n }\r\n kbd {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #94a3b8;\r\n padding: 2px 6px;\r\n border-radius: 4px;\r\n font-size: 10px;\r\n }\r\n\r\n .list-header {\r\n display: flex;\r\n justify-content: space-between;\r\n padding: 8px 14px;\r\n font-size: 11px;\r\n color: #64748b;\r\n background: #0f172a;\r\n border-bottom: 1px solid #1e293b;\r\n position: sticky;\r\n top: 0;\r\n }\r\n\r\n .action-item {\r\n border-bottom: 1px solid #1e293b;\r\n transition: background 0.1s;\r\n }\r\n .action-item:hover { background: rgba(30,41,59,0.5); }\r\n .action-item.expanded { background: #1e293b; }\r\n\r\n .action-row {\r\n display: flex;\r\n align-items: center;\r\n padding: 8px 10px;\r\n gap: 8px;\r\n cursor: pointer;\r\n }\r\n .action-index {\r\n color: #475569;\r\n font-size: 10px;\r\n min-width: 18px;\r\n text-align: right;\r\n }\r\n .action-type-badge {\r\n font-size: 14px;\r\n min-width: 20px;\r\n text-align: center;\r\n }\r\n .action-info {\r\n flex: 1;\r\n min-width: 0;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 1px;\r\n }\r\n .action-desc {\r\n font-size: 12px;\r\n color: #cbd5e1;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n .action-selector {\r\n font-size: 10px;\r\n color: #64748b;\r\n font-family: 'Cascadia Code', 'Consolas', monospace;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n }\r\n .action-time {\r\n font-size: 10px;\r\n color: #475569;\r\n white-space: nowrap;\r\n }\r\n .remove-btn {\r\n background: none;\r\n border: none;\r\n color: #475569;\r\n cursor: pointer;\r\n font-size: 12px;\r\n padding: 2px 5px;\r\n border-radius: 3px;\r\n opacity: 0;\r\n transition: opacity 0.15s, color 0.15s;\r\n }\r\n .action-row:hover .remove-btn { opacity: 1; }\r\n .remove-btn:hover { color: #f87171; }\r\n\r\n .action-detail {\r\n padding: 10px 14px;\r\n background: rgba(15,23,42,0.7);\r\n border-top: 1px solid #1e293b;\r\n }\r\n .detail-grid {\r\n display: grid;\r\n grid-template-columns: auto 1fr;\r\n gap: 4px 10px;\r\n margin-bottom: 8px;\r\n align-items: start;\r\n }\r\n .detail-label { font-size: 10px; color: #64748b; padding-top: 2px; white-space: nowrap; }\r\n .detail-value {\r\n font-size: 11px;\r\n color: #93c5fd;\r\n font-family: 'Cascadia Code', 'Consolas', monospace;\r\n word-break: break-all;\r\n }\r\n .url-val { color: #6ee7b7; }\r\n .strategy-badge {\r\n font-size: 10px;\r\n padding: 1px 6px;\r\n border-radius: 3px;\r\n font-family: monospace;\r\n }\r\n .strat-data-testid { background: #064e3b; color: #34d399; }\r\n .strat-data-cy { background: #064e3b; color: #34d399; }\r\n .strat-id { background: #1e3a8a; color: #93c5fd; }\r\n .strat-name { background: #44337a; color: #c4b5fd; }\r\n .strat-class { background: #374151; color: #9ca3af; }\r\n .strat-combined { background: #292524; color: #d6d3d1; }\r\n\r\n .note-area { margin-top: 6px; }\r\n .note-input {\r\n width: 100%;\r\n box-sizing: border-box;\r\n background: #0f172a;\r\n border: 1px solid #334155;\r\n color: #e2e8f0;\r\n border-radius: 5px;\r\n padding: 6px 8px;\r\n font-size: 11px;\r\n resize: vertical;\r\n }\r\n .note-input:focus { outline: none; border-color: #3b82f6; }\r\n `],\r\n})\r\nexport class ActionListComponent {\r\n @Input() session: RecordingSession | null = null;\r\n @Output() removeAction = new EventEmitter<string>();\r\n @Output() addNote = new EventEmitter<{ id: string; note: string }>();\r\n\r\n expandedId = signal<string | null>(null);\r\n noteMap: Record<string, string> = {};\r\n\r\n toggleExpand(id: string): void {\r\n this.expandedId.update(v => v === id ? null : id);\r\n }\r\n\r\n onRemove(id: string, e: Event): void {\r\n e.stopPropagation();\r\n this.removeAction.emit(id);\r\n }\r\n\r\n onAddNote(id: string): void {\r\n this.addNote.emit({ id, note: this.noteMap[id] ?? '' });\r\n }\r\n\r\n getActionIcon(type: string): string {\r\n const icons: Record<string, string> = {\r\n click: '👆',\r\n dblclick: '👆👆',\r\n input: '⌨️',\r\n select: '📋',\r\n submit: '📤',\r\n navigation: '🔗',\r\n keypress: '⌨️',\r\n scroll: '↕️',\r\n hover: '🖱️',\r\n assertion: '✅',\r\n screenshot: '📸',\r\n };\r\n return icons[type] ?? '•';\r\n }\r\n\r\n formatTime(ts: number): string {\r\n return new Date(ts).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\r\n }\r\n\r\n formatDuration(start: number, end: number): string {\r\n const s = Math.round((end - start) / 1000);\r\n return s < 60 ? `${s}s` : `${Math.floor(s/60)}m ${s%60}s`;\r\n }\r\n}\r\n","import { Component, Input, signal, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { GeneratedTest } from '../models/recorded-action.model';\r\n\r\n@Component({\r\n selector: 'app-test-preview',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"test-preview\" data-debug-panel>\r\n @if (!test) {\r\n <div class=\"empty-state\">\r\n <div class=\"empty-icon\">🤖</div>\r\n <p>Noch kein Test generiert.</p>\r\n <p class=\"hint\">Zeichne Aktionen auf und klicke „🤖 → Cypress Test\".</p>\r\n </div>\r\n } @else {\r\n <div class=\"test-toolbar\" data-debug-panel>\r\n <div class=\"test-meta\">\r\n <span class=\"model-tag\">{{ test.model }}</span>\r\n <span class=\"gen-time\">{{ formatDate(test.generatedAt) }}</span>\r\n </div>\r\n <div class=\"test-actions\">\r\n <button class=\"action-btn\" title=\"Kopieren\" (click)=\"copyCode()\">\r\n {{ copied() ? '✅ Kopiert!' : '📋 Kopieren' }}\r\n </button>\r\n <button class=\"action-btn\" title=\"Herunterladen\" (click)=\"downloadCode()\">\r\n 💾 Download\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"code-container\">\r\n <pre class=\"code-block\"><code [innerHTML]=\"highlightedCode()\"></code></pre>\r\n </div>\r\n }\r\n </div>\r\n `,\r\n styles: [`\r\n .test-preview { height: 100%; display: flex; flex-direction: column; }\r\n\r\n .empty-state {\r\n text-align: center;\r\n padding: 32px 20px;\r\n color: #64748b;\r\n }\r\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\r\n .empty-state p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n\r\n .test-toolbar {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 8px 12px;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n flex-shrink: 0;\r\n gap: 8px;\r\n }\r\n .test-meta { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\r\n .model-tag {\r\n background: #312e81;\r\n color: #a5b4fc;\r\n font-size: 10px;\r\n padding: 2px 7px;\r\n border-radius: 4px;\r\n font-weight: 600;\r\n white-space: nowrap;\r\n }\r\n .gen-time { font-size: 10px; color: #64748b; white-space: nowrap; }\r\n .test-actions { display: flex; gap: 6px; flex-shrink: 0; }\r\n .action-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 4px 10px;\r\n border-radius: 5px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n white-space: nowrap;\r\n transition: background 0.15s;\r\n }\r\n .action-btn:hover { background: #475569; }\r\n\r\n .code-container {\r\n flex: 1;\r\n overflow: auto;\r\n }\r\n .code-container::-webkit-scrollbar { width: 5px; height: 5px; }\r\n .code-container::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\r\n\r\n .code-block {\r\n margin: 0;\r\n padding: 14px;\r\n font-family: 'Cascadia Code', 'Consolas', 'Fira Code', monospace;\r\n font-size: 11px;\r\n line-height: 1.7;\r\n color: #e2e8f0;\r\n white-space: pre;\r\n tab-size: 2;\r\n }\r\n\r\n /* Syntax Highlighting */\r\n :global(.kw) { color: #c084fc; }\r\n :global(.str) { color: #86efac; }\r\n :global(.fn) { color: #67e8f9; }\r\n :global(.cm) { color: #64748b; font-style: italic; }\r\n :global(.num) { color: #fb923c; }\r\n :global(.cy) { color: #fbbf24; font-weight: 600; }\r\n `],\r\n})\r\nexport class TestPreviewComponent {\r\n @Input() test: GeneratedTest | null = null;\r\n\r\n copied = signal(false);\r\n\r\n highlightedCode = computed(() => {\r\n if (!this.test) return '';\r\n return this.syntaxHighlight(this.test.code);\r\n });\r\n\r\n private syntaxHighlight(code: string): string {\r\n return code\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n // Comments\r\n .replace(/(\\/\\/[^\\n]*)/g, '<span class=\"cm\">$1</span>')\r\n // cy. commands\r\n .replace(/\\b(cy)\\b/g, '<span class=\"cy\">$1</span>')\r\n // Keywords\r\n .replace(/\\b(describe|it|beforeEach|afterEach|before|after|context|specify|const|let|var|function|return|import|export|from|async|await|new)\\b/g, '<span class=\"kw\">$1</span>')\r\n // Strings\r\n .replace(/('[^']*'|\"[^\"]*\"|`[^`]*`)/g, '<span class=\"str\">$1</span>')\r\n // Numbers\r\n .replace(/\\b(\\d+)\\b/g, '<span class=\"num\">$1</span>');\r\n }\r\n\r\n async copyCode(): Promise<void> {\r\n if (!this.test) return;\r\n await navigator.clipboard.writeText(this.test.code);\r\n this.copied.set(true);\r\n setTimeout(() => this.copied.set(false), 2000);\r\n }\r\n\r\n downloadCode(): void {\r\n if (!this.test) return;\r\n const blob = new Blob([this.test.code], { type: 'text/typescript' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = `cypress-test-${new Date().toISOString().slice(0, 10)}.cy.ts`;\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n formatDate(ts: number): string {\r\n return new Date(ts).toLocaleString('de-DE', {\r\n day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit',\r\n });\r\n }\r\n}\r\n","import { Component, Output, EventEmitter, inject } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { AiGeneratorService } from '../services/ai-generator.service';\r\n\r\n@Component({\r\n selector: 'app-settings-dialog',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <div class=\"overlay\" data-debug-panel (click)=\"onOverlayClick($event)\">\r\n <div class=\"dialog\" data-debug-panel>\r\n <div class=\"dialog-header\">\r\n <h2>⚙️ Einstellungen</h2>\r\n <button class=\"close-btn\" (click)=\"close.emit()\">✕</button>\r\n </div>\r\n\r\n <div class=\"dialog-body\">\r\n <div class=\"field-group\">\r\n <label>KI Webhook-URL</label>\r\n <input\r\n data-debug-panel\r\n class=\"field-input\"\r\n type=\"url\"\r\n [(ngModel)]=\"localUrl\"\r\n placeholder=\"https://deine-ki-api.de/generate\"\r\n />\r\n <p class=\"field-hint\">\r\n Die aufgezeichnete Session wird als JSON per POST an diese URL gesendet.\r\n Die Antwort wird als Cypress-Test angezeigt.\r\n </p>\r\n </div>\r\n\r\n <div class=\"info-box\">\r\n <p>📦 POST-Body: Die Session als JSON (<code>actions</code>, <code>startUrl</code>, ...)</p>\r\n <p>📄 Erwartete Antwort: Cypress-Test-Code als Plain-Text</p>\r\n <p>⌨️ Shortcuts: <kbd>Ctrl+Shift+D</kbd> Panel &nbsp; <kbd>Ctrl+Shift+R</kbd> Aufnahme</p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"dialog-footer\">\r\n <button class=\"btn-cancel\" (click)=\"close.emit()\">Abbrechen</button>\r\n <button class=\"btn-save\" (click)=\"save()\">💾 Speichern</button>\r\n </div>\r\n </div>\r\n </div>\r\n `,\r\n styles: [`\r\n .overlay {\r\n position: fixed; inset: 0; background: rgba(0,0,0,0.7);\r\n z-index: 100000; display: flex; align-items: center; justify-content: center;\r\n backdrop-filter: blur(4px);\r\n }\r\n .dialog {\r\n background: #0f172a; border: 1px solid #1e3a5f; border-radius: 12px;\r\n width: 440px; max-width: 95vw; display: flex; flex-direction: column;\r\n box-shadow: 0 25px 60px rgba(0,0,0,0.6); overflow: hidden;\r\n }\r\n .dialog-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 18px; background: #1e293b; border-bottom: 1px solid #334155;\r\n }\r\n .dialog-header h2 { margin: 0; font-size: 15px; color: #f1f5f9; font-weight: 600; }\r\n .close-btn {\r\n background: none; border: none; color: #94a3b8;\r\n cursor: pointer; font-size: 16px; padding: 4px; border-radius: 4px;\r\n }\r\n .close-btn:hover { color: #f1f5f9; background: #334155; }\r\n .dialog-body { padding: 18px; display: flex; flex-direction: column; gap: 16px; }\r\n .field-group { display: flex; flex-direction: column; gap: 6px; }\r\n label {\r\n font-size: 12px; font-weight: 600; color: #94a3b8;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .field-input {\r\n background: #1e293b; border: 1px solid #334155; color: #e2e8f0;\r\n border-radius: 6px; padding: 10px 12px; font-size: 13px;\r\n width: 100%; box-sizing: border-box;\r\n }\r\n .field-input:focus { outline: none; border-color: #3b82f6; }\r\n .field-hint { font-size: 11px; color: #64748b; margin: 0; line-height: 1.5; }\r\n .info-box {\r\n background: rgba(30,41,59,0.5); border: 1px solid #1e3a5f;\r\n border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 6px;\r\n }\r\n .info-box p { margin: 0; font-size: 11px; color: #64748b; }\r\n .info-box code {\r\n background: #1e293b; color: #34d399; padding: 1px 4px;\r\n border-radius: 3px; font-family: monospace;\r\n }\r\n kbd {\r\n background: #1e293b; border: 1px solid #334155; color: #94a3b8;\r\n padding: 1px 5px; border-radius: 3px; font-size: 10px;\r\n }\r\n .dialog-footer {\r\n display: flex; gap: 8px; justify-content: flex-end;\r\n padding: 14px 18px; background: #1e293b; border-top: 1px solid #334155;\r\n }\r\n .btn-cancel, .btn-save {\r\n padding: 8px 20px; border-radius: 6px; font-size: 13px;\r\n font-weight: 600; cursor: pointer; border: none; transition: filter 0.15s;\r\n }\r\n .btn-cancel { background: #334155; color: #94a3b8; }\r\n .btn-cancel:hover { filter: brightness(1.2); }\r\n .btn-save { background: #2563eb; color: #fff; }\r\n .btn-save:hover { filter: brightness(1.1); }\r\n `],\r\n})\r\nexport class SettingsDialogComponent {\r\n @Output() close = new EventEmitter<void>();\r\n private ai = inject(AiGeneratorService);\r\n localUrl = this.ai.webhookUrl();\r\n\r\n save(): void {\r\n this.ai.setWebhookUrl(this.localUrl.trim());\r\n this.close.emit();\r\n }\r\n\r\n onOverlayClick(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).classList.contains('overlay')) {\r\n this.close.emit();\r\n }\r\n }\r\n}\r\n","import {\r\n Component, ElementRef, ViewChild, OnDestroy, inject, signal,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\r\n\r\n@Component({\r\n selector: 'app-session-replay',\r\n standalone: true,\r\n imports: [CommonModule],\r\n template: `\r\n <div class=\"replay-panel\" data-debug-panel>\r\n <!-- Hidden file input for import -->\r\n <input\r\n #fileInput\r\n type=\"file\"\r\n accept=\".json\"\r\n style=\"display:none\"\r\n data-debug-panel\r\n (change)=\"onFileSelected($event)\"\r\n />\r\n\r\n @if (!rrweb.hasEvents()) {\r\n <div class=\"replay-empty\">\r\n <div class=\"replay-icon\">📽️</div>\r\n <p>Kein Replay verfügbar.</p>\r\n <p class=\"hint\">Starte eine Aufnahme — rrweb zeichnet den DOM parallel mit.</p>\r\n <button class=\"replay-btn import\" (click)=\"fileInput.click()\">\r\n 📂 JSON importieren\r\n </button>\r\n @if (importError()) {\r\n <p class=\"import-error\">{{ importError() }}</p>\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"replay-info\">\r\n <span class=\"event-count\">{{ rrweb.eventCount() }} Events aufgezeichnet</span>\r\n @if (importedFilename()) {\r\n <span class=\"imported-badge\">📂 {{ importedFilename() }}</span>\r\n }\r\n </div>\r\n <div class=\"replay-actions\">\r\n <button class=\"replay-btn primary\" (click)=\"openOverlay()\">\r\n ▶ Replay abspielen\r\n </button>\r\n <button class=\"replay-btn\" (click)=\"exportSession()\">\r\n 💾 JSON exportieren\r\n </button>\r\n <button class=\"replay-btn import\" (click)=\"fileInput.click()\">\r\n 📂 Importieren\r\n </button>\r\n </div>\r\n <p class=\"replay-hint\">\r\n Der Replay öffnet sich als Vollbild-Overlay über der aktuellen Seite.\r\n </p>\r\n @if (importError()) {\r\n <p class=\"import-error\">{{ importError() }}</p>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Fullscreen Replay Overlay -->\r\n @if (overlayOpen()) {\r\n <div class=\"replay-overlay\" data-debug-panel>\r\n <div class=\"overlay-header\" data-debug-panel>\r\n <span class=\"overlay-title\">📽️ Session Replay</span>\r\n <div class=\"overlay-controls\" data-debug-panel>\r\n <button class=\"ovl-btn\" (click)=\"pauseResume()\">\r\n {{ isPlaying() ? '⏸ Pause' : '▶ Play' }}\r\n </button>\r\n <button class=\"ovl-btn\" (click)=\"restart()\">⟳ Neustart</button>\r\n <button class=\"ovl-btn close-ovl\" (click)=\"closeOverlay()\">✕ Schließen</button>\r\n </div>\r\n </div>\r\n <div #replayContainer class=\"overlay-stage\" data-debug-panel></div>\r\n </div>\r\n }\r\n `,\r\n styles: [`\r\n .replay-panel {\r\n padding: 20px 16px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 14px;\r\n }\r\n\r\n .replay-empty {\r\n text-align: center;\r\n padding: 20px 0;\r\n color: #64748b;\r\n }\r\n .replay-icon { font-size: 36px; margin-bottom: 8px; }\r\n .replay-empty p { margin: 4px 0; font-size: 13px; }\r\n .hint { font-size: 11px; color: #475569; }\r\n\r\n .replay-info {\r\n background: #1e293b;\r\n border-radius: 6px;\r\n padding: 8px 12px;\r\n }\r\n .event-count { font-size: 12px; color: #6ee7b7; font-weight: 600; }\r\n\r\n .replay-actions { display: flex; gap: 8px; }\r\n .replay-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 8px 14px;\r\n border-radius: 6px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .replay-btn:hover { background: #475569; }\r\n .replay-btn.primary { background: #1d4ed8; color: #fff; }\r\n .replay-btn.primary:hover { background: #2563eb; }\r\n\r\n .replay-hint { font-size: 11px; color: #475569; margin: 0; }\r\n\r\n .replay-btn.import { background: #1e3a5f; color: #93c5fd; }\r\n .replay-btn.import:hover { background: #1e4070; }\r\n\r\n .imported-badge {\r\n font-size: 11px;\r\n color: #93c5fd;\r\n margin-left: 8px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n max-width: 150px;\r\n display: inline-block;\r\n vertical-align: middle;\r\n }\r\n\r\n .import-error {\r\n font-size: 11px;\r\n color: #fca5a5;\r\n margin: 4px 0 0;\r\n }\r\n\r\n /* ── Fullscreen Overlay ── */\r\n .replay-overlay {\r\n position: fixed;\r\n inset: 0;\r\n z-index: 99997;\r\n background: #000;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n .overlay-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 16px;\r\n background: #0f172a;\r\n border-bottom: 1px solid #1e293b;\r\n flex-shrink: 0;\r\n }\r\n .overlay-title { font-size: 14px; font-weight: 600; color: #f1f5f9; }\r\n .overlay-controls { display: flex; gap: 8px; }\r\n .ovl-btn {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #cbd5e1;\r\n padding: 5px 12px;\r\n border-radius: 5px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .ovl-btn:hover { background: #334155; }\r\n .close-ovl { color: #fca5a5; }\r\n .close-ovl:hover { background: rgba(220,38,38,0.2); }\r\n\r\n .overlay-stage {\r\n flex: 1;\r\n overflow: hidden;\r\n position: relative;\r\n background: #f8fafc;\r\n }\r\n\r\n /* Scale the rrweb iframe to fill available space */\r\n :host ::ng-deep .replayer-wrapper {\r\n position: absolute !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n transform-origin: top left !important;\r\n }\r\n :host ::ng-deep .replayer-wrapper iframe {\r\n pointer-events: none;\r\n display: block;\r\n }\r\n `],\r\n})\r\nexport class SessionReplayComponent implements OnDestroy {\r\n @ViewChild('replayContainer') replayContainer?: ElementRef<HTMLDivElement>;\r\n\r\n rrweb = inject(RrwebRecorderService);\r\n overlayOpen = signal(false);\r\n isPlaying = signal(false);\r\n importError = signal<string | null>(null);\r\n importedFilename = signal<string | null>(null);\r\n\r\n async openOverlay(): Promise<void> {\r\n this.overlayOpen.set(true);\r\n this.isPlaying.set(false);\r\n // Wait for the DOM to render the overlay\r\n await new Promise(r => setTimeout(r, 50));\r\n await this.startPlay();\r\n }\r\n\r\n closeOverlay(): void {\r\n this.rrweb.destroyReplayer();\r\n this.overlayOpen.set(false);\r\n this.isPlaying.set(false);\r\n }\r\n\r\n async pauseResume(): Promise<void> {\r\n if (this.isPlaying()) {\r\n this.rrweb.pauseReplay();\r\n this.isPlaying.set(false);\r\n } else {\r\n this.rrweb.resumeReplay();\r\n this.isPlaying.set(true);\r\n }\r\n }\r\n\r\n async restart(): Promise<void> {\r\n this.rrweb.destroyReplayer();\r\n await new Promise(r => setTimeout(r, 50));\r\n await this.startPlay();\r\n }\r\n\r\n exportSession(): void {\r\n this.rrweb.downloadEvents();\r\n }\r\n\r\n onFileSelected(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n const file = input.files?.[0];\r\n if (!file) return;\r\n\r\n // Reset input so the same file can be re-selected after clearing\r\n input.value = '';\r\n\r\n this.importError.set(null);\r\n\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n try {\r\n const events = this.rrweb.importEvents(reader.result as string);\r\n if (events.length === 0) {\r\n this.importError.set('Keine Events in der Datei gefunden.');\r\n this.importedFilename.set(null);\r\n } else {\r\n this.importedFilename.set(file.name);\r\n }\r\n } catch {\r\n this.importError.set('Ungültiges JSON-Format.');\r\n this.importedFilename.set(null);\r\n }\r\n };\r\n reader.onerror = () => this.importError.set('Datei konnte nicht gelesen werden.');\r\n reader.readAsText(file);\r\n }\r\n\r\n private async startPlay(): Promise<void> {\r\n if (!this.replayContainer) return;\r\n const container = this.replayContainer.nativeElement;\r\n\r\n await this.rrweb.startReplay(container);\r\n\r\n // Scale iframe to fill the stage container\r\n this.scaleReplayer(container);\r\n this.isPlaying.set(true);\r\n }\r\n\r\n private scaleReplayer(container: HTMLElement): void {\r\n // rrweb injects .replayer-wrapper with an iframe sized to the recorded viewport\r\n setTimeout(() => {\r\n const wrapper = container.querySelector('.replayer-wrapper') as HTMLElement;\r\n if (!wrapper) return;\r\n\r\n const iframe = wrapper.querySelector('iframe') as HTMLIFrameElement;\r\n const wrapW = iframe?.offsetWidth || wrapper.offsetWidth || 1280;\r\n const wrapH = iframe?.offsetHeight || wrapper.offsetHeight || 720;\r\n const stageW = container.offsetWidth;\r\n const stageH = container.offsetHeight;\r\n\r\n if (!stageW || !stageH || !wrapW || !wrapH) return;\r\n\r\n const scale = Math.min(stageW / wrapW, stageH / wrapH);\r\n const offsetX = (stageW - wrapW * scale) / 2;\r\n const offsetY = (stageH - wrapH * scale) / 2;\r\n\r\n wrapper.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n }, 300);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.rrweb.destroyReplayer();\r\n }\r\n}\r\n","import {\r\n Component, signal, computed, inject, OnInit, OnDestroy,\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { RecorderService } from '../services/recorder.service';\r\nimport { AiGeneratorService } from '../services/ai-generator.service';\r\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\r\nimport { RecordingSession } from '../models/recorded-action.model';\r\nimport { ActionListComponent } from '../action-list/action-list.component';\r\nimport { TestPreviewComponent } from '../test-preview/test-preview.component';\r\nimport { SettingsDialogComponent } from '../settings-dialog/settings-dialog.component';\r\nimport { SessionReplayComponent } from '../session-replay/session-replay.component';\r\n\r\ntype PanelTab = 'actions' | 'test' | 'sessions' | 'replay';\r\ntype PanelPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\r\n\r\n@Component({\r\n selector: 'app-debug-panel',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule, ActionListComponent, TestPreviewComponent, SettingsDialogComponent, SessionReplayComponent],\r\n template: `\r\n <!-- Toggle FAB -->\r\n <button\r\n data-debug-panel\r\n class=\"debug-fab\"\r\n [class.recording]=\"recorder.isRecording()\"\r\n [class.pulse]=\"recorder.isRecording() && !recorder.isPaused()\"\r\n (click)=\"togglePanel()\"\r\n [title]=\"panelOpen() ? 'Debug Panel schließen' : 'Debug Panel öffnen'\"\r\n >\r\n <span class=\"fab-icon\">{{ recorder.isRecording() ? '⏺' : '🐛' }}</span>\r\n @if (recorder.isRecording() && recorder.actionCount() > 0) {\r\n <span class=\"fab-badge\">{{ recorder.actionCount() }}</span>\r\n }\r\n </button>\r\n\r\n <!-- Main Panel -->\r\n @if (panelOpen()) {\r\n <div\r\n data-debug-panel\r\n class=\"debug-panel\"\r\n [class]=\"'pos-' + position()\"\r\n [style.width.px]=\"panelWidth()\"\r\n >\r\n <!-- Header -->\r\n <div class=\"panel-header\" (mousedown)=\"startDrag($event)\">\r\n <div class=\"header-left\">\r\n <span class=\"panel-icon\">🐛</span>\r\n <span class=\"panel-title\">Debug Recorder</span>\r\n @if (recorder.isRecording()) {\r\n <span class=\"rec-indicator\" [class.paused]=\"recorder.isPaused()\">\r\n {{ recorder.isPaused() ? '⏸ PAUSED' : '⏺ REC' }}\r\n </span>\r\n }\r\n </div>\r\n <div class=\"header-actions\">\r\n <button class=\"icon-btn\" title=\"Einstellungen\" (click)=\"showSettings.set(true)\">⚙️</button>\r\n <button class=\"icon-btn\" title=\"Position wechseln\" (click)=\"cyclePosition()\">📌</button>\r\n <button class=\"icon-btn\" title=\"Schließen\" (click)=\"togglePanel()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Session Name Input (only when not recording) -->\r\n @if (!recorder.isRecording()) {\r\n <div class=\"session-setup\">\r\n <input\r\n data-debug-panel\r\n class=\"session-input\"\r\n type=\"text\"\r\n [(ngModel)]=\"sessionName\"\r\n placeholder=\"Session-Name (optional)\"\r\n />\r\n <textarea\r\n data-debug-panel\r\n class=\"session-desc\"\r\n [(ngModel)]=\"sessionDesc\"\r\n placeholder=\"Fehlerbeschreibung...\"\r\n rows=\"2\"\r\n ></textarea>\r\n </div>\r\n }\r\n\r\n <!-- Recording Controls -->\r\n <div class=\"recording-controls\" data-debug-panel>\r\n @if (!recorder.isRecording()) {\r\n <button class=\"ctrl-btn start\" (click)=\"startRecording()\">\r\n ▶ Aufnahme starten\r\n </button>\r\n } @else {\r\n <button class=\"ctrl-btn pause\" (click)=\"recorder.pauseRecording()\">\r\n {{ recorder.isPaused() ? '▶ Fortsetzen' : '⏸ Pause' }}\r\n </button>\r\n <button class=\"ctrl-btn stop\" (click)=\"stopRecording()\">\r\n ⏹ Stoppen\r\n </button>\r\n <button class=\"ctrl-btn clear\" title=\"Aktionen löschen\" (click)=\"recorder.clearCurrentSession()\">\r\n 🗑\r\n </button>\r\n }\r\n\r\n @if (hasActions()) {\r\n <button\r\n class=\"ctrl-btn generate\"\r\n [disabled]=\"aiService.isGenerating() || !aiService.webhookUrl()\"\r\n [title]=\"!aiService.webhookUrl() ? 'Webhook-URL in Einstellungen eintragen' : 'Cypress Test generieren'\"\r\n (click)=\"generateTest()\"\r\n >\r\n @if (aiService.isGenerating()) {\r\n <span class=\"spinner\">⟳</span> Generiere...\r\n } @else {\r\n 🤖 → Cypress Test\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Error Banner -->\r\n @if (aiService.error()) {\r\n <div class=\"error-banner\" data-debug-panel>\r\n ⚠️ {{ aiService.error() }}\r\n </div>\r\n }\r\n\r\n <!-- Tabs -->\r\n <div class=\"tab-bar\" data-debug-panel>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'actions'\"\r\n (click)=\"activeTab.set('actions')\"\r\n >\r\n Aktionen\r\n @if (recorder.actionCount() > 0) {\r\n <span class=\"tab-badge\">{{ recorder.actionCount() }}</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'replay'\"\r\n (click)=\"activeTab.set('replay')\"\r\n title=\"rrweb Session Replay\"\r\n >\r\n 📽️ Replay\r\n @if (rrweb.eventCount() > 0) {\r\n <span class=\"tab-badge\">{{ rrweb.eventCount() }}</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'test'\"\r\n [disabled]=\"!aiService.lastTest()\"\r\n (click)=\"activeTab.set('test')\"\r\n >\r\n 🤖 Test\r\n @if (aiService.lastTest()) {\r\n <span class=\"tab-badge new\">NEU</span>\r\n }\r\n </button>\r\n <button\r\n class=\"tab-btn\"\r\n [class.active]=\"activeTab() === 'sessions'\"\r\n [disabled]=\"recorder.sessions().length === 0\"\r\n (click)=\"activeTab.set('sessions')\"\r\n >\r\n Sessions ({{ recorder.sessions().length }})\r\n </button>\r\n </div>\r\n\r\n <!-- Tab Content -->\r\n <div class=\"tab-content\">\r\n @if (activeTab() === 'actions') {\r\n <app-action-list\r\n [session]=\"recorder.currentSession()\"\r\n (removeAction)=\"recorder.removeAction($event)\"\r\n (addNote)=\"recorder.addNote($event.id, $event.note)\"\r\n />\r\n }\r\n\r\n @if (activeTab() === 'replay') {\r\n <app-session-replay />\r\n }\r\n\r\n @if (activeTab() === 'test') {\r\n <app-test-preview [test]=\"aiService.lastTest()\" />\r\n }\r\n\r\n @if (activeTab() === 'sessions') {\r\n <div class=\"sessions-list\">\r\n @for (session of recorder.sessions(); track session.id) {\r\n <div class=\"session-card\">\r\n <div class=\"session-card-header\">\r\n <span class=\"session-name\">{{ session.name }}</span>\r\n <span class=\"session-meta\">{{ session.actions.length }} Aktionen</span>\r\n </div>\r\n <div class=\"session-card-actions\">\r\n <button class=\"sm-btn\" (click)=\"loadAndGenerate(session)\">🤖 Neu generieren</button>\r\n <button class=\"sm-btn danger\" (click)=\"recorder.deleteSession(session.id)\">🗑</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Resize Handle -->\r\n <div class=\"resize-handle\" (mousedown)=\"startResize($event)\">⠿</div>\r\n </div>\r\n }\r\n\r\n <!-- Settings Dialog -->\r\n @if (showSettings()) {\r\n <app-settings-dialog (close)=\"showSettings.set(false)\" />\r\n }\r\n `,\r\n styles: [`\r\n .debug-fab {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: 99999;\r\n width: 52px;\r\n height: 52px;\r\n border-radius: 50%;\r\n border: none;\r\n background: #1e293b;\r\n color: white;\r\n font-size: 22px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\r\n transition: transform 0.2s, background 0.2s;\r\n position: fixed;\r\n }\r\n .debug-fab:hover { transform: scale(1.1); background: #334155; }\r\n .debug-fab.recording { background: #dc2626; }\r\n .debug-fab.pulse { animation: fabPulse 1.5s ease-in-out infinite; }\r\n @keyframes fabPulse {\r\n 0%, 100% { box-shadow: 0 4px 20px rgba(220,38,38,0.4); }\r\n 50% { box-shadow: 0 4px 30px rgba(220,38,38,0.9), 0 0 0 8px rgba(220,38,38,0.15); }\r\n }\r\n .fab-badge {\r\n position: absolute;\r\n top: -4px;\r\n right: -4px;\r\n background: #f59e0b;\r\n color: #000;\r\n font-size: 10px;\r\n font-weight: 700;\r\n min-width: 18px;\r\n height: 18px;\r\n border-radius: 9px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 0 4px;\r\n }\r\n\r\n .debug-panel {\r\n position: fixed;\r\n z-index: 99998;\r\n width: 420px;\r\n max-height: 80vh;\r\n background: #0f172a;\r\n color: #e2e8f0;\r\n border-radius: 12px;\r\n border: 1px solid #1e3a5f;\r\n box-shadow: 0 25px 60px rgba(0,0,0,0.6);\r\n display: flex;\r\n flex-direction: column;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n font-size: 13px;\r\n overflow: hidden;\r\n }\r\n .pos-bottom-right { bottom: 88px; right: 24px; }\r\n .pos-bottom-left { bottom: 88px; left: 24px; }\r\n .pos-top-right { top: 24px; right: 24px; }\r\n .pos-top-left { top: 24px; left: 24px; }\r\n\r\n .panel-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 10px 14px;\r\n background: #1e293b;\r\n border-bottom: 1px solid #334155;\r\n cursor: move;\r\n user-select: none;\r\n flex-shrink: 0;\r\n }\r\n .header-left { display: flex; align-items: center; gap: 8px; }\r\n .panel-icon { font-size: 16px; }\r\n .panel-title { font-weight: 600; font-size: 14px; color: #f1f5f9; }\r\n .rec-indicator {\r\n font-size: 10px;\r\n font-weight: 700;\r\n color: #ef4444;\r\n background: rgba(239,68,68,0.15);\r\n padding: 2px 7px;\r\n border-radius: 4px;\r\n animation: blink 1s step-end infinite;\r\n }\r\n .rec-indicator.paused { color: #f59e0b; background: rgba(245,158,11,0.15); animation: none; }\r\n @keyframes blink { 50% { opacity: 0.4; } }\r\n .header-actions { display: flex; gap: 4px; }\r\n .icon-btn {\r\n background: none;\r\n border: none;\r\n color: #94a3b8;\r\n cursor: pointer;\r\n padding: 4px;\r\n border-radius: 4px;\r\n font-size: 14px;\r\n line-height: 1;\r\n transition: color 0.15s, background 0.15s;\r\n }\r\n .icon-btn:hover { color: #f1f5f9; background: #334155; }\r\n\r\n .session-setup {\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #1e293b;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n flex-shrink: 0;\r\n }\r\n .session-input, .session-desc {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n color: #e2e8f0;\r\n border-radius: 6px;\r\n padding: 6px 10px;\r\n font-size: 12px;\r\n width: 100%;\r\n box-sizing: border-box;\r\n resize: vertical;\r\n }\r\n .session-input:focus, .session-desc:focus {\r\n outline: none;\r\n border-color: #3b82f6;\r\n }\r\n\r\n .recording-controls {\r\n display: flex;\r\n gap: 6px;\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #1e293b;\r\n flex-wrap: wrap;\r\n flex-shrink: 0;\r\n }\r\n .ctrl-btn {\r\n border: none;\r\n border-radius: 6px;\r\n padding: 6px 14px;\r\n font-size: 12px;\r\n font-weight: 600;\r\n cursor: pointer;\r\n transition: filter 0.15s, transform 0.1s;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n }\r\n .ctrl-btn:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); }\r\n .ctrl-btn:active:not(:disabled) { transform: translateY(0); }\r\n .ctrl-btn:disabled { opacity: 0.5; cursor: not-allowed; }\r\n .ctrl-btn.start { background: #16a34a; color: #fff; }\r\n .ctrl-btn.stop { background: #dc2626; color: #fff; }\r\n .ctrl-btn.pause { background: #d97706; color: #fff; }\r\n .ctrl-btn.generate { background: #7c3aed; color: #fff; flex: 1; justify-content: center; }\r\n .ctrl-btn.clear { background: #374151; color: #9ca3af; padding: 6px 10px; }\r\n .spinner { display: inline-block; animation: spin 0.8s linear infinite; }\r\n @keyframes spin { to { transform: rotate(360deg); } }\r\n\r\n .error-banner {\r\n background: rgba(220,38,38,0.15);\r\n border-left: 3px solid #dc2626;\r\n color: #fca5a5;\r\n padding: 8px 14px;\r\n font-size: 12px;\r\n flex-shrink: 0;\r\n }\r\n\r\n .tab-bar {\r\n display: flex;\r\n border-bottom: 1px solid #1e293b;\r\n flex-shrink: 0;\r\n }\r\n .tab-btn {\r\n flex: 1;\r\n background: none;\r\n border: none;\r\n color: #64748b;\r\n padding: 8px 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n border-bottom: 2px solid transparent;\r\n transition: color 0.15s;\r\n }\r\n .tab-btn:hover:not(:disabled) { color: #cbd5e1; }\r\n .tab-btn.active { color: #60a5fa; border-bottom-color: #3b82f6; }\r\n .tab-btn:disabled { opacity: 0.4; cursor: not-allowed; }\r\n .tab-badge {\r\n background: #334155;\r\n color: #94a3b8;\r\n font-size: 10px;\r\n padding: 1px 5px;\r\n border-radius: 3px;\r\n }\r\n .tab-badge.new { background: #7c3aed; color: #e9d5ff; }\r\n\r\n .tab-content {\r\n overflow-y: auto;\r\n flex: 1;\r\n min-height: 0;\r\n }\r\n .tab-content::-webkit-scrollbar { width: 5px; }\r\n .tab-content::-webkit-scrollbar-track { background: transparent; }\r\n .tab-content::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\r\n\r\n .sessions-list { padding: 10px 14px; display: flex; flex-direction: column; gap: 8px; }\r\n .session-card {\r\n background: #1e293b;\r\n border: 1px solid #334155;\r\n border-radius: 8px;\r\n padding: 10px;\r\n }\r\n .session-card-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 8px;\r\n }\r\n .session-name { font-weight: 600; color: #f1f5f9; font-size: 13px; }\r\n .session-meta { font-size: 11px; color: #64748b; }\r\n .session-card-actions { display: flex; gap: 6px; }\r\n .sm-btn {\r\n background: #334155;\r\n border: none;\r\n color: #cbd5e1;\r\n padding: 4px 10px;\r\n border-radius: 5px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n }\r\n .sm-btn:hover { background: #475569; }\r\n .sm-btn.danger { color: #fca5a5; }\r\n .sm-btn.danger:hover { background: rgba(220,38,38,0.2); }\r\n\r\n .resize-handle {\r\n text-align: center;\r\n color: #334155;\r\n cursor: ns-resize;\r\n font-size: 16px;\r\n padding: 2px;\r\n flex-shrink: 0;\r\n background: #0f172a;\r\n user-select: none;\r\n }\r\n .resize-handle:hover { color: #64748b; }\r\n `],\r\n})\r\nexport class DebugPanelComponent implements OnInit, OnDestroy {\r\n recorder = inject(RecorderService);\r\n aiService = inject(AiGeneratorService);\r\n rrweb = inject(RrwebRecorderService);\r\n\r\n panelOpen = signal(false);\r\n activeTab = signal<PanelTab>('actions');\r\n position = signal<PanelPosition>('bottom-right');\r\n panelWidth = signal(420);\r\n showSettings = signal(false);\r\n sessionName = '';\r\n sessionDesc = '';\r\n\r\n hasActions = computed(\r\n () => (this.recorder.currentSession()?.actions.length ?? 0) > 0 ||\r\n (this.recorder.sessions().length > 0)\r\n );\r\n\r\n private resizing = false;\r\n private resizeStartY = 0;\r\n private resizeStartH = 0;\r\n\r\n ngOnInit(): void {\r\n // Keyboard shortcut: Ctrl+Shift+D\r\n document.addEventListener('keydown', this.handleHotkey);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n document.removeEventListener('keydown', this.handleHotkey);\r\n }\r\n\r\n private handleHotkey = (e: KeyboardEvent) => {\r\n if (e.ctrlKey && e.shiftKey && e.key === 'D') {\r\n e.preventDefault();\r\n this.togglePanel();\r\n }\r\n if (e.ctrlKey && e.shiftKey && e.key === 'R') {\r\n e.preventDefault();\r\n if (this.recorder.isRecording()) {\r\n this.stopRecording();\r\n } else {\r\n this.startRecording();\r\n }\r\n }\r\n };\r\n\r\n togglePanel(): void {\r\n this.panelOpen.update(v => !v);\r\n if (this.panelOpen() && !this.recorder.currentSession()) {\r\n this.activeTab.set('actions');\r\n }\r\n }\r\n\r\n cyclePosition(): void {\r\n const positions: PanelPosition[] = ['bottom-right', 'bottom-left', 'top-right', 'top-left'];\r\n const idx = positions.indexOf(this.position());\r\n this.position.set(positions[(idx + 1) % positions.length]);\r\n }\r\n\r\n startRecording(): void {\r\n this.recorder.startRecording(\r\n this.sessionName || undefined,\r\n this.sessionDesc || undefined\r\n );\r\n // Start rrweb in parallel for visual replay\r\n this.rrweb.startRecording();\r\n this.activeTab.set('actions');\r\n }\r\n\r\n stopRecording(): void {\r\n const session = this.recorder.stopRecording();\r\n this.rrweb.stopRecording();\r\n if (session) {\r\n this.activeTab.set('actions');\r\n }\r\n }\r\n\r\n async generateTest(): Promise<void> {\r\n const session = this.recorder.currentSession() ?? this.recorder.sessions().at(-1);\r\n if (!session) return;\r\n await this.aiService.generateCypressTest(session);\r\n this.activeTab.set('test');\r\n }\r\n\r\n async loadAndGenerate(session: RecordingSession): Promise<void> {\r\n await this.aiService.generateCypressTest(session);\r\n this.activeTab.set('test');\r\n }\r\n\r\n // Drag to reposition\r\n startDrag(e: MouseEvent): void {\r\n if ((e.target as HTMLElement).closest('button')) return;\r\n const panel = (e.currentTarget as HTMLElement).parentElement!;\r\n const startX = e.clientX - panel.getBoundingClientRect().left;\r\n const startY = e.clientY - panel.getBoundingClientRect().top;\r\n\r\n const onMove = (ev: MouseEvent) => {\r\n panel.style.left = `${ev.clientX - startX}px`;\r\n panel.style.top = `${ev.clientY - startY}px`;\r\n panel.style.right = 'auto';\r\n panel.style.bottom = 'auto';\r\n };\r\n const onUp = () => {\r\n document.removeEventListener('mousemove', onMove);\r\n document.removeEventListener('mouseup', onUp);\r\n };\r\n document.addEventListener('mousemove', onMove);\r\n document.addEventListener('mouseup', onUp);\r\n }\r\n\r\n // Resize height\r\n startResize(e: MouseEvent): void {\r\n const panel = (e.currentTarget as HTMLElement).parentElement!;\r\n this.resizeStartY = e.clientY;\r\n this.resizeStartH = panel.getBoundingClientRect().height;\r\n\r\n const onMove = (ev: MouseEvent) => {\r\n const newH = Math.max(250, this.resizeStartH + (ev.clientY - this.resizeStartY));\r\n panel.style.maxHeight = `${newH}px`;\r\n };\r\n const onUp = () => {\r\n document.removeEventListener('mousemove', onMove);\r\n document.removeEventListener('mouseup', onUp);\r\n };\r\n document.addEventListener('mousemove', onMove);\r\n document.addEventListener('mouseup', onUp);\r\n e.preventDefault();\r\n }\r\n}\r\n","/*\r\n * Public API Surface of debug-recorder\r\n */\r\n\r\n// Main entry component — add this to your Angular app\r\nexport * from './lib/debug-panel/debug-panel.component';\r\n\r\n// Sub-components (if you need them individually)\r\nexport * from './lib/action-list/action-list.component';\r\nexport * from './lib/test-preview/test-preview.component';\r\nexport * from './lib/session-replay/session-replay.component';\r\nexport * from './lib/settings-dialog/settings-dialog.component';\r\n\r\n// Services\r\nexport * from './lib/services/recorder.service';\r\nexport * from './lib/services/ai-generator.service';\r\nexport * from './lib/services/rrweb-recorder.service';\r\n\r\n// Models / interfaces\r\nexport * from './lib/models/recorded-action.model';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1"],"mappings":"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"}