Files
enterprise_digital-platform/IT_asset_management/app/templates/dashboard/index.html
T
ske087 7d24e7f527 IT Assets: add role-based auth system and portal user sync
Auth:
- Fix local login (was redirecting to portal; now authenticates AdminUser directly)
- Portal SSO still takes priority in production via nginx headers

Role system (admin | editor | readonly):
- New app/utils/decorators.py with editor_required and admin_required decorators
- All write routes protected with editor_required (create/edit/delete/import/mask)
- Settings user management protected with admin_required
- Sidebar hides write-only links for readonly users
- Dashboard quick actions and list page buttons hidden for readonly

Settings page:
- Role colour badges (admin=red, editor=blue, readonly=grey)
- Inline role changer per user (dropdown auto-submit)
- Reset password modal per user
- Delete user button with confirmation
- Add user form includes role selector with legend

Portal user sync:
- New /internal/sync-user endpoint receives user pre-creation from portal
- INTERNAL_SYNC_SECRET added to config
- portal/config.py: added internal_url for itassets app so _sync_user_to_app works
2026-07-08 21:35:16 +03:00

172 lines
6.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends 'base.html' %}
{% block title %}Dashboard IT Asset Management{% endblock %}
{% block breadcrumb %}<li class="breadcrumb-item active">Dashboard</li>{% endblock %}
{% block content %}
<div class="page-header mb-4">
<h1><i class="bi bi-speedometer2 me-2"></i>Dashboard</h1>
</div>
<!-- ── Stat Cards ──────────────────────────────────────────────── -->
<div class="row g-3 mb-4">
<!-- Users -->
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#1a3a5c;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-people-fill stat-icon"></i>
<div>
<div class="stat-value">{{ stats.active_users }}</div>
<div class="stat-label">Active Users</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#6f42c1;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-eye-slash-fill stat-icon"></i>
<div>
<div class="stat-value">{{ stats.masked_users }}</div>
<div class="stat-label">Masked Records</div>
</div>
</div>
</div>
</div>
<!-- Assets -->
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#198754;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-laptop stat-icon"></i>
<div>
<div class="stat-value">{{ stats.available_assets }}</div>
<div class="stat-label">Available Assets</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#0d6efd;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-arrow-left-right stat-icon"></i>
<div>
<div class="stat-value">{{ stats.assigned_assets }}</div>
<div class="stat-label">Assigned Assets</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#ffc107; color:#000 !important;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-tools stat-icon"></i>
<div>
<div class="stat-value">{{ stats.maintenance_assets }}</div>
<div class="stat-label">In Maintenance</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#6c757d;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-hdd-fill stat-icon"></i>
<div>
<div class="stat-value">{{ stats.total_assets }}</div>
<div class="stat-label">Total Assets</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#0dcaf0; color:#000 !important;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-file-earmark-text stat-icon"></i>
<div>
<div class="stat-value">{{ stats.total_paperwork }}</div>
<div class="stat-label">Documents</div>
</div>
</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card stat-card text-white" style="background:#fd7e14;">
<div class="card-body d-flex align-items-center gap-3">
<i class="bi bi-person-badge stat-icon"></i>
<div>
<div class="stat-value">{{ stats.active_assignments }}</div>
<div class="stat-label">Open Assignments</div>
</div>
</div>
</div>
</div>
</div>
<!-- ── Quick Actions ──────────────────────────────────────────── -->
{% if current_user.is_editor %}
<div class="row g-3 mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-body py-2">
<span class="text-muted me-3" style="font-size:.8rem;">QUICK ACTIONS</span>
<a href="{{ url_for('assets.create') }}" class="btn btn-sm btn-outline-primary me-2">
<i class="bi bi-plus-circle me-1"></i>Add Asset
</a>
<a href="{{ url_for('assignments.create') }}" class="btn btn-sm btn-outline-success me-2">
<i class="bi bi-arrow-left-right me-1"></i>Assign Asset
</a>
<a href="{{ url_for('paperwork.create') }}" class="btn btn-sm btn-outline-info me-2">
<i class="bi bi-file-earmark-plus me-1"></i>New Document
</a>
<a href="{{ url_for('users.import_page') }}" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-cloud-download me-1"></i>Import Users
</a>
</div>
</div>
</div>
</div>
{% endif %}
<!-- ── Recent Assignments ─────────────────────────────────────── -->
<div class="card border-0 shadow-sm">
<div class="card-header bg-white fw-semibold py-3">
<i class="bi bi-clock-history me-2 text-primary"></i>Current Assignments (latest 10)
</div>
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>User</th>
<th>Windows ID</th>
<th>Asset</th>
<th>Serial / Service Tag</th>
<th>Since</th>
<th></th>
</tr>
</thead>
<tbody>
{% for a in recent_assignments %}
<tr {% if a.user.is_masked %}class="masked-row"{% endif %}>
<td>{{ a.user.display_name }}</td>
<td><code>{{ a.user.windows_id }}</code></td>
<td>{{ a.asset.brand or '' }} {{ a.asset.model or '' }}</td>
<td>
<code>{{ a.asset.serial_number }}</code>
{% if a.asset.service_tag %}<br><small class="text-muted">{{ a.asset.service_tag }}</small>{% endif %}
</td>
<td>{{ a.assigned_date.strftime('%d/%m/%Y') if a.assigned_date else '—' }}</td>
<td>
<a href="{{ url_for('assets.detail', asset_id=a.asset.id) }}"
class="btn btn-xs btn-outline-secondary btn-sm py-0 px-2">
<i class="bi bi-eye"></i>
</a>
</td>
</tr>
{% else %}
<tr><td colspan="6" class="text-center text-muted py-3">No active assignments.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}