Files
enterprise_digital-platform/IT_asset_management/app/templates/users/index.html
T
ske087 83a8f79c36 IT Assets: make GDPR Mask function discoverable from users list
- Users list: add eye-slash icon button per unmasked row (editor+ only)
  clicking opens a compact confirmation modal inline in the list
- User detail: gate Edit / Assign / Mask buttons behind is_editor check
  (button was shown to all but route already blocked readonly users)
2026-07-09 01:04:00 +03:00

159 lines
6.6 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 %}Users IT Asset Management{% endblock %}
{% block breadcrumb %}
<li class="breadcrumb-item"><a href="{{ url_for('dashboard.index') }}">Home</a></li>
<li class="breadcrumb-item active">Users</li>
{% endblock %}
{% block content %}
<div class="page-header d-flex align-items-center justify-content-between mb-4">
<h1><i class="bi bi-people-fill me-2"></i>Users</h1>
{% if current_user.is_editor %}
<div class="d-flex gap-2">
<a href="{{ url_for('users.import_page') }}" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-cloud-download me-1"></i>Import
</a>
<a href="{{ url_for('users.create') }}" class="btn btn-primary btn-sm">
<i class="bi bi-person-plus me-1"></i>Add User
</a>
</div>
{% endif %}
</div>
<!-- Filters -->
<form method="GET" class="row g-2 mb-3">
<div class="col-md-5">
<div class="input-group input-group-sm">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="text" name="q" class="form-control" placeholder="Search name, email, WID, dept…" value="{{ q }}">
</div>
</div>
<div class="col-auto">
<div class="form-check form-check-inline mt-1">
<input class="form-check-input" type="checkbox" name="masked" value="1" id="chkMasked"
{% if show_masked %}checked{% endif %} onchange="this.form.submit()">
<label class="form-check-label" for="chkMasked">Show masked users</label>
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-sm btn-primary">Search</button>
<a href="{{ url_for('users.index') }}" class="btn btn-sm btn-outline-secondary">Clear</a>
</div>
</form>
<div class="card border-0 shadow-sm">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Windows ID</th>
<th>Name</th>
<th>Email</th>
<th>Department</th>
<th>Job Title</th>
<th>Source</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
{% for u in pagination.items %}
<tr {% if u.is_masked %}class="masked-row"{% endif %}>
<td><code>{{ u.windows_id }}</code></td>
<td>
<a href="{{ url_for('users.detail', user_id=u.id) }}">{{ u.display_name }}</a>
{% if u.is_masked %}<span class="badge badge-masked ms-1">MASKED</span>{% endif %}
</td>
<td>{{ u.display_email }}</td>
<td>{{ u.department or '—' }}</td>
<td>{{ u.job_title or '—' }}</td>
<td>
<span class="badge bg-secondary">{{ u.import_source }}</span>
</td>
<td>
{% if not u.is_masked and u.is_active %}
<span class="badge bg-success">Active</span>
{% elif not u.is_masked %}
<span class="badge bg-warning text-dark">Inactive</span>
{% else %}
<span class="badge badge-masked">Masked</span>
{% endif %}
</td>
<td>
<a href="{{ url_for('users.detail', user_id=u.id) }}" class="btn btn-sm btn-outline-secondary py-0 px-2">
<i class="bi bi-eye"></i>
</a>
{% if not u.is_masked and current_user.is_editor %}
<button class="btn btn-sm btn-outline-danger py-0 px-2 ms-1"
title="GDPR Mask — permanently erase PII"
data-bs-toggle="modal"
data-bs-target="#maskModal{{ u.id }}">
<i class="bi bi-eye-slash"></i>
</button>
<!-- Mask modal for list row -->
<div class="modal fade" id="maskModal{{ u.id }}" tabindex="-1">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header border-0 pb-0">
<h6 class="modal-title text-danger"><i class="bi bi-eye-slash me-1"></i>Mask User</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p class="mb-1">Permanently erase all PII for <strong>{{ u.display_name }}</strong>?</p>
<p class="small text-muted mb-0">Name, email and phone will be replaced with <em>[MASKED]</em>. Windows ID and asset history are kept. <strong>Cannot be undone.</strong></p>
</div>
<div class="modal-footer border-0 pt-0">
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Cancel</button>
<form method="POST" action="{{ url_for('users.mask', user_id=u.id) }}" class="d-inline">
<button type="submit" class="btn btn-sm btn-danger">
<i class="bi bi-eye-slash me-1"></i>Confirm
</button>
</form>
</div>
</div>
</div>
</div>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="8" class="text-center text-muted py-4">No users found.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if pagination.pages > 1 %}
<div class="card-footer bg-white d-flex justify-content-between align-items-center py-2">
<small class="text-muted">
Showing {{ pagination.first }}{{ pagination.last }} of {{ pagination.total }}
</small>
<nav>
<ul class="pagination pagination-sm mb-0">
{% if pagination.has_prev %}
<li class="page-item">
<a class="page-link" href="{{ url_for('users.index', page=pagination.prev_num, q=q, masked='1' if show_masked else '0') }}"></a>
</li>
{% endif %}
{% for p in pagination.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
{% if p %}
<li class="page-item {% if p == pagination.page %}active{% endif %}">
<a class="page-link" href="{{ url_for('users.index', page=p, q=q, masked='1' if show_masked else '0') }}">{{ p }}</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link"></span></li>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<li class="page-item">
<a class="page-link" href="{{ url_for('users.index', page=pagination.next_num, q=q, masked='1' if show_masked else '0') }}"></a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
</div>
{% endblock %}