mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
refactor: Consolidate settings and dependencies into single modal
Merged the two gear icons in the header bar into one unified Settings modal. Added a "Tools" tab to display dependency status, removing the separate dependencies modal and button. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -391,6 +391,99 @@ function switchSettingsTab(tabName) {
|
||||
document.querySelectorAll('.settings-section').forEach(section => {
|
||||
section.classList.toggle('active', section.id === `settings-${tabName}`);
|
||||
});
|
||||
|
||||
// Load tools/dependencies when that tab is selected
|
||||
if (tabName === 'tools') {
|
||||
loadSettingsTools();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load tool dependencies into settings modal
|
||||
*/
|
||||
function loadSettingsTools() {
|
||||
const content = document.getElementById('settingsToolsContent');
|
||||
if (!content) return;
|
||||
|
||||
content.innerHTML = '<div style="text-align: center; padding: 30px; color: var(--text-dim);">Loading dependencies...</div>';
|
||||
|
||||
fetch('/dependencies')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status !== 'success') {
|
||||
content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
let totalMissing = 0;
|
||||
|
||||
for (const [modeKey, mode] of Object.entries(data.modes)) {
|
||||
const statusColor = mode.ready ? 'var(--accent-green)' : 'var(--accent-red)';
|
||||
const statusIcon = mode.ready ? '✓' : '✗';
|
||||
|
||||
html += `
|
||||
<div style="background: var(--bg-tertiary); border-radius: 6px; padding: 12px; margin-bottom: 10px; border-left: 3px solid ${statusColor};">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-weight: 600; color: var(--accent-cyan); font-size: 13px;">${mode.name}</span>
|
||||
<span style="color: ${statusColor}; font-size: 11px; font-weight: bold;">${statusIcon} ${mode.ready ? 'Ready' : 'Missing'}</span>
|
||||
</div>
|
||||
<div style="display: grid; gap: 6px;">
|
||||
`;
|
||||
|
||||
for (const [toolName, tool] of Object.entries(mode.tools)) {
|
||||
const installed = tool.installed;
|
||||
const dotColor = installed ? 'var(--accent-green)' : 'var(--accent-red)';
|
||||
const requiredBadge = tool.required ? '<span style="background: var(--accent-orange); color: #000; padding: 1px 4px; border-radius: 3px; font-size: 9px; margin-left: 4px;">REQ</span>' : '';
|
||||
|
||||
if (!installed) totalMissing++;
|
||||
|
||||
let installCmd = '';
|
||||
if (tool.install) {
|
||||
if (tool.install.pip) {
|
||||
installCmd = tool.install.pip;
|
||||
} else if (data.pkg_manager && tool.install[data.pkg_manager]) {
|
||||
installCmd = tool.install[data.pkg_manager];
|
||||
} else if (tool.install.manual) {
|
||||
installCmd = tool.install.manual;
|
||||
}
|
||||
}
|
||||
|
||||
html += `
|
||||
<div style="display: flex; align-items: center; gap: 8px; padding: 6px 8px; background: var(--bg-secondary); border-radius: 4px; font-size: 11px;">
|
||||
<span style="color: ${dotColor}; font-size: 12px;">●</span>
|
||||
<div style="flex: 1; min-width: 0;">
|
||||
<span style="font-weight: 500;">${toolName}${requiredBadge}</span>
|
||||
<div style="font-size: 10px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${tool.description}</div>
|
||||
</div>
|
||||
${!installed && installCmd ? `
|
||||
<code style="font-size: 9px; background: var(--bg-tertiary); padding: 2px 6px; border-radius: 3px; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${installCmd}">${installCmd}</code>
|
||||
` : ''}
|
||||
<span style="font-size: 10px; color: ${dotColor}; font-weight: bold; min-width: 45px; text-align: right;">${installed ? 'OK' : 'MISSING'}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += '</div></div>';
|
||||
}
|
||||
|
||||
// Summary at top
|
||||
const summaryHtml = `
|
||||
<div style="background: ${totalMissing > 0 ? 'rgba(255, 100, 0, 0.1)' : 'rgba(0, 255, 100, 0.1)'}; border: 1px solid ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'}; border-radius: 6px; padding: 10px 12px; margin-bottom: 12px;">
|
||||
<div style="font-size: 13px; font-weight: bold; color: ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'};">
|
||||
${totalMissing > 0 ? '⚠️ ' + totalMissing + ' tool(s) not found' : '✓ All tools installed'}
|
||||
</div>
|
||||
<div style="font-size: 11px; color: var(--text-dim); margin-top: 3px;">
|
||||
OS: ${data.os} | Package Manager: ${data.pkg_manager}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
content.innerHTML = summaryHtml + html;
|
||||
})
|
||||
.catch(err => {
|
||||
content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies: ' + err.message + '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize settings on page load
|
||||
|
||||
@@ -385,8 +385,6 @@
|
||||
<span class="icon-moon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg></span>
|
||||
<span class="icon-sun icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg></span>
|
||||
</button>
|
||||
<button class="nav-tool-btn" onclick="showDependencies()" title="Check Tool Dependencies"
|
||||
id="depsBtn"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span></button>
|
||||
<a href="/controller/monitor" class="nav-tool-btn" title="Network Monitor - Multi-Agent View" style="text-decoration: none;"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span></a>
|
||||
<a href="/controller/manage" class="nav-tool-btn" title="Manage Remote Agents" style="text-decoration: none;"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg></span></a>
|
||||
<button class="nav-tool-btn" onclick="showSettings()" title="Settings"><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span></button>
|
||||
@@ -11686,38 +11684,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dependencies Modal -->
|
||||
<div id="depsModal" class="help-modal" onclick="if(event.target === this) hideDependencies()">
|
||||
<div class="help-content" style="max-width: 800px;">
|
||||
<button class="help-close" onclick="hideDependencies()">×</button>
|
||||
<h2>Tool Dependencies</h2>
|
||||
<p style="color: var(--text-dim); margin-bottom: 15px;">Check which tools are installed for each mode. <span
|
||||
style="color: var(--accent-green);">●</span> = Installed, <span
|
||||
style="color: var(--accent-red);">●</span> = Missing</p>
|
||||
<div id="depsContent" style="max-height: 60vh; overflow-y: auto;">
|
||||
<div style="text-align: center; padding: 40px; color: var(--text-dim);">
|
||||
Loading dependencies...
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 20px; padding-top: 15px; border-top: 1px solid var(--border-color);">
|
||||
<h3 style="margin-bottom: 10px;">Quick Install (Debian/Ubuntu)</h3>
|
||||
<div
|
||||
style="background: var(--bg-tertiary); padding: 10px; border-radius: 4px; font-family: monospace; font-size: 11px; overflow-x: auto;">
|
||||
<div>sudo apt install rtl-sdr multimon-ng rtl-433 aircrack-ng bluez dump1090-mutability hcxdumptool
|
||||
hcxtools</div>
|
||||
<div style="margin-top: 5px;">pip install skyfield flask</div>
|
||||
</div>
|
||||
<div style="margin-top: 10px; font-size: 11px; color: var(--text-dim);">
|
||||
<strong>Note:</strong> ACARS decoding requires <code>acarsdec</code> which must be built from
|
||||
source.
|
||||
See <a href="https://github.com/TLeconte/acarsdec" target="_blank"
|
||||
style="color: var(--accent-cyan);">github.com/TLeconte/acarsdec</a> or run
|
||||
<code>./setup.sh</code> for automated installation.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Satellite Add Modal -->
|
||||
<div id="satModal" class="help-modal" onclick="if(event.target === this) closeSatModal()">
|
||||
<div class="help-content" style="max-width: 600px;">
|
||||
@@ -11779,105 +11745,6 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showDependencies() {
|
||||
document.getElementById('depsModal').classList.add('active');
|
||||
loadDependencies();
|
||||
}
|
||||
|
||||
function hideDependencies() {
|
||||
document.getElementById('depsModal').classList.remove('active');
|
||||
}
|
||||
|
||||
function loadDependencies() {
|
||||
const content = document.getElementById('depsContent');
|
||||
content.innerHTML = '<div style="text-align: center; padding: 40px; color: var(--text-dim);">Loading dependencies...</div>';
|
||||
|
||||
fetch('/dependencies')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status !== 'success') {
|
||||
content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
let totalMissing = 0;
|
||||
|
||||
for (const [modeKey, mode] of Object.entries(data.modes)) {
|
||||
const statusColor = mode.ready ? 'var(--accent-green)' : 'var(--accent-red)';
|
||||
const statusIcon = mode.ready ? '✓' : '✗';
|
||||
|
||||
html += `
|
||||
<div style="background: var(--bg-tertiary); border-radius: 8px; padding: 15px; margin-bottom: 15px; border-left: 3px solid ${statusColor};">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||
<h3 style="margin: 0; color: var(--accent-cyan);">${mode.name}</h3>
|
||||
<span style="color: ${statusColor}; font-weight: bold;">${statusIcon} ${mode.ready ? 'Ready' : 'Missing Required'}</span>
|
||||
</div>
|
||||
<div style="display: grid; gap: 8px;">
|
||||
`;
|
||||
|
||||
for (const [toolName, tool] of Object.entries(mode.tools)) {
|
||||
const installed = tool.installed;
|
||||
const dotColor = installed ? 'var(--accent-green)' : 'var(--accent-red)';
|
||||
const requiredBadge = tool.required ? '<span style="background: var(--accent-orange); color: #000; padding: 1px 5px; border-radius: 3px; font-size: 9px; margin-left: 5px;">REQUIRED</span>' : '';
|
||||
|
||||
if (!installed) totalMissing++;
|
||||
|
||||
// Get install command for current OS
|
||||
let installCmd = '';
|
||||
if (tool.install) {
|
||||
if (tool.install.pip) {
|
||||
installCmd = tool.install.pip;
|
||||
} else if (data.pkg_manager && tool.install[data.pkg_manager]) {
|
||||
installCmd = tool.install[data.pkg_manager];
|
||||
} else if (tool.install.manual) {
|
||||
installCmd = tool.install.manual;
|
||||
}
|
||||
}
|
||||
|
||||
html += `
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 8px; background: var(--bg-secondary); border-radius: 4px;">
|
||||
<span style="color: ${dotColor}; font-size: 16px;">●</span>
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: bold;">${toolName}${requiredBadge}</div>
|
||||
<div style="font-size: 11px; color: var(--text-dim);">${tool.description}</div>
|
||||
</div>
|
||||
${!installed && installCmd ? `
|
||||
<code style="font-size: 10px; background: var(--bg-tertiary); padding: 4px 8px; border-radius: 3px; max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${installCmd}">${installCmd}</code>
|
||||
` : ''}
|
||||
<span style="font-size: 11px; color: ${dotColor}; font-weight: bold;">${installed ? 'OK' : 'MISSING'}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
html += '</div></div>';
|
||||
}
|
||||
|
||||
// Summary at top
|
||||
const summaryHtml = `
|
||||
<div style="background: ${totalMissing > 0 ? 'rgba(255, 100, 0, 0.1)' : 'rgba(0, 255, 100, 0.1)'}; border: 1px solid ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'}; border-radius: 8px; padding: 15px; margin-bottom: 20px;">
|
||||
<div style="font-size: 16px; font-weight: bold; color: ${totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'};">
|
||||
${totalMissing > 0 ? '⚠️ ' + totalMissing + ' tool(s) not found' : '✓ All tools installed'}
|
||||
</div>
|
||||
<div style="font-size: 12px; color: var(--text-dim); margin-top: 5px;">
|
||||
OS: ${data.os} | Package Manager: ${data.pkg_manager}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
content.innerHTML = summaryHtml + html;
|
||||
|
||||
// Update button indicator
|
||||
const btn = document.getElementById('depsBtn');
|
||||
if (btn) {
|
||||
btn.style.color = totalMissing > 0 ? 'var(--accent-orange)' : 'var(--accent-green)';
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
content.innerHTML = '<div style="color: var(--accent-red);">Error loading dependencies: ' + err.message + '</div>';
|
||||
});
|
||||
}
|
||||
|
||||
// Check dependencies on page load
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Check if user dismissed the startup check
|
||||
@@ -11902,12 +11769,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
const btn = document.getElementById('depsBtn');
|
||||
if (btn && missingModes > 0) {
|
||||
btn.style.color = 'var(--accent-orange)';
|
||||
btn.title = missingModes + ' mode(s) have missing tools - click to see details';
|
||||
}
|
||||
|
||||
// Show startup prompt if tools are missing and not dismissed
|
||||
// Only show if disclaimer has been accepted
|
||||
const disclaimerAccepted = localStorage.getItem('disclaimerAccepted') === 'true';
|
||||
@@ -11951,7 +11812,7 @@
|
||||
<strong style="color: var(--accent-orange);">${modeCount} mode(s)</strong> require tools that aren't installed.
|
||||
</p>
|
||||
<div style="display: flex; flex-direction: column; gap: 8px;">
|
||||
<button class="action-btn" onclick="closeStartupDeps(); showDependencies();" style="padding: 10px 16px; font-size: 12px;">
|
||||
<button class="action-btn" onclick="closeStartupDeps(); showSettings(); switchSettingsTab('tools');" style="padding: 10px 16px; font-size: 12px;">
|
||||
View Details & Install
|
||||
</button>
|
||||
<label style="display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--text-dim); cursor: pointer;">
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div class="settings-tabs">
|
||||
<button class="settings-tab active" data-tab="offline" onclick="switchSettingsTab('offline')">Offline</button>
|
||||
<button class="settings-tab" data-tab="display" onclick="switchSettingsTab('display')">Display</button>
|
||||
<button class="settings-tab" data-tab="tools" onclick="switchSettingsTab('tools')">Tools</button>
|
||||
<button class="settings-tab" data-tab="about" onclick="switchSettingsTab('about')">About</button>
|
||||
</div>
|
||||
|
||||
@@ -146,6 +147,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tools Section -->
|
||||
<div id="settings-tools" class="settings-section">
|
||||
<div class="settings-group">
|
||||
<div class="settings-group-title">Tool Dependencies</div>
|
||||
<p style="color: var(--text-dim); margin-bottom: 15px; font-size: 12px;">
|
||||
Check which external tools are installed for each mode.
|
||||
<span style="color: var(--accent-green);">●</span> = Installed,
|
||||
<span style="color: var(--accent-red);">●</span> = Missing
|
||||
</p>
|
||||
<div id="settingsToolsContent" style="max-height: 45vh; overflow-y: auto;">
|
||||
<div style="text-align: center; padding: 30px; color: var(--text-dim);">
|
||||
Loading dependencies...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-group" style="margin-top: 15px;">
|
||||
<div class="settings-group-title">Quick Install (Debian/Ubuntu)</div>
|
||||
<div style="background: var(--bg-tertiary); padding: 10px; border-radius: 4px; font-family: var(--font-mono); font-size: 10px; overflow-x: auto;">
|
||||
<div>sudo apt install rtl-sdr multimon-ng rtl-433 aircrack-ng bluez dump1090-mutability hcxdumptool hcxtools</div>
|
||||
<div style="margin-top: 5px;">pip install skyfield flask</div>
|
||||
</div>
|
||||
<div style="margin-top: 10px; font-size: 11px; color: var(--text-dim);">
|
||||
<strong>Note:</strong> ACARS decoding requires <code>acarsdec</code> which must be built from source.
|
||||
See <a href="https://github.com/TLeconte/acarsdec" target="_blank" style="color: var(--accent-cyan);">github.com/TLeconte/acarsdec</a> or run <code>./setup.sh</code> for automated installation.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- About Section -->
|
||||
<div id="settings-about" class="settings-section">
|
||||
<div class="settings-group">
|
||||
|
||||
Reference in New Issue
Block a user