mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Revert TSCM menu changes - restore original layout
The simplified layout was causing display issues. Reverting to the original working version. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -36,7 +36,11 @@ from utils.database import (
|
||||
set_active_tscm_baseline,
|
||||
update_tscm_sweep,
|
||||
)
|
||||
from utils.tscm.baseline import BaselineComparator, BaselineRecorder
|
||||
from utils.tscm.baseline import (
|
||||
BaselineComparator,
|
||||
BaselineRecorder,
|
||||
get_comparison_for_active_baseline,
|
||||
)
|
||||
from utils.tscm.correlation import (
|
||||
CorrelationEngine,
|
||||
get_correlation_engine,
|
||||
@@ -1447,6 +1451,20 @@ def _run_sweep(
|
||||
correlations = correlation.correlate_devices()
|
||||
findings = correlation.get_all_findings()
|
||||
|
||||
# Run baseline comparison if a baseline was provided
|
||||
baseline_comparison = None
|
||||
if baseline:
|
||||
comparator = BaselineComparator(baseline)
|
||||
baseline_comparison = comparator.compare_all(
|
||||
wifi_devices=list(all_wifi.values()),
|
||||
bt_devices=list(all_bt.values()),
|
||||
rf_signals=all_rf
|
||||
)
|
||||
logger.info(
|
||||
f"Baseline comparison: {baseline_comparison['total_new']} new, "
|
||||
f"{baseline_comparison['total_missing']} missing"
|
||||
)
|
||||
|
||||
# Finalize identity engine and get MAC-randomization resistant clusters
|
||||
identity_engine.finalize_all_sessions()
|
||||
identity_summary = identity_engine.get_summary()
|
||||
@@ -1462,6 +1480,7 @@ def _run_sweep(
|
||||
'severity_counts': severity_counts,
|
||||
'correlation_summary': findings.get('summary', {}),
|
||||
'identity_summary': identity_summary.get('statistics', {}),
|
||||
'baseline_comparison': baseline_comparison,
|
||||
},
|
||||
threats_found=threats_found,
|
||||
completed=True
|
||||
@@ -1474,6 +1493,18 @@ def _run_sweep(
|
||||
'needs_review_count': findings['summary'].get('needs_review', 0),
|
||||
})
|
||||
|
||||
# Emit baseline comparison if a baseline was used
|
||||
if baseline_comparison:
|
||||
_emit_event('baseline_comparison', {
|
||||
'baseline_id': baseline.get('id'),
|
||||
'baseline_name': baseline.get('name'),
|
||||
'total_new': baseline_comparison['total_new'],
|
||||
'total_missing': baseline_comparison['total_missing'],
|
||||
'wifi': baseline_comparison.get('wifi'),
|
||||
'bluetooth': baseline_comparison.get('bluetooth'),
|
||||
'rf': baseline_comparison.get('rf'),
|
||||
})
|
||||
|
||||
# Emit device identity cluster findings (MAC-randomization resistant)
|
||||
_emit_event('identity_clusters', {
|
||||
'total_clusters': identity_summary['statistics'].get('total_clusters', 0),
|
||||
@@ -1494,6 +1525,8 @@ def _run_sweep(
|
||||
'needs_review_devices': findings['summary'].get('needs_review', 0),
|
||||
'correlations_found': len(correlations),
|
||||
'identity_clusters': identity_summary['statistics'].get('total_clusters', 0),
|
||||
'baseline_new_devices': baseline_comparison['total_new'] if baseline_comparison else 0,
|
||||
'baseline_missing_devices': baseline_comparison['total_missing'] if baseline_comparison else 0,
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
@@ -1625,6 +1658,43 @@ def get_active_baseline():
|
||||
return jsonify({'status': 'success', 'baseline': baseline})
|
||||
|
||||
|
||||
@tscm_bp.route('/baseline/compare', methods=['POST'])
|
||||
def compare_against_baseline():
|
||||
"""
|
||||
Compare provided device data against the active baseline.
|
||||
|
||||
Expects JSON body with:
|
||||
- wifi_devices: list of WiFi devices (optional)
|
||||
- bt_devices: list of Bluetooth devices (optional)
|
||||
- rf_signals: list of RF signals (optional)
|
||||
|
||||
Returns comparison showing new, missing, and matching devices.
|
||||
"""
|
||||
data = request.get_json() or {}
|
||||
|
||||
wifi_devices = data.get('wifi_devices')
|
||||
bt_devices = data.get('bt_devices')
|
||||
rf_signals = data.get('rf_signals')
|
||||
|
||||
# Use the convenience function that gets active baseline
|
||||
comparison = get_comparison_for_active_baseline(
|
||||
wifi_devices=wifi_devices,
|
||||
bt_devices=bt_devices,
|
||||
rf_signals=rf_signals
|
||||
)
|
||||
|
||||
if comparison is None:
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'No active baseline set'
|
||||
}), 400
|
||||
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'comparison': comparison
|
||||
})
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Threat Endpoints
|
||||
# =============================================================================
|
||||
|
||||
@@ -1,50 +1,5 @@
|
||||
/* TSCM Styles */
|
||||
|
||||
/* TSCM Collapsible Sections */
|
||||
.tscm-collapsible {
|
||||
padding: 0 !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tscm-collapsible-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.tscm-collapsible-header:hover {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
.tscm-collapse-icon {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.tscm-collapsible-content {
|
||||
padding: 0 12px 12px 12px;
|
||||
}
|
||||
.tscm-collapsible.expanded .tscm-collapse-icon {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
/* TSCM Tool Buttons */
|
||||
.tscm-tool-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
.tscm-tool-btn:hover {
|
||||
background: rgba(74, 158, 255, 0.15);
|
||||
}
|
||||
|
||||
/* TSCM Threat Cards */
|
||||
.threat-card {
|
||||
display: flex;
|
||||
|
||||
@@ -194,7 +194,8 @@
|
||||
<label title="Show aircraft trails"><input type="checkbox" id="showTrails" onchange="toggleTrails()"> Trails</label>
|
||||
<label title="Show range rings"><input type="checkbox" id="showRangeRings" checked onchange="drawRangeRings()"> Rings</label>
|
||||
<label title="Radar sweep overlay"><input type="checkbox" id="radarOverlay" onchange="toggleRadarOverlay()"> Radar</label>
|
||||
<label title="Audio alerts"><input type="checkbox" id="alertToggle" checked onchange="toggleAlerts()"> Alerts</label>
|
||||
<label title="Audio alerts for military/emergency"><input type="checkbox" id="alertToggle" checked onchange="toggleAlerts()"> Alerts</label>
|
||||
<label title="Sound when new aircraft detected"><input type="checkbox" id="detectionSoundToggle" onchange="toggleDetectionSound()"> Ping</label>
|
||||
<select id="aircraftFilter" onchange="applyFilter()" title="Filter aircraft">
|
||||
<option value="all">All Aircraft</option>
|
||||
<option value="military">Military</option>
|
||||
@@ -298,6 +299,8 @@
|
||||
let currentFilter = 'all';
|
||||
let alertedAircraft = {};
|
||||
let alertsEnabled = true;
|
||||
let detectionSoundEnabled = localStorage.getItem('adsb_detectionSound') !== 'false'; // Default on
|
||||
let soundedAircraft = {}; // Track aircraft we've played detection sound for
|
||||
let currentView = 'map'; // 'map' or 'radar'
|
||||
|
||||
// Watchlist - persisted to localStorage
|
||||
@@ -576,6 +579,31 @@
|
||||
alertsEnabled = document.getElementById('alertToggle').checked;
|
||||
}
|
||||
|
||||
function toggleDetectionSound() {
|
||||
detectionSoundEnabled = document.getElementById('detectionSoundToggle').checked;
|
||||
localStorage.setItem('adsb_detectionSound', detectionSoundEnabled);
|
||||
}
|
||||
|
||||
function playDetectionSound() {
|
||||
if (!detectionSoundEnabled) return;
|
||||
try {
|
||||
const ctx = getAudioContext();
|
||||
const oscillator = ctx.createOscillator();
|
||||
const gainNode = ctx.createGain();
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(ctx.destination);
|
||||
// Soft, quick ping - 1000Hz for 100ms
|
||||
oscillator.frequency.setValueAtTime(1000, ctx.currentTime);
|
||||
oscillator.type = 'sine';
|
||||
gainNode.gain.setValueAtTime(0.1, ctx.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.1);
|
||||
oscillator.start(ctx.currentTime);
|
||||
oscillator.stop(ctx.currentTime + 0.1);
|
||||
} catch (e) {
|
||||
console.warn('Detection sound failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// WATCHLIST FUNCTIONS
|
||||
// ============================================
|
||||
@@ -1920,6 +1948,10 @@ ACARS: ${r.statistics.acarsMessages} messages`;
|
||||
if (obsLatInput) obsLatInput.value = observerLocation.lat.toFixed(4);
|
||||
if (obsLonInput) obsLonInput.value = observerLocation.lon.toFixed(4);
|
||||
|
||||
// Initialize detection sound toggle from localStorage
|
||||
const detectionToggle = document.getElementById('detectionSoundToggle');
|
||||
if (detectionToggle) detectionToggle.checked = detectionSoundEnabled;
|
||||
|
||||
initMap();
|
||||
initDeviceSelectors();
|
||||
updateClock();
|
||||
@@ -2485,6 +2517,13 @@ sudo make install</code>
|
||||
const icao = data.icao;
|
||||
if (!icao) return;
|
||||
|
||||
// Check if this is a new aircraft we haven't seen this session
|
||||
const isNewAircraft = !soundedAircraft[icao];
|
||||
if (isNewAircraft) {
|
||||
soundedAircraft[icao] = true;
|
||||
playDetectionSound();
|
||||
}
|
||||
|
||||
aircraft[icao] = {
|
||||
...aircraft[icao],
|
||||
...data,
|
||||
|
||||
@@ -7530,23 +7530,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// TSCM collapsible section toggle
|
||||
function toggleTscmSection(contentId) {
|
||||
const content = document.getElementById(contentId);
|
||||
const icon = document.getElementById(contentId + 'Icon');
|
||||
const section = content.closest('.tscm-collapsible');
|
||||
|
||||
if (content.style.display === 'none') {
|
||||
content.style.display = 'block';
|
||||
icon.textContent = '-';
|
||||
section.classList.add('expanded');
|
||||
} else {
|
||||
content.style.display = 'none';
|
||||
icon.textContent = '+';
|
||||
section.classList.remove('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
async function startTscmSweep() {
|
||||
const sweepType = document.getElementById('tscmSweepType').value;
|
||||
const baselineId = document.getElementById('tscmBaselineSelect').value || null;
|
||||
|
||||
@@ -1,25 +1,137 @@
|
||||
<!-- TSCM MODE (Counter-Surveillance) -->
|
||||
<div id="tscmMode" class="mode-content">
|
||||
<!-- Primary Action Area -->
|
||||
<div class="section">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
|
||||
<h3 style="margin: 0;">TSCM Sweep</h3>
|
||||
<span style="font-size: 9px; background: var(--accent-orange); color: #000; padding: 2px 6px; border-radius: 3px; text-transform: uppercase;">Alpha</span>
|
||||
<h3 style="display: flex; align-items: center; gap: 8px;">TSCM Sweep <span style="font-size: 9px; font-weight: normal; background: var(--accent-orange); color: #000; padding: 2px 6px; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.5px;">Alpha</span></h3>
|
||||
<div class="form-group">
|
||||
<label>Sweep Type</label>
|
||||
<select id="tscmSweepType">
|
||||
<option value="quick">Quick Scan (2 min)</option>
|
||||
<option value="standard" selected>Standard (5 min)</option>
|
||||
<option value="full">Full Sweep (15 min)</option>
|
||||
<option value="wireless_cameras">Wireless Cameras</option>
|
||||
<option value="body_worn">Body-Worn Devices</option>
|
||||
<option value="gps_trackers">GPS Trackers</option>
|
||||
</select>
|
||||
</div>
|
||||
<select id="tscmSweepType" style="width: 100%; margin-bottom: 12px;">
|
||||
<option value="quick">Quick Scan (2 min)</option>
|
||||
<option value="standard" selected>Standard (5 min)</option>
|
||||
<option value="full">Full Sweep (15 min)</option>
|
||||
<option value="wireless_cameras">Wireless Cameras</option>
|
||||
<option value="body_worn">Body-Worn Devices</option>
|
||||
<option value="gps_trackers">GPS Trackers</option>
|
||||
</select>
|
||||
<button class="run-btn" id="startTscmBtn" onclick="startTscmSweep()" style="width: 100%;">
|
||||
Start Sweep
|
||||
<div class="form-group">
|
||||
<label>Compare Against</label>
|
||||
<select id="tscmBaselineSelect">
|
||||
<option value="">No Baseline</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Scan Sources</h3>
|
||||
<div class="form-group" style="margin-bottom: 8px;">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="checkbox" id="tscmWifiEnabled" checked style="margin: 0;">
|
||||
<label for="tscmWifiEnabled" style="flex: 1; margin: 0;">WiFi Networks</label>
|
||||
</div>
|
||||
<select id="tscmWifiInterface" style="width: 100%; margin-top: 4px; font-size: 11px;">
|
||||
<option value="">Select WiFi interface...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 8px;">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="checkbox" id="tscmBtEnabled" checked style="margin: 0;">
|
||||
<label for="tscmBtEnabled" style="flex: 1; margin: 0;">Bluetooth Devices</label>
|
||||
</div>
|
||||
<select id="tscmBtInterface" style="width: 100%; margin-top: 4px; font-size: 11px;">
|
||||
<option value="">Select Bluetooth adapter...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 8px;">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<input type="checkbox" id="tscmRfEnabled" style="margin: 0;">
|
||||
<label for="tscmRfEnabled" style="flex: 1; margin: 0;">RF Signals</label>
|
||||
</div>
|
||||
<select id="tscmSdrDevice" style="width: 100%; margin-top: 4px; font-size: 11px;">
|
||||
<option value="">Select SDR device...</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="preset-btn" onclick="refreshTscmDevices()" style="width: 100%; margin-top: 8px; font-size: 10px;">
|
||||
🔄 Refresh Devices
|
||||
</button>
|
||||
<button class="stop-btn" id="stopTscmBtn" onclick="stopTscmSweep()" style="display: none; width: 100%;">
|
||||
Stop Sweep
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Baseline Management</h3>
|
||||
<div class="form-group">
|
||||
<input type="text" id="tscmBaselineName" placeholder="Baseline name...">
|
||||
</div>
|
||||
<button class="run-btn" id="tscmRecordBaselineBtn" onclick="tscmRecordBaseline()" style="width: 100%; padding: 8px;">
|
||||
Record New Baseline
|
||||
</button>
|
||||
<button class="stop-btn" id="tscmStopBaselineBtn" onclick="tscmStopBaseline()" style="width: 100%; padding: 8px; display: none;">
|
||||
Stop Recording
|
||||
</button>
|
||||
<div id="tscmBaselineStatus" style="margin-top: 8px; font-size: 11px; color: var(--text-muted);"></div>
|
||||
</div>
|
||||
|
||||
<button class="run-btn" id="startTscmBtn" onclick="startTscmSweep()">
|
||||
Start Sweep
|
||||
</button>
|
||||
<button class="stop-btn" id="stopTscmBtn" onclick="stopTscmSweep()" style="display: none;">
|
||||
Stop Sweep
|
||||
</button>
|
||||
<button class="preset-btn" id="tscmReportBtn" onclick="generateTscmReport()" style="display: none; width: 100%; margin-top: 8px; background: var(--accent-cyan); color: #000; font-weight: 600;">
|
||||
📄 Generate Report
|
||||
</button>
|
||||
|
||||
<!-- Meeting Window Control -->
|
||||
<div class="section" id="tscmMeetingSection" style="margin-top: 12px;">
|
||||
<h3>Meeting Window</h3>
|
||||
<div id="tscmMeetingStatus" style="font-size: 11px; color: var(--text-muted); margin-bottom: 8px;">
|
||||
No active meeting
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" id="tscmMeetingName" placeholder="Meeting name (optional)">
|
||||
</div>
|
||||
<button class="run-btn" id="tscmStartMeetingBtn" onclick="tscmStartMeeting()" style="width: 100%; padding: 8px;">
|
||||
🎯 Start Meeting Window
|
||||
</button>
|
||||
<button class="stop-btn" id="tscmEndMeetingBtn" onclick="tscmEndMeeting()" style="width: 100%; padding: 8px; display: none;">
|
||||
⏹ End Meeting Window
|
||||
</button>
|
||||
<div style="font-size: 9px; color: var(--text-muted); margin-top: 4px;">
|
||||
Devices detected during meetings get flagged
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="section" style="margin-top: 12px;">
|
||||
<h3>Quick Actions</h3>
|
||||
<div style="display: flex; flex-direction: column; gap: 6px;">
|
||||
<button class="preset-btn" onclick="tscmShowCapabilities()" style="width: 100%; font-size: 10px;">
|
||||
⚙️ View Capabilities
|
||||
</button>
|
||||
<button class="preset-btn" onclick="tscmShowKnownDevices()" style="width: 100%; font-size: 10px;">
|
||||
✅ Known Devices
|
||||
</button>
|
||||
<button class="preset-btn" onclick="tscmShowCases()" style="width: 100%; font-size: 10px;">
|
||||
📁 Cases
|
||||
</button>
|
||||
<button class="preset-btn" onclick="tscmShowPlaybooks()" style="width: 100%; font-size: 10px;">
|
||||
📋 Playbooks
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Export Options -->
|
||||
<div class="section" id="tscmExportSection" style="margin-top: 12px; display: none;">
|
||||
<h3>Export Report</h3>
|
||||
<div style="display: flex; gap: 6px;">
|
||||
<button class="preset-btn" onclick="tscmDownloadPdf()" style="flex: 1; font-size: 10px;">
|
||||
📄 PDF
|
||||
</button>
|
||||
<button class="preset-btn" onclick="tscmDownloadAnnex('json')" style="flex: 1; font-size: 10px;">
|
||||
📊 JSON
|
||||
</button>
|
||||
<button class="preset-btn" onclick="tscmDownloadAnnex('csv')" style="flex: 1; font-size: 10px;">
|
||||
📈 CSV
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Futuristic Scanner Progress -->
|
||||
@@ -44,99 +156,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Report Button (shown after scan) -->
|
||||
<button class="preset-btn" id="tscmReportBtn" onclick="generateTscmReport()" style="display: none; width: 100%; margin-top: 8px; background: var(--accent-cyan); color: #000; font-weight: 600;">
|
||||
Generate Report
|
||||
</button>
|
||||
|
||||
<!-- Export Options (shown after scan) -->
|
||||
<div id="tscmExportSection" style="display: none; margin-top: 8px;">
|
||||
<div style="display: flex; gap: 6px;">
|
||||
<button class="preset-btn" onclick="tscmDownloadPdf()" style="flex: 1; font-size: 10px;">PDF</button>
|
||||
<button class="preset-btn" onclick="tscmDownloadAnnex('json')" style="flex: 1; font-size: 10px;">JSON</button>
|
||||
<button class="preset-btn" onclick="tscmDownloadAnnex('csv')" style="flex: 1; font-size: 10px;">CSV</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scan Sources -->
|
||||
<div class="section" style="margin-top: 12px;">
|
||||
<div style="display: flex; flex-direction: column; gap: 6px;">
|
||||
<label style="display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer;">
|
||||
<input type="checkbox" id="tscmWifiEnabled" checked style="margin: 0;">
|
||||
<span>WiFi</span>
|
||||
<select id="tscmWifiInterface" style="margin-left: auto; font-size: 10px; padding: 2px 4px; max-width: 100px;">
|
||||
<option value="">Auto</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer;">
|
||||
<input type="checkbox" id="tscmBtEnabled" checked style="margin: 0;">
|
||||
<span>Bluetooth</span>
|
||||
<select id="tscmBtInterface" style="margin-left: auto; font-size: 10px; padding: 2px 4px; max-width: 100px;">
|
||||
<option value="">Auto</option>
|
||||
</select>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer;">
|
||||
<input type="checkbox" id="tscmRfEnabled" style="margin: 0;">
|
||||
<span>RF/SDR</span>
|
||||
<select id="tscmSdrDevice" style="margin-left: auto; font-size: 10px; padding: 2px 4px; max-width: 100px;">
|
||||
<option value="">None</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<button class="preset-btn" onclick="refreshTscmDevices()" style="width: 100%; margin-top: 8px; font-size: 10px; padding: 4px;">
|
||||
Refresh Devices
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Baseline -->
|
||||
<div class="section" style="margin-top: 8px;">
|
||||
<div class="form-group" style="margin-bottom: 8px;">
|
||||
<label style="font-size: 11px;">Compare Against</label>
|
||||
<select id="tscmBaselineSelect" style="width: 100%;">
|
||||
<option value="">No Baseline</option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="text" id="tscmBaselineName" placeholder="New baseline name..." style="width: 100%; margin-bottom: 6px; font-size: 11px;">
|
||||
<button class="preset-btn" id="tscmRecordBaselineBtn" onclick="tscmRecordBaseline()" style="width: 100%; font-size: 10px; padding: 4px;">
|
||||
Record Baseline
|
||||
</button>
|
||||
<button class="stop-btn" id="tscmStopBaselineBtn" onclick="tscmStopBaseline()" style="width: 100%; display: none; font-size: 10px; padding: 4px;">
|
||||
Stop Recording
|
||||
</button>
|
||||
<div id="tscmBaselineStatus" style="margin-top: 4px; font-size: 10px; color: var(--text-muted);"></div>
|
||||
</div>
|
||||
|
||||
<!-- Meeting Window -->
|
||||
<div class="section" id="tscmMeetingSection" style="margin-top: 8px;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px;">
|
||||
<span style="font-size: 11px; color: var(--text-secondary);">Meeting Window</span>
|
||||
<span id="tscmMeetingStatus" style="font-size: 10px; color: var(--text-muted);">Inactive</span>
|
||||
</div>
|
||||
<input type="text" id="tscmMeetingName" placeholder="Meeting name (optional)" style="width: 100%; margin-bottom: 6px; font-size: 11px;">
|
||||
<button class="preset-btn" id="tscmStartMeetingBtn" onclick="tscmStartMeeting()" style="width: 100%; font-size: 10px; padding: 4px;">
|
||||
Start Meeting
|
||||
</button>
|
||||
<button class="stop-btn" id="tscmEndMeetingBtn" onclick="tscmEndMeeting()" style="width: 100%; display: none; font-size: 10px; padding: 4px;">
|
||||
End Meeting
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Compact Tools Row -->
|
||||
<div style="display: flex; gap: 6px; margin-top: 12px;">
|
||||
<button class="preset-btn tscm-tool-btn" onclick="tscmShowCapabilities()" title="Capabilities">
|
||||
<span style="font-size: 14px;">⚙️</span>
|
||||
</button>
|
||||
<button class="preset-btn tscm-tool-btn" onclick="tscmShowKnownDevices()" title="Known Devices">
|
||||
<span style="font-size: 14px;">✅</span>
|
||||
</button>
|
||||
<button class="preset-btn tscm-tool-btn" onclick="tscmShowCases()" title="Cases">
|
||||
<span style="font-size: 14px;">📁</span>
|
||||
</button>
|
||||
<button class="preset-btn tscm-tool-btn" onclick="tscmShowPlaybooks()" title="Playbooks">
|
||||
<span style="font-size: 14px;">📋</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Device Warnings -->
|
||||
<div id="tscmDeviceWarnings" style="display: none; margin-top: 8px; padding: 8px; background: rgba(255,153,51,0.1); border: 1px solid rgba(255,153,51,0.3); border-radius: 4px;"></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user