887 lines
46 KiB
HTML
887 lines
46 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Configuración - AutoBackups{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<h1 class="mb-4">
|
|
<i class="bi bi-sliders"></i> Configuración del Sistema
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<!-- Alert container for messages -->
|
|
<div id="config-alerts"></div>
|
|
|
|
<!-- Configuration Tabs -->
|
|
<ul class="nav nav-tabs" id="configTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="general-tab" data-bs-toggle="tab"
|
|
data-bs-target="#general" type="button" role="tab">
|
|
<i class="bi bi-gear-fill"></i> General
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="directories-tab" data-bs-toggle="tab"
|
|
data-bs-target="#directories" type="button" role="tab">
|
|
<i class="bi bi-folder"></i> Directorios
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="backup-tab" data-bs-toggle="tab"
|
|
data-bs-target="#backup" type="button" role="tab">
|
|
<i class="bi bi-archive"></i> Backup
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="everything-tab" data-bs-toggle="tab"
|
|
data-bs-target="#everything" type="button" role="tab">
|
|
<i class="bi bi-search"></i> Everything API
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="web-tab" data-bs-toggle="tab"
|
|
data-bs-target="#web" type="button" role="tab">
|
|
<i class="bi bi-globe"></i> Web Interface
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="logging-tab" data-bs-toggle="tab"
|
|
data-bs-target="#logging" type="button" role="tab">
|
|
<i class="bi bi-file-text"></i> Logging
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content mt-3" id="configTabContent">
|
|
<!-- General Settings Tab -->
|
|
<div class="tab-pane fade show active" id="general" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5><i class="bi bi-gear-fill"></i> Configuración General</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="general-form">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="backup_destination" class="form-label">Destino de Backups</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="backup_destination"
|
|
value="{{ config.backup_destination }}" required>
|
|
<button type="button" class="btn btn-outline-secondary" id="browse-backup-dest">
|
|
<i class="bi bi-folder"></i>
|
|
</button>
|
|
</div>
|
|
<div class="form-text">Directorio donde se almacenarán los backups</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="default_schedule" class="form-label">Programación por Defecto</label>
|
|
<select class="form-select" id="default_schedule">
|
|
<option value="manual" {% if config.global_settings.default_schedule == 'manual' %}selected{% endif %}>Manual</option>
|
|
<option value="daily" {% if config.global_settings.default_schedule == 'daily' %}selected{% endif %}>Diario</option>
|
|
<option value="weekly" {% if config.global_settings.default_schedule == 'weekly' %}selected{% endif %}>Semanal</option>
|
|
<option value="monthly" {% if config.global_settings.default_schedule == 'monthly' %}selected{% endif %}>Mensual</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="default_schedule_time" class="form-label">Hora de Programación</label>
|
|
<input type="time" class="form-control" id="default_schedule_time"
|
|
value="{{ config.global_settings.default_schedule_time }}">
|
|
<div class="form-text">Hora por defecto para ejecutar backups automáticos</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="scan_interval_minutes" class="form-label">Intervalo de Escaneo (minutos)</label>
|
|
<input type="number" class="form-control" id="scan_interval_minutes"
|
|
value="{{ config.global_settings.scan_interval_minutes }}" min="1" max="1440">
|
|
<div class="form-text">Frecuencia de búsqueda de nuevos proyectos</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="min_backup_interval_minutes" class="form-label">Intervalo Mínimo de Backup (minutos)</label>
|
|
<input type="number" class="form-control" id="min_backup_interval_minutes"
|
|
value="{{ config.global_settings.min_backup_interval_minutes }}" min="1">
|
|
<div class="form-text">Tiempo mínimo entre backups del mismo proyecto</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="min_free_space_mb" class="form-label">Espacio Libre Mínimo (MB)</label>
|
|
<input type="number" class="form-control" id="min_free_space_mb"
|
|
value="{{ config.global_settings.min_free_space_mb }}" min="50">
|
|
<div class="form-text">Espacio mínimo requerido antes de hacer backup</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="retry_delay_hours" class="form-label">Retraso de Reintento (horas)</label>
|
|
<input type="number" class="form-control" id="retry_delay_hours"
|
|
value="{{ config.global_settings.retry_delay_hours }}" min="0" step="0.5">
|
|
<div class="form-text">Tiempo de espera antes de reintentar un backup fallido</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="backup_timeout_minutes" class="form-label">Timeout de Backup (minutos)</label>
|
|
<input type="number" class="form-control" id="backup_timeout_minutes"
|
|
value="{{ config.global_settings.backup_timeout_minutes }}" min="0">
|
|
<div class="form-text">Tiempo máximo para completar un backup (0 = sin límite)</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Guardar Configuración General
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Observation Directories Tab -->
|
|
<div class="tab-pane fade" id="directories" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5><i class="bi bi-folder"></i> Directorios de Observación</h5>
|
|
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#addDirectoryModal">
|
|
<i class="bi bi-plus-circle"></i> Agregar Directorio
|
|
</button>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="directories-list">
|
|
{% for dir in config.observation_directories %}
|
|
<div class="card mb-2 directory-item" data-index="{{ loop.index0 }}">
|
|
<div class="card-body">
|
|
<div class="row align-items-center">
|
|
<div class="col-md-4">
|
|
<strong>{{ dir.path }}</strong>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<span class="badge bg-info">{{ dir.type }}</span>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<small class="text-muted">{{ dir.description or 'Sin descripción' }}</small>
|
|
</div>
|
|
<div class="col-md-2 text-end">
|
|
<div class="form-check form-switch d-inline-block me-2">
|
|
<input class="form-check-input" type="checkbox"
|
|
{% if dir.enabled %}checked{% endif %}
|
|
onchange="toggleDirectory({{ loop.index0 }}, this.checked)">
|
|
</div>
|
|
<button type="button" class="btn btn-danger btn-sm"
|
|
onclick="removeDirectory({{ loop.index0 }})">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Backup Options Tab -->
|
|
<div class="tab-pane fade" id="backup" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5><i class="bi bi-archive"></i> Opciones de Backup</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="backup-form">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="compression_level" class="form-label">Nivel de Compresión</label>
|
|
<input type="range" class="form-range" id="compression_level"
|
|
min="0" max="9" value="{{ config.backup_options.compression_level }}"
|
|
oninput="document.getElementById('compression_value').textContent = this.value">
|
|
<div class="d-flex justify-content-between">
|
|
<small>Rápido (0)</small>
|
|
<span id="compression_value">{{ config.backup_options.compression_level }}</span>
|
|
<small>Máximo (9)</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="hash_algorithm" class="form-label">Algoritmo de Hash</label>
|
|
<select class="form-select" id="hash_algorithm">
|
|
<option value="md5" {% if config.backup_options.hash_algorithm == 'md5' %}selected{% endif %}>MD5</option>
|
|
<option value="sha1" {% if config.backup_options.hash_algorithm == 'sha1' %}selected{% endif %}>SHA1</option>
|
|
<option value="sha256" {% if config.backup_options.hash_algorithm == 'sha256' %}selected{% endif %}>SHA256</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="process_priority" class="form-label">Prioridad del Proceso</label>
|
|
<select class="form-select" id="process_priority">
|
|
<option value="low" {% if config.backup_options.process_priority == 'low' %}selected{% endif %}>Baja</option>
|
|
<option value="normal" {% if config.backup_options.process_priority == 'normal' %}selected{% endif %}>Normal</option>
|
|
<option value="high" {% if config.backup_options.process_priority == 'high' %}selected{% endif %}>Alta</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="backup_type" class="form-label">Tipo de Backup</label>
|
|
<select class="form-select" id="backup_type">
|
|
<option value="complete" {% if config.backup_options.backup_type == 'complete' %}selected{% endif %}>Completo</option>
|
|
<option value="incremental" {% if config.backup_options.backup_type == 'incremental' %}selected{% endif %}>Incremental</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="filename_format" class="form-label">Formato de Nombre de Archivo</label>
|
|
<input type="text" class="form-control" id="filename_format"
|
|
value="{{ config.backup_options.filename_format }}">
|
|
<div class="form-text">Formato: HH-MM-SS_projects.zip</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="date_format" class="form-label">Formato de Fecha</label>
|
|
<input type="text" class="form-control" id="date_format"
|
|
value="{{ config.backup_options.date_format }}">
|
|
<div class="form-text">Formato: YYYY-MM-DD</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="include_subdirectories"
|
|
{% if config.backup_options.include_subdirectories %}checked{% endif %}>
|
|
<label class="form-check-label" for="include_subdirectories">
|
|
Incluir Subdirectorios
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="preserve_directory_structure"
|
|
{% if config.backup_options.preserve_directory_structure %}checked{% endif %}>
|
|
<label class="form-check-label" for="preserve_directory_structure">
|
|
Preservar Estructura de Directorios
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="sequential_execution"
|
|
{% if config.backup_options.sequential_execution %}checked{% endif %}>
|
|
<label class="form-check-label" for="sequential_execution">
|
|
Ejecución Secuencial
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Guardar Opciones de Backup
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Everything API Tab -->
|
|
<div class="tab-pane fade" id="everything" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5><i class="bi bi-search"></i> Configuración Everything API</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="everything-form">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="everything_enabled"
|
|
{% if config.everything_api.enabled %}checked{% endif %}>
|
|
<label class="form-check-label" for="everything_enabled">
|
|
<strong>Habilitar Everything API</strong>
|
|
</label>
|
|
<div class="form-text">Utilizar Everything para búsquedas rápidas de archivos</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="mb-3">
|
|
<label for="dll_path" class="form-label">Ruta de la DLL</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="dll_path"
|
|
value="{{ config.everything_api.dll_path }}" required>
|
|
<button type="button" class="btn btn-outline-secondary" id="browse-dll">
|
|
<i class="bi bi-folder"></i>
|
|
</button>
|
|
</div>
|
|
<div class="form-text">Ruta a Everything32.dll o Everything64.dll</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="search_depth" class="form-label">Profundidad de Búsqueda</label>
|
|
<input type="number" class="form-control" id="search_depth"
|
|
value="{{ config.everything_api.search_depth }}" min="-1">
|
|
<div class="form-text">-1 = Sin límite</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="skip_last_level_for_s7p"
|
|
{% if config.everything_api.skip_last_level_for_s7p %}checked{% endif %}>
|
|
<label class="form-check-label" for="skip_last_level_for_s7p">
|
|
Omitir Último Nivel para S7P
|
|
</label>
|
|
<div class="form-text">Optimización específica para proyectos Siemens S7</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Guardar Configuración Everything
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Web Interface Tab -->
|
|
<div class="tab-pane fade" id="web" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5><i class="bi bi-globe"></i> Configuración Web Interface</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="web-form">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="web_host" class="form-label">Host</label>
|
|
<input type="text" class="form-control" id="web_host"
|
|
value="{{ config.web_interface.host }}" required>
|
|
<div class="form-text">Dirección IP para el servidor web</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="web_port" class="form-label">Puerto</label>
|
|
<input type="number" class="form-control" id="web_port"
|
|
value="{{ config.web_interface.port }}" min="1" max="65535" required>
|
|
<div class="form-text">Puerto para el servidor web</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="web_debug"
|
|
{% if config.web_interface.debug %}checked{% endif %}>
|
|
<label class="form-check-label" for="web_debug">
|
|
Modo Debug
|
|
</label>
|
|
<div class="form-text">Habilitar solo para desarrollo</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Guardar Configuración Web
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Logging Tab -->
|
|
<div class="tab-pane fade" id="logging" role="tabpanel">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5><i class="bi bi-file-text"></i> Configuración de Logging</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="logging-form">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="log_level" class="form-label">Nivel de Log</label>
|
|
<select class="form-select" id="log_level">
|
|
<option value="DEBUG" {% if config.logging.level == 'DEBUG' %}selected{% endif %}>DEBUG</option>
|
|
<option value="INFO" {% if config.logging.level == 'INFO' %}selected{% endif %}>INFO</option>
|
|
<option value="WARNING" {% if config.logging.level == 'WARNING' %}selected{% endif %}>WARNING</option>
|
|
<option value="ERROR" {% if config.logging.level == 'ERROR' %}selected{% endif %}>ERROR</option>
|
|
<option value="CRITICAL" {% if config.logging.level == 'CRITICAL' %}selected{% endif %}>CRITICAL</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="max_log_files" class="form-label">Máximo de Archivos de Log</label>
|
|
<input type="number" class="form-control" id="max_log_files"
|
|
value="{{ config.logging.max_log_files }}" min="1" max="100">
|
|
<div class="form-text">Número máximo de archivos de log a mantener</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label for="log_rotation_days" class="form-label">Rotación de Logs (días)</label>
|
|
<input type="number" class="form-control" id="log_rotation_days"
|
|
value="{{ config.logging.log_rotation_days }}" min="1" max="365">
|
|
<div class="form-text">Días después de los cuales rotar logs</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Guardar Configuración de Logging
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Directory Modal -->
|
|
<div class="modal fade" id="addDirectoryModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Agregar Directorio de Observación</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="add-directory-form">
|
|
<div class="mb-3">
|
|
<label for="new_directory_path" class="form-label">Ruta del Directorio</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="new_directory_path" required>
|
|
<button type="button" class="btn btn-outline-secondary" id="browse-new-directory">
|
|
<i class="bi bi-folder"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="new_directory_type" class="form-label">Tipo de Proyecto</label>
|
|
<select class="form-select" id="new_directory_type" required>
|
|
<option value="siemens_s7">Siemens S7</option>
|
|
<option value="siemens_tia">Siemens TIA Portal</option>
|
|
<option value="generic">Genérico</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="new_directory_description" class="form-label">Descripción</label>
|
|
<input type="text" class="form-control" id="new_directory_description"
|
|
placeholder="Descripción opcional del directorio">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
|
|
<button type="button" class="btn btn-primary" onclick="addDirectory()">
|
|
<i class="bi bi-plus-circle"></i> Agregar
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
// Configuration management functions
|
|
function showAlert(message, type = 'success') {
|
|
const alertContainer = document.getElementById('config-alerts');
|
|
const alert = document.createElement('div');
|
|
alert.className = `alert alert-${type} alert-dismissible fade show`;
|
|
alert.innerHTML = `
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
`;
|
|
alertContainer.appendChild(alert);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(() => {
|
|
if (alert.parentNode) {
|
|
alert.remove();
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
// General configuration form
|
|
document.getElementById('general-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
backup_destination: document.getElementById('backup_destination').value,
|
|
global_settings: {
|
|
default_schedule: document.getElementById('default_schedule').value,
|
|
default_schedule_time: document.getElementById('default_schedule_time').value,
|
|
scan_interval_minutes: parseInt(document.getElementById('scan_interval_minutes').value),
|
|
min_backup_interval_minutes: parseInt(document.getElementById('min_backup_interval_minutes').value),
|
|
min_free_space_mb: parseInt(document.getElementById('min_free_space_mb').value),
|
|
retry_delay_hours: parseFloat(document.getElementById('retry_delay_hours').value),
|
|
backup_timeout_minutes: parseInt(document.getElementById('backup_timeout_minutes').value)
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config/general', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Configuración general guardada correctamente', 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al guardar configuración: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
});
|
|
|
|
// Backup options form
|
|
document.getElementById('backup-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
compression_level: parseInt(document.getElementById('compression_level').value),
|
|
hash_algorithm: document.getElementById('hash_algorithm').value,
|
|
process_priority: document.getElementById('process_priority').value,
|
|
backup_type: document.getElementById('backup_type').value,
|
|
filename_format: document.getElementById('filename_format').value,
|
|
date_format: document.getElementById('date_format').value,
|
|
include_subdirectories: document.getElementById('include_subdirectories').checked,
|
|
preserve_directory_structure: document.getElementById('preserve_directory_structure').checked,
|
|
sequential_execution: document.getElementById('sequential_execution').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config/backup_options', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Opciones de backup guardadas correctamente', 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al guardar opciones: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
});
|
|
|
|
// Everything API form
|
|
document.getElementById('everything-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
enabled: document.getElementById('everything_enabled').checked,
|
|
dll_path: document.getElementById('dll_path').value,
|
|
search_depth: parseInt(document.getElementById('search_depth').value),
|
|
skip_last_level_for_s7p: document.getElementById('skip_last_level_for_s7p').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config/everything_api', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Configuración de Everything API guardada correctamente', 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al guardar configuración: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
});
|
|
|
|
// Web interface form
|
|
document.getElementById('web-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
host: document.getElementById('web_host').value,
|
|
port: parseInt(document.getElementById('web_port').value),
|
|
debug: document.getElementById('web_debug').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config/web_interface', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Configuración web guardada correctamente', 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al guardar configuración: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
});
|
|
|
|
// Logging form
|
|
document.getElementById('logging-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = {
|
|
level: document.getElementById('log_level').value,
|
|
max_log_files: parseInt(document.getElementById('max_log_files').value),
|
|
log_rotation_days: parseInt(document.getElementById('log_rotation_days').value)
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config/logging', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Configuración de logging guardada correctamente', 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al guardar configuración: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
});
|
|
|
|
// Directory management functions
|
|
async function addDirectory() {
|
|
const path = document.getElementById('new_directory_path').value;
|
|
const type = document.getElementById('new_directory_type').value;
|
|
const description = document.getElementById('new_directory_description').value;
|
|
|
|
if (!path || !type) {
|
|
showAlert('Por favor complete los campos requeridos', 'warning');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/config/directories', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
path: path,
|
|
type: type,
|
|
description: description
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Directorio agregado correctamente', 'success');
|
|
document.getElementById('add-directory-form').reset();
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('addDirectoryModal'));
|
|
modal.hide();
|
|
// Reload the page to show the new directory
|
|
setTimeout(() => window.location.reload(), 1000);
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al agregar directorio: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
}
|
|
|
|
async function removeDirectory(index) {
|
|
if (!confirm('¿Está seguro de que desea eliminar este directorio?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/config/directories/${index}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert('Directorio eliminado correctamente', 'success');
|
|
// Reload the page to reflect changes
|
|
setTimeout(() => window.location.reload(), 1000);
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al eliminar directorio: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
}
|
|
|
|
async function toggleDirectory(index, enabled) {
|
|
try {
|
|
const response = await fetch(`/api/config/directories/${index}/toggle`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ enabled: enabled })
|
|
});
|
|
|
|
if (response.ok) {
|
|
showAlert(`Directorio ${enabled ? 'habilitado' : 'deshabilitado'} correctamente`, 'success');
|
|
} else {
|
|
const error = await response.json();
|
|
showAlert('Error al cambiar estado del directorio: ' + error.error, 'danger');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Error de conexión: ' + error.message, 'danger');
|
|
}
|
|
}
|
|
|
|
// File browser functionality using tkinter native dialogs
|
|
async function openDirectorySelector(targetInputId, title = 'Seleccionar Directorio') {
|
|
try {
|
|
// Obtener directorio inicial del input actual
|
|
const currentValue = document.getElementById(targetInputId).value;
|
|
const initialDir = currentValue || '';
|
|
|
|
// Encontrar el botón que activó la función
|
|
const button = event.target.closest('button');
|
|
const originalContent = button.innerHTML;
|
|
|
|
// Mostrar indicador de carga
|
|
button.innerHTML = '<i class="bi bi-clock"></i>';
|
|
button.disabled = true;
|
|
|
|
// Llamar al endpoint que abre el diálogo nativo
|
|
const response = await fetch('/api/directories/select', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
initial_dir: initialDir,
|
|
title: title
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
// Restaurar botón
|
|
button.innerHTML = originalContent;
|
|
button.disabled = false;
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.error || 'Error en el servidor');
|
|
}
|
|
|
|
if (data.success && data.selected_path) {
|
|
// Usuario seleccionó un directorio
|
|
document.getElementById(targetInputId).value = data.selected_path;
|
|
showAlert(`Directorio seleccionado: ${data.selected_path}`, 'success');
|
|
} else if (data.message) {
|
|
// Usuario canceló
|
|
showAlert(data.message, 'info');
|
|
}
|
|
|
|
} catch (error) {
|
|
// Restaurar botón en caso de error
|
|
const button = event.target.closest('button');
|
|
if (button && originalContent) {
|
|
button.innerHTML = originalContent;
|
|
button.disabled = false;
|
|
}
|
|
showAlert(`Error seleccionando directorio: ${error.message}`, 'danger');
|
|
console.error('Directory selection error:', error);
|
|
}
|
|
}
|
|
|
|
// File browser button handlers
|
|
document.getElementById('browse-backup-dest')?.addEventListener('click', function(event) {
|
|
openDirectorySelector('backup_destination', 'Seleccionar Destino de Backups');
|
|
});
|
|
|
|
document.getElementById('browse-dll')?.addEventListener('click', function(event) {
|
|
openDirectorySelector('dll_path', 'Seleccionar ubicación de Everything DLL');
|
|
});
|
|
|
|
document.getElementById('browse-new-directory')?.addEventListener('click', function(event) {
|
|
openDirectorySelector('new_directory_path', 'Seleccionar Directorio para Observación');
|
|
});
|
|
</script>
|
|
{% endblock %}
|