botserver/templates/tools.html
Rodrigo Rodriguez (Pragmatismo) 46d6ff6268 Add desktop tools, antivirus, and editor modules
- Add desktop tools module with drive cleaner, Windows optimizer, and
  Brave browser installer
- Add antivirus module with ClamAV integration and Windows Defender
  management
- Add tools.html template for settings page integration
- Add standalone editor.html for file editing
- Re-export new types from desktop and security
2025-11-29 21:23:19 -03:00

1019 lines
28 KiB
HTML

<!-- Tools Section Template for Settings -->
<!-- This is loaded via HTMX into the settings page -->
<div class="tools-section" id="tools-container">
<!-- Desktop Only Warning (shown via JS if not in Tauri) -->
<div class="tools-warning" id="desktop-warning" style="display: none;">
<div class="warning-icon">⚠️</div>
<div class="warning-content">
<h4>Desktop Mode Recommended</h4>
<p>Some tools require the desktop application for full functionality.</p>
</div>
</div>
<!-- Drive Cleaner Card -->
<div class="setting-card">
<h3 class="card-title">
<span class="card-icon">🧹</span>
Drive Cleaner
</h3>
<p class="card-description">
Remove temporary files, browser cache, and other junk to free up disk space.
</p>
<!-- Disk Info -->
<div class="disk-info-section">
<div class="section-header-row">
<h4>Disk Space</h4>
<button class="btn btn-small" id="btn-analyze-disk"
hx-get="/api/v1/desktop/disk-info"
hx-target="#disk-info-container"
hx-indicator="#analyze-spinner">
<span id="analyze-spinner" class="htmx-indicator spinner"></span>
🔍 Analyze
</button>
</div>
<div id="disk-info-container" class="disk-info-container">
<p class="no-data">Click "Analyze" to scan your disks</p>
</div>
</div>
<!-- Cleanup Categories -->
<div class="cleanup-categories">
<h4>Select items to clean:</h4>
<div class="category-grid">
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="temp_files" checked>
<span class="category-icon">📁</span>
<span class="category-name">Temporary Files</span>
<span class="category-desc">System and app temp files</span>
</label>
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="browser_cache">
<span class="category-icon">🌐</span>
<span class="category-name">Browser Cache</span>
<span class="category-desc">Chrome, Edge, Brave, Firefox</span>
</label>
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="recycle_bin">
<span class="category-icon">🗑️</span>
<span class="category-name">Recycle Bin</span>
<span class="category-desc">Empty trash/recycle bin</span>
</label>
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="thumbnails">
<span class="category-icon">🖼️</span>
<span class="category-name">Thumbnails</span>
<span class="category-desc">Image preview cache</span>
</label>
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="logs">
<span class="category-icon">📋</span>
<span class="category-name">Old Logs</span>
<span class="category-desc">Log files older than 7 days</span>
</label>
<label class="category-item">
<input type="checkbox" class="cleanup-category" value="update_cache">
<span class="category-icon">🔄</span>
<span class="category-name">Update Cache</span>
<span class="category-desc">Windows Update downloads</span>
</label>
</div>
</div>
<!-- Cleanup Progress -->
<div class="progress-section" id="cleanup-progress-section" style="display: none;">
<div class="progress-bar-container">
<div class="progress-bar" id="cleanup-progress-bar"></div>
</div>
<p class="progress-text" id="cleanup-progress-text">Preparing...</p>
</div>
<!-- Cleanup Results -->
<div id="cleanup-results"></div>
<!-- Cleanup Actions -->
<div class="card-actions">
<button class="btn btn-primary" id="btn-clean-all"
hx-post="/api/v1/desktop/cleanup"
hx-vals='js:{categories: getSelectedCategories()}'
hx-target="#cleanup-results"
hx-indicator="#cleanup-spinner">
<span id="cleanup-spinner" class="htmx-indicator spinner"></span>
🧹 Clean Selected
</button>
<button class="btn btn-secondary" id="btn-empty-recycle"
hx-post="/api/v1/desktop/cleanup"
hx-vals='{"categories": ["recycle_bin"]}'
hx-target="#cleanup-results">
🗑️ Empty Recycle Bin
</button>
</div>
</div>
<!-- Antivirus Card -->
<div class="setting-card">
<h3 class="card-title">
<span class="card-icon">🛡️</span>
Antivirus
</h3>
<p class="card-description">
Scan your system for threats using ClamAV open-source antivirus engine.
</p>
<!-- Protection Status -->
<div id="protection-status" class="protection-status"
hx-get="/api/v1/security/status"
hx-trigger="load, every 30s"
hx-swap="innerHTML">
<div class="status-loading">Loading protection status...</div>
</div>
<!-- Windows Defender Toggle -->
<div class="setting-row defender-row">
<div class="setting-info">
<div class="setting-label">🪟 Use General Bots Instead of Windows Defender</div>
<div class="setting-hint">
Disable Windows Defender and use General Bots protection (requires admin)
</div>
</div>
<div class="setting-control">
<label class="toggle-switch">
<input type="checkbox" id="toggle-defender"
hx-post="/api/v1/security/defender/toggle"
hx-trigger="change"
hx-swap="none">
<span class="toggle-slider"></span>
</label>
</div>
</div>
<!-- Scan Progress -->
<div class="progress-section" id="scan-progress-section" style="display: none;">
<div class="progress-bar-container">
<div class="progress-bar" id="scan-progress-bar"></div>
</div>
<p class="progress-text" id="scan-progress-text">Scanning...</p>
</div>
<!-- Threats List -->
<div id="threats-list" class="threats-list"
hx-get="/api/v1/security/threats"
hx-trigger="load"
hx-swap="innerHTML">
</div>
<!-- Scan Actions -->
<div class="card-actions">
<button class="btn btn-primary" id="btn-quick-scan"
hx-post="/api/v1/security/scan"
hx-vals='{"scan_type": "quick"}'
hx-target="#scan-progress-section"
hx-swap="outerHTML">
⚡ Quick Scan
</button>
<button class="btn btn-secondary" id="btn-full-scan"
hx-post="/api/v1/security/scan"
hx-vals='{"scan_type": "full"}'
hx-target="#scan-progress-section">
🔍 Full Scan
</button>
<button class="btn btn-secondary" id="btn-update-definitions"
hx-post="/api/v1/security/definitions/update"
hx-swap="none">
📥 Update Definitions
</button>
</div>
</div>
<!-- Windows Optimizer Card -->
<div class="setting-card">
<h3 class="card-title">
<span class="card-icon"></span>
Optimize Windows
</h3>
<p class="card-description">
Optimize your Windows system for better performance using
<a href="https://github.com/Metaljisawa/OptimizationWindowsV1" target="_blank">OptimizationWindowsV1</a>.
</p>
<!-- Optimization Tasks -->
<div class="optimization-tasks">
<div class="task-grid">
<div class="task-item">
<span class="task-icon">💾</span>
<div class="task-info">
<span class="task-name">Defragment Disk</span>
<span class="task-desc">Optimize disk for faster access</span>
</div>
<button class="btn btn-small" id="btn-defrag"
hx-post="/api/v1/desktop/optimize"
hx-vals='{"tasks": ["defragment_disk"]}'
hx-swap="none">
Run
</button>
</div>
<div class="task-item">
<span class="task-icon">🧠</span>
<div class="task-info">
<span class="task-name">Clear Memory</span>
<span class="task-desc">Free up RAM for better performance</span>
</div>
<button class="btn btn-small" id="btn-clear-memory"
hx-post="/api/v1/desktop/optimize"
hx-vals='{"tasks": ["clear_memory"]}'
hx-swap="none">
Run
</button>
</div>
<div class="task-item">
<span class="task-icon">🚀</span>
<div class="task-info">
<span class="task-name">Optimize Services</span>
<span class="task-desc">Disable unnecessary services</span>
</div>
<button class="btn btn-small" id="btn-optimize-services"
hx-post="/api/v1/desktop/optimize"
hx-vals='{"tasks": ["optimize_services"]}'
hx-swap="none">
Run
</button>
</div>
<div class="task-item">
<span class="task-icon">🎯</span>
<div class="task-info">
<span class="task-name">Startup Programs</span>
<span class="task-desc">Manage startup applications</span>
</div>
<button class="btn btn-small" id="btn-startup"
hx-post="/api/v1/desktop/optimize"
hx-vals='{"tasks": ["disable_startup_programs"]}'
hx-swap="none">
Run
</button>
</div>
</div>
</div>
<!-- Optimization Actions -->
<div class="card-actions">
<button class="btn btn-primary" id="btn-optimize-windows"
hx-post="/api/v1/desktop/optimize"
hx-vals='{"tasks": ["all"]}'
hx-swap="none"
hx-indicator="#optimize-spinner">
<span id="optimize-spinner" class="htmx-indicator spinner"></span>
⚡ Run Full Optimization
</button>
<button class="btn btn-secondary" id="btn-run-script"
hx-post="/api/v1/desktop/optimize/script"
hx-swap="none">
📜 Run External Script
</button>
</div>
</div>
<!-- Software Installation Card -->
<div class="setting-card">
<h3 class="card-title">
<span class="card-icon">📦</span>
Install Software
</h3>
<p class="card-description">
Quickly install recommended software on your system.
</p>
<!-- Software List -->
<div class="software-list">
<div class="software-item">
<div class="software-icon">🦁</div>
<div class="software-info">
<span class="software-name">Brave Browser</span>
<span class="software-desc">Privacy-focused browser with built-in ad blocker</span>
</div>
<button class="btn btn-primary btn-small" id="btn-install-brave"
hx-post="/api/v1/desktop/install/brave"
hx-target="#install-progress-section"
hx-swap="outerHTML">
Install
</button>
</div>
</div>
<!-- Install Progress -->
<div class="progress-section" id="install-progress-section" style="display: none;">
<div class="progress-bar-container">
<div class="progress-bar" id="install-progress-bar"></div>
</div>
<p class="progress-text" id="install-progress-text">Installing...</p>
</div>
</div>
<!-- Notification -->
<div class="notification" id="tools-notification"></div>
</div>
<style>
/* Tools Section Styles */
.tools-section {
max-width: 900px;
}
.tools-warning {
display: flex;
align-items: flex-start;
gap: 16px;
padding: 16px 20px;
background: rgba(245, 158, 11, 0.1);
border: 1px solid rgba(245, 158, 11, 0.3);
border-radius: 8px;
margin-bottom: 24px;
}
.warning-icon {
font-size: 24px;
}
.warning-content h4 {
margin-bottom: 4px;
color: #f59e0b;
}
.warning-content p {
font-size: 13px;
color: var(--text-secondary, #94a3b8);
}
.card-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
.card-icon {
font-size: 24px;
}
.card-description {
color: var(--text-secondary, #94a3b8);
font-size: 14px;
margin-bottom: 24px;
}
.card-description a {
color: var(--accent-color, #3b82f6);
text-decoration: none;
}
.card-description a:hover {
text-decoration: underline;
}
/* Disk Info */
.disk-info-section {
margin-bottom: 24px;
}
.section-header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.section-header-row h4 {
font-size: 14px;
font-weight: 600;
}
.disk-info-container {
background: var(--bg-tertiary, #334155);
border-radius: 8px;
padding: 16px;
}
.disk-item {
margin-bottom: 16px;
}
.disk-item:last-child {
margin-bottom: 0;
}
.disk-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 14px;
}
.disk-name {
font-weight: 500;
}
.disk-usage {
color: var(--text-secondary, #94a3b8);
}
.disk-bar {
height: 8px;
background: var(--bg-secondary, #1e293b);
border-radius: 4px;
overflow: hidden;
}
.disk-bar-fill {
height: 100%;
border-radius: 4px;
transition: width 0.3s ease;
}
.disk-bar-fill.normal {
background: linear-gradient(90deg, #22c55e, #4ade80);
}
.disk-bar-fill.warning {
background: linear-gradient(90deg, #f59e0b, #fbbf24);
}
.disk-bar-fill.critical {
background: linear-gradient(90deg, #ef4444, #f87171);
}
.disk-footer {
display: flex;
justify-content: space-between;
margin-top: 8px;
font-size: 12px;
color: var(--text-secondary, #94a3b8);
}
/* Cleanup Categories */
.cleanup-categories h4 {
font-size: 14px;
font-weight: 600;
margin-bottom: 16px;
}
.category-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
margin-bottom: 24px;
}
.category-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 12px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
.category-item:hover {
background: var(--bg-secondary, #1e293b);
}
.category-item:has(input:checked) {
border-color: var(--accent-color, #3b82f6);
background: rgba(59, 130, 246, 0.1);
}
.category-item input {
margin-top: 4px;
}
.category-icon {
font-size: 20px;
}
.category-name {
display: block;
font-weight: 500;
font-size: 14px;
}
.category-desc {
display: block;
font-size: 12px;
color: var(--text-secondary, #94a3b8);
}
/* Progress Section */
.progress-section {
margin: 20px 0;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.progress-bar-container {
height: 8px;
background: var(--bg-secondary, #1e293b);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--accent-color, #3b82f6), #60a5fa);
border-radius: 4px;
width: 0%;
transition: width 0.3s ease;
}
.progress-text {
font-size: 13px;
color: var(--text-secondary, #94a3b8);
text-align: center;
}
/* Cleanup Results */
.cleanup-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 16px;
}
.cleanup-stats .stat-item {
text-align: center;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.cleanup-stats .stat-value {
display: block;
font-size: 24px;
font-weight: 700;
color: var(--accent-color, #3b82f6);
}
.cleanup-stats .stat-label {
display: block;
font-size: 12px;
color: var(--text-secondary, #94a3b8);
margin-top: 4px;
}
.cleanup-errors {
padding: 12px;
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 8px;
}
.cleanup-errors h4 {
color: #ef4444;
font-size: 13px;
margin-bottom: 8px;
}
.cleanup-errors ul {
font-size: 12px;
color: var(--text-secondary, #94a3b8);
padding-left: 20px;
}
/* Protection Status */
.protection-status {
margin-bottom: 24px;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px;
}
.status-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
text-align: center;
}
.status-item.active {
border: 1px solid rgba(34, 197, 94, 0.3);
background: rgba(34, 197, 94, 0.1);
}
.status-item.inactive {
border: 1px solid rgba(239, 68, 68, 0.3);
background: rgba(239, 68, 68, 0.1);
}
.status-icon {
font-size: 24px;
margin-bottom: 8px;
}
.status-label {
font-size: 12px;
color: var(--text-secondary, #94a3b8);
margin-bottom: 4px;
}
.status-value {
font-weight: 600;
font-size: 14px;
}
/* Defender Row */
.defender-row {
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
margin-bottom: 24px;
}
/* Threats List */
.threats-list {
margin-bottom: 24px;
}
.no-threats {
text-align: center;
padding: 32px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.no-threats-icon {
font-size: 48px;
display: block;
margin-bottom: 12px;
}
.threat-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
margin-bottom: 8px;
border-left: 4px solid transparent;
}
.threat-item.severity-critical {
border-left-color: #dc2626;
background: rgba(220, 38, 38, 0.1);
}
.threat-item.severity-high {
border-left-color: #ea580c;
background: rgba(234, 88, 12, 0.1);
}
.threat-item.severity-medium {
border-left-color: #ca8a04;
background: rgba(202, 138, 4, 0.1);
}
.threat-item.severity-low {
border-left-color: #16a34a;
}
.threat-icon {
font-size: 24px;
}
.threat-info {
flex: 1;
}
.threat-name {
font-weight: 600;
font-size: 14px;
margin-bottom: 4px;
}
.threat-path {
font-size: 12px;
color: var(--text-secondary, #94a3b8);
word-break: break-all;
}
.threat-type {
display: inline-block;
font-size: 11px;
padding: 2px 8px;
background: var(--bg-secondary, #1e293b);
border-radius: 4px;
margin-top: 4px;
}
.threat-actions {
display: flex;
gap: 8px;
}
/* Optimization Tasks */
.optimization-tasks {
margin-bottom: 24px;
}
.task-grid {
display: flex;
flex-direction: column;
gap: 12px;
}
.task-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.task-icon {
font-size: 24px;
}
.task-info {
flex: 1;
}
.task-name {
display: block;
font-weight: 500;
font-size: 14px;
}
.task-desc {
display: block;
font-size: 12px;
color: var(--text-secondary, #94a3b8);
}
/* Software List */
.software-list {
margin-bottom: 24px;
}
.software-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.software-icon {
font-size: 32px;
}
.software-info {
flex: 1;
}
.software-name {
display: block;
font-weight: 600;
font-size: 15px;
}
.software-desc {
display: block;
font-size: 13px;
color: var(--text-secondary, #94a3b8);
}
/* Card Actions */
.card-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 18px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: var(--accent-color, #3b82f6);
color: white;
}
.btn-primary:hover {
background: var(--accent-hover, #2563eb);
}
.btn-secondary {
background: var(--bg-tertiary, #334155);
color: var(--text-primary, #f1f5f9);
}
.btn-secondary:hover {
background: var(--border-color, #475569);
}
.btn-danger {
background: #ef4444;
color: white;
}
.btn-danger:hover {
background: #dc2626;
}
.btn-small {
padding: 6px 12px;
font-size: 13px;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Spinner */
.spinner {
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top-color: currentColor;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline-block;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Toggle Switch */
.toggle-switch {
position: relative;
display: inline-block;
width: 48px;
height: 26px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--text-secondary, #94a3b8);
transition: 0.3s;
border-radius: 26px;
}
.toggle-slider:before {
position: absolute;
content: "";
height: 20px;
width: 20px;
left: 3px;
bottom: 3px;
background: white;
transition: 0.3s;
border-radius: 50%;
}
.toggle-switch input:checked + .toggle-slider {
background: var(--accent-color, #3b82f6);
}
.toggle-switch input:checked + .toggle-slider:before {
transform: translateX(22px);
}
/* Notification */
.notification {
position: fixed;
bottom: 20px;
right: 20px;
padding: 14px 24px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transform: translateX(150%);
transition: transform 0.3s ease;
z-index: 1000;
}
.notification.show {
transform: translateX(0);
}
.notification.success {
border-left: 4px solid #22c55e;
}
.notification.error {
border-left: 4px solid #ef4444;
}
.notification.warning {
border-left: 4px solid #f59e0b;
}
/* Responsive */
@media (max-width: 768px) {
.category-grid {
grid-template-columns: 1fr;
}
.status-grid {
grid-template-columns: repeat(2, 1fr);
}
.cleanup-stats {
grid-template-columns: 1fr;
}
.card-actions {
flex-direction: column;
}
.card-actions .btn {
width: 100%;
}
}
</style>
<script>
// Helper function to get selected cleanup categories
function getSelectedCategories() {
const checkboxes = document.querySelectorAll('.cleanup-category:checked');
return Array.from(checkboxes).map(cb => cb.value);
}
// Show desktop warning if not in Tauri
if (typeof window.__TAURI__ === 'undefined') {
const warning = document.getElementById('desktop-warning');
if (warning) {
warning.style.display = 'flex';
}
}
// HTMX event handlers
document.body.addEventListener('htmx:afterSwap', function(evt) {
// Handle successful responses
if (evt.detail.successful) {
showNotification('Operation completed successfully', 'success');
}
});
document.body.addEventListener('htmx:responseError', function(evt) {
showNotification('Operation failed: ' + evt.detail.error, 'error');
});
// Show notification
function showNotification(message, type = 'success') {
const notification = document.getElementById('tools-notification');
if (notification) {
notification.textContent = message;
notification.className = `notification ${type} show`;
setTimeout(() => {
notification.classList.remove('show');
}, 3000);
}
}
</script>