Initial commit: Quality App v2 - FG Scan Module with Reports
This commit is contained in:
266
app/templates/modules/settings/app_keys.html
Normal file
266
app/templates/modules/settings/app_keys.html
Normal file
@@ -0,0 +1,266 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}App Keys Management{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-5">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="mb-2">
|
||||
<i class="fas fa-key"></i> App Keys Management
|
||||
</h1>
|
||||
<p class="text-muted mb-0">Manage API keys and printer pairing keys for QZ Tray</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="list-group">
|
||||
<a href="{{ url_for('settings.general_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-sliders-h"></i> General Settings
|
||||
</a>
|
||||
<a href="{{ url_for('settings.user_management') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-users"></i> User Management
|
||||
</a>
|
||||
<a href="{{ url_for('settings.app_keys') }}" class="list-group-item list-group-item-action active">
|
||||
<i class="fas fa-key"></i> App Keys
|
||||
</a>
|
||||
<a href="{{ url_for('settings.database_management') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-cogs"></i> Database Management
|
||||
</a>
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<!-- QZ Tray Pairing Keys Section -->
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-print"></i> QZ Tray Printer Pairing Keys
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="fas fa-exclamation-circle"></i> {{ error }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if success %}
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<i class="fas fa-check-circle"></i> {{ success }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Generate New Pairing Key Form -->
|
||||
<div class="mb-4 p-3 bg-light rounded">
|
||||
<h6 class="mb-3">Generate New Pairing Key</h6>
|
||||
<form method="POST" action="{{ url_for('settings.generate_pairing_key') }}" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="printer_name" class="form-label">Printer Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="printer_name" name="printer_name"
|
||||
placeholder="e.g., Label Printer 1" required>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="validity_days" class="form-label">Validity (days) <span class="text-danger">*</span></label>
|
||||
<select class="form-select" id="validity_days" name="validity_days" required>
|
||||
<option value="30">30 Days</option>
|
||||
<option value="60">60 Days</option>
|
||||
<option value="90" selected>90 Days</option>
|
||||
<option value="180">180 Days</option>
|
||||
<option value="365">1 Year</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label"> </label>
|
||||
<button type="submit" class="btn btn-success w-100">
|
||||
<i class="fas fa-plus"></i> Generate Key
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Active Pairing Keys Table -->
|
||||
<h6 class="mb-3">Active Pairing Keys</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Printer Name</th>
|
||||
<th>Pairing Key</th>
|
||||
<th>Valid Until</th>
|
||||
<th>Days Remaining</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if pairing_keys %}
|
||||
{% for key in pairing_keys %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ key.printer_name }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
<code class="text-primary">{{ key.pairing_key }}</code>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2"
|
||||
onclick="copyToClipboard('{{ key.pairing_key }}')">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<small>{{ key.valid_until }}</small>
|
||||
</td>
|
||||
<td>
|
||||
{% set days_left = key.days_remaining %}
|
||||
{% if days_left > 30 %}
|
||||
<span class="badge bg-success">{{ days_left }} days</span>
|
||||
{% elif days_left > 0 %}
|
||||
<span class="badge bg-warning">{{ days_left }} days</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">Expired</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<form method="POST" action="{{ url_for('settings.delete_pairing_key', key_id=key.id) }}"
|
||||
style="display: inline;"
|
||||
onsubmit="return confirm('Are you sure you want to delete this pairing key?');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4">
|
||||
<div class="empty-state-message">
|
||||
<i class="fas fa-inbox" style="font-size: 24px; margin-right: 10px;"></i>
|
||||
<span>No pairing keys found. Create one to enable QZ Tray printing.</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App API Keys Section -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-code"></i> Application API Keys
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Generate New API Key Form -->
|
||||
<div class="mb-4 p-3 bg-light rounded">
|
||||
<h6 class="mb-3">Generate New API Key</h6>
|
||||
<form method="POST" action="{{ url_for('settings.generate_api_key') }}" class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="key_name" class="form-label">Key Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="key_name" name="key_name"
|
||||
placeholder="e.g., External Service API" required>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="key_type" class="form-label">Key Type <span class="text-danger">*</span></label>
|
||||
<select class="form-select" id="key_type" name="key_type" required>
|
||||
<option value="app_key">App Key</option>
|
||||
<option value="external_service">External Service</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label"> </label>
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="fas fa-plus"></i> Generate Key
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Active API Keys Table -->
|
||||
<h6 class="mb-3">Active API Keys</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key Name</th>
|
||||
<th>Key Type</th>
|
||||
<th>API Key</th>
|
||||
<th>Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if api_keys %}
|
||||
{% for key in api_keys %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ key.key_name }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">{{ key.key_type }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<code class="text-primary">{{ key.api_key[:20] }}...</code>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2"
|
||||
onclick="copyToClipboard('{{ key.api_key }}')">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<small>{{ key.created_at.strftime('%Y-%m-%d %H:%M') if key.created_at else 'N/A' }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<form method="POST" action="{{ url_for('settings.delete_api_key', key_id=key.id) }}"
|
||||
style="display: inline;"
|
||||
onsubmit="return confirm('Are you sure you want to delete this API key?');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4">
|
||||
<div class="empty-state-message">
|
||||
<i class="fas fa-inbox" style="font-size: 24px; margin-right: 10px;"></i>
|
||||
<span>No API keys found. Create one for external integrations.</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="fas fa-info-circle"></i> <strong>Note:</strong> Keep your API keys secure and never share them publicly.
|
||||
Regenerate keys if you suspect they have been compromised.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
alert('Key copied to clipboard!');
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy:', err);
|
||||
alert('Failed to copy key');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user