initiales bauen mit mistral
This commit is contained in:
1 parent
7e2e8bdf59
commit
c74bca1e13
22 files changed
+5642
No files matched your search
@@ -0,0 +1,256 @@
|
||||
{# ==============================================================================
|
||||
Formeleon - Multi-tenant Form Generator
|
||||
Author: Björn Runden <br@runden.net>
|
||||
Template: admin/tenants/view.html
|
||||
Description: View and edit tenant details with associated forms.
|
||||
============================================================================== #}
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ tenant.name }} - Formeleon{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1><i class="bi bi-buildings"></i> {{ tenant.name }}</h1>
|
||||
<p class="text-muted mb-0">
|
||||
ID: <code>{{ tenant.id }}</code> |
|
||||
Status: <span class="badge bg-{{ 'success' if tenant.status.value == 'active' else 'warning' if tenant.status.value == 'suspended' else 'danger' }}">
|
||||
{{ tenant.status.value }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ url_for('admin.list_tenants') }}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Tenants
|
||||
</a>
|
||||
{% if is_admin %}
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#editTenantModal">
|
||||
<i class="bi bi-pencil"></i> Edit
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{# Tenant Details Card #}
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5><i class="bi bi-info-circle"></i> Tenant Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row mb-0">
|
||||
<dt class="col-sm-4">Public Key:</dt>
|
||||
<dd class="col-sm-8">
|
||||
<code class="text-break">{{ tenant.public_key }}</code>
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn"
|
||||
onclick="copyToClipboard('{{ tenant.public_key }}', function() { alert('Copied to clipboard!'); })">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-4">Allowed Origins:</dt>
|
||||
<dd class="col-sm-8">{{ tenant.allowed_origins }}</dd>
|
||||
|
||||
<dt class="col-sm-4">Created:</dt>
|
||||
<dd class="col-sm-8">{{ tenant.created_at.strftime('%Y-%m-%d %H:%M:%S') if tenant.created_at else 'N/A' }}</dd>
|
||||
|
||||
<dt class="col-sm-4">Last Updated:</dt>
|
||||
<dd class="col-sm-8">{{ tenant.updated_at.strftime('%Y-%m-%d %H:%M:%S') if tenant.updated_at else 'N/A' }}</dd>
|
||||
|
||||
<dt class="col-sm-4">Configuration:</dt>
|
||||
<dd class="col-sm-8">
|
||||
<pre class="mb-0 bg-light p-2 rounded">{{ tenant.config|tojson(indent=2) if tenant.config else '{}' }}</pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Tenant Statistics #}
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5><i class="bi bi-graph-up"></i> Statistics</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center">
|
||||
<div class="col-6 col-md-3 mb-3">
|
||||
<div class="card bg-light h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="mb-0">{{ forms|length }}</h3>
|
||||
<p class="text-muted mb-0">Forms</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3 mb-3">
|
||||
<div class="card bg-light h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="mb-0">{{ tenant.submissions|length }}</h3>
|
||||
<p class="text-muted mb-0">Submissions</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<div class="card bg-light h-100">
|
||||
<div class="card-body">
|
||||
<h3 class="mb-0">
|
||||
{% if tenant.users %}
|
||||
{{ tenant.users|length }}
|
||||
{% else %}
|
||||
0
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p class="text-muted mb-0">Associated Users</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Forms List #}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
||||
<h5><i class="bi bi-file-earmark-text"></i> Forms ({{ forms|length }})</h5>
|
||||
<a href="{{ url_for('admin.create_form') }}?tenant_id={{ tenant.id }}" class="btn btn-sm btn-primary">
|
||||
<i class="bi bi-plus"></i> Create Form
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% if forms %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>ID</th>
|
||||
<th>Status</th>
|
||||
<th>Created</th>
|
||||
<th>Submissions</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for form in forms %}
|
||||
<tr>
|
||||
<td>{{ form.name }}</td>
|
||||
<td><code>{{ form.id }}</code></td>
|
||||
<td>
|
||||
<span class="badge bg-{{ 'success' if form.is_active else 'secondary' }}">
|
||||
{{ 'Active' if form.is_active else 'Inactive' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ form.created_at.strftime('%Y-%m-%d') if form.created_at else 'N/A' }}</td>
|
||||
<td>{{ form.submissions|length }}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{{ url_for('admin.view_form', form_id=form.id) }}" class="btn btn-outline-secondary" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
{% if is_admin or user in tenant.users %}
|
||||
<a href="{{ url_for('admin.view_form', form_id=form.id) }}" class="btn btn-outline-primary" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="p-4 text-center text-muted">
|
||||
<i class="bi bi-file-earmark-text display-4"></i>
|
||||
<p>No forms created yet</p>
|
||||
<a href="{{ url_for('admin.create_form') }}?tenant_id={{ tenant.id }}" class="btn btn-primary">
|
||||
<i class="bi bi-plus"></i> Create First Form
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Edit Tenant Modal #}
|
||||
{% if is_admin %}
|
||||
<div class="modal fade" id="editTenantModal" tabindex="-1" aria-labelledby="editTenantModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editTenantModalLabel"><i class="bi bi-pencil"></i> Edit Tenant</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="POST" action="{{ url_for('admin.view_tenant', tenant_id=tenant.id) }}">
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="edit_name" class="form-label">Tenant Name *</label>
|
||||
<input type="text" class="form-control" id="edit_name" name="name"
|
||||
value="{{ tenant.name }}" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="edit_public_key" class="form-label">Public Key *</label>
|
||||
<input type="text" class="form-control" id="edit_public_key" name="public_key"
|
||||
value="{{ tenant.public_key }}" required>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<label for="edit_allowed_origins" class="form-label">Allowed Origins *</label>
|
||||
<input type="text" class="form-control" id="edit_allowed_origins" name="allowed_origins"
|
||||
value="{{ tenant.allowed_origins }}" required>
|
||||
<div class="form-text">Comma-separated list of allowed domains</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="edit_status" class="form-label">Status</label>
|
||||
<select class="form-select" id="edit_status" name="status">
|
||||
<option value="active" {% if tenant.status.value == 'active' %}selected{% endif %}>Active</option>
|
||||
<option value="suspended" {% if tenant.status.value == 'suspended' %}selected{% endif %}>Suspended</option>
|
||||
<option value="inactive" {% if tenant.status.value == 'inactive' %}selected{% endif %}>Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x"></i> Cancel
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
// Copy to clipboard function
|
||||
function copyToClipboard(text, callback) {
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}).catch(function(err) {
|
||||
console.error('Failed to copy: ', err);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user