angular-debug-recorder 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -13
- package/esm2022/lib/action-list/action-list.component.mjs +161 -161
- package/esm2022/lib/debug-panel/debug-panel.component.mjs +385 -385
- package/esm2022/lib/services/rrweb-recorder.service.mjs +32 -21
- package/esm2022/lib/session-replay/session-replay.component.mjs +85 -85
- package/esm2022/lib/settings-dialog/settings-dialog.component.mjs +75 -75
- package/esm2022/lib/test-preview/test-preview.component.mjs +59 -59
- package/fesm2022/angular-debug-recorder.mjs +791 -780
- package/fesm2022/angular-debug-recorder.mjs.map +1 -1
- package/lib/services/rrweb-recorder.service.d.ts +5 -4
- package/package.json +1 -1
|
@@ -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 private _events = signal<eventWithTime[]>([]);\r\n private _isRecording = signal(false);\r\n private stopFn?: () => void;\r\n private replayer?: any;\r\n\r\n events = this._events.asReadonly();\r\n isRecording = this._isRecording.asReadonly();\r\n\r\n constructor(private zone: NgZone) {}\r\n\r\n async startRecording(): Promise<void> {\r\n // Dynamically import rrweb to avoid SSR issues and reduce initial bundle\r\n const { record } = await import('rrweb');\r\n this._events.set([]);\r\n this._isRecording.set(true);\r\n\r\n this.stopFn = record({\r\n emit: (event: eventWithTime) => {\r\n this.zone.run(() => {\r\n this._events.update(ev => [...ev, event]);\r\n });\r\n },\r\n // Note: blockSelector is omitted — rrweb 2.0.0-alpha.4 calls node.matches()\r\n // on TextNodes/CommentNodes which don't have that method, crashing 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 return this._events();\r\n }\r\n\r\n getEvents(): eventWithTime[] {\r\n return this._events();\r\n }\r\n\r\n clearEvents(): void {\r\n this._events.set([]);\r\n }\r\n\r\n hasEvents(): boolean {\r\n return this._events().length > 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._events();\r\n\r\n if (eventsToReplay.length === 0) return;\r\n\r\n // Destroy previous replayer\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._events(), 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._events.set(events);\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';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RecordedAction, RecordingSession } from '../models/recorded-action.model';\n\n@Component({\n selector: 'app-action-list',\n standalone: true,\n imports: [CommonModule, FormsModule],\n template: `\n <div class=\"action-list\" data-debug-panel>\n @if (!session || session.actions.length === 0) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">🎬</div>\n <p>Noch keine Aktionen aufgezeichnet.</p>\n <p class=\"hint\">Starte die Aufnahme und interagiere mit der App.</p>\n <div class=\"shortcuts-hint\">\n <kbd>Ctrl+Shift+D</kbd> Panel \n <kbd>Ctrl+Shift+R</kbd> Record\n </div>\n </div>\n } @else {\n <div class=\"list-header\">\n <span class=\"list-count\">{{ session.actions.length }} Aktionen</span>\n <span class=\"list-duration\">\n @if (session.endTime) {\n {{ formatDuration(session.startTime, session.endTime) }}\n } @else {\n Live\n }\n </span>\n </div>\n\n @for (action of session.actions; track action.id; let i = $index) {\n <div class=\"action-item\" [class.expanded]=\"expandedId() === action.id\">\n <div class=\"action-row\" (click)=\"toggleExpand(action.id)\">\n <span class=\"action-index\">{{ i + 1 }}</span>\n <span class=\"action-type-badge\" [class]=\"'type-' + action.type\">\n {{ getActionIcon(action.type) }}\n </span>\n <div class=\"action-info\">\n <span class=\"action-desc\">{{ action.description }}</span>\n <span class=\"action-selector\">{{ action.selector }}</span>\n </div>\n <span class=\"action-time\">{{ formatTime(action.timestamp) }}</span>\n <button\n class=\"remove-btn\"\n data-debug-panel\n title=\"Aktion entfernen\"\n (click)=\"onRemove(action.id, $event)\"\n >✕</button>\n </div>\n\n @if (expandedId() === action.id) {\n <div class=\"action-detail\" data-debug-panel>\n <div class=\"detail-grid\">\n <span class=\"detail-label\">Selector</span>\n <code class=\"detail-value\">{{ action.selector }}</code>\n @if (action.value) {\n <span class=\"detail-label\">Wert</span>\n <code class=\"detail-value\">{{ action.value }}</code>\n }\n @if (action.element?.tagName) {\n <span class=\"detail-label\">Element</span>\n <code class=\"detail-value\"><{{ action.element?.tagName }}></code>\n }\n <span class=\"detail-label\">Strategie</span>\n <span class=\"detail-value strategy-badge\" [class]=\"'strat-' + action.selectorStrategy\">\n {{ action.selectorStrategy }}\n </span>\n <span class=\"detail-label\">URL</span>\n <code class=\"detail-value url-val\">{{ action.url }}</code>\n </div>\n <div class=\"note-area\">\n <textarea\n data-debug-panel\n class=\"note-input\"\n [(ngModel)]=\"noteMap[action.id]\"\n placeholder=\"Notiz zu dieser Aktion...\"\n rows=\"2\"\n (blur)=\"onAddNote(action.id)\"\n ></textarea>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n `,\n styles: [`\n .action-list { padding: 0; }\n\n .empty-state {\n text-align: center;\n padding: 32px 20px;\n color: #64748b;\n }\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\n .empty-state p { margin: 4px 0; font-size: 13px; }\n .hint { font-size: 11px; color: #475569; }\n .shortcuts-hint {\n margin-top: 12px;\n font-size: 11px;\n color: #475569;\n }\n kbd {\n background: #1e293b;\n border: 1px solid #334155;\n color: #94a3b8;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 10px;\n }\n\n .list-header {\n display: flex;\n justify-content: space-between;\n padding: 8px 14px;\n font-size: 11px;\n color: #64748b;\n background: #0f172a;\n border-bottom: 1px solid #1e293b;\n position: sticky;\n top: 0;\n }\n\n .action-item {\n border-bottom: 1px solid #1e293b;\n transition: background 0.1s;\n }\n .action-item:hover { background: rgba(30,41,59,0.5); }\n .action-item.expanded { background: #1e293b; }\n\n .action-row {\n display: flex;\n align-items: center;\n padding: 8px 10px;\n gap: 8px;\n cursor: pointer;\n }\n .action-index {\n color: #475569;\n font-size: 10px;\n min-width: 18px;\n text-align: right;\n }\n .action-type-badge {\n font-size: 14px;\n min-width: 20px;\n text-align: center;\n }\n .action-info {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n }\n .action-desc {\n font-size: 12px;\n color: #cbd5e1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .action-selector {\n font-size: 10px;\n color: #64748b;\n font-family: 'Cascadia Code', 'Consolas', monospace;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .action-time {\n font-size: 10px;\n color: #475569;\n white-space: nowrap;\n }\n .remove-btn {\n background: none;\n border: none;\n color: #475569;\n cursor: pointer;\n font-size: 12px;\n padding: 2px 5px;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.15s, color 0.15s;\n }\n .action-row:hover .remove-btn { opacity: 1; }\n .remove-btn:hover { color: #f87171; }\n\n .action-detail {\n padding: 10px 14px;\n background: rgba(15,23,42,0.7);\n border-top: 1px solid #1e293b;\n }\n .detail-grid {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 10px;\n margin-bottom: 8px;\n align-items: start;\n }\n .detail-label { font-size: 10px; color: #64748b; padding-top: 2px; white-space: nowrap; }\n .detail-value {\n font-size: 11px;\n color: #93c5fd;\n font-family: 'Cascadia Code', 'Consolas', monospace;\n word-break: break-all;\n }\n .url-val { color: #6ee7b7; }\n .strategy-badge {\n font-size: 10px;\n padding: 1px 6px;\n border-radius: 3px;\n font-family: monospace;\n }\n .strat-data-testid { background: #064e3b; color: #34d399; }\n .strat-data-cy { background: #064e3b; color: #34d399; }\n .strat-id { background: #1e3a8a; color: #93c5fd; }\n .strat-name { background: #44337a; color: #c4b5fd; }\n .strat-class { background: #374151; color: #9ca3af; }\n .strat-combined { background: #292524; color: #d6d3d1; }\n\n .note-area { margin-top: 6px; }\n .note-input {\n width: 100%;\n box-sizing: border-box;\n background: #0f172a;\n border: 1px solid #334155;\n color: #e2e8f0;\n border-radius: 5px;\n padding: 6px 8px;\n font-size: 11px;\n resize: vertical;\n }\n .note-input:focus { outline: none; border-color: #3b82f6; }\n `],\n})\nexport class ActionListComponent {\n @Input() session: RecordingSession | null = null;\n @Output() removeAction = new EventEmitter<string>();\n @Output() addNote = new EventEmitter<{ id: string; note: string }>();\n\n expandedId = signal<string | null>(null);\n noteMap: Record<string, string> = {};\n\n toggleExpand(id: string): void {\n this.expandedId.update(v => v === id ? null : id);\n }\n\n onRemove(id: string, e: Event): void {\n e.stopPropagation();\n this.removeAction.emit(id);\n }\n\n onAddNote(id: string): void {\n this.addNote.emit({ id, note: this.noteMap[id] ?? '' });\n }\n\n getActionIcon(type: string): string {\n const icons: Record<string, string> = {\n click: '👆',\n dblclick: '👆👆',\n input: '⌨️',\n select: '📋',\n submit: '📤',\n navigation: '🔗',\n keypress: '⌨️',\n scroll: '↕️',\n hover: '🖱️',\n assertion: '✅',\n screenshot: '📸',\n };\n return icons[type] ?? '•';\n }\n\n formatTime(ts: number): string {\n return new Date(ts).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n }\n\n formatDuration(start: number, end: number): string {\n const s = Math.round((end - start) / 1000);\n return s < 60 ? `${s}s` : `${Math.floor(s/60)}m ${s%60}s`;\n }\n}\n","import { Component, Input, signal, computed } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { GeneratedTest } from '../models/recorded-action.model';\n\n@Component({\n selector: 'app-test-preview',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"test-preview\" data-debug-panel>\n @if (!test) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">🤖</div>\n <p>Noch kein Test generiert.</p>\n <p class=\"hint\">Zeichne Aktionen auf und klicke „🤖 → Cypress Test\".</p>\n </div>\n } @else {\n <div class=\"test-toolbar\" data-debug-panel>\n <div class=\"test-meta\">\n <span class=\"model-tag\">{{ test.model }}</span>\n <span class=\"gen-time\">{{ formatDate(test.generatedAt) }}</span>\n </div>\n <div class=\"test-actions\">\n <button class=\"action-btn\" title=\"Kopieren\" (click)=\"copyCode()\">\n {{ copied() ? '✅ Kopiert!' : '📋 Kopieren' }}\n </button>\n <button class=\"action-btn\" title=\"Herunterladen\" (click)=\"downloadCode()\">\n 💾 Download\n </button>\n </div>\n </div>\n\n <div class=\"code-container\">\n <pre class=\"code-block\"><code [innerHTML]=\"highlightedCode()\"></code></pre>\n </div>\n }\n </div>\n `,\n styles: [`\n .test-preview { height: 100%; display: flex; flex-direction: column; }\n\n .empty-state {\n text-align: center;\n padding: 32px 20px;\n color: #64748b;\n }\n .empty-icon { font-size: 40px; margin-bottom: 10px; }\n .empty-state p { margin: 4px 0; font-size: 13px; }\n .hint { font-size: 11px; color: #475569; }\n\n .test-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #1e293b;\n border-bottom: 1px solid #334155;\n flex-shrink: 0;\n gap: 8px;\n }\n .test-meta { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n .model-tag {\n background: #312e81;\n color: #a5b4fc;\n font-size: 10px;\n padding: 2px 7px;\n border-radius: 4px;\n font-weight: 600;\n white-space: nowrap;\n }\n .gen-time { font-size: 10px; color: #64748b; white-space: nowrap; }\n .test-actions { display: flex; gap: 6px; flex-shrink: 0; }\n .action-btn {\n background: #334155;\n border: none;\n color: #cbd5e1;\n padding: 4px 10px;\n border-radius: 5px;\n font-size: 11px;\n cursor: pointer;\n white-space: nowrap;\n transition: background 0.15s;\n }\n .action-btn:hover { background: #475569; }\n\n .code-container {\n flex: 1;\n overflow: auto;\n }\n .code-container::-webkit-scrollbar { width: 5px; height: 5px; }\n .code-container::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\n\n .code-block {\n margin: 0;\n padding: 14px;\n font-family: 'Cascadia Code', 'Consolas', 'Fira Code', monospace;\n font-size: 11px;\n line-height: 1.7;\n color: #e2e8f0;\n white-space: pre;\n tab-size: 2;\n }\n\n /* Syntax Highlighting */\n :global(.kw) { color: #c084fc; }\n :global(.str) { color: #86efac; }\n :global(.fn) { color: #67e8f9; }\n :global(.cm) { color: #64748b; font-style: italic; }\n :global(.num) { color: #fb923c; }\n :global(.cy) { color: #fbbf24; font-weight: 600; }\n `],\n})\nexport class TestPreviewComponent {\n @Input() test: GeneratedTest | null = null;\n\n copied = signal(false);\n\n highlightedCode = computed(() => {\n if (!this.test) return '';\n return this.syntaxHighlight(this.test.code);\n });\n\n private syntaxHighlight(code: string): string {\n return code\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n // Comments\n .replace(/(\\/\\/[^\\n]*)/g, '<span class=\"cm\">$1</span>')\n // cy. commands\n .replace(/\\b(cy)\\b/g, '<span class=\"cy\">$1</span>')\n // Keywords\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>')\n // Strings\n .replace(/('[^']*'|\"[^\"]*\"|`[^`]*`)/g, '<span class=\"str\">$1</span>')\n // Numbers\n .replace(/\\b(\\d+)\\b/g, '<span class=\"num\">$1</span>');\n }\n\n async copyCode(): Promise<void> {\n if (!this.test) return;\n await navigator.clipboard.writeText(this.test.code);\n this.copied.set(true);\n setTimeout(() => this.copied.set(false), 2000);\n }\n\n downloadCode(): void {\n if (!this.test) return;\n const blob = new Blob([this.test.code], { type: 'text/typescript' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `cypress-test-${new Date().toISOString().slice(0, 10)}.cy.ts`;\n a.click();\n URL.revokeObjectURL(url);\n }\n\n formatDate(ts: number): string {\n return new Date(ts).toLocaleString('de-DE', {\n day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit',\n });\n }\n}\n","import { Component, Output, EventEmitter, inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { AiGeneratorService } from '../services/ai-generator.service';\n\n@Component({\n selector: 'app-settings-dialog',\n standalone: true,\n imports: [CommonModule, FormsModule],\n template: `\n <div class=\"overlay\" data-debug-panel (click)=\"onOverlayClick($event)\">\n <div class=\"dialog\" data-debug-panel>\n <div class=\"dialog-header\">\n <h2>⚙️ Einstellungen</h2>\n <button class=\"close-btn\" (click)=\"close.emit()\">✕</button>\n </div>\n\n <div class=\"dialog-body\">\n <div class=\"field-group\">\n <label>KI Webhook-URL</label>\n <input\n data-debug-panel\n class=\"field-input\"\n type=\"url\"\n [(ngModel)]=\"localUrl\"\n placeholder=\"https://deine-ki-api.de/generate\"\n />\n <p class=\"field-hint\">\n Die aufgezeichnete Session wird als JSON per POST an diese URL gesendet.\n Die Antwort wird als Cypress-Test angezeigt.\n </p>\n </div>\n\n <div class=\"info-box\">\n <p>📦 POST-Body: Die Session als JSON (<code>actions</code>, <code>startUrl</code>, ...)</p>\n <p>📄 Erwartete Antwort: Cypress-Test-Code als Plain-Text</p>\n <p>⌨️ Shortcuts: <kbd>Ctrl+Shift+D</kbd> Panel <kbd>Ctrl+Shift+R</kbd> Aufnahme</p>\n </div>\n </div>\n\n <div class=\"dialog-footer\">\n <button class=\"btn-cancel\" (click)=\"close.emit()\">Abbrechen</button>\n <button class=\"btn-save\" (click)=\"save()\">💾 Speichern</button>\n </div>\n </div>\n </div>\n `,\n styles: [`\n .overlay {\n position: fixed; inset: 0; background: rgba(0,0,0,0.7);\n z-index: 100000; display: flex; align-items: center; justify-content: center;\n backdrop-filter: blur(4px);\n }\n .dialog {\n background: #0f172a; border: 1px solid #1e3a5f; border-radius: 12px;\n width: 440px; max-width: 95vw; display: flex; flex-direction: column;\n box-shadow: 0 25px 60px rgba(0,0,0,0.6); overflow: hidden;\n }\n .dialog-header {\n display: flex; align-items: center; justify-content: space-between;\n padding: 14px 18px; background: #1e293b; border-bottom: 1px solid #334155;\n }\n .dialog-header h2 { margin: 0; font-size: 15px; color: #f1f5f9; font-weight: 600; }\n .close-btn {\n background: none; border: none; color: #94a3b8;\n cursor: pointer; font-size: 16px; padding: 4px; border-radius: 4px;\n }\n .close-btn:hover { color: #f1f5f9; background: #334155; }\n .dialog-body { padding: 18px; display: flex; flex-direction: column; gap: 16px; }\n .field-group { display: flex; flex-direction: column; gap: 6px; }\n label {\n font-size: 12px; font-weight: 600; color: #94a3b8;\n text-transform: uppercase; letter-spacing: 0.05em;\n }\n .field-input {\n background: #1e293b; border: 1px solid #334155; color: #e2e8f0;\n border-radius: 6px; padding: 10px 12px; font-size: 13px;\n width: 100%; box-sizing: border-box;\n }\n .field-input:focus { outline: none; border-color: #3b82f6; }\n .field-hint { font-size: 11px; color: #64748b; margin: 0; line-height: 1.5; }\n .info-box {\n background: rgba(30,41,59,0.5); border: 1px solid #1e3a5f;\n border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 6px;\n }\n .info-box p { margin: 0; font-size: 11px; color: #64748b; }\n .info-box code {\n background: #1e293b; color: #34d399; padding: 1px 4px;\n border-radius: 3px; font-family: monospace;\n }\n kbd {\n background: #1e293b; border: 1px solid #334155; color: #94a3b8;\n padding: 1px 5px; border-radius: 3px; font-size: 10px;\n }\n .dialog-footer {\n display: flex; gap: 8px; justify-content: flex-end;\n padding: 14px 18px; background: #1e293b; border-top: 1px solid #334155;\n }\n .btn-cancel, .btn-save {\n padding: 8px 20px; border-radius: 6px; font-size: 13px;\n font-weight: 600; cursor: pointer; border: none; transition: filter 0.15s;\n }\n .btn-cancel { background: #334155; color: #94a3b8; }\n .btn-cancel:hover { filter: brightness(1.2); }\n .btn-save { background: #2563eb; color: #fff; }\n .btn-save:hover { filter: brightness(1.1); }\n `],\n})\nexport class SettingsDialogComponent {\n @Output() close = new EventEmitter<void>();\n private ai = inject(AiGeneratorService);\n localUrl = this.ai.webhookUrl();\n\n save(): void {\n this.ai.setWebhookUrl(this.localUrl.trim());\n this.close.emit();\n }\n\n onOverlayClick(e: MouseEvent): void {\n if ((e.target as HTMLElement).classList.contains('overlay')) {\n this.close.emit();\n }\n }\n}\n","import {\n Component, ElementRef, ViewChild, OnDestroy, inject, signal,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\n\n@Component({\n selector: 'app-session-replay',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"replay-panel\" data-debug-panel>\n @if (!rrweb.hasEvents()) {\n <div class=\"replay-empty\">\n <div class=\"replay-icon\">📽️</div>\n <p>Kein Replay verfügbar.</p>\n <p class=\"hint\">Starte eine Aufnahme — rrweb zeichnet den DOM parallel mit.</p>\n </div>\n } @else {\n <div class=\"replay-info\">\n <span class=\"event-count\">{{ rrweb.events().length }} Events aufgezeichnet</span>\n </div>\n <div class=\"replay-actions\">\n <button class=\"replay-btn primary\" (click)=\"openOverlay()\">\n ▶ Replay abspielen\n </button>\n <button class=\"replay-btn\" (click)=\"exportSession()\">\n 💾 JSON exportieren\n </button>\n </div>\n <p class=\"replay-hint\">\n Der Replay öffnet sich als Vollbild-Overlay über der aktuellen Seite.\n </p>\n }\n </div>\n\n <!-- Fullscreen Replay Overlay -->\n @if (overlayOpen()) {\n <div class=\"replay-overlay\" data-debug-panel>\n <div class=\"overlay-header\" data-debug-panel>\n <span class=\"overlay-title\">📽️ Session Replay</span>\n <div class=\"overlay-controls\" data-debug-panel>\n <button class=\"ovl-btn\" (click)=\"pauseResume()\">\n {{ isPlaying() ? '⏸ Pause' : '▶ Play' }}\n </button>\n <button class=\"ovl-btn\" (click)=\"restart()\">⟳ Neustart</button>\n <button class=\"ovl-btn close-ovl\" (click)=\"closeOverlay()\">✕ Schließen</button>\n </div>\n </div>\n <div #replayContainer class=\"overlay-stage\" data-debug-panel></div>\n </div>\n }\n `,\n styles: [`\n .replay-panel {\n padding: 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n }\n\n .replay-empty {\n text-align: center;\n padding: 20px 0;\n color: #64748b;\n }\n .replay-icon { font-size: 36px; margin-bottom: 8px; }\n .replay-empty p { margin: 4px 0; font-size: 13px; }\n .hint { font-size: 11px; color: #475569; }\n\n .replay-info {\n background: #1e293b;\n border-radius: 6px;\n padding: 8px 12px;\n }\n .event-count { font-size: 12px; color: #6ee7b7; font-weight: 600; }\n\n .replay-actions { display: flex; gap: 8px; }\n .replay-btn {\n background: #334155;\n border: none;\n color: #cbd5e1;\n padding: 8px 14px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n .replay-btn:hover { background: #475569; }\n .replay-btn.primary { background: #1d4ed8; color: #fff; }\n .replay-btn.primary:hover { background: #2563eb; }\n\n .replay-hint { font-size: 11px; color: #475569; margin: 0; }\n\n /* ── Fullscreen Overlay ── */\n .replay-overlay {\n position: fixed;\n inset: 0;\n z-index: 99997;\n background: #000;\n display: flex;\n flex-direction: column;\n }\n .overlay-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 16px;\n background: #0f172a;\n border-bottom: 1px solid #1e293b;\n flex-shrink: 0;\n }\n .overlay-title { font-size: 14px; font-weight: 600; color: #f1f5f9; }\n .overlay-controls { display: flex; gap: 8px; }\n .ovl-btn {\n background: #1e293b;\n border: 1px solid #334155;\n color: #cbd5e1;\n padding: 5px 12px;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n }\n .ovl-btn:hover { background: #334155; }\n .close-ovl { color: #fca5a5; }\n .close-ovl:hover { background: rgba(220,38,38,0.2); }\n\n .overlay-stage {\n flex: 1;\n overflow: hidden;\n position: relative;\n background: #f8fafc;\n }\n\n /* Scale the rrweb iframe to fill available space */\n :host ::ng-deep .replayer-wrapper {\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n transform-origin: top left !important;\n }\n :host ::ng-deep .replayer-wrapper iframe {\n pointer-events: none;\n }\n `],\n})\nexport class SessionReplayComponent implements OnDestroy {\n @ViewChild('replayContainer') replayContainer?: ElementRef<HTMLDivElement>;\n\n rrweb = inject(RrwebRecorderService);\n overlayOpen = signal(false);\n isPlaying = signal(false);\n\n async openOverlay(): Promise<void> {\n this.overlayOpen.set(true);\n this.isPlaying.set(false);\n // Wait for the DOM to render the overlay\n await new Promise(r => setTimeout(r, 50));\n await this.startPlay();\n }\n\n closeOverlay(): void {\n this.rrweb.destroyReplayer();\n this.overlayOpen.set(false);\n this.isPlaying.set(false);\n }\n\n async pauseResume(): Promise<void> {\n if (this.isPlaying()) {\n this.rrweb.pauseReplay();\n this.isPlaying.set(false);\n } else {\n this.rrweb.resumeReplay();\n this.isPlaying.set(true);\n }\n }\n\n async restart(): Promise<void> {\n this.rrweb.destroyReplayer();\n await new Promise(r => setTimeout(r, 50));\n await this.startPlay();\n }\n\n exportSession(): void {\n this.rrweb.downloadEvents();\n }\n\n private async startPlay(): Promise<void> {\n if (!this.replayContainer) return;\n const container = this.replayContainer.nativeElement;\n\n await this.rrweb.startReplay(container);\n\n // Scale iframe to fill the stage container\n this.scaleReplayer(container);\n this.isPlaying.set(true);\n }\n\n private scaleReplayer(container: HTMLElement): void {\n // rrweb injects .replayer-wrapper with an iframe sized to the recorded viewport\n setTimeout(() => {\n const wrapper = container.querySelector('.replayer-wrapper') as HTMLElement;\n if (!wrapper) return;\n\n const iframe = wrapper.querySelector('iframe') as HTMLIFrameElement;\n const wrapW = iframe?.offsetWidth || wrapper.offsetWidth || 1280;\n const wrapH = iframe?.offsetHeight || wrapper.offsetHeight || 720;\n const stageW = container.offsetWidth;\n const stageH = container.offsetHeight;\n\n if (!stageW || !stageH || !wrapW || !wrapH) return;\n\n const scale = Math.min(stageW / wrapW, stageH / wrapH);\n const offsetX = (stageW - wrapW * scale) / 2;\n const offsetY = (stageH - wrapH * scale) / 2;\n\n wrapper.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\n }, 300);\n }\n\n ngOnDestroy(): void {\n this.rrweb.destroyReplayer();\n }\n}\n","import {\n Component, signal, computed, inject, OnInit, OnDestroy,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { RecorderService } from '../services/recorder.service';\nimport { AiGeneratorService } from '../services/ai-generator.service';\nimport { RrwebRecorderService } from '../services/rrweb-recorder.service';\nimport { RecordingSession } from '../models/recorded-action.model';\nimport { ActionListComponent } from '../action-list/action-list.component';\nimport { TestPreviewComponent } from '../test-preview/test-preview.component';\nimport { SettingsDialogComponent } from '../settings-dialog/settings-dialog.component';\nimport { SessionReplayComponent } from '../session-replay/session-replay.component';\n\ntype PanelTab = 'actions' | 'test' | 'sessions' | 'replay';\ntype PanelPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n\n@Component({\n selector: 'app-debug-panel',\n standalone: true,\n imports: [CommonModule, FormsModule, ActionListComponent, TestPreviewComponent, SettingsDialogComponent, SessionReplayComponent],\n template: `\n <!-- Toggle FAB -->\n <button\n data-debug-panel\n class=\"debug-fab\"\n [class.recording]=\"recorder.isRecording()\"\n [class.pulse]=\"recorder.isRecording() && !recorder.isPaused()\"\n (click)=\"togglePanel()\"\n [title]=\"panelOpen() ? 'Debug Panel schließen' : 'Debug Panel öffnen'\"\n >\n <span class=\"fab-icon\">{{ recorder.isRecording() ? '⏺' : '🐛' }}</span>\n @if (recorder.isRecording() && recorder.actionCount() > 0) {\n <span class=\"fab-badge\">{{ recorder.actionCount() }}</span>\n }\n </button>\n\n <!-- Main Panel -->\n @if (panelOpen()) {\n <div\n data-debug-panel\n class=\"debug-panel\"\n [class]=\"'pos-' + position()\"\n [style.width.px]=\"panelWidth()\"\n >\n <!-- Header -->\n <div class=\"panel-header\" (mousedown)=\"startDrag($event)\">\n <div class=\"header-left\">\n <span class=\"panel-icon\">🐛</span>\n <span class=\"panel-title\">Debug Recorder</span>\n @if (recorder.isRecording()) {\n <span class=\"rec-indicator\" [class.paused]=\"recorder.isPaused()\">\n {{ recorder.isPaused() ? '⏸ PAUSED' : '⏺ REC' }}\n </span>\n }\n </div>\n <div class=\"header-actions\">\n <button class=\"icon-btn\" title=\"Einstellungen\" (click)=\"showSettings.set(true)\">⚙️</button>\n <button class=\"icon-btn\" title=\"Position wechseln\" (click)=\"cyclePosition()\">📌</button>\n <button class=\"icon-btn\" title=\"Schließen\" (click)=\"togglePanel()\">✕</button>\n </div>\n </div>\n\n <!-- Session Name Input (only when not recording) -->\n @if (!recorder.isRecording()) {\n <div class=\"session-setup\">\n <input\n data-debug-panel\n class=\"session-input\"\n type=\"text\"\n [(ngModel)]=\"sessionName\"\n placeholder=\"Session-Name (optional)\"\n />\n <textarea\n data-debug-panel\n class=\"session-desc\"\n [(ngModel)]=\"sessionDesc\"\n placeholder=\"Fehlerbeschreibung...\"\n rows=\"2\"\n ></textarea>\n </div>\n }\n\n <!-- Recording Controls -->\n <div class=\"recording-controls\" data-debug-panel>\n @if (!recorder.isRecording()) {\n <button class=\"ctrl-btn start\" (click)=\"startRecording()\">\n ▶ Aufnahme starten\n </button>\n } @else {\n <button class=\"ctrl-btn pause\" (click)=\"recorder.pauseRecording()\">\n {{ recorder.isPaused() ? '▶ Fortsetzen' : '⏸ Pause' }}\n </button>\n <button class=\"ctrl-btn stop\" (click)=\"stopRecording()\">\n ⏹ Stoppen\n </button>\n <button class=\"ctrl-btn clear\" title=\"Aktionen löschen\" (click)=\"recorder.clearCurrentSession()\">\n 🗑\n </button>\n }\n\n @if (hasActions()) {\n <button\n class=\"ctrl-btn generate\"\n [disabled]=\"aiService.isGenerating() || !aiService.webhookUrl()\"\n [title]=\"!aiService.webhookUrl() ? 'Webhook-URL in Einstellungen eintragen' : 'Cypress Test generieren'\"\n (click)=\"generateTest()\"\n >\n @if (aiService.isGenerating()) {\n <span class=\"spinner\">⟳</span> Generiere...\n } @else {\n 🤖 → Cypress Test\n }\n </button>\n }\n </div>\n\n <!-- Error Banner -->\n @if (aiService.error()) {\n <div class=\"error-banner\" data-debug-panel>\n ⚠️ {{ aiService.error() }}\n </div>\n }\n\n <!-- Tabs -->\n <div class=\"tab-bar\" data-debug-panel>\n <button\n class=\"tab-btn\"\n [class.active]=\"activeTab() === 'actions'\"\n (click)=\"activeTab.set('actions')\"\n >\n Aktionen\n @if (recorder.actionCount() > 0) {\n <span class=\"tab-badge\">{{ recorder.actionCount() }}</span>\n }\n </button>\n <button\n class=\"tab-btn\"\n [class.active]=\"activeTab() === 'replay'\"\n (click)=\"activeTab.set('replay')\"\n title=\"rrweb Session Replay\"\n >\n 📽️ Replay\n @if (rrweb.events().length > 0) {\n <span class=\"tab-badge\">{{ rrweb.events().length }}</span>\n }\n </button>\n <button\n class=\"tab-btn\"\n [class.active]=\"activeTab() === 'test'\"\n [disabled]=\"!aiService.lastTest()\"\n (click)=\"activeTab.set('test')\"\n >\n 🤖 Test\n @if (aiService.lastTest()) {\n <span class=\"tab-badge new\">NEU</span>\n }\n </button>\n <button\n class=\"tab-btn\"\n [class.active]=\"activeTab() === 'sessions'\"\n [disabled]=\"recorder.sessions().length === 0\"\n (click)=\"activeTab.set('sessions')\"\n >\n Sessions ({{ recorder.sessions().length }})\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\">\n @if (activeTab() === 'actions') {\n <app-action-list\n [session]=\"recorder.currentSession()\"\n (removeAction)=\"recorder.removeAction($event)\"\n (addNote)=\"recorder.addNote($event.id, $event.note)\"\n />\n }\n\n @if (activeTab() === 'replay') {\n <app-session-replay />\n }\n\n @if (activeTab() === 'test') {\n <app-test-preview [test]=\"aiService.lastTest()\" />\n }\n\n @if (activeTab() === 'sessions') {\n <div class=\"sessions-list\">\n @for (session of recorder.sessions(); track session.id) {\n <div class=\"session-card\">\n <div class=\"session-card-header\">\n <span class=\"session-name\">{{ session.name }}</span>\n <span class=\"session-meta\">{{ session.actions.length }} Aktionen</span>\n </div>\n <div class=\"session-card-actions\">\n <button class=\"sm-btn\" (click)=\"loadAndGenerate(session)\">🤖 Neu generieren</button>\n <button class=\"sm-btn danger\" (click)=\"recorder.deleteSession(session.id)\">🗑</button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Resize Handle -->\n <div class=\"resize-handle\" (mousedown)=\"startResize($event)\">⠿</div>\n </div>\n }\n\n <!-- Settings Dialog -->\n @if (showSettings()) {\n <app-settings-dialog (close)=\"showSettings.set(false)\" />\n }\n `,\n styles: [`\n .debug-fab {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 99999;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n border: none;\n background: #1e293b;\n color: white;\n font-size: 22px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\n transition: transform 0.2s, background 0.2s;\n position: fixed;\n }\n .debug-fab:hover { transform: scale(1.1); background: #334155; }\n .debug-fab.recording { background: #dc2626; }\n .debug-fab.pulse { animation: fabPulse 1.5s ease-in-out infinite; }\n @keyframes fabPulse {\n 0%, 100% { box-shadow: 0 4px 20px rgba(220,38,38,0.4); }\n 50% { box-shadow: 0 4px 30px rgba(220,38,38,0.9), 0 0 0 8px rgba(220,38,38,0.15); }\n }\n .fab-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n background: #f59e0b;\n color: #000;\n font-size: 10px;\n font-weight: 700;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n }\n\n .debug-panel {\n position: fixed;\n z-index: 99998;\n width: 420px;\n max-height: 80vh;\n background: #0f172a;\n color: #e2e8f0;\n border-radius: 12px;\n border: 1px solid #1e3a5f;\n box-shadow: 0 25px 60px rgba(0,0,0,0.6);\n display: flex;\n flex-direction: column;\n font-family: 'Segoe UI', system-ui, sans-serif;\n font-size: 13px;\n overflow: hidden;\n }\n .pos-bottom-right { bottom: 88px; right: 24px; }\n .pos-bottom-left { bottom: 88px; left: 24px; }\n .pos-top-right { top: 24px; right: 24px; }\n .pos-top-left { top: 24px; left: 24px; }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n background: #1e293b;\n border-bottom: 1px solid #334155;\n cursor: move;\n user-select: none;\n flex-shrink: 0;\n }\n .header-left { display: flex; align-items: center; gap: 8px; }\n .panel-icon { font-size: 16px; }\n .panel-title { font-weight: 600; font-size: 14px; color: #f1f5f9; }\n .rec-indicator {\n font-size: 10px;\n font-weight: 700;\n color: #ef4444;\n background: rgba(239,68,68,0.15);\n padding: 2px 7px;\n border-radius: 4px;\n animation: blink 1s step-end infinite;\n }\n .rec-indicator.paused { color: #f59e0b; background: rgba(245,158,11,0.15); animation: none; }\n @keyframes blink { 50% { opacity: 0.4; } }\n .header-actions { display: flex; gap: 4px; }\n .icon-btn {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n font-size: 14px;\n line-height: 1;\n transition: color 0.15s, background 0.15s;\n }\n .icon-btn:hover { color: #f1f5f9; background: #334155; }\n\n .session-setup {\n padding: 10px 14px;\n border-bottom: 1px solid #1e293b;\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-shrink: 0;\n }\n .session-input, .session-desc {\n background: #1e293b;\n border: 1px solid #334155;\n color: #e2e8f0;\n border-radius: 6px;\n padding: 6px 10px;\n font-size: 12px;\n width: 100%;\n box-sizing: border-box;\n resize: vertical;\n }\n .session-input:focus, .session-desc:focus {\n outline: none;\n border-color: #3b82f6;\n }\n\n .recording-controls {\n display: flex;\n gap: 6px;\n padding: 10px 14px;\n border-bottom: 1px solid #1e293b;\n flex-wrap: wrap;\n flex-shrink: 0;\n }\n .ctrl-btn {\n border: none;\n border-radius: 6px;\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: filter 0.15s, transform 0.1s;\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .ctrl-btn:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); }\n .ctrl-btn:active:not(:disabled) { transform: translateY(0); }\n .ctrl-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n .ctrl-btn.start { background: #16a34a; color: #fff; }\n .ctrl-btn.stop { background: #dc2626; color: #fff; }\n .ctrl-btn.pause { background: #d97706; color: #fff; }\n .ctrl-btn.generate { background: #7c3aed; color: #fff; flex: 1; justify-content: center; }\n .ctrl-btn.clear { background: #374151; color: #9ca3af; padding: 6px 10px; }\n .spinner { display: inline-block; animation: spin 0.8s linear infinite; }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n .error-banner {\n background: rgba(220,38,38,0.15);\n border-left: 3px solid #dc2626;\n color: #fca5a5;\n padding: 8px 14px;\n font-size: 12px;\n flex-shrink: 0;\n }\n\n .tab-bar {\n display: flex;\n border-bottom: 1px solid #1e293b;\n flex-shrink: 0;\n }\n .tab-btn {\n flex: 1;\n background: none;\n border: none;\n color: #64748b;\n padding: 8px 4px;\n font-size: 12px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n border-bottom: 2px solid transparent;\n transition: color 0.15s;\n }\n .tab-btn:hover:not(:disabled) { color: #cbd5e1; }\n .tab-btn.active { color: #60a5fa; border-bottom-color: #3b82f6; }\n .tab-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n .tab-badge {\n background: #334155;\n color: #94a3b8;\n font-size: 10px;\n padding: 1px 5px;\n border-radius: 3px;\n }\n .tab-badge.new { background: #7c3aed; color: #e9d5ff; }\n\n .tab-content {\n overflow-y: auto;\n flex: 1;\n min-height: 0;\n }\n .tab-content::-webkit-scrollbar { width: 5px; }\n .tab-content::-webkit-scrollbar-track { background: transparent; }\n .tab-content::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }\n\n .sessions-list { padding: 10px 14px; display: flex; flex-direction: column; gap: 8px; }\n .session-card {\n background: #1e293b;\n border: 1px solid #334155;\n border-radius: 8px;\n padding: 10px;\n }\n .session-card-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n }\n .session-name { font-weight: 600; color: #f1f5f9; font-size: 13px; }\n .session-meta { font-size: 11px; color: #64748b; }\n .session-card-actions { display: flex; gap: 6px; }\n .sm-btn {\n background: #334155;\n border: none;\n color: #cbd5e1;\n padding: 4px 10px;\n border-radius: 5px;\n font-size: 11px;\n cursor: pointer;\n transition: background 0.15s;\n }\n .sm-btn:hover { background: #475569; }\n .sm-btn.danger { color: #fca5a5; }\n .sm-btn.danger:hover { background: rgba(220,38,38,0.2); }\n\n .resize-handle {\n text-align: center;\n color: #334155;\n cursor: ns-resize;\n font-size: 16px;\n padding: 2px;\n flex-shrink: 0;\n background: #0f172a;\n user-select: none;\n }\n .resize-handle:hover { color: #64748b; }\n `],\n})\nexport class DebugPanelComponent implements OnInit, OnDestroy {\n recorder = inject(RecorderService);\n aiService = inject(AiGeneratorService);\n rrweb = inject(RrwebRecorderService);\n\n panelOpen = signal(false);\n activeTab = signal<PanelTab>('actions');\n position = signal<PanelPosition>('bottom-right');\n panelWidth = signal(420);\n showSettings = signal(false);\n sessionName = '';\n sessionDesc = '';\n\n hasActions = computed(\n () => (this.recorder.currentSession()?.actions.length ?? 0) > 0 ||\n (this.recorder.sessions().length > 0)\n );\n\n private resizing = false;\n private resizeStartY = 0;\n private resizeStartH = 0;\n\n ngOnInit(): void {\n // Keyboard shortcut: Ctrl+Shift+D\n document.addEventListener('keydown', this.handleHotkey);\n }\n\n ngOnDestroy(): void {\n document.removeEventListener('keydown', this.handleHotkey);\n }\n\n private handleHotkey = (e: KeyboardEvent) => {\n if (e.ctrlKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n this.togglePanel();\n }\n if (e.ctrlKey && e.shiftKey && e.key === 'R') {\n e.preventDefault();\n if (this.recorder.isRecording()) {\n this.stopRecording();\n } else {\n this.startRecording();\n }\n }\n };\n\n togglePanel(): void {\n this.panelOpen.update(v => !v);\n if (this.panelOpen() && !this.recorder.currentSession()) {\n this.activeTab.set('actions');\n }\n }\n\n cyclePosition(): void {\n const positions: PanelPosition[] = ['bottom-right', 'bottom-left', 'top-right', 'top-left'];\n const idx = positions.indexOf(this.position());\n this.position.set(positions[(idx + 1) % positions.length]);\n }\n\n startRecording(): void {\n this.recorder.startRecording(\n this.sessionName || undefined,\n this.sessionDesc || undefined\n );\n // Start rrweb in parallel for visual replay\n this.rrweb.startRecording();\n this.activeTab.set('actions');\n }\n\n stopRecording(): void {\n const session = this.recorder.stopRecording();\n this.rrweb.stopRecording();\n if (session) {\n this.activeTab.set('actions');\n }\n }\n\n async generateTest(): Promise<void> {\n const session = this.recorder.currentSession() ?? this.recorder.sessions().at(-1);\n if (!session) return;\n await this.aiService.generateCypressTest(session);\n this.activeTab.set('test');\n }\n\n async loadAndGenerate(session: RecordingSession): Promise<void> {\n await this.aiService.generateCypressTest(session);\n this.activeTab.set('test');\n }\n\n // Drag to reposition\n startDrag(e: MouseEvent): void {\n if ((e.target as HTMLElement).closest('button')) return;\n const panel = (e.currentTarget as HTMLElement).parentElement!;\n const startX = e.clientX - panel.getBoundingClientRect().left;\n const startY = e.clientY - panel.getBoundingClientRect().top;\n\n const onMove = (ev: MouseEvent) => {\n panel.style.left = `${ev.clientX - startX}px`;\n panel.style.top = `${ev.clientY - startY}px`;\n panel.style.right = 'auto';\n panel.style.bottom = 'auto';\n };\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n }\n\n // Resize height\n startResize(e: MouseEvent): void {\n const panel = (e.currentTarget as HTMLElement).parentElement!;\n this.resizeStartY = e.clientY;\n this.resizeStartH = panel.getBoundingClientRect().height;\n\n const onMove = (ev: MouseEvent) => {\n const newH = Math.max(250, this.resizeStartH + (ev.clientY - this.resizeStartY));\n panel.style.maxHeight = `${newH}px`;\n };\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n e.preventDefault();\n }\n}\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":["../../../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 \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\"><{{ action.element?.tagName }}></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, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\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 <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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"}
|
|
@@ -3,18 +3,19 @@ import type { eventWithTime } from '@rrweb/types';
|
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
export declare class RrwebRecorderService {
|
|
5
5
|
private zone;
|
|
6
|
-
private
|
|
6
|
+
private _eventsArray;
|
|
7
|
+
private _eventCount;
|
|
7
8
|
private _isRecording;
|
|
8
9
|
private stopFn?;
|
|
9
10
|
private replayer?;
|
|
10
|
-
|
|
11
|
+
eventCount: import("@angular/core").Signal<number>;
|
|
11
12
|
isRecording: import("@angular/core").Signal<boolean>;
|
|
12
13
|
constructor(zone: NgZone);
|
|
14
|
+
hasEvents(): boolean;
|
|
15
|
+
getEvents(): eventWithTime[];
|
|
13
16
|
startRecording(): Promise<void>;
|
|
14
17
|
stopRecording(): eventWithTime[];
|
|
15
|
-
getEvents(): eventWithTime[];
|
|
16
18
|
clearEvents(): void;
|
|
17
|
-
hasEvents(): boolean;
|
|
18
19
|
startReplay(container: HTMLElement, events?: eventWithTime[]): Promise<void>;
|
|
19
20
|
pauseReplay(): void;
|
|
20
21
|
resumeReplay(): void;
|