2025-06-19 14:25:42 -04:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Select or Create Tenant - KCAP Demo Server< / title >
< link href = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel = "stylesheet" >
2025-10-20 17:40:04 -04:00
< link rel = "stylesheet" href = "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" >
2025-06-19 14:25:42 -04:00
< / head >
< body >
< div class = "container mt-5" >
< h1 class = "text-center mb-4" > KCAP Demo Server - Multi-Tenant< / h1 >
2025-06-19 14:35:13 -04:00
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
< div class = "alert alert-{{ 'success' if category == 'success' else 'danger' }} alert-dismissible fade show" role = "alert" >
{{ message }}
< button type = "button" class = "btn-close" data-bs-dismiss = "alert" aria-label = "Close" > < / button >
< / div >
{% endfor %}
{% endif %}
{% endwith %}
2025-06-19 14:25:42 -04:00
< div class = "row justify-content-center" >
< div class = "col-md-8" >
< div class = "card" >
< div class = "card-header" >
< h3 > Select an Existing Tenant< / h3 >
< / div >
< div class = "card-body" >
{% if tenants %}
< div class = "list-group" >
{% for tenant in tenants %}
2025-06-19 14:35:13 -04:00
< div class = "list-group-item d-flex justify-content-between align-items-center" >
< a href = "/{{ tenant.id }}/" class = "text-decoration-none flex-grow-1" >
< div class = "d-flex w-100 justify-content-between" >
< h5 class = "mb-1" > {{ tenant.name }}< / h5 >
< small > {{ tenant.created_at }}< / small >
< / div >
< p class = "mb-1" > Username: {{ tenant.username }}< / p >
2025-10-20 17:40:04 -04:00
< p class = "mb-1" >
< strong > Knox Capture AR Template URL:< / strong >
< code > {{ server_url }}/{{ tenant.id }}/< / code >
< / p >
2025-06-19 14:35:13 -04:00
< small > ID: {{ tenant.id }}< / small >
< / a >
2025-10-20 17:40:04 -04:00
< button type = "button" class = "btn btn-sm btn-outline-primary me-2" data-bs-toggle = "modal" data-bs-target = "#qrModal-{{ tenant.id }}" onclick = "event.stopPropagation();" >
< i class = "bi bi-qr-code" > < / i >
< / button >
2025-06-19 14:35:13 -04:00
< form method = "POST" action = "/tenant/{{ tenant.id }}/delete" class = "ms-3" onsubmit = "return confirmDelete('{{ tenant.name }}')" >
< button type = "submit" class = "btn btn-danger btn-sm" > Delete< / button >
< / form >
< / div >
2025-06-19 14:25:42 -04:00
{% endfor %}
< / div >
{% else %}
< p class = "text-muted" > No tenants exist yet. Create one below!< / p >
{% endif %}
< / div >
< / div >
< div class = "card mt-4" >
< div class = "card-header" >
< h3 > Create a New Tenant< / h3 >
< / div >
< div class = "card-body" >
< form id = "newTenantForm" >
< div class = "mb-3" >
< label for = "tenantId" class = "form-label" > Tenant ID< / label >
< input type = "text" class = "form-control" id = "tenantId" placeholder = "e.g., demo-company" required pattern = "[a-zA-Z0-9_-]+" >
< small class = "form-text text-muted" > Only letters, numbers, hyphens, and underscores allowed< / small >
< / div >
< button type = "submit" class = "btn btn-primary" > Create & Enter Tenant< / button >
< / form >
< / div >
< / div >
< div class = "mt-4 text-center" >
< p class = "text-muted" >
< strong > Note:< / strong > When you access a tenant URL directly (e.g., /my-tenant/),
it will be automatically created with default credentials (admin/admin).
< / p >
2025-06-19 16:03:50 -04:00
< a href = "/settings" class = "btn btn-secondary mt-3" > Server Settings< / a >
2025-06-19 14:25:42 -04:00
< / div >
< / div >
< / div >
< / div >
2025-10-20 17:40:04 -04:00
<!-- QR Code Modals for each tenant -->
{% for tenant in tenants %}
< div class = "modal fade" id = "qrModal-{{ tenant.id }}" tabindex = "-1" aria-labelledby = "qrModalLabel-{{ tenant.id }}" aria-hidden = "true" >
< div class = "modal-dialog modal-dialog-centered" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" id = "qrModalLabel-{{ tenant.id }}" > AR Template URL QR Code - {{ tenant.name }}< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Close" > < / button >
< / div >
< div class = "modal-body text-center" >
< p class = "text-muted mb-3" > Scan this QR code for the Knox Capture AR Template URL:< / p >
< div class = "mb-3" >
< img src = "/{{ tenant.id }}/qrcode/template" alt = "AR Template QR Code" class = "img-fluid" style = "max-width: 300px;" >
< / div >
< code class = "d-block mt-2" > {{ server_url }}/{{ tenant.id }}/< / code >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Close< / button >
< / div >
< / div >
< / div >
< / div >
{% endfor %}
2025-06-19 14:35:13 -04:00
< script src = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" > < / script >
2025-06-19 14:25:42 -04:00
< script >
2025-06-19 14:35:13 -04:00
const reservedIds = ['admin', 'api', 'login', 'logout', 'arcontentfields', 'arinfo',
'images', 'barcodes', 'static', 'assets', 'js', 'css', 'tenant',
'auth', 'oauth', 'callback', 'webhook', 'health', 'status'];
2025-06-19 14:25:42 -04:00
document.getElementById('newTenantForm').addEventListener('submit', function(e) {
e.preventDefault();
const tenantId = document.getElementById('tenantId').value;
if (tenantId) {
2025-06-19 16:08:18 -04:00
// Convert to lowercase for consistency
const normalizedId = tenantId.toLowerCase();
if (reservedIds.includes(normalizedId)) {
2025-06-19 14:35:13 -04:00
alert(`"${tenantId}" is a reserved name and cannot be used as a tenant ID.`);
return;
}
2025-06-19 16:08:18 -04:00
// Use the normalized (lowercase) ID in the URL
window.location.href = '/' + normalizedId + '/';
2025-06-19 14:25:42 -04:00
}
});
2025-06-19 14:35:13 -04:00
function confirmDelete(tenantName) {
return confirm(`Are you sure you want to delete the tenant "${tenantName}"?\n\nThis will permanently delete all products and data associated with this tenant.`);
}
2025-06-19 14:25:42 -04:00
< / script >
< / body >
< / html >