238 lines
12 KiB
HTML
238 lines
12 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block content %}
|
|
<div class="container mt-4">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-10">
|
|
|
|
<!-- Database & Redis Status -->
|
|
<div class="row g-2 mb-3">
|
|
<div class="col-md-8">
|
|
<div id="dbStatus" class="alert alert-info mb-0">
|
|
<i class="fas fa-database me-2"></i>
|
|
<span>Checking database status...</span>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
{% if redis_enabled %}
|
|
{% if redis_connected %}
|
|
<div class="alert alert-success mb-0">
|
|
<i class="fas fa-bolt me-2"></i>Redis Cache: <strong>Active</strong>
|
|
</div>
|
|
{% else %}
|
|
<div class="alert alert-warning mb-0">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>Redis: <strong>Offline</strong>
|
|
</div>
|
|
{% endif %}
|
|
{% else %}
|
|
<div class="alert alert-secondary mb-0">
|
|
<i class="fas fa-bolt me-2"></i>Redis: <strong>Disabled</strong>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Cache Stats Panel (Collapsible) -->
|
|
{% if redis_enabled and redis_connected %}
|
|
<div class="card mb-3">
|
|
<div class="card-header bg-light" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#cacheStatsPanel">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span>
|
|
<i class="fas fa-chart-bar me-2"></i>Cache Statistics
|
|
</span>
|
|
<i class="fas fa-chevron-down"></i>
|
|
</div>
|
|
</div>
|
|
<div id="cacheStatsPanel" class="collapse">
|
|
<div class="card-body">
|
|
<div id="cacheStatsContent">
|
|
<div class="text-center py-3">
|
|
<div class="spinner-border spinner-border-sm text-primary" role="status"></div>
|
|
<span class="ms-2">Loading cache statistics...</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3 border-top pt-3">
|
|
<button class="btn btn-sm btn-warning" onclick="flushCache()">
|
|
<i class="fas fa-trash me-1"></i>Flush Cache (redis)
|
|
</button>
|
|
<button class="btn btn-sm btn-info" onclick="loadCacheStats()">
|
|
<i class="fas fa-sync me-1"></i>Refresh Stats
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Main Card -->
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-white">
|
|
<h4 class="mb-0">
|
|
<i class="fas fa-globe me-2"></i>Generate Geo-Blocking Configuration
|
|
</h4>
|
|
</div>
|
|
<div class="card-body p-4">
|
|
<form id="generateForm">
|
|
|
|
<!-- Country Selection -->
|
|
<div class="mb-4">
|
|
<label class="form-label fw-bold">
|
|
<i class="fas fa-flag me-2"></i>Select Countries to Block
|
|
</label>
|
|
<div class="row g-1 mb-2" id="countryList">
|
|
{% for country in countries %}
|
|
<div class="col-xxl-1 col-xl-2 col-lg-2 col-md-3 col-sm-4 col-6">
|
|
<div class="form-check form-check-compact">
|
|
<input class="form-check-input" type="checkbox"
|
|
name="countries" value="{{ country.code }}"
|
|
id="country_{{ country.code }}">
|
|
<label class="form-check-label" for="country_{{ country.code }}" title="{{ country.name }}">
|
|
{{ country.flag }} {{ country.code }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="selectAll()">
|
|
<i class="fas fa-check-double me-1"></i>Select All
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="deselectAll()">
|
|
<i class="fas fa-times me-1"></i>Deselect All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Application Type -->
|
|
<div class="mb-4">
|
|
<label class="form-label fw-bold">
|
|
<i class="fas fa-server me-2"></i>Output Format
|
|
</label>
|
|
<select class="form-select form-select-lg" id="appType" name="app_type" onchange="updateVariants()">
|
|
<option value="raw-cidr">Raw CIDR List</option>
|
|
<option value="nginx">Nginx</option>
|
|
<option value="apache">Apache</option>
|
|
<option value="haproxy">HAProxy</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Variant Selection -->
|
|
<div class="mb-4" id="variantSection">
|
|
<label class="form-label fw-bold">
|
|
<i class="fas fa-cog me-2"></i>Configuration Style
|
|
</label>
|
|
<select class="form-select form-select-lg" id="appVariant" name="app_variant" onchange="updateVariantDescription()">
|
|
</select>
|
|
<div id="variantDescription" class="mt-2" style="display: none;">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Aggregate Option -->
|
|
<div class="mb-4">
|
|
<label class="form-label fw-bold">
|
|
<i class="fas fa-sliders-h me-2"></i>Options
|
|
</label>
|
|
<div class="aggregate-card">
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" role="switch"
|
|
id="aggregate" name="aggregate" checked>
|
|
<label class="form-check-label" for="aggregate">
|
|
<strong>Aggregate IP networks</strong><br>
|
|
<small class="text-muted">Combines adjacent networks into larger CIDR blocks for smaller files</small>
|
|
</label>
|
|
</div>
|
|
|
|
{% if redis_enabled and redis_connected %}
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" role="switch"
|
|
id="useCache" name="use_cache" checked>
|
|
<label class="form-check-label" for="useCache">
|
|
<strong><i class="fas fa-bolt text-warning"></i> Use Redis Cache</strong><br>
|
|
<small class="text-muted">Instant generation for previously cached configurations (<100ms)</small>
|
|
</label>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="row g-2">
|
|
<div class="col-md-6">
|
|
<button type="button" class="btn btn-outline-primary btn-lg w-100" onclick="previewConfiguration()">
|
|
<i class="fas fa-eye me-2"></i>Preview
|
|
</button>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<button type="submit" class="btn btn-primary btn-lg w-100" id="generateBtn">
|
|
<i class="fas fa-download me-2"></i>Download
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Progress -->
|
|
<div id="progressSection" class="mt-3" style="display: none;">
|
|
<div class="progress" style="height: 2rem;">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
|
role="progressbar"
|
|
style="width: 0%"
|
|
aria-valuenow="0"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100">
|
|
<span id="progressPercentage">0%</span>
|
|
</div>
|
|
</div>
|
|
<div class="text-center mt-2">
|
|
<small class="text-muted" id="progressMessage">Initializing...</small>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Result -->
|
|
<div id="resultSection" class="mt-3" style="display: none;">
|
|
<div class="alert" role="alert">
|
|
<span id="resultMessage"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Preview Modal -->
|
|
<div class="modal fade" id="previewModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
<i class="fas fa-file-code me-2"></i>Configuration Preview
|
|
<span id="cacheIndicator"></span>
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="copyToClipboard()">
|
|
<i class="fas fa-copy me-1"></i>Copy to Clipboard
|
|
</button>
|
|
<span id="previewStats" class="ms-3 text-muted"></span>
|
|
</div>
|
|
<pre class="mb-0"><code id="previewContent"></code></pre>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" onclick="downloadFromPreview()">
|
|
<i class="fas fa-download me-2"></i>Download
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='js/progress.js') }}?v={{ js_hash }}"></script>
|
|
<script src="{{ url_for('static', filename='js/cache.js') }}?v={{ js_hash }}"></script>
|
|
{% endblock %}
|