@dynamicu/chromedebug-mcp 2.7.2 → 2.7.4

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.
@@ -3,7 +3,7 @@ const EXTENSION_VERSION = '2.0.4-BUILD-20250119';
3
3
  // console.log(`[popup.js] Loaded version: ${EXTENSION_VERSION}`);
4
4
 
5
5
  // LemonSqueezy purchase URL for PRO upgrade
6
- const PRO_PURCHASE_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
6
+ const PRO_PURCHASE_URL = 'https://chromedebug.com/checkout/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
7
7
  const IS_PRO_VERSION = chrome.runtime.getManifest().name.includes('PRO');
8
8
 
9
9
  // Global variables for recording functionality
@@ -11,6 +11,7 @@ let isRecording = false;
11
11
  let recordingTimer = null;
12
12
  let recordingStartTime = null;
13
13
  let isStoppingRecording = false;
14
+ let isVideoModeActive = false; // Track if we're in video recording mode
14
15
 
15
16
  // Countdown timer variables
16
17
  let countdownTimer = null;
@@ -23,6 +24,17 @@ let isWorkflowRecording = false;
23
24
  let workflowRecordingTimer = null;
24
25
  let workflowStartTime = null;
25
26
 
27
+ // Screenshot recording variables
28
+ let isScreenshotRecording = false;
29
+ let screenshotRecordingTimer = null;
30
+ let screenshotStartTime = null;
31
+
32
+ // Recording tab filter: 'all', 'screen', 'video'
33
+ let recordingTabFilter = 'all';
34
+
35
+ // Workflow tab filter: 'all', 'workflow', 'screenshot'
36
+ let workflowTabFilter = 'all';
37
+
26
38
  // Debounce timer for screenshot quality slider
27
39
  let screenshotQualityDebounceTimer = null;
28
40
 
@@ -150,6 +162,67 @@ function stopWorkflowTimer() {
150
162
  }
151
163
  }
152
164
 
