04/09 update: redesign user's roles

This commit is contained in:
2026-04-09 17:36:32 -04:00
parent 857372f781
commit dba4cc8b96
29 changed files with 194 additions and 114 deletions
+1 -1
View File
@@ -109,7 +109,7 @@
<strong>{{ entry.username }}</strong>
</td>
<td>
<span class="badge bg-{% if entry.user_role == 'admin' %}danger{% elif entry.user_role == 'supervisor' %}warning{% else %}info{% endif %} bg-opacity-75">
<span class="badge bg-{% if entry.user_role == 'admin' %}danger{% elif entry.user_role == 'director' %}warning{% else %}info{% endif %} bg-opacity-75">
{{ entry.user_role | title }}
</span>
</td>
+1 -1
View File
@@ -86,7 +86,7 @@
<dt class="col-sm-4 text-muted">Role at Time</dt>
<dd class="col-sm-8">
<span class="badge bg-{% if entry.user_role == 'admin' %}danger{% elif entry.user_role == 'supervisor' %}warning{% else %}info{% endif %}">
<span class="badge bg-{% if entry.user_role == 'admin' %}danger{% elif entry.user_role == 'director' %}warning{% else %}info{% endif %}">
{{ entry.user_role | title }}
</span>
</dd>
+2 -2
View File
@@ -28,8 +28,8 @@
<p class="text-muted mb-1" style="font-size:.85rem;">@{{ current_user.username }}</p>
{% endif %}
<p class="text-muted mb-2">{{ current_user.email }}</p>
<span class="badge fs-6 bg-{% if current_user.role == 'admin' %}danger{% elif current_user.role == 'supervisor' %}warning{% else %}info{% endif %}">
<i class="bi bi-{% if current_user.role == 'admin' %}shield-fill{% elif current_user.role == 'supervisor' %}star-fill{% else %}person-badge-fill{% endif %} me-1"></i>
<span class="badge fs-6 bg-{% if current_user.role == 'admin' %}danger{% elif current_user.role == 'director' %}warning{% else %}info{% endif %}">
<i class="bi bi-{% if current_user.role == 'admin' %}shield-fill{% elif current_user.role == 'director' %}star-fill{% else %}person-badge-fill{% endif %} me-1"></i>
{{ current_user.role | title }}
</span>
<hr>
+4 -5
View File
@@ -3,12 +3,11 @@
{% block title %}User Management{% endblock %}
{% block content %}
<div class="row mb-4 align-items-center">
<div class="col">
<div class="row mb-4">
<div class="col-md-6">
<h2><i class="bi bi-people-fill"></i> Internal User Management</h2>
<p class="text-muted mb-0">Manage staff accounts (Admin, Supervisor, Inspector, Project Manager). For customer accounts, visit <a href="{{ url_for('customers.index') }}">Customer Management</a>.</p>
</div>
<div class="col-auto">
<div class="col-md-6 text-end">
<a href="{{ url_for('auth.create_user') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> Add User
</a>
@@ -37,7 +36,7 @@
<td>{{ user.full_name or '—' }}</td>
<td>{{ user.email }}</td>
<td>
<span class="badge bg-{% if user.role == 'admin' %}danger{% elif user.role == 'supervisor' %}warning{% elif user.role == 'project_manager' %}primary{% elif user.role == 'customer' %}success{% else %}info{% endif %}">
<span class="badge bg-{% if user.role == 'admin' %}danger{% elif user.role == 'director' %}warning{% elif user.role == 'project_manager' %}primary{% elif user.role == 'customer' %}success{% else %}info{% endif %}">
{{ user.role.replace('_',' ')|title }}
</span>
</td>
+7 -5
View File
@@ -101,7 +101,7 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('dashboard.index') }}">Dashboard</a>
</li>
{% if current_user.role in ['admin', 'supervisor', 'project_manager'] %}
{% if current_user.role in ['admin', 'director', 'project_manager'] %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('projects.index') }}">Projects</a>
</li>
@@ -109,7 +109,7 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('facilities.list_facilities') }}">Facilities</a>
</li>
{% if current_user.role != 'customer' %}
{% if current_user.role in ['admin', 'director'] %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('templates.index') }}">Templates</a>
</li>
@@ -120,7 +120,7 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('reports.index') }}">Reports</a>
</li>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('scheduled_reports.index') }}">Scheduled Reports</a>
</li>
@@ -128,7 +128,7 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('issues.index') }}">Issues</a>
</li>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<li class="nav-item">
<a class="nav-link d-flex align-items-center gap-1"
href="{{ url_for('issues.verification_queue') }}">
@@ -142,13 +142,15 @@
</a>
</li>
{% endif %}
{% if current_user.role == 'admin' %}
{% if current_user.role in ['admin', 'director'] %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.list_users') }}">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('customers.index') }}">Customers</a>
</li>
{% endif %}
{% if current_user.role == 'admin' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('audit.index') }}">Audit Trail</a>
</li>
+5 -5
View File
@@ -5,7 +5,7 @@
<div class="row mb-3 align-items-center">
<div class="col">
<h2 class="mb-0">Welcome, {{ current_user.username }}!</h2>
<span class="badge bg-{% if current_user.role == 'admin' %}danger{% elif current_user.role == 'supervisor' %}warning{% elif current_user.role == 'project_manager' %}primary{% elif current_user.role == 'customer' %}success{% else %}info{% endif %} mt-1">
<span class="badge bg-{% if current_user.role == 'admin' %}danger{% elif current_user.role == 'director' %}warning{% elif current_user.role == 'project_manager' %}primary{% elif current_user.role == 'customer' %}success{% else %}info{% endif %} mt-1">
{{ current_user.role.replace('_',' ')|title }}
</span>
</div>
@@ -171,8 +171,8 @@
</div>
{% endif %}
{# ── System quick stats (admin/supervisor) ──────────────────────────────── #}
{% if current_user.role in ['admin', 'supervisor'] %}
{# ── System quick stats (admin/director) ─────────────────────────────────── #}
{% if current_user.role in ['admin', 'director'] %}
<div class="row g-3 mb-4">
<div class="col-6 col-md-{% if current_user.role == 'admin' %}4{% else %}6{% endif %}">
<div class="card shadow-sm text-center">
@@ -208,7 +208,7 @@
{# ── Score trend chart + Facility performance ───────────────────────────── #}
<div class="row g-3 mb-4">
<div class="col-lg-{% if current_user.role in ['admin','supervisor'] and facility_perf %}7{% else %}12{% endif %}">
<div class="col-lg-{% if current_user.role in ['admin','director'] and facility_perf %}7{% else %}12{% endif %}">
<div class="card shadow-sm h-100">
<div class="card-header bg-light fw-semibold">
<i class="bi bi-graph-up me-1"></i>Inspection Score Trend (Last 30 Days)
@@ -226,7 +226,7 @@
</div>
</div>
{% if current_user.role in ['admin', 'supervisor'] and facility_perf %}
{% if current_user.role in ['admin', 'director'] and facility_perf %}
<div class="col-lg-5">
<div class="card shadow-sm h-100">
<div class="card-header bg-light fw-semibold">
+1 -1
View File
@@ -8,7 +8,7 @@
<h2><i class="bi bi-building"></i> Facilities</h2>
</div>
<div class="col-md-6 text-end">
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('facilities.create_facility') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> Add Facility
</a>
+3 -3
View File
@@ -8,13 +8,13 @@
<h2><i class="bi bi-building"></i> {{ facility.name }}</h2>
</div>
<div class="col-md-4 text-end d-flex gap-2 justify-content-end align-items-start">
{% if current_user.role in ['admin', 'supervisor', 'project_manager', 'customer'] %}
{% if current_user.role in ['admin', 'director', 'project_manager', 'customer'] %}
<a href="{{ url_for('reports.facility_report', facility_id=facility.id) }}"
class="btn btn-outline-info">
<i class="bi bi-graph-up-arrow"></i> Scorecard
</a>
{% endif %}
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('facilities.edit_facility', facility_id=facility.id) }}" class="btn btn-outline-primary">
<i class="bi bi-pencil"></i> Edit
</a>
@@ -126,7 +126,7 @@
</td>
<td>{{ area.inspections.count() }}</td>
<td>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('facilities.edit_area', area_id=area.id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-pencil"></i>
</a>
+3 -3
View File
@@ -83,7 +83,7 @@
{% else %}
<a href="{{ url_for('inspections.view', inspection_id=ins.id) }}" class="btn btn-sm btn-outline-secondary">View</a>
{% endif %}
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<button type="button"
class="btn btn-sm btn-outline-danger ms-1"
data-bs-toggle="modal"
@@ -121,7 +121,7 @@
{% endif %}
</div>
</div>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<!-- Delete Inspection Confirmation Modal -->
<div class="modal fade" id="deleteInspectionModal" tabindex="-1" aria-labelledby="deleteInspectionModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
@@ -155,7 +155,7 @@
{% endblock %}
{% block extra_js %}
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<script>
document.addEventListener('DOMContentLoaded', function () {
const modal = document.getElementById('deleteInspectionModal');
+1 -1
View File
@@ -356,7 +356,7 @@
<i class="bi bi-arrow-repeat"></i> Re-inspect
</a>
{% endif %}
{% if current_user.role in ['admin','supervisor'] %}
{% if current_user.role in ['admin','director'] %}
{% if not inspection.follow_up_required %}
<button type="button" class="btn btn-sm btn-outline-warning"
data-bs-toggle="modal" data-bs-target="#followupModal"
+3 -3
View File
@@ -3,7 +3,7 @@
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-exclamation-triangle"></i> Issues</h2>
{% if current_user.role in ['admin','supervisor'] %}
{% if current_user.role in ['admin','director'] %}
<a href="{{ url_for('issues.create') }}" class="btn btn-danger">
<i class="bi bi-plus-circle"></i> Log Issue
</a>
@@ -100,13 +100,13 @@
<a href="{{ url_for('issues.view', issue_id=issue.id) }}"
class="btn btn-sm btn-outline-secondary">
{% if current_user.role in ['admin','supervisor'] or issue.assigned_to == current_user.id %}
{% if current_user.role in ['admin','director'] or issue.assigned_to == current_user.id %}
<i class="bi bi-pencil"></i> Edit
{% else %}
<i class="bi bi-eye"></i> View
{% endif %}
</a>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<form method="POST" action="{{ url_for('issues.delete', issue_id=issue.id) }}"
class="d-inline"
onsubmit="return confirm('Permanently delete Issue #{{ issue.id }}? This cannot be undone.');">
+7 -7
View File
@@ -83,8 +83,8 @@
<hr>
<div class="alert alert-info py-2 mb-0">
<i class="bi bi-hourglass-split me-1"></i>
<strong>Awaiting supervisor verification.</strong>
{% if current_user.role in ['admin','supervisor'] %}
<strong>Awaiting director verification.</strong>
{% if current_user.role in ['admin','director'] %}
<form method="POST" action="{{ url_for('issues.verify', issue_id=issue.id) }}" class="mt-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="mb-2">
@@ -163,7 +163,7 @@
</div>
{# ── Update Form ────────────────────────────────────────────────────── #}
{% set can_edit = current_user.role in ['admin','supervisor'] or issue.assigned_to == current_user.id %}
{% set can_edit = current_user.role in ['admin','director'] or issue.assigned_to == current_user.id %}
{% if can_edit %}
<div class="card shadow-sm">
<div class="card-header bg-light"><h6 class="mb-0">Update Issue</h6></div>
@@ -174,7 +174,7 @@
{{ form.status.label(class="form-label fw-semibold") }}
{{ form.status(class="form-select") }}
</div>
{% if current_user.role in ['admin','supervisor'] %}
{% if current_user.role in ['admin','director'] %}
<div class="mb-3">
{{ form.assigned_to.label(class="form-label fw-semibold") }}
{{ form.assigned_to(class="form-select") }}
@@ -209,7 +209,7 @@
class="mt-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-outline-info w-100"
onclick="return confirm('Mark this issue as pending supervisor verification?')">
onclick="return confirm('Mark this issue as pending director verification?')">
<i class="bi bi-hourglass-split me-1"></i> Request Verification
</button>
</form>
@@ -224,7 +224,7 @@
<a href="{{ url_for('issues.index') }}" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> Back to Issues
</a>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<button type="button" class="btn btn-outline-danger btn-sm"
data-bs-toggle="modal" data-bs-target="#deleteIssueModal">
<i class="bi bi-trash"></i> Delete Issue
@@ -232,7 +232,7 @@
{% endif %}
</div>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteIssueModal" tabindex="-1" aria-labelledby="deleteIssueModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
+2 -2
View File
@@ -6,7 +6,7 @@
<div class="col">
<h2><i class="bi bi-folder2-open"></i> Projects</h2>
</div>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<div class="col-auto">
<a href="{{ url_for('projects.create') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> New Project
@@ -52,7 +52,7 @@
<a href="{{ url_for('projects.view', project_id=project.id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> View
</a>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('projects.edit', project_id=project.id) }}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil"></i> Edit
</a>
+1 -1
View File
@@ -15,7 +15,7 @@
{% endif %}
</div>
<div class="col-auto d-flex gap-2">
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('projects.edit', project_id=project.id) }}" class="btn btn-outline-secondary">
<i class="bi bi-pencil"></i> Edit
</a>
+4 -4
View File
@@ -8,7 +8,7 @@
<h2><i class="bi bi-file-earmark-text"></i> Inspection Templates</h2>
</div>
<div class="col-md-6 text-end">
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('templates.create_template') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> Create Template
</a>
@@ -41,7 +41,7 @@
<i class="bi bi-eye"></i> View
</a>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<!-- Rename -->
<button type="button"
class="btn btn-sm btn-outline-secondary"
@@ -90,7 +90,7 @@
{% endfor %}
</div>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<!-- Edit Template Modal -->
<div class="modal fade" id="renameModal" tabindex="-1" aria-labelledby="renameModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
@@ -190,7 +190,7 @@
{% endblock %}
{% block extra_js %}
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<script>
document.addEventListener('DOMContentLoaded', function () {
// Edit template modal
+2 -2
View File
@@ -89,7 +89,7 @@
{% endif %}
</div>
<div class="d-flex gap-2 flex-shrink-0 mt-1">
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('templates.form_editor', template_id=template.id) }}" class="btn btn-primary btn-sm">
<i class="bi bi-pencil-square"></i> Edit Form
</a>
@@ -167,7 +167,7 @@
<div class="empty-state">
<i class="bi bi-layout-text-sidebar-reverse"></i>
<p>No fields defined yet.</p>
{% if current_user.role in ['admin', 'supervisor'] %}
{% if current_user.role in ['admin', 'director'] %}
<a href="{{ url_for('templates.form_editor', template_id=template.id) }}"
class="btn btn-primary btn-sm mt-3">
<i class="bi bi-plus-circle"></i> Open Form Editor