125 lines
5.0 KiB
HTML
125 lines
5.0 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}Settings — Enterprise Digital Platform{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="settings-wrapper">
|
|
<div class="settings-header">
|
|
<h2 class="section-title">Settings</h2>
|
|
<div class="settings-tabs">
|
|
<a href="{{ url_for('settings.index') }}" class="tab-link active">Users & Access</a>
|
|
<a href="{{ url_for('settings.api_keys') }}" class="tab-link">API Keys</a>
|
|
<a href="{{ url_for('settings.modules') }}" class="tab-link">Modules</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-section">
|
|
<div class="section-toolbar">
|
|
<h3>Portal Users</h3>
|
|
<a href="{{ url_for('settings.new_user') }}" class="btn btn-primary btn-sm">+ New User</a>
|
|
</div>
|
|
|
|
<div class="table-wrapper">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Username</th>
|
|
<th>Email</th>
|
|
<th>Role</th>
|
|
<th>Last Login</th>
|
|
{% for app in registered_apps %}
|
|
<th class="app-col" style="border-top: 3px solid {{ app.color }};">
|
|
{{ app.icon }} {{ app.name }}<br/>
|
|
<small style="font-weight:400; color:var(--text-muted);">access / role</small>
|
|
</th>
|
|
{% endfor %}
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for user in users %}
|
|
<tr>
|
|
<td><strong>{{ user.username }}</strong></td>
|
|
<td class="text-muted">{{ user.email }}</td>
|
|
<td>
|
|
{% if user.is_admin %}
|
|
<span class="badge badge-admin">admin</span>
|
|
{% else %}
|
|
<span class="badge badge-user">user</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-muted">
|
|
{{ user.last_login.strftime('%Y-%m-%d %H:%M') if user.last_login else '—' }}
|
|
</td>
|
|
|
|
{# Per-app role dropdown — auto-submits on change #}
|
|
{% for app in registered_apps %}
|
|
{% set cur_access = user.app_accesses.filter_by(app_name=app['id']).first() %}
|
|
{% set cur_role = cur_access.app_role if cur_access and cur_access.is_active and cur_access.app_role else ('active' if (cur_access and cur_access.is_active) else 'none') %}
|
|
<td class="center">
|
|
<form method="POST" action="{{ url_for('settings.update_access', user_id=user.id) }}"
|
|
class="inline-form">
|
|
{# Carry all other apps' current values as hidden inputs #}
|
|
{% for other in registered_apps %}
|
|
{% if other['id'] != app['id'] %}
|
|
{% set oa = user.app_accesses.filter_by(app_name=other['id']).first() %}
|
|
{% if oa and oa.is_active %}
|
|
<input type="hidden" name="role_{{ other['id'] }}"
|
|
value="{{ oa.app_role if oa.app_role else 'user' }}" />
|
|
{% else %}
|
|
<input type="hidden" name="role_{{ other['id'] }}" value="none" />
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
<select name="role_{{ app['id'] }}"
|
|
class="app-role-select"
|
|
style="--app-color: {{ app.color }};"
|
|
onchange="this.closest('form').submit()"
|
|
title="{{ app['name'] }} access for {{ user.username }}"
|
|
{% if user.id == current_user.id and app['id'] == 'portal' %}disabled{% endif %}>
|
|
<option value="none" {% if not (cur_access and cur_access.is_active) %}selected{% endif %}>
|
|
— no access
|
|
</option>
|
|
<option value="user"
|
|
{% if cur_access and cur_access.is_active and (not cur_access.app_role or cur_access.app_role == 'user') %}selected{% endif %}>
|
|
✓ user
|
|
</option>
|
|
<option value="admin"
|
|
{% if cur_access and cur_access.is_active and cur_access.app_role == 'admin' %}selected{% endif %}>
|
|
★ admin
|
|
</option>
|
|
</select>
|
|
</form>
|
|
</td>
|
|
{% endfor %}
|
|
|
|
<td>
|
|
{% if user.id != current_user.id %}
|
|
<form method="POST" action="{{ url_for('settings.delete_user', user_id=user.id) }}"
|
|
onsubmit="return confirm('Delete user {{ user.username }}?')">
|
|
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
|
|
</form>
|
|
{% else %}
|
|
<span class="text-muted">—</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.querySelectorAll('.app-role-select').forEach(function(sel) {
|
|
function refresh() {
|
|
if (sel.value !== 'none') sel.classList.add('has-access');
|
|
else sel.classList.remove('has-access');
|
|
}
|
|
refresh();
|
|
sel.addEventListener('change', refresh);
|
|
});
|
|
</script>
|
|
{% endblock %}
|