mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
A superuser's page of a user was a heading, two unlabelled icon buttons and three tabs: the VMs a table of check columns, the SSH keys a table that pushed the page sideways on a phone. Now a card at the top shows the user's name, role, Blocked when they are, username, email, groups, last login and joining date, with Edit user and Email OTP QR code as labelled buttons and links to the sections below with their counts. The VMs card shows each VM with its host and what the user may do beyond power and console as badges in the VM Users tab's words (Change settings, Delete the VM, Change console settings), with Change access and Remove from user in a menu, and Add VM in its header. The SSH keys and the API tokens are cards; the key rows are now one include with the user's own Profile, and both lists say when they are empty. The full key shows over its fingerprint. The tab script had no page left and goes.
97 lines
6.6 KiB
HTML
97 lines
6.6 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% load i18n %}
|
|
{% load bootstrap_icons %}
|
|
|
|
{% block title %}{% trans "User Profile" %} - {{ user }}{% endblock %}
|
|
{% block page_heading %}{% trans "User Profile" %}{% endblock page_heading %}
|
|
|
|
{% block content %}
|
|
<section class="card mb-4" aria-labelledby="identity-title">
|
|
<div class="card-body">
|
|
<div class="row g-3 align-items-start">
|
|
<div class="col-lg-8">
|
|
<div class="d-flex flex-wrap align-items-center gap-2">
|
|
<h2 class="h4 mb-0 text-break" id="identity-title">{{ user.get_full_name|default:user.username }}</h2>
|
|
{% if user.is_superuser %}
|
|
<span class="badge text-bg-secondary">{% trans "Superuser" %}</span>
|
|
{% elif user.is_staff %}
|
|
<span class="badge text-bg-secondary">{% trans "Template editor" %}</span>
|
|
{% endif %}
|
|
{% if not user.is_active %}<span class="badge text-bg-danger">{% trans "Blocked" %}</span>{% endif %}
|
|
</div>
|
|
<div class="d-flex flex-wrap align-items-center gap-2 small mt-2">
|
|
<span class="text-body-secondary text-break">{{ user.username }}</span>
|
|
{% if user.email %}<span class="text-break">{{ user.email }}</span>{% endif %}
|
|
{% for group in user.groups.all %}<span class="badge text-bg-light border mw-100 text-wrap text-break">{{ group.name }}</span>{% endfor %}
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-2 gap-md-4 small text-body-secondary mt-3">
|
|
<span>{% trans "Last login" %} {{ user.last_login|date:"Y-m-d H:i"|default:_("never") }}</span>
|
|
<span>{% trans "Joined" %} {{ user.date_joined|date:"Y-m-d" }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4 d-flex flex-wrap justify-content-lg-end gap-2">
|
|
<a href="{% url 'admin:user_update' user.id %}?next={% url 'accounts:account' user.id %}" class="btn btn-primary">{% bs_icon 'pencil' %} {% trans "Edit user" %}</a>
|
|
{% if otp_enabled %}
|
|
<form method="post" action="{% url 'accounts:admin_email_otp' user.id %}">{% csrf_token %}
|
|
<button type="submit" class="btn btn-outline-secondary">{% bs_icon 'qr-code' %} {% trans "Email OTP QR code" %}</button>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<nav class="card-footer d-flex flex-wrap gap-3 small" aria-label="{% trans 'User sections' %}">
|
|
<a href="#instances">{% trans "VMs" %} <span class="badge text-bg-light border">{{ user_insts|length }}</span></a>
|
|
<a href="#public-keys">{% trans "SSH Keys" %} <span class="badge text-bg-light border">{{ publickeys|length }}</span></a>
|
|
<a href="#apitokens">{% trans "API Tokens" %} <span class="badge text-bg-light border">{{ api_tokens|length }}</span></a>
|
|
</nav>
|
|
</section>
|
|
|
|
<section class="card mb-4" id="instances" aria-labelledby="instances-title">
|
|
<div class="card-header d-flex flex-wrap align-items-center justify-content-between gap-2">
|
|
<h2 class="h5 mb-0" id="instances-title">{% trans "VMs" %} <span class="badge text-bg-light border">{{ user_insts|length }}</span></h2>
|
|
<a href="{% url 'accounts:user_instance_create' user.id %}" class="btn btn-sm btn-primary">{% bs_icon 'plus-lg' %} {% trans "Add VM" %}</a>
|
|
</div>
|
|
<div class="list-group list-group-flush">
|
|
{% for inst in user_insts %}
|
|
<div class="list-group-item py-3">
|
|
<div class="d-flex align-items-start align-items-md-center gap-3">
|
|
<div class="row g-2 align-items-center flex-grow-1" style="min-width: 0;">
|
|
<div class="col-12 col-md-6">
|
|
<a class="fw-semibold text-break" href="{% url 'instances:instance' inst.instance.id %}">{{ inst.instance.name }}</a>
|
|
<div class="small text-body-secondary text-break">{% trans "Host" %}: {{ inst.instance.compute.name }}</div>
|
|
</div>
|
|
<div class="col-12 col-md-6 d-flex flex-wrap gap-1">
|
|
{# the rights as the VM's Users tab names them: every owner powers the VM and opens its console #}
|
|
{% if inst.is_change %}<span class="badge text-bg-light border">{% trans "Change settings" %}</span>{% endif %}
|
|
{% if inst.is_delete %}<span class="badge text-bg-light border">{% trans "Delete the VM" %}</span>{% endif %}
|
|
{% if inst.is_change and inst.is_vnc %}<span class="badge text-bg-light border">{% trans "Change console settings" %}</span>{% endif %}
|
|
{% if not inst.is_change and not inst.is_delete %}<span class="small text-body-secondary">{% trans "Power and console only" %}</span>{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="dropdown flex-shrink-0">
|
|
<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="dropdown" aria-expanded="false"
|
|
aria-label="{% blocktrans with name=inst.instance.name %}Actions for {{ name }}{% endblocktrans %}">{% bs_icon 'three-dots' %}</button>
|
|
<ul class="dropdown-menu dropdown-menu-end">
|
|
<li><a class="dropdown-item" href="{% url 'accounts:user_instance_update' inst.id %}">{% trans "Change access" %}</a></li>
|
|
<li><a class="dropdown-item text-danger" href="{% url 'accounts:user_instance_delete' inst.id %}">{% trans "Remove from user" %}</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="list-group-item text-body-secondary">{% trans "No VMs." %}</div>
|
|
{% endfor %}
|
|
</div>
|
|
</section>
|
|
|
|
<section class="card mb-4" id="public-keys" aria-labelledby="public-keys-title">
|
|
<div class="card-header"><h2 class="h5 mb-0" id="public-keys-title">{% trans "SSH Keys" %} <span class="badge text-bg-light border">{{ publickeys|length }}</span></h2></div>
|
|
<div class="list-group list-group-flush">{% include "ssh_key_list.html" with owner=user %}</div>
|
|
</section>
|
|
|
|
<section class="card" id="apitokens" aria-labelledby="apitokens-title">
|
|
<div class="card-header"><h2 class="h5 mb-0" id="apitokens-title">{% trans "API Tokens" %} <span class="badge text-bg-light border">{{ api_tokens|length }}</span></h2></div>
|
|
<div class="list-group list-group-flush">{% include "api_token_list.html" with owner=user %}</div>
|
|
</section>
|
|
{% endblock content %}
|