432 lines
19 KiB
HTML
432 lines
19 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ tenant.display_name }} - Tenant Details - {{ block.super }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h1 class="h3 mb-1">{{ tenant.display_name }}</h1>
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb mb-0">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'core:tenant_list' %}">Tenants</a></li>
|
|
<li class="breadcrumb-item active">{{ tenant.name }}</li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
<div class="btn-group">
|
|
<a href="{% url 'core:tenant_update' tenant.pk %}" class="btn btn-primary">
|
|
<i class="fas fa-edit me-2"></i>Edit Tenant
|
|
</a>
|
|
<div class="dropdown">
|
|
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
|
<i class="fas fa-cog me-2"></i>Actions
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
{% if tenant.is_active %}
|
|
<li><a class="dropdown-item text-warning" href="#" onclick="deactivateTenant()">
|
|
<i class="fas fa-pause me-2"></i>Deactivate Tenant
|
|
</a></li>
|
|
{% else %}
|
|
<li><a class="dropdown-item text-success" href="#" onclick="activateTenant()">
|
|
<i class="fas fa-play me-2"></i>Activate Tenant
|
|
</a></li>
|
|
{% endif %}
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#" onclick="exportTenantData()">
|
|
<i class="fas fa-download me-2"></i>Export Data
|
|
</a></li>
|
|
<li><a class="dropdown-item text-danger" href="{% url 'core:tenant_delete' tenant.pk %}">
|
|
<i class="fas fa-trash me-2"></i>Delete Tenant
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status Alert -->
|
|
{% if not tenant.is_active %}
|
|
<div class="alert alert-warning" role="alert">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
This tenant is currently <strong>inactive</strong>. Users will not be able to access the system.
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="row">
|
|
<!-- Basic Information -->
|
|
<div class="col-lg-8">
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-info-circle me-2"></i>Basic Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Organization Name</label>
|
|
<p class="fw-bold">{{ tenant.name }}</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Display Name</label>
|
|
<p class="fw-bold">{{ tenant.display_name }}</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Organization Type</label>
|
|
<p>
|
|
<span class="badge bg-info">{{ tenant.get_organization_type_display }}</span>
|
|
</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Domain</label>
|
|
<p>
|
|
{% if tenant.domain %}
|
|
<code>{{ tenant.domain }}</code>
|
|
{% else %}
|
|
<span class="text-muted">Not configured</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Status</label>
|
|
<p>
|
|
{% if tenant.is_active %}
|
|
<span class="badge bg-success">Active</span>
|
|
{% else %}
|
|
<span class="badge bg-danger">Inactive</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Tenant ID</label>
|
|
<p>
|
|
<code>{{ tenant.tenant_id }}</code>
|
|
<button class="btn btn-sm btn-outline-secondary ms-2" onclick="copyToClipboard('{{ tenant.tenant_id }}')">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Created</label>
|
|
<p>{{ tenant.created_at|date:"F d, Y \a\t H:i" }}</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Last Updated</label>
|
|
<p>{{ tenant.updated_at|date:"F d, Y \a\t H:i" }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if tenant.description %}
|
|
<div class="mt-3">
|
|
<label class="form-label text-muted">Description</label>
|
|
<p>{{ tenant.description|linebreaks }}</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Contact Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-address-book me-2"></i>Contact Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Primary Email</label>
|
|
<p>
|
|
{% if tenant.contact_email %}
|
|
<a href="mailto:{{ tenant.contact_email }}">{{ tenant.contact_email }}</a>
|
|
{% else %}
|
|
<span class="text-muted">Not provided</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Phone Number</label>
|
|
<p>
|
|
{% if tenant.contact_phone %}
|
|
<a href="tel:{{ tenant.contact_phone }}">{{ tenant.contact_phone }}</a>
|
|
{% else %}
|
|
<span class="text-muted">Not provided</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Website</label>
|
|
<p>
|
|
{% if tenant.website %}
|
|
<a href="{{ tenant.website }}" target="_blank">{{ tenant.website }}</a>
|
|
{% else %}
|
|
<span class="text-muted">Not provided</span>
|
|
{% endif %}
|
|
</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Timezone</label>
|
|
<p>{{ tenant.timezone|default:"Not configured" }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if tenant.address %}
|
|
<div class="mt-3">
|
|
<label class="form-label text-muted">Address</label>
|
|
<p>{{ tenant.address|linebreaks }}</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuration Settings -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-cogs me-2"></i>Configuration Settings
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Max Users</label>
|
|
<p>{{ tenant.max_users|default:"Unlimited" }}</p>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Storage Limit</label>
|
|
<p>{{ tenant.storage_limit_gb|default:"Unlimited" }}{% if tenant.storage_limit_gb %} GB{% endif %}</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Features Enabled</label>
|
|
<div>
|
|
{% if tenant.features_enabled %}
|
|
{% for feature in tenant.features_enabled %}
|
|
<span class="badge bg-primary me-1">{{ feature }}</span>
|
|
{% endfor %}
|
|
{% else %}
|
|
<span class="text-muted">Default features</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- Quick Stats -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-chart-bar me-2"></i>Quick Stats
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row text-center">
|
|
<div class="col-6 mb-3">
|
|
<div class="border-end">
|
|
<h4 class="text-primary mb-1">{{ tenant.total_users|default:0 }}</h4>
|
|
<small class="text-muted">Total Users</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 mb-3">
|
|
<h4 class="text-success mb-1">{{ tenant.active_users|default:0 }}</h4>
|
|
<small class="text-muted">Active Users</small>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="border-end">
|
|
<h4 class="text-info mb-1">{{ tenant.total_departments|default:0 }}</h4>
|
|
<small class="text-muted">Departments</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<h4 class="text-warning mb-1">{{ tenant.storage_used_gb|default:0 }}</h4>
|
|
<small class="text-muted">GB Used</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Activity -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-history me-2"></i>Recent Activity
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if recent_activities %}
|
|
{% for activity in recent_activities %}
|
|
<div class="d-flex align-items-start mb-3">
|
|
<div class="avatar-sm bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3">
|
|
<i class="fas fa-{{ activity.icon|default:'circle' }}"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<p class="mb-1">{{ activity.description }}</p>
|
|
<small class="text-muted">{{ activity.timestamp|timesince }} ago</small>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted text-center">No recent activity</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Health -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-heartbeat me-2"></i>System Health
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<span class="text-muted">Database</span>
|
|
<span class="badge bg-success">Healthy</span>
|
|
</div>
|
|
<div class="progress" style="height: 4px;">
|
|
<div class="progress-bar bg-success" style="width: 95%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<span class="text-muted">Storage</span>
|
|
<span class="badge bg-warning">75%</span>
|
|
</div>
|
|
<div class="progress" style="height: 4px;">
|
|
<div class="progress-bar bg-warning" style="width: 75%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<span class="text-muted">API Response</span>
|
|
<span class="badge bg-success">Good</span>
|
|
</div>
|
|
<div class="progress" style="height: 4px;">
|
|
<div class="progress-bar bg-success" style="width: 88%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function copyToClipboard(text) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
// Show success feedback
|
|
const button = event.target.closest('button');
|
|
const originalIcon = button.innerHTML;
|
|
button.innerHTML = '<i class="fas fa-check"></i>';
|
|
button.classList.add('btn-success');
|
|
button.classList.remove('btn-outline-secondary');
|
|
|
|
setTimeout(() => {
|
|
button.innerHTML = originalIcon;
|
|
button.classList.remove('btn-success');
|
|
button.classList.add('btn-outline-secondary');
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
function activateTenant() {
|
|
if (confirm('Activate this tenant? Users will be able to access the system.')) {
|
|
fetch(`{% url 'core:activate_tenant' tenant.pk %}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': getCsrfToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error activating tenant: ' + data.error);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('Error activating tenant');
|
|
});
|
|
}
|
|
}
|
|
|
|
function deactivateTenant() {
|
|
if (confirm('Deactivate this tenant? This will prevent users from accessing the system.')) {
|
|
fetch(`{% url 'core:deactivate_tenant' tenant.pk %}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': getCsrfToken()
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
location.reload();
|
|
} else {
|
|
alert('Error deactivating tenant: ' + data.error);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('Error deactivating tenant');
|
|
});
|
|
}
|
|
}
|
|
|
|
{#function exportTenantData() {#}
|
|
{# window.open(`{% url 'core:' tenant.pk %}`, '_blank');#}
|
|
{# }#}
|
|
|
|
function getCsrfToken() {
|
|
return document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.avatar-sm {
|
|
width: 32px;
|
|
height: 32px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.progress {
|
|
background-color: #e9ecef;
|
|
}
|
|
|
|
.card-body .row.text-center .border-end {
|
|
border-right: 1px solid #dee2e6 !important;
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.card-body .row.text-center .border-end {
|
|
border-right: none !important;
|
|
border-bottom: 1px solid #dee2e6 !important;
|
|
padding-bottom: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|