165
+ // Screenshot recording UI update function
166
+ function updateScreenshotRecordingUI() {
167
+ const screenshotBtn = document.getElementById('screenshotRecordBtn');
168
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
169
+ const screenshotSettings = document.getElementById('screenshotRecordingSettings');
170
+
171
+ if (screenshotBtn) {
172
+ if (isScreenshotRecording) {
173
+ screenshotBtn.textContent = '⏹️ Stop Screenshot Recording';
174
+ screenshotBtn.style.background = '#e91e63';
175
+ screenshotBtn.classList.add('recording');
176
+ startScreenshotTimer();
177
+ // Hide settings during recording
178
+ if (screenshotSettings) {
179
+ screenshotSettings.style.display = 'none';
180
+ }
181
+ } else {
182
+ screenshotBtn.innerHTML = '📸 Start Screenshot Recording <span id="screenshotProBadge" style="position: absolute; top: -4px; right: -4px; background: linear-gradient(135deg, #FFD700, #FFA500); color: #000; font-size: 8px; padding: 1px 4px; border-radius: 3px; font-weight: bold;">PRO</span>';
183
+ screenshotBtn.style.background = '#FF9800';
184
+ screenshotBtn.classList.remove('recording');
185
+ stopScreenshotTimer();
186
+ if (screenshotStatus) {
187
+ screenshotStatus.textContent = '';
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ function startScreenshotTimer() {
194
+ // Get stored start time or use current time
195
+ chrome.storage.local.get(['screenshotStartTime'], (result) => {
196
+ screenshotStartTime = result.screenshotStartTime || Date.now();
197
+
198
+ screenshotRecordingTimer = setInterval(() => {
199
+ const elapsed = Math.floor((Date.now() - screenshotStartTime) / 1000);
200
+ const minutes = Math.floor(elapsed / 60);
201
+ const seconds = elapsed % 60;
202
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
203
+ if (screenshotStatus) {
204
+ screenshotStatus.innerHTML = `📸 Recording: <span class="recording-timer">${minutes}:${seconds.toString().padStart(2, '0')}</span>`;
205
+ }
206
+ }, 1000);
207
+
208
+ // Update timer immediately
209
+ const elapsed = Math.floor((Date.now() - screenshotStartTime) / 1000);
210
+ const minutes = Math.floor(elapsed / 60);
211
+ const seconds = elapsed % 60;
212
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
213
+ if (screenshotStatus) {
214
+ screenshotStatus.innerHTML = `📸 Recording: <span class="recording-timer">${minutes}:${seconds.toString().padStart(2, '0')}</span>`;
215
+ }
216
+ });
217
+ }
218
+
219
+ function stopScreenshotTimer() {
220
+ if (screenshotRecordingTimer) {
221
+ clearInterval(screenshotRecordingTimer);
222
+ screenshotRecordingTimer = null;
223
+ }
224
+ }
225
+
153
226
  // Smart tiered port discovery configuration
154
227
  const PORT_TIERS = {
155
228
  // Try common ports first with short timeout (fast discovery)
@@ -477,33 +550,80 @@ chromedebug-mcp-server`;
477
550
 
478
551
 
479
552
  function updateRecordingUI() {
553
+ console.log('[updateRecordingUI] Called with isRecording:', isRecording, 'isVideoModeActive:', isVideoModeActive);
480
554
  const recordBtn = document.getElementById('recordBtn');
481
555
  const recordingStatus = document.getElementById('recordingStatus');
482
556
  const manualSnapshotBtn = document.getElementById('manualSnapshotBtn');
483
557
  const countdownDisplay = document.getElementById('countdownDisplay');
484
-
558
+ const videoRecBtn = document.getElementById('startVideoRecordingBtn');
559
+
485
560
  if (recordBtn) {
486
561
  if (isRecording) {
487
- recordBtn.textContent = 'Stop Recording';
488
- recordBtn.classList.add('recording');
562
+ // Check if we're in video mode
563
+ if (isVideoModeActive) {
564
+ console.log('[updateRecordingUI] VIDEO MODE: Setting recordBtn disabled, videoRecBtn to Stop');
565
+ // Video mode: grey out regular recording button
566
+ recordBtn.textContent = 'Start Recording';
567
+ recordBtn.disabled = true;
568
+ recordBtn.style.background = '#999';
569
+ recordBtn.classList.remove('recording');
570
+
571
+ // Update video button to show Stop
572
+ if (videoRecBtn) {
573
+ videoRecBtn.textContent = '🎥 Stop Video Recording';
574
+ videoRecBtn.style.background = '#f44336';
575
+ videoRecBtn.disabled = false;
576
+ }
577
+
578
+ if (recordingStatus) {
579
+ recordingStatus.innerHTML = '<strong style="color: #4CAF50;">🎥 Video Recording Active</strong><br>' +
580
+ '<small>No indicator shown. Click Stop to end.</small>';
581
+ }
582
+ } else {
583
+ // Normal recording mode
584
+ console.log('[updateRecordingUI] NORMAL MODE: Setting recordBtn to Stop, videoRecBtn disabled');
585
+ recordBtn.textContent = 'Stop Recording';
586
+ recordBtn.classList.add('recording');
587
+ recordBtn.disabled = false;
588
+ recordBtn.style.background = '';
589
+
590
+ // Grey out video button during normal recording
591
+ if (videoRecBtn) {
592
+ videoRecBtn.textContent = '🎥 Start Video Recording';
593
+ videoRecBtn.disabled = true;
594
+ videoRecBtn.style.background = '#999';
595
+ }
596
+ }
597
+
489
598
  startRecordingTimer();
490
-
599
+
491
600
  // Show manual snapshot button
492
601
  if (manualSnapshotBtn) {
493
602
  manualSnapshotBtn.style.display = 'block';
494
603
  }
495
-
496
- // Show countdown if frame rate is 3+ seconds
497
- if (currentFrameRate >= 3 && countdownDisplay) {
604
+
605
+ // Show countdown if frame rate is 3+ seconds (not in video mode)
606
+ if (!isVideoModeActive && currentFrameRate >= 3 && countdownDisplay) {
498
607
  countdownDisplay.style.display = 'block';
499
608
  startCountdownTimer();
500
609
  }
501
610
  } else {
611
+ // Not recording - reset everything
612
+ console.log('[updateRecordingUI] NOT RECORDING: Resetting both buttons');
502
613
  recordBtn.textContent = 'Start Recording';
503
614
  recordBtn.classList.remove('recording');
615
+ recordBtn.disabled = false;
616
+ recordBtn.style.background = '#f44336';
504
617
  stopRecordingTimer();
505
618
  stopCountdownTimer();
506
-
619
+
620
+ // Reset Video Recording button
621
+ if (videoRecBtn) {
622
+ videoRecBtn.textContent = '🎥 Start Video Recording';
623
+ videoRecBtn.disabled = false;
624
+ videoRecBtn.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
625
+ }
626
+
507
627
  // Hide manual snapshot button and countdown
508
628
  if (manualSnapshotBtn) {
509
629
  manualSnapshotBtn.style.display = 'none';
@@ -511,10 +631,13 @@ function updateRecordingUI() {
511
631
  if (countdownDisplay) {
512
632
  countdownDisplay.style.display = 'none';
513
633
  }
514
-
634
+
515
635
  if (recordingStatus) {
516
636
  recordingStatus.textContent = '';
517
637
  }
638
+
639
+ // Reset video mode flag
640
+ isVideoModeActive = false;
518
641
  }
519
642
  }
520
643
  }
@@ -771,7 +894,7 @@ function loadRecordings() {
771
894
  });
772
895
  }
773
896
 
774
- function addRecording(recordingId, isSession = false, isFrameCapture = false, serverPort = null, type = null, sessionName = null) {
897
+ function addRecording(recordingId, isSession = false, isFrameCapture = false, serverPort = null, type = null, sessionName = null, isVideoMode = false) {
775
898
  chrome.storage.local.get(['recordings'], (result) => {
776
899
  const recordings = result.recordings || [];
777
900
  recordings.unshift({
@@ -781,14 +904,77 @@ function addRecording(recordingId, isSession = false, isFrameCapture = false, se
781
904
  isFrameCapture: isFrameCapture,
782
905
  serverPort: serverPort,
783
906
  type: type || (isSession ? 'session' : isFrameCapture ? 'recording' : 'recording'),
784
- name: sessionName
907
+ name: sessionName,
908
+ isVideoMode: isVideoMode
785
909
  }); // Add to beginning
786
910
  chrome.storage.local.set({ recordings }, () => {
911
+ // Auto-switch to the relevant tab
912
+ if (isVideoMode) {
913
+ switchRecordingTab('video');
914
+ } else {
915
+ switchRecordingTab('screen');
916
+ }
787
917
  updateRecordingsDisplay(recordings);
788
918
  });
789
919
  });
790
920
  }
791
921
 
922
+ // Switch recording tab and update UI
923
+ function switchRecordingTab(tabName) {
924
+ recordingTabFilter = tabName;
925
+
926
+ // Update tab button styles
927
+ const allBtn = document.getElementById('tabAllRecordings');
928
+ const screenBtn = document.getElementById('tabScreenRecordings');
929
+ const videoBtn = document.getElementById('tabVideoRecordings');
930
+
931
+ [allBtn, screenBtn, videoBtn].forEach(btn => {
932
+ if (btn) {
933
+ btn.style.background = '#e0e0e0';
934
+ btn.style.color = '#333';
935
+ btn.classList.remove('active');
936
+ }
937
+ });
938
+
939
+ const activeBtn = tabName === 'all' ? allBtn : tabName === 'screen' ? screenBtn : videoBtn;
940
+ if (activeBtn) {
941
+ activeBtn.style.background = '#2196F3';
942
+ activeBtn.style.color = 'white';
943
+ activeBtn.classList.add('active');
944
+ }
945
+
946
+ // Reload screen recordings with the new filter applied
947
+ loadScreenRecordings();
948
+ }
949
+
950
+ // Switch workflow tab and update UI
951
+ function switchWorkflowTab(tabName) {
952
+ workflowTabFilter = tabName;
953
+
954
+ // Update tab button styles
955
+ const allBtn = document.getElementById('tabAllWorkflows');
956
+ const workflowBtn = document.getElementById('tabWorkflowOnly');
957
+ const screenshotBtn = document.getElementById('tabScreenshotsOnly');
958
+
959
+ [allBtn, workflowBtn, screenshotBtn].forEach(btn => {
960
+ if (btn) {
961
+ btn.style.background = '#e0e0e0';
962
+ btn.style.color = '#333';
963
+ btn.classList.remove('active');
964
+ }
965
+ });
966
+
967
+ const activeBtn = tabName === 'all' ? allBtn : tabName === 'workflow' ? workflowBtn : screenshotBtn;
968
+ if (activeBtn) {
969
+ activeBtn.style.background = '#9c27b0';
970
+ activeBtn.style.color = 'white';
971
+ activeBtn.classList.add('active');
972
+ }
973
+
974
+ // Reload workflow recordings with the new filter applied
975
+ loadWorkflowRecordings();
976
+ }
977
+
792
978
  function deleteRecording(recordingId) {
793
979
  // First, tell the background script to delete from server
794
980
  chrome.runtime.sendMessage({
@@ -806,23 +992,49 @@ function deleteRecording(recordingId) {
806
992
  });
807
993
  }
808
994
 
995
+ // Store all recordings for filtering
996
+ let allRecordings = [];
997
+
809
998
  function updateRecordingsDisplay(recordings) {
810
999
  const container = document.getElementById('recordingsContainer');
811
1000
  const listDiv = document.getElementById('recordingsList');
812
1001
 
813
1002
  if (!container || !listDiv) return;
814
1003
 
1004
+ // Store all recordings for tab filtering
1005
+ allRecordings = recordings;
1006
+
815
1007
  if (recordings.length === 0) {
816
1008
  listDiv.style.display = 'none';
817
1009
  return;
818
1010
  }
819
1011
 
820
1012
  listDiv.style.display = 'block';
821
- container.innerHTML = recordings.map(recording => {
1013
+
1014
+ // Filter recordings based on selected tab
1015
+ let filteredRecordings = recordings;
1016
+ if (recordingTabFilter === 'video') {
1017
+ filteredRecordings = recordings.filter(r => normalizeIsVideoMode(r.isVideoMode));
1018
+ } else if (recordingTabFilter === 'screen') {
1019
+ filteredRecordings = recordings.filter(r => !normalizeIsVideoMode(r.isVideoMode));
1020
+ }
1021
+
1022
+ if (filteredRecordings.length === 0) {
1023
+ container.innerHTML = '<div style="text-align: center; color: #999; padding: 20px; font-size: 11px;">No recordings in this category</div>';
1024
+ return;
1025
+ }
1026
+
1027
+ container.innerHTML = filteredRecordings.map(recording => {
822
1028
  const portInfo = recording.serverPort ? ` - Port: ${recording.serverPort}` : '';
823
1029
  let typeInfo = '';
824
1030
  let typeIcon = '';
825
1031
 
1032
+ // Determine recording type badge
1033
+ const isVideo = normalizeIsVideoMode(recording.isVideoMode);
1034
+ const typeBadge = isVideo
1035
+ ? '<span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">VIDEO</span>'
1036
+ : '<span style="background: #4CAF50; color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">SCREEN</span>';
1037
+
826
1038
  if (recording.type === 'snapshot') {
827
1039
  typeInfo = ' (snapshot)';
828
1040
  typeIcon = '📸 ';
@@ -841,7 +1053,7 @@ function updateRecordingsDisplay(recordings) {
841
1053
  <div class="recording-info">
842
1054
  <div class="recording-id" title="${recording.id}">
843
1055
  <span class="recording-id-text">${typeIcon}${displayName}</span>
844
- ${typeInfo}${portInfo}
1056
+ ${typeBadge}${typeInfo}${portInfo}
845
1057
  </div>
846
1058
  </div>
847
1059
  <div class="recording-buttons">
@@ -1236,20 +1448,29 @@ document.addEventListener('DOMContentLoaded', () => {
1236
1448
  'frameRate',
1237
1449
  'imageQuality',
1238
1450
  'frameFlash',
1451
+ 'mouseTrackingEnabled',
1452
+ 'mouseSampleInterval',
1239
1453
  'workflowRecording',
1454
+ 'screenshotRecording',
1240
1455
  'includeLogsInExport',
1241
1456
  'workflowScreenshotsEnabled',
1242
1457
  'workflowScreenshotFormat',
1243
1458
  'workflowScreenshotQuality',
1244
1459
  'workflowScreenshotMaxWidth'
1245
1460
  ], (result) => {
1246
-
1461
+
1247
1462
  // Restore workflow recording state
1248
1463
  if (result.workflowRecording === true) {
1249
1464
  isWorkflowRecording = true;
1250
1465
  updateWorkflowRecordingUI();
1251
1466
  }
1252
-
1467
+
1468
+ // Restore screenshot recording state
1469
+ if (result.screenshotRecording === true) {
1470
+ isScreenshotRecording = true;
1471
+ updateScreenshotRecordingUI();
1472
+ }
1473
+
1253
1474
  // Restore include logs checkbox state (default to true)
1254
1475
  if (includeLogsCheckbox) {
1255
1476
  includeLogsCheckbox.checked = result.includeLogsInExport !== false;
@@ -1284,6 +1505,20 @@ document.addEventListener('DOMContentLoaded', () => {
1284
1505
  });
1285
1506
  }
1286
1507
 
1508
+ // Restore mouse tracking settings (available for all users)
1509
+ const enableMouseTrackingCheckbox = document.getElementById('enableMouseTracking');
1510
+ const mouseSampleRateSelect = document.getElementById('mouseSampleRate');
1511
+
1512
+ if (enableMouseTrackingCheckbox && mouseSampleRateSelect) {
1513
+ // Mouse tracking is available for all users
1514
+ const mouseTrackingEnabled = result.mouseTrackingEnabled === true;
1515
+ const mouseSampleInterval = result.mouseSampleInterval || 100;
1516
+
1517
+ enableMouseTrackingCheckbox.checked = mouseTrackingEnabled;
1518
+ mouseSampleRateSelect.value = mouseSampleInterval;
1519
+ mouseSampleRateSelect.disabled = !mouseTrackingEnabled;
1520
+ }
1521
+
1287
1522
  // Restore workflow screenshot settings
1288
1523
  const enableScreenshotsCheckbox = document.getElementById('enableScreenshotsCheckbox');
1289
1524
  const screenshotFormat = document.getElementById('screenshotFormat');
@@ -1321,10 +1556,51 @@ document.addEventListener('DOMContentLoaded', () => {
1321
1556
  // Load saved recordings (legacy)
1322
1557
  loadRecordings();
1323
1558
 
1559
+ // Setup recording type tab handlers
1560
+ const tabAllBtn = document.getElementById('tabAllRecordings');
1561
+ const tabScreenBtn = document.getElementById('tabScreenRecordings');
1562
+ const tabVideoBtn = document.getElementById('tabVideoRecordings');
1563
+
1564
+ if (tabAllBtn) {
1565
+ tabAllBtn.addEventListener('click', () => switchRecordingTab('all'));
1566
+ }
1567
+ if (tabScreenBtn) {
1568
+ tabScreenBtn.addEventListener('click', () => switchRecordingTab('screen'));
1569
+ }
1570
+ if (tabVideoBtn) {
1571
+ tabVideoBtn.addEventListener('click', () => switchRecordingTab('video'));
1572
+ }
1573
+
1574
+ // Setup workflow type tab handlers
1575
+ const tabAllWorkflowsBtn = document.getElementById('tabAllWorkflows');
1576
+ const tabWorkflowOnlyBtn = document.getElementById('tabWorkflowOnly');
1577
+ const tabScreenshotsOnlyBtn = document.getElementById('tabScreenshotsOnly');
1578
+
1579
+ if (tabAllWorkflowsBtn) {
1580
+ tabAllWorkflowsBtn.addEventListener('click', () => switchWorkflowTab('all'));
1581
+ }
1582
+ if (tabWorkflowOnlyBtn) {
1583
+ tabWorkflowOnlyBtn.addEventListener('click', () => switchWorkflowTab('workflow'));
1584
+ }
1585
+ if (tabScreenshotsOnlyBtn) {
1586
+ tabScreenshotsOnlyBtn.addEventListener('click', () => switchWorkflowTab('screenshot'));
1587
+ }
1588
+
1324
1589
  // Load screen and workflow recordings with saved preferences
1325
1590
  loadScreenRecordings();
1326
1591
  loadWorkflowRecordings();
1327
-
1592
+
1593
+ // Setup Delete All button event listeners
1594
+ const deleteAllWorkflowsBtn = document.getElementById('deleteAllWorkflowsBtn');
1595
+ if (deleteAllWorkflowsBtn) {
1596
+ deleteAllWorkflowsBtn.addEventListener('click', deleteAllWorkflowRecordings);
1597
+ }
1598
+
1599
+ const deleteAllScreenRecordingsBtn = document.getElementById('deleteAllScreenRecordingsBtn');
1600
+ if (deleteAllScreenRecordingsBtn) {
1601
+ deleteAllScreenRecordingsBtn.addEventListener('click', deleteAllScreenRecordings);
1602
+ }
1603
+
1328
1604
  // Setup recording settings event listeners
1329
1605
  const frameRateSelect = document.getElementById('frameRate');
1330
1606
  const imageQualitySelect = document.getElementById('imageQuality');
@@ -1347,12 +1623,29 @@ document.addEventListener('DOMContentLoaded', () => {
1347
1623
  chrome.storage.local.set({ frameFlash: frameFlashCheckbox.checked });
1348
1624
  });
1349
1625
  }
1350
-
1626
+
1627
+ // Setup mouse tracking event listeners (PRO-only)
1628
+ const enableMouseTrackingCheckbox = document.getElementById('enableMouseTracking');
1629
+ const mouseSampleRateSelect = document.getElementById('mouseSampleRate');
1630
+
1631
+ if (enableMouseTrackingCheckbox && mouseSampleRateSelect) {
1632
+ enableMouseTrackingCheckbox.addEventListener('change', () => {
1633
+ const isEnabled = enableMouseTrackingCheckbox.checked && IS_PRO_VERSION;
1634
+ mouseSampleRateSelect.disabled = !isEnabled;
1635
+ chrome.storage.local.set({ mouseTrackingEnabled: isEnabled });
1636
+ });
1637
+
1638
+ mouseSampleRateSelect.addEventListener('change', () => {
1639
+ chrome.storage.local.set({ mouseSampleInterval: parseInt(mouseSampleRateSelect.value) });
1640
+ });
1641
+ }
1642
+
1351
1643
  // Check initial recording state from storage
1352
- chrome.storage.local.get(['recordingActive', 'recordingStartTime', 'pendingRecording', 'pendingTabId'], (result) => {
1644
+ chrome.storage.local.get(['recordingActive', 'recordingStartTime', 'pendingRecording', 'pendingTabId', 'isVideoModeActive'], (result) => {
1353
1645
  if (result.recordingActive) {
1354
1646
  isRecording = true;
1355
1647
  recordingStartTime = result.recordingStartTime || Date.now();
1648
+ isVideoModeActive = result.isVideoModeActive || false;
1356
1649
  updateRecordingUI();
1357
1650
  // console.log('Restored recording state from storage');
1358
1651
  } else if (result.pendingRecording && result.pendingTabId) {
@@ -1457,6 +1750,13 @@ document.addEventListener('DOMContentLoaded', () => {
1457
1750
  console.error('Error starting recording:', chrome.runtime.lastError);
1458
1751
  recordingStatus.textContent = 'Error: ' + chrome.runtime.lastError.message;
1459
1752
  recordBtn.textContent = 'Start Recording';
1753
+ // Reset Video Recording button on error
1754
+ const videoRecBtn = document.getElementById('startVideoRecordingBtn');
1755
+ if (videoRecBtn) {
1756
+ videoRecBtn.textContent = '🎥 Video Recording';
1757
+ videoRecBtn.disabled = false;
1758
+ videoRecBtn.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
1759
+ }
1460
1760
  return;
1461
1761
  }
1462
1762
 
@@ -1464,14 +1764,36 @@ document.addEventListener('DOMContentLoaded', () => {
1464
1764
  // console.log('Recording started successfully');
1465
1765
  isRecording = true;
1466
1766
  recordingStartTime = Date.now();
1467
-
1767
+
1468
1768
  // Capture current frame rate for countdown timer
1469
1769
  currentFrameRate = settings.frameRate;
1470
-
1770
+
1771
+ // Send mouse tracking settings to content script (available for all users)
1772
+ chrome.storage.local.get(['mouseTrackingEnabled', 'mouseSampleInterval'], (mouseSettings) => {
1773
+ const mouseTrackingEnabled = mouseSettings.mouseTrackingEnabled === true;
1774
+ const mouseSampleInterval = mouseSettings.mouseSampleInterval || 100;
1775
+
1776
+ chrome.tabs.sendMessage(tab.id, {
1777
+ action: 'setMouseTrackingSettings',
1778
+ enabled: mouseTrackingEnabled,
1779
+ sampleInterval: mouseSampleInterval
1780
+ }).catch(err => {
1781
+ // Ignore errors if content script isn't ready yet
1782
+ // console.warn('[Mouse Tracking] Failed to send settings:', err);
1783
+ });
1784
+ });
1785
+
1471
1786
  updateRecordingUI();
1472
1787
  } else {
1473
1788
  recordingStatus.textContent = 'Error: ' + (response?.error || 'Failed to start recording');
1474
1789
  recordBtn.textContent = 'Start Recording';
1790
+ // Reset Video Recording button on error
1791
+ const videoRecBtn = document.getElementById('startVideoRecordingBtn');
1792
+ if (videoRecBtn) {
1793
+ videoRecBtn.textContent = '🎥 Video Recording';
1794
+ videoRecBtn.disabled = false;
1795
+ videoRecBtn.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
1796
+ }
1475
1797
  }
1476
1798
  });
1477
1799
  } catch (error) {
@@ -1481,6 +1803,13 @@ document.addEventListener('DOMContentLoaded', () => {
1481
1803
  }
1482
1804
  recordBtn.disabled = false;
1483
1805
  recordBtn.textContent = 'Start Recording';
1806
+ // Reset Video Recording button on error
1807
+ const videoRecBtn = document.getElementById('startVideoRecordingBtn');
1808
+ if (videoRecBtn) {
1809
+ videoRecBtn.textContent = '🎥 Video Recording';
1810
+ videoRecBtn.disabled = false;
1811
+ videoRecBtn.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
1812
+ }
1484
1813
  }
1485
1814
  } else if (isRecording && !isStoppingRecording) {
1486
1815
  // Stop recording
@@ -1548,6 +1877,216 @@ document.addEventListener('DOMContentLoaded', () => {
1548
1877
  });
1549
1878
  }
1550
1879
 
1880
+ // Setup Video Recording button handler (optimized for video export)
1881
+ const startVideoRecordingBtn = document.getElementById('startVideoRecordingBtn');
1882
+ // isVideoModeActive is now a global variable defined at the top
1883
+
1884
+ if (startVideoRecordingBtn) {
1885
+ startVideoRecordingBtn.addEventListener('click', async (e) => {
1886
+ e.preventDefault();
1887
+
1888
+ // Immediate guard against double-clicks
1889
+ if (startVideoRecordingBtn.disabled) return;
1890
+
1891
+ // Handle stop action if video recording is active
1892
+ if (isVideoModeActive && isRecording) {
1893
+ try {
1894
+ startVideoRecordingBtn.disabled = true;
1895
+ startVideoRecordingBtn.textContent = '🎥 Stopping...';
1896
+
1897
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
1898
+ if (tab && tab.id) {
1899
+ await chrome.runtime.sendMessage({
1900
+ action: 'stopRecording',
1901
+ tabId: tab.id
1902
+ });
1903
+
1904
+ // Reset UI state
1905
+ isRecording = false;
1906
+ isVideoModeActive = false;
1907
+
1908
+ // Clear video mode and recording state from storage
1909
+ chrome.storage.local.set({
1910
+ isVideoModeActive: false,
1911
+ recordingActive: false
1912
+ });
1913
+
1914
+ // Use updateRecordingUI() for consistent button state management
1915
+ updateRecordingUI();
1916
+
1917
+ if (recordingStatus) {
1918
+ recordingStatus.textContent = 'Video recording stopped.';
1919
+ }
1920
+ }
1921
+ } catch (error) {
1922
+ console.error('Error stopping video recording:', error);
1923
+ // Re-enable button on error (keep as Stop since recording may still be active)
1924
+ startVideoRecordingBtn.disabled = false;
1925
+ }
1926
+ return;
1927
+ }
1928
+
1929
+ if (isRecording || isStoppingRecording) {
1930
+ // Already recording (non-video mode) - show message
1931
+ if (recordingStatus) {
1932
+ recordingStatus.textContent = 'Recording already in progress. Stop it first.';
1933
+ }
1934
+ return;
1935
+ }
1936
+
1937
+ try {
1938
+ // Check FREE tier usage limit before starting
1939
+ const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
1940
+ if (usageCheck && !usageCheck.allowed) {
1941
+ if (recordingStatus) {
1942
+ recordingStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
1943
+ `<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited.</small>`;
1944
+ }
1945
+ return;
1946
+ }
1947
+
1948
+ // Get the current active tab
1949
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
1950
+
1951
+ if (!tab || !tab.id) {
1952
+ console.error('No active tab found');
1953
+ if (recordingStatus) {
1954
+ recordingStatus.textContent = 'Error: No active tab';
1955
+ }
1956
+ return;
1957
+ }
1958
+
1959
+ // Check if server is running
1960
+ const serverStatus = await checkServerStatus();
1961
+ const isBrowserOnlyMode = !serverStatus.connected;
1962
+
1963
+ // Set optimal video settings (4 FPS, 90% quality, mouse tracking ON)
1964
+ const videoSettings = {
1965
+ frameRate: 0.25, // 4 FPS for smooth video playback
1966
+ imageQuality: 90, // Best quality for promotional content
1967
+ frameFlash: false, // No flash during capture
1968
+ videoMode: true // Flag for content.js to hide indicator
1969
+ };
1970
+
1971
+ // Save settings temporarily for this session
1972
+ await chrome.storage.local.set({
1973
+ mouseTrackingEnabled: true, // Auto-enable mouse tracking for video mode
1974
+ mouseSampleInterval: 50 // Fast mouse tracking (50ms)
1975
+ });
1976
+
1977
+ // Update UI elements to reflect video mode settings
1978
+ const frameRateSelect = document.getElementById('frameRate');
1979
+ const imageQualitySelect = document.getElementById('imageQuality');
1980
+ const enableMouseTrackingCheckbox = document.getElementById('enableMouseTracking');
1981
+ const mouseSampleRateSelect = document.getElementById('mouseSampleRate');
1982
+
1983
+ if (frameRateSelect) frameRateSelect.value = '0.5'; // Closest available option
1984
+ if (imageQualitySelect) imageQualitySelect.value = '70'; // Closest available option
1985
+ if (enableMouseTrackingCheckbox) {
1986
+ enableMouseTrackingCheckbox.checked = true;
1987
+ if (mouseSampleRateSelect) {
1988
+ mouseSampleRateSelect.disabled = false;
1989
+ mouseSampleRateSelect.value = '50';
1990
+ }
1991
+ }
1992
+
1993
+ // Disable button while starting
1994
+ startVideoRecordingBtn.textContent = '🎥 Starting...';
1995
+ startVideoRecordingBtn.disabled = true;
1996
+
1997
+ // Start recording with video mode settings
1998
+ console.log('[Video Recording] Sending settings to background:', {
1999
+ frameRate: videoSettings.frameRate,
2000
+ imageQuality: videoSettings.imageQuality,
2001
+ frameFlash: videoSettings.frameFlash,
2002
+ videoMode: true,
2003
+ maxWidth: 1280,
2004
+ maxHeight: 720
2005
+ });
2006
+ const response = await new Promise((resolve) => {
2007
+ chrome.runtime.sendMessage({
2008
+ action: 'startRecording',
2009
+ tabId: tab.id,
2010
+ settings: {
2011
+ frameRate: videoSettings.frameRate,
2012
+ imageQuality: videoSettings.imageQuality,
2013
+ frameFlash: videoSettings.frameFlash,
2014
+ videoMode: true, // Tells content.js to hide indicator after countdown
2015
+ maxWidth: 1280, // HD resolution for video export
2016
+ maxHeight: 720
2017
+ },
2018
+ mode: isBrowserOnlyMode ? 'browser-only' : 'server'
2019
+ }, resolve);
2020
+ });
2021
+
2022
+ if (response && response.success) {
2023
+ console.log('[Video Recording] Recording started successfully, setting isVideoModeActive = true');
2024
+ isRecording = true;
2025
+ isVideoModeActive = true; // Track that we're in video mode
2026
+ recordingStartTime = Date.now();
2027
+ currentFrameRate = videoSettings.frameRate;
2028
+
2029
+ // Save video mode state to storage for popup reopen
2030
+ chrome.storage.local.set({
2031
+ isVideoModeActive: true,
2032
+ recordingActive: true,
2033
+ recordingStartTime: recordingStartTime
2034
+ });
2035
+
2036
+ // Send mouse tracking settings to content script
2037
+ chrome.tabs.sendMessage(tab.id, {
2038
+ action: 'setMouseTrackingSettings',
2039
+ enabled: true,
2040
+ sampleInterval: 50
2041
+ }).catch(err => {
2042
+ // Ignore errors if content script isn't ready yet
2043
+ });
2044
+
2045
+ console.log('[Video Recording] Calling updateRecordingUI with isVideoModeActive:', isVideoModeActive);
2046
+ // Use updateRecordingUI() for consistent button state management
2047
+ // This ensures all buttons are properly updated based on isVideoModeActive flag
2048
+ updateRecordingUI();
2049
+
2050
+ // ALSO explicitly set button states here as backup
2051
+ const recordBtn = document.getElementById('recordBtn');
2052
+ const videoRecBtn = document.getElementById('startVideoRecordingBtn');
2053
+ if (recordBtn) {
2054
+ recordBtn.textContent = 'Start Recording';
2055
+ recordBtn.disabled = true;
2056
+ recordBtn.style.background = '#999';
2057
+ }
2058
+ if (videoRecBtn) {
2059
+ videoRecBtn.textContent = '🎥 Stop Video Recording';
2060
+ videoRecBtn.style.background = '#f44336';
2061
+ videoRecBtn.disabled = false;
2062
+ }
2063
+
2064
+ if (recordingStatus) {
2065
+ recordingStatus.innerHTML = '<strong style="color: #4CAF50;">🎥 Video Recording Active</strong><br>' +
2066
+ '<small>Click 🎥 Stop Video Recording to end.</small>';
2067
+ }
2068
+ } else {
2069
+ if (recordingStatus) {
2070
+ recordingStatus.textContent = 'Error: ' + (response?.error || 'Failed to start video recording');
2071
+ }
2072
+ // Reset state and UI on failure
2073
+ isRecording = false;
2074
+ isVideoModeActive = false;
2075
+ updateRecordingUI();
2076
+ }
2077
+ } catch (error) {
2078
+ console.error('Error starting video recording:', error);
2079
+ if (recordingStatus) {
2080
+ recordingStatus.textContent = 'Error: ' + error.message;
2081
+ }
2082
+ // Reset state and UI on error
2083
+ isRecording = false;
2084
+ isVideoModeActive = false;
2085
+ updateRecordingUI();
2086
+ }
2087
+ });
2088
+ }
2089
+
1551
2090
  /*
1552
2091
  * SNAPSHOT FEATURE DISABLED (2025-10-01)
1553
2092
  * Snapshot button click handler disabled - see SNAPSHOT_FEATURE_DISABLED.md
@@ -1572,39 +2111,60 @@ document.addEventListener('DOMContentLoaded', () => {
1572
2111
  workflowRecordBtn.addEventListener('click', async () => {
1573
2112
  if (!isWorkflowRecording) {
1574
2113
  // Start workflow recording
2114
+ console.log('[Workflow] Button clicked');
2115
+
2116
+ // Store original button text and disable button
2117
+ const originalButtonText = workflowRecordBtn.textContent;
2118
+ workflowRecordBtn.disabled = true;
2119
+ workflowRecordBtn.textContent = '⏳ Checking...';
2120
+
1575
2121
  try {
1576
2122
  // Check if server is running before starting workflow recording
1577
2123
  const serverStatus = await checkServerStatus();
1578
2124
  if (!serverStatus.connected) {
1579
- console.error('Server not running');
2125
+ console.error('[Workflow] Server not running');
1580
2126
  const workflowStatus = document.getElementById('workflowRecordingStatus');
1581
2127
  if (workflowStatus) {
1582
2128
  workflowStatus.innerHTML = '<strong style="color: #f44336;">Error: Server not running</strong><br>' +
1583
2129
  '<small>Please start the Chrome Debug server first</small>';
1584
2130
  }
2131
+ // Show toast notification for better visibility
2132
+ showToast('Server not running. Start Chrome Debug server first.', 4000, 'error');
1585
2133
  // Clear error message after 5 seconds
1586
2134
  setTimeout(() => {
1587
2135
  if (workflowStatus) workflowStatus.textContent = '';
1588
2136
  }, 5000);
2137
+ // Restore button state
2138
+ workflowRecordBtn.disabled = false;
2139
+ workflowRecordBtn.textContent = originalButtonText;
1589
2140
  return;
1590
2141
  }
1591
2142
 
1592
2143
  // Check FREE tier usage limit before starting
1593
2144
  const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
1594
2145
  if (usageCheck && !usageCheck.allowed) {
1595
- // console.log('[Usage] Daily limit reached:', usageCheck);
2146
+ console.log('[Workflow] Daily limit reached:', usageCheck);
1596
2147
  const workflowStatus = document.getElementById('workflowRecordingStatus');
1597
2148
  if (workflowStatus) {
1598
2149
  workflowStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
1599
2150
  `<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited recordings.</small>`;
1600
2151
  }
2152
+ // Show toast notification for better visibility
2153
+ showToast(`Daily limit reached (${usageCheck.count}/${usageCheck.limit}). Upgrade to Pro for unlimited recordings.`, 4000, 'error');
2154
+ // Restore button state
2155
+ workflowRecordBtn.disabled = false;
2156
+ workflowRecordBtn.textContent = originalButtonText;
1601
2157
  return;
1602
2158
  }
1603
2159
 
1604
2160
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
1605
2161
 
1606
2162
  if (!tab || !tab.id) {
1607
- console.error('No active tab found');
2163
+ console.error('[Workflow] No active tab found');
2164
+ showToast('No active tab found. Please try again.', 3000, 'error');
2165
+ // Restore button state
2166
+ workflowRecordBtn.disabled = false;
2167
+ workflowRecordBtn.textContent = originalButtonText;
1608
2168
  return;
1609
2169
  }
1610
2170
 
@@ -1666,13 +2226,21 @@ document.addEventListener('DOMContentLoaded', () => {
1666
2226
  isWorkflowRecording = true;
1667
2227
  // Save state and start time to storage
1668
2228
  const startTime = Date.now();
1669
- chrome.storage.local.set({
2229
+ chrome.storage.local.set({
1670
2230
  workflowRecording: true,
1671
2231
  workflowStartTime: startTime
1672
2232
  });
1673
2233
  workflowStartTime = startTime;
2234
+ // Re-enable button and update UI for recording state
2235
+ workflowRecordBtn.disabled = false;
1674
2236
  updateWorkflowRecordingUI();
1675
2237
  if (workflowRecordingsList) workflowRecordingsList.style.display = 'none';
2238
+ } else {
2239
+ // Retry failed
2240
+ console.error('[Workflow] Retry failed:', retryResponse);
2241
+ showToast('Failed to start workflow recording after content script injection.', 3000, 'error');
2242
+ workflowRecordBtn.disabled = false;
2243
+ workflowRecordBtn.textContent = originalButtonText;
1676
2244
  }
1677
2245
  });
1678
2246
  }, 100);
@@ -1687,14 +2255,28 @@ document.addEventListener('DOMContentLoaded', () => {
1687
2255
  workflowStartTime: startTime
1688
2256
  });
1689
2257
  workflowStartTime = startTime;
2258
+ // Re-enable button and update UI for recording state
2259
+ workflowRecordBtn.disabled = false;
1690
2260
  updateWorkflowRecordingUI();
1691
2261
  // Hide any previous results
1692
2262
  if (workflowRecordingsList) workflowRecordingsList.style.display = 'none';
2263
+ } else {
2264
+ // Response received but not successful
2265
+ console.error('[Workflow] Failed to start recording:', response);
2266
+ showToast('Failed to start workflow recording. Please try again.', 3000, 'error');
2267
+ workflowRecordBtn.disabled = false;
2268
+ workflowRecordBtn.textContent = originalButtonText;
1693
2269
  }
1694
2270
  });
1695
2271
  } catch (error) {
1696
- console.error('Error starting workflow recording:', error);
2272
+ console.error('[Workflow] Error starting workflow recording:', error);
2273
+ showToast('Error starting workflow recording. Please try again.', 3000, 'error');
2274
+ // Restore button state on error
2275
+ workflowRecordBtn.disabled = false;
2276
+ workflowRecordBtn.textContent = originalButtonText;
1697
2277
  }
2278
+ // Note: Button state is managed by updateWorkflowRecordingUI() on success
2279
+ // or restored explicitly in catch/early returns on failure
1698
2280
  } else {
1699
2281
  // Stop workflow recording
1700
2282
  try {
@@ -1765,7 +2347,241 @@ document.addEventListener('DOMContentLoaded', () => {
1765
2347
  chrome.storage.local.set({ includeLogsInExport: includeLogsCheckbox.checked });
1766
2348
  });
1767
2349
  }
1768
-
2350
+
2351
+ // Setup screenshot recording button
2352
+ const screenshotRecordBtn = document.getElementById('screenshotRecordBtn');
2353
+
2354
+ if (screenshotRecordBtn) {
2355
+ screenshotRecordBtn.addEventListener('click', async () => {
2356
+ if (!isScreenshotRecording) {
2357
+ // Start screenshot recording
2358
+ console.log('[Screenshot] Button clicked');
2359
+
2360
+ // Store original button text and disable button
2361
+ const originalButtonText = screenshotRecordBtn.textContent;
2362
+ screenshotRecordBtn.disabled = true;
2363
+ screenshotRecordBtn.textContent = '⏳ Checking...';
2364
+
2365
+ try {
2366
+ // Check if server is running before starting screenshot recording
2367
+ const serverStatus = await checkServerStatus();
2368
+ if (!serverStatus.connected) {
2369
+ console.error('[Screenshot] Server not running');
2370
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
2371
+ if (screenshotStatus) {
2372
+ screenshotStatus.innerHTML = '<strong style="color: #f44336;">Error: Server not running</strong><br>' +
2373
+ '<small>Please start the Chrome Debug server first</small>';
2374
+ }
2375
+ // Show toast notification for better visibility
2376
+ showToast('Server not running. Start Chrome Debug server first.', 4000, 'error');
2377
+ // Clear error message after 5 seconds
2378
+ setTimeout(() => {
2379
+ if (screenshotStatus) screenshotStatus.textContent = '';
2380
+ }, 5000);
2381
+ // Restore button state
2382
+ screenshotRecordBtn.disabled = false;
2383
+ screenshotRecordBtn.textContent = originalButtonText;
2384
+ return;
2385
+ }
2386
+
2387
+ // Check FREE tier usage limit before starting
2388
+ const usageCheck = await chrome.runtime.sendMessage({ action: 'checkUsageLimit' });
2389
+ if (usageCheck && !usageCheck.allowed) {
2390
+ console.log('[Screenshot] Daily limit reached:', usageCheck);
2391
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
2392
+ if (screenshotStatus) {
2393
+ screenshotStatus.innerHTML = '<strong style="color: #f44336;">Daily limit reached</strong><br>' +
2394
+ `<small>${usageCheck.count}/${usageCheck.limit} recordings used today.<br>Upgrade to Pro for unlimited recordings.</small>`;
2395
+ }
2396
+ // Show toast notification for better visibility
2397
+ showToast(`Daily limit reached (${usageCheck.count}/${usageCheck.limit}). Upgrade to Pro for unlimited recordings.`, 4000, 'error');
2398
+ // Restore button state
2399
+ screenshotRecordBtn.disabled = false;
2400
+ screenshotRecordBtn.textContent = originalButtonText;
2401
+ return;
2402
+ }
2403
+
2404
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
2405
+
2406
+ if (!tab || !tab.id) {
2407
+ console.error('[Screenshot] No active tab found');
2408
+ showToast('No active tab found. Please try again.', 3000, 'error');
2409
+ // Restore button state
2410
+ screenshotRecordBtn.disabled = false;
2411
+ screenshotRecordBtn.textContent = originalButtonText;
2412
+ return;
2413
+ }
2414
+
2415
+ // Get screenshot recording settings
2416
+ const hideCursor = document.getElementById('hideMouseCursorCheckbox')?.checked ?? true;
2417
+ const countdown = parseInt(document.getElementById('screenshotCountdown')?.value) || 3;
2418
+
2419
+ const screenshotModeSettings = {
2420
+ hideCursor: hideCursor,
2421
+ countdown: countdown
2422
+ };
2423
+
2424
+ // Send message to background script to start screenshot recording
2425
+ chrome.runtime.sendMessage({
2426
+ action: 'startScreenshotRecording',
2427
+ tabId: tab.id,
2428
+ settings: screenshotModeSettings
2429
+ }, (response) => {
2430
+ if (chrome.runtime.lastError) {
2431
+ // Check if this tab allows content script injection
2432
+ if (!tab.url || tab.url.startsWith('chrome://') || tab.url.startsWith('chrome-extension://') || tab.url.startsWith('moz-extension://')) {
2433
+ const screenshotStatus = document.getElementById('screenshotRecordingStatus');
2434
+ if (screenshotStatus) {
2435
+ screenshotStatus.innerHTML = '<strong style="color: #f44336;">Cannot record on this page</strong>';
2436
+ }
2437
+ return;
2438
+ }
2439
+ // Inject content script if needed
2440
+ chrome.scripting.executeScript({
2441
+ target: { tabId: tab.id },
2442
+ files: ['content.js']
2443
+ }, () => {
2444
+ if (chrome.runtime.lastError) {
2445
+ console.error('Failed to inject content script:', chrome.runtime.lastError);
2446
+ return;
2447
+ }
2448
+ chrome.scripting.insertCSS({
2449
+ target: { tabId: tab.id },
2450
+ files: ['content.css']
2451
+ }, () => {
2452
+ if (chrome.runtime.lastError) {
2453
+ console.error('Failed to inject CSS:', chrome.runtime.lastError);
2454
+ return;
2455
+ }
2456
+ // Try again after injection
2457
+ setTimeout(() => {
2458
+ chrome.runtime.sendMessage({
2459
+ action: 'startScreenshotRecording',
2460
+ tabId: tab.id,
2461
+ settings: screenshotModeSettings
2462
+ }, (retryResponse) => {
2463
+ if (retryResponse && retryResponse.success) {
2464
+ isScreenshotRecording = true;
2465
+ // Save state and start time to storage
2466
+ const startTime = Date.now();
2467
+ chrome.storage.local.set({
2468
+ screenshotRecording: true,
2469
+ screenshotStartTime: startTime,
2470
+ screenshotSessionId: retryResponse.sessionId
2471
+ });
2472
+ screenshotStartTime = startTime;
2473
+ // Re-enable button and update UI for recording state
2474
+ screenshotRecordBtn.disabled = false;
2475
+ updateScreenshotRecordingUI();
2476
+ if (workflowRecordingsList) workflowRecordingsList.style.display = 'none';
2477
+ } else {
2478
+ // Retry failed
2479
+ console.error('[Screenshot] Retry failed:', retryResponse);
2480
+ showToast('Failed to start screenshot recording after content script injection.', 3000, 'error');
2481
+ screenshotRecordBtn.disabled = false;
2482
+ screenshotRecordBtn.textContent = originalButtonText;
2483
+ }
2484
+ });
2485
+ }, 100);
2486
+ });
2487
+ });
2488
+ } else if (response && response.success) {
2489
+ isScreenshotRecording = true;
2490
+ // Save state and start time to storage
2491
+ const startTime = Date.now();
2492
+ chrome.storage.local.set({
2493
+ screenshotRecording: true,
2494
+ screenshotStartTime: startTime,
2495
+ screenshotSessionId: response.sessionId
2496
+ });
2497
+ screenshotStartTime = startTime;
2498
+ // Re-enable button and update UI for recording state
2499
+ screenshotRecordBtn.disabled = false;
2500
+ updateScreenshotRecordingUI();
2501
+ // Hide any previous results
2502
+ if (workflowRecordingsList) workflowRecordingsList.style.display = 'none';
2503
+ } else {
2504
+ // Response received but not successful
2505
+ console.error('[Screenshot] Failed to start recording:', response);
2506
+ showToast('Failed to start screenshot recording. Please try again.', 3000, 'error');
2507
+ screenshotRecordBtn.disabled = false;
2508
+ screenshotRecordBtn.textContent = originalButtonText;
2509
+ }
2510
+ });
2511
+ } catch (error) {
2512
+ console.error('[Screenshot] Error starting screenshot recording:', error);
2513
+ showToast('Error starting screenshot recording. Please try again.', 3000, 'error');
2514
+ // Restore button state on error
2515
+ screenshotRecordBtn.disabled = false;
2516
+ screenshotRecordBtn.textContent = originalButtonText;
2517
+ }
2518
+ // Note: Button state is managed by updateScreenshotRecordingUI() on success
2519
+ // or restored explicitly in catch/early returns on failure
2520
+ } else {
2521
+ // Stop screenshot recording
2522
+ try {
2523
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
2524
+
2525
+ if (!tab || !tab.id) {
2526
+ console.error('No active tab found');
2527
+ return;
2528
+ }
2529
+
2530
+ // Send message to background script to stop screenshot recording
2531
+ chrome.runtime.sendMessage({
2532
+ action: 'stopScreenshotRecording',
2533
+ tabId: tab.id
2534
+ }, async (response) => {
2535
+ if (chrome.runtime.lastError) {
2536
+ console.error('Error stopping screenshot recording:', chrome.runtime.lastError);
2537
+ // Still stop recording in UI even if there was an error
2538
+ isScreenshotRecording = false;
2539
+ chrome.storage.local.set({
2540
+ screenshotRecording: false,
2541
+ screenshotStartTime: null,
2542
+ screenshotSessionId: null
2543
+ });
2544
+ updateScreenshotRecordingUI();
2545
+ alert('Error stopping screenshot recording. The recording may have been lost.');
2546
+ return;
2547
+ }
2548
+
2549
+ if (response && response.success) {
2550
+ isScreenshotRecording = false;
2551
+ // Clear state from storage
2552
+ chrome.storage.local.set({
2553
+ screenshotRecording: false,
2554
+ screenshotStartTime: null,
2555
+ screenshotSessionId: null
2556
+ });
2557
+ updateScreenshotRecordingUI();
2558
+
2559
+ // Show loading overlay over workflow recording section
2560
+ showSectionLoading('workflow-recording-section', 'Saving screenshot recording...');
2561
+
2562
+ try {
2563
+ // Single source of truth - load from server
2564
+ await loadWorkflowRecordings(true);
2565
+
2566
+ // Show success toast
2567
+ const screenshotCount = response.screenshotCount || 0;
2568
+ showToast(`Screenshot recording saved! ${screenshotCount} screenshots captured`, 3000, 'success');
2569
+ } catch (error) {
2570
+ console.error('Error loading workflow recordings:', error);
2571
+ showToast('Error loading recordings. Please refresh.', 3000, 'error');
2572
+ } finally {
2573
+ // Always hide loading overlay
2574
+ hideSectionLoading('workflow-recording-section');
2575
+ }
2576
+ }
2577
+ });
2578
+ } catch (error) {
2579
+ console.error('Error stopping screenshot recording:', error);
2580
+ }
2581
+ }
2582
+ });
2583
+ }
2584
+
1769
2585
  // Setup save restore point button
1770
2586
  const saveRestorePointBtn = document.getElementById('saveRestorePointBtn');
1771
2587
  const restorePointsList = document.getElementById('restorePointsList');
@@ -2138,11 +2954,13 @@ async function loadWorkflowRecordings(autoShow = false) {
2138
2954
  const ports = CONFIG_PORTS;
2139
2955
  for (const port of ports) {
2140
2956
  try {
2141
- const response = await fetch(`http://localhost:${port}/chromedebug/workflow-recordings`);
2957
+ // Add filter parameter based on workflowTabFilter
2958
+ const filterParam = workflowTabFilter !== 'all' ? `?mode=${workflowTabFilter}` : '';
2959
+ const response = await fetch(`http://localhost:${port}/chromedebug/workflow-recordings${filterParam}`);
2142
2960
  if (response.ok) {
2143
2961
  const data = await response.json();
2144
2962
  // console.log('Loaded workflow recordings from port', port, ':', data);
2145
-
2963
+
2146
2964
  // Handle both data.recordings and direct array response
2147
2965
  const recordings = data.recordings || data;
2148
2966
 
@@ -2152,16 +2970,22 @@ async function loadWorkflowRecordings(autoShow = false) {
2152
2970
  recordings.forEach(recording => {
2153
2971
  const workflowItem = document.createElement('div');
2154
2972
  workflowItem.className = 'recording-item';
2155
-
2973
+
2156
2974
  const displayName = recording.name || `Workflow ${recording.session_id}`;
2157
2975
  const date = new Date(recording.timestamp);
2158
2976
  const formattedDate = date.toLocaleString();
2159
-
2977
+
2978
+ // Determine recording type badge
2979
+ const recordingMode = recording.recording_mode || 'workflow';
2980
+ const typeBadge = recordingMode === 'screenshot'
2981
+ ? '<span style="background: #FF9800; color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">SCREENSHOT</span>'
2982
+ : '<span style="background: #9c27b0; color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">WORKFLOW</span>';
2983
+
2160
2984
  workflowItem.innerHTML = `
2161
2985
  <div class="recording-info">
2162
- <div style="font-weight: bold; margin-bottom: 4px;">${displayName}</div>
2986
+ <div style="font-weight: bold; margin-bottom: 4px;">${displayName}${typeBadge}</div>
2163
2987
  <div style="color: #666; font-size: 11px;">
2164
- ${recording.total_actions} actions • ${formattedDate}
2988
+ ${recording.total_actions} ${recordingMode === 'screenshot' ? 'screenshots' : 'actions'} • ${formattedDate}
2165
2989
  </div>
2166
2990
  ${recording.screenshot_settings ? '<div style="color: #2196F3; font-size: 10px;">&#128248; Screenshots included</div>' : ''}
2167
2991
  </div>
@@ -2249,10 +3073,17 @@ async function loadWorkflowRecordings(autoShow = false) {
2249
3073
  workflowRecordingsContainer.appendChild(workflowItem);
2250
3074
  });
2251
3075
  } else {
2252
- // Show "No recordings found" message
3076
+ // Show "No recordings found" message with context about current filter
2253
3077
  const noRecordingsMsg = document.createElement('div');
2254
3078
  noRecordingsMsg.style.cssText = 'color: #666; font-size: 13px; text-align: center; padding: 20px;';
2255
- noRecordingsMsg.textContent = 'No workflow recordings found';
3079
+ // Show filter-specific message when a category filter is selected
3080
+ if (workflowTabFilter === 'workflow') {
3081
+ noRecordingsMsg.textContent = 'No workflow recordings in this category';
3082
+ } else if (workflowTabFilter === 'screenshot') {
3083
+ noRecordingsMsg.textContent = 'No screenshot recordings in this category';
3084
+ } else {
3085
+ noRecordingsMsg.textContent = 'No workflow recordings found';
3086
+ }
2256
3087
  workflowRecordingsContainer.appendChild(noRecordingsMsg);
2257
3088
  }
2258
3089
  break; // Found working server
@@ -2271,7 +3102,9 @@ async function loadWorkflowRecordings(autoShow = false) {
2271
3102
  }
2272
3103
 
2273
3104
  // Handle visibility based on recordings and user preference
2274
- if (!hasRecordings) {
3105
+ // CRITICAL FIX: When a tab filter is selected (not 'all'), keep the section visible
3106
+ // so users can switch back to other tabs. Only hide if 'all' filter returns no results.
3107
+ if (!hasRecordings && workflowTabFilter === 'all') {
2275
3108
  workflowRecordingsList.style.display = 'none';
2276
3109
  } else {
2277
3110
  // Get user's saved preference
@@ -2290,6 +3123,12 @@ async function loadWorkflowRecordings(autoShow = false) {
2290
3123
  }
2291
3124
  }
2292
3125
  }
3126
+
3127
+ // Show/hide Delete All button based on recording count
3128
+ const deleteAllWorkflowsBtn = document.getElementById('deleteAllWorkflowsBtn');
3129
+ if (deleteAllWorkflowsBtn) {
3130
+ deleteAllWorkflowsBtn.style.display = hasRecordings ? 'block' : 'none';
3131
+ }
2293
3132
  }
2294
3133
 
2295
3134
  // Function to play a workflow
@@ -2437,6 +3276,190 @@ async function deleteWorkflowRecording(recordingId) {
2437
3276
  }
2438
3277
  }
2439
3278
 
3279
+ // Function to delete all workflow recordings
3280
+ async function deleteAllWorkflowRecordings() {
3281
+ try {
3282
+ // Get current count for confirmation
3283
+ const workflowRecordingsContainer = document.getElementById('workflowRecordingsContainer');
3284
+ const recordingItems = workflowRecordingsContainer?.querySelectorAll('.recording-item') || [];
3285
+ const recordingCount = recordingItems.length;
3286
+
3287
+ if (recordingCount === 0) {
3288
+ alert('No workflow recordings to delete');
3289
+ return;
3290
+ }
3291
+
3292
+ // Check if workflow recording is in progress
3293
+ const workflowRecordBtn = document.getElementById('workflowRecordBtn');
3294
+ if (workflowRecordBtn && workflowRecordBtn.textContent.includes('Stop')) {
3295
+ alert('Cannot delete all while workflow recording is in progress. Stop recording first.');
3296
+ return;
3297
+ }
3298
+
3299
+ // First confirmation dialog
3300
+ const confirmMessage = `Are you sure you want to delete ALL ${recordingCount} workflow recording(s)?\n\nThis will also delete:\n- All associated restore points\n- All recorded actions and logs\n\nThis action CANNOT be undone!`;
3301
+ if (!confirm(confirmMessage)) {
3302
+ return;
3303
+ }
3304
+
3305
+ // Second confirmation for safety
3306
+ const finalConfirm = confirm('Final confirmation: Delete all workflow recordings permanently?');
3307
+ if (!finalConfirm) {
3308
+ return;
3309
+ }
3310
+
3311
+ // Disable button during deletion
3312
+ const deleteBtn = document.getElementById('deleteAllWorkflowsBtn');
3313
+ const originalText = deleteBtn.textContent;
3314
+ deleteBtn.disabled = true;
3315
+ deleteBtn.textContent = 'Deleting...';
3316
+
3317
+ // Delete from server
3318
+ const ports = CONFIG_PORTS;
3319
+ let deleted = false;
3320
+
3321
+ for (const port of ports) {
3322
+ try {
3323
+ const response = await fetch(`http://localhost:${port}/chromedebug/workflow-recordings/all`, {
3324
+ method: 'DELETE'
3325
+ });
3326
+
3327
+ if (response.ok) {
3328
+ const result = await response.json();
3329
+ deleted = true;
3330
+ alert(`Successfully deleted ${result.deletedCount} workflow recording(s)`);
3331
+
3332
+ // Reload the list
3333
+ loadWorkflowRecordings();
3334
+ break; // Found working server
3335
+ }
3336
+ } catch (error) {
3337
+ console.error(`Failed to delete all workflows from port ${port}:`, error);
3338
+ }
3339
+ }
3340
+
3341
+ if (!deleted) {
3342
+ alert('Failed to connect to server. Please ensure Chrome Debug server is running.');
3343
+ }
3344
+
3345
+ // Re-enable button
3346
+ deleteBtn.disabled = false;
3347
+ deleteBtn.textContent = originalText;
3348
+
3349
+ } catch (error) {
3350
+ console.error('Error deleting all workflow recordings:', error);
3351
+ alert('An error occurred while deleting recordings');
3352
+ // Re-enable button on error
3353
+ const deleteBtn = document.getElementById('deleteAllWorkflowsBtn');
3354
+ if (deleteBtn) {
3355
+ deleteBtn.disabled = false;
3356
+ deleteBtn.textContent = 'Delete All';
3357
+ }
3358
+ }
3359
+ }
3360
+
3361
+ // Function to delete all screen recordings
3362
+ async function deleteAllScreenRecordings() {
3363
+ try {
3364
+ // Count recordings from the list
3365
+ const recordingsContainer = document.getElementById('recordingsContainer');
3366
+ const recordingItems = recordingsContainer?.querySelectorAll('.recording-item') || [];
3367
+ const recordingCount = recordingItems.length;
3368
+
3369
+ if (recordingCount === 0) {
3370
+ alert('No screen recordings to delete');
3371
+ return;
3372
+ }
3373
+
3374
+ // Check if screen recording is in progress
3375
+ const recordBtn = document.getElementById('recordBtn');
3376
+ if (recordBtn && recordBtn.textContent.includes('Stop')) {
3377
+ alert('Cannot delete all while screen recording is in progress. Stop recording first.');
3378
+ return;
3379
+ }
3380
+
3381
+ // First confirmation dialog
3382
+ const confirmMessage = `Are you sure you want to delete ALL ${recordingCount} screen recording(s)?\n\nThis includes both server and browser-only recordings.\n\nThis action CANNOT be undone!`;
3383
+ if (!confirm(confirmMessage)) {
3384
+ return;
3385
+ }
3386
+
3387
+ // Second confirmation for safety
3388
+ const finalConfirm = confirm('Final confirmation: Delete all screen recordings permanently?');
3389
+ if (!finalConfirm) {
3390
+ return;
3391
+ }
3392
+
3393
+ // Disable button during deletion
3394
+ const deleteBtn = document.getElementById('deleteAllScreenRecordingsBtn');
3395
+ const originalText = deleteBtn.textContent;
3396
+ deleteBtn.disabled = true;
3397
+ deleteBtn.textContent = 'Deleting...';
3398
+
3399
+ let deletedCount = 0;
3400
+
3401
+ // Delete browser-only recordings first
3402
+ try {
3403
+ const result = await chrome.runtime.sendMessage({
3404
+ action: 'deleteAllBrowserRecordings'
3405
+ });
3406
+
3407
+ if (result && result.success) {
3408
+ deletedCount += result.deletedCount;
3409
+ }
3410
+ } catch (error) {
3411
+ console.error('Failed to delete browser-only recordings:', error);
3412
+ }
3413
+
3414
+ // Delete server recordings
3415
+ const ports = CONFIG_PORTS;
3416
+ for (const port of ports) {
3417
+ try {
3418
+ const response = await fetch(`http://localhost:${port}/chromedebug/recordings/all`, {
3419
+ method: 'DELETE'
3420
+ });
3421
+
3422
+ if (response.ok) {
3423
+ const result = await response.json();
3424
+ deletedCount += result.deletedCount;
3425
+ break; // Found working server
3426
+ }
3427
+ } catch (error) {
3428
+ console.error(`Failed to delete all recordings from port ${port}:`, error);
3429
+ }
3430
+ }
3431
+
3432
+ if (deletedCount > 0) {
3433
+ alert(`Successfully deleted ${deletedCount} screen recording(s)`);
3434
+ // Reload the list
3435
+ loadScreenRecordings();
3436
+ } else {
3437
+ alert('No recordings were deleted. Please check server connection.');
3438
+ }
3439
+
3440
+ // Re-enable button
3441
+ deleteBtn.disabled = false;
3442
+ deleteBtn.textContent = originalText;
3443
+
3444
+ } catch (error) {
3445
+ console.error('Error deleting all screen recordings:', error);
3446
+ alert('An error occurred while deleting recordings');
3447
+ // Re-enable button on error
3448
+ const deleteBtn = document.getElementById('deleteAllScreenRecordingsBtn');
3449
+ if (deleteBtn) {
3450
+ deleteBtn.disabled = false;
3451
+ deleteBtn.textContent = 'Delete All';
3452
+ }
3453
+ }
3454
+ }
3455
+
3456
+ // Helper function to normalize isVideoMode to boolean
3457
+ function normalizeIsVideoMode(value) {
3458
+ if (value === true || value === 1 || value === 'true' || value === '1') return true;
3459
+ if (value === false || value === 0 || value === 'false' || value === '0' || value === null || value === undefined) return false;
3460
+ return Boolean(value);
3461
+ }
3462
+
2440
3463
  // Function to load and display screen recordings
2441
3464
  async function loadScreenRecordings(autoShow = false) {
2442
3465
  const recordingsList = document.getElementById('recordingsList');
@@ -2466,6 +3489,11 @@ async function loadScreenRecordings(autoShow = false) {
2466
3489
 
2467
3490
  // Display each browser-only recording
2468
3491
  browserRecordings.forEach(recording => {
3492
+ // Apply tab filter - normalize isVideoMode to handle various types
3493
+ const isVideo = normalizeIsVideoMode(recording.isVideoMode);
3494
+ if (recordingTabFilter === 'video' && !isVideo) return;
3495
+ if (recordingTabFilter === 'screen' && isVideo) return;
3496
+
2469
3497
  const recordingItem = document.createElement('div');
2470
3498
  recordingItem.className = 'recording-item';
2471
3499
 
@@ -2473,10 +3501,17 @@ async function loadScreenRecordings(autoShow = false) {
2473
3501
  const formattedDate = date.toLocaleString();
2474
3502
  const displayName = recording.title || `Recording ${recording.sessionId}`;
2475
3503
 
3504
+ // Determine recording type badge for browser-only recordings
3505
+ const isVideoBrowser = normalizeIsVideoMode(recording.isVideoMode);
3506
+ const typeBadgeBrowser = isVideoBrowser
3507
+ ? '<span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">VIDEO</span>'
3508
+ : '<span style="background: #4CAF50; color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">SCREEN</span>';
3509
+
2476
3510
  recordingItem.innerHTML = `
2477
3511
  <div class="recording-info">
2478
3512
  <div class="recording-id" title="${recording.sessionId}">
2479
3513
  <span class="recording-id-text">🌐 ${displayName}</span>
3514
+ ${typeBadgeBrowser}
2480
3515
  <span style="font-size: 10px; background: #ff9800; color: white; padding: 2px 6px; border-radius: 3px; margin-left: 4px;">BROWSER-ONLY</span>
2481
3516
  <span style="color: #666; font-size: 11px; margin-left: 8px;">${recording.frameCount || 0} frames • ${formattedDate}</span>
2482
3517
  </div>
@@ -2589,8 +3624,18 @@ async function loadScreenRecordings(autoShow = false) {
2589
3624
  hasRecordings = true;
2590
3625
  recordingsList.style.display = 'block';
2591
3626
 
3627
+ // Debug logging
3628
+ console.log('[Popup] Loaded recordings from server:', data.length, 'total');
3629
+ console.log('[Popup] Current tab filter:', recordingTabFilter);
3630
+ console.log('[Popup] Sample recording isVideoMode values:', data.slice(0, 3).map(r => ({ id: r.sessionId, isVideoMode: r.isVideoMode, type: typeof r.isVideoMode })));
3631
+
2592
3632
  // Display each screen recording
2593
3633
  data.forEach(recording => {
3634
+ // Apply tab filter - normalize isVideoMode to handle various types
3635
+ const isVideo = normalizeIsVideoMode(recording.isVideoMode);
3636
+ if (recordingTabFilter === 'video' && !isVideo) return;
3637
+ if (recordingTabFilter === 'screen' && isVideo) return;
3638
+
2594
3639
  const recordingItem = document.createElement('div');
2595
3640
  recordingItem.className = 'recording-item';
2596
3641
 
@@ -2603,10 +3648,16 @@ async function loadScreenRecordings(autoShow = false) {
2603
3648
  const displayName = recording.name || `Recording ${recording.sessionId}`;
2604
3649
  // console.log('Display name:', displayName);
2605
3650
 
3651
+ // Determine recording type badge (already computed above for filter)
3652
+ const typeBadge = isVideo
3653
+ ? '<span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">VIDEO</span>'
3654
+ : '<span style="background: #4CAF50; color: white; font-size: 8px; padding: 1px 4px; border-radius: 3px; margin-left: 4px;">SCREEN</span>';
3655
+
2606
3656
  recordingItem.innerHTML = `
2607
3657
  <div class="recording-info">
2608
3658
  <div class="recording-id" title="${recording.sessionId}">
2609
3659
  <span class="recording-id-text">🎥 ${displayName}</span>
3660
+ ${typeBadge}
2610
3661
  <span style="color: #666; font-size: 11px; margin-left: 8px;">${recording.totalFrames} frames • ${formattedDate}</span>
2611
3662
  </div>
2612
3663
  </div>
@@ -2708,6 +3759,11 @@ async function loadScreenRecordings(autoShow = false) {
2708
3759
  }
2709
3760
  }
2710
3761
 
3762
+ // Check if all recordings were filtered out
3763
+ if (hasRecordings && recordingsContainer.children.length === 0) {
3764
+ recordingsContainer.innerHTML = `<div style="text-align: center; color: #999; padding: 20px; font-size: 11px;">No ${recordingTabFilter === 'all' ? '' : recordingTabFilter + ' '}recordings found</div>`;
3765
+ }
3766
+
2711
3767
  // Handle visibility based on recordings and user preference
2712
3768
  if (!hasRecordings) {
2713
3769
  recordingsList.style.display = 'none';
@@ -2728,6 +3784,12 @@ async function loadScreenRecordings(autoShow = false) {
2728
3784
  }
2729
3785
  }
2730
3786
  }
3787
+
3788
+ // Show/hide Delete All button based on recording count
3789
+ const deleteAllScreenRecordingsBtn = document.getElementById('deleteAllScreenRecordingsBtn');
3790
+ if (deleteAllScreenRecordingsBtn) {
3791
+ deleteAllScreenRecordingsBtn.style.display = hasRecordings ? 'block' : 'none';
3792
+ }
2731
3793
  }
2732
3794
 
2733
3795
  /*
@@ -2886,11 +3948,17 @@ async function loadSnapshots() {
2886
3948
  // Listen for storage changes
2887
3949
  chrome.storage.onChanged.addListener((changes, namespace) => {
2888
3950
  if (namespace === 'local') {
3951
+ // Update isVideoModeActive from storage if it changed
3952
+ if (changes.isVideoModeActive) {
3953
+ isVideoModeActive = changes.isVideoModeActive.newValue === true;
3954
+ console.log('[Storage Listener] isVideoModeActive changed to:', isVideoModeActive);
3955
+ }
2889
3956
  if (changes.recordingActive && !isStoppingRecording) {
2890
3957
  isRecording = changes.recordingActive.newValue === true;
2891
3958
  if (changes.recordingStartTime) {
2892
3959
  recordingStartTime = changes.recordingStartTime.newValue;
2893
3960
  }
3961
+ console.log('[Storage Listener] recordingActive changed, isRecording:', isRecording, 'isVideoModeActive:', isVideoModeActive);
2894
3962
  updateRecordingUI();
2895
3963
  }
2896
3964
  if (changes.workflowRecording) {
@@ -2920,8 +3988,8 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
2920
3988
  if (recordingStatus) {
2921
3989
  recordingStatus.innerHTML = `<strong style="color: #4CAF50;">Recording saved!</strong>`;
2922
3990
  }
2923
- // Add to recordings list
2924
- addRecording(request.recordingId);
3991
+ // Add to recordings list - use request.isVideoMode if available, otherwise false
3992
+ addRecording(request.recordingId, false, false, null, null, null, request.isVideoMode || false);
2925
3993
  // Clear status after 3 seconds
2926
3994
  setTimeout(() => {
2927
3995
  if (recordingStatus) recordingStatus.textContent = '';