wtf
All checks were successful
CI - Build Tonehaus Docker image / tonehaus-ci-build (push) Successful in 2m0s
All checks were successful
CI - Build Tonehaus Docker image / tonehaus-ci-build (push) Successful in 2m0s
This commit is contained in:
@@ -2,17 +2,61 @@
|
||||
{% block title %}User Management{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="h4 mb-4">User management</h1>
|
||||
{% set createPanelOpen = form.vars.submitted and not form.vars.valid %}
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-4">
|
||||
<h1 class="h4 mb-0">User management</h1>
|
||||
<button class="btn btn-accent" type="button" data-bs-toggle="collapse" data-bs-target="#create-user-panel" aria-expanded="{{ createPanelOpen ? 'true' : 'false' }}" aria-controls="create-user-panel">
|
||||
Create user
|
||||
</button>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-8">
|
||||
<div class="col-12">
|
||||
<div class="collapse {{ createPanelOpen ? 'show' : '' }}" id="create-user-panel">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="h6 mb-0">Create user</h2>
|
||||
<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#create-user-panel" aria-controls="create-user-panel">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
{{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.email, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.email, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.email) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.displayName, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.displayName, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.displayName) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.plainPassword.first, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.plainPassword.first, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.plainPassword.first) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.plainPassword.second, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.plainPassword.second, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.plainPassword.second) }}
|
||||
</div>
|
||||
{{ form_errors(form.plainPassword) }}
|
||||
<button class="btn btn-success w-100" type="submit">Create account</button>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="h6 mb-0">Accounts</h2>
|
||||
<span class="text-secondary small">{{ rows|length }} total</span>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle">
|
||||
<div class="mui-table-wrapper">
|
||||
<table class="mui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
@@ -51,10 +95,23 @@
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-semibold">{{ user.displayName ?? '—' }}</div>
|
||||
<div class="mui-table__title-avatar">
|
||||
{% set avatar = user.profileImagePath %}
|
||||
{% if avatar %}
|
||||
<img src="{{ avatar }}" alt="Avatar for {{ user.displayName ?? user.email }}">
|
||||
{% else %}
|
||||
<div class="rounded-3 bg-secondary-subtle text-secondary fw-semibold d-flex align-items-center justify-content-center" style="width:40px;height:40px;">
|
||||
{{ (user.displayName ?? user.email)|slice(0,1)|upper }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<div class="mui-table__title">{{ user.displayName ?? '—' }}</div>
|
||||
<div class="mui-table__subtitle d-md-none">{{ user.email }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>
|
||||
<td class="align-middle d-none d-md-table-cell">{{ user.email }}</td>
|
||||
<td class="align-middle">
|
||||
{% for role in user.roles %}
|
||||
{% if role == 'ROLE_ADMIN' %}
|
||||
<span class="badge text-bg-danger">Admin</span>
|
||||
@@ -65,8 +122,8 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-center">{{ row.albumCount }}</td>
|
||||
<td class="text-center">{{ row.reviewCount }}</td>
|
||||
<td class="mui-table__metric">{{ row.albumCount }}</td>
|
||||
<td class="mui-table__metric">{{ row.reviewCount }}</td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
<form method="post" action="{{ path('admin_users_promote', {id: user.id}) }}" onsubmit="return confirm('{% if isModerator %}Remove moderator access from {{ user.email }}?{% else %}Promote {{ user.email }} to moderator?{% endif %}');">
|
||||
@@ -97,37 +154,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h2 class="h6 mb-3">Create user</h2>
|
||||
{{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.email, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.email, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.email) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.displayName, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.displayName, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.displayName) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.plainPassword.first, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.plainPassword.first, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.plainPassword.first) }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
{{ form_label(form.plainPassword.second, null, {label_attr: {class: 'form-label'}}) }}
|
||||
{{ form_widget(form.plainPassword.second, {attr: {class: 'form-control'}}) }}
|
||||
{{ form_errors(form.plainPassword.second) }}
|
||||
</div>
|
||||
{{ form_errors(form.plainPassword) }}
|
||||
<button class="btn btn-success w-100" type="submit">Create account</button>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
@@ -11,7 +11,19 @@
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-1">{{ album.name }}</h5>
|
||||
<div class="text-secondary mb-2">{{ album.artists|map(a => a.name)|join(', ') }}</div>
|
||||
<p class="text-secondary mb-2">Released {{ album.release_date }} • {{ album.total_tracks }} tracks</p>
|
||||
{% set release_text = album.release_date is defined and album.release_date ? album.release_date : 'Not provided' %}
|
||||
{% set track_count = album.total_tracks is defined and album.total_tracks ? album.total_tracks : 0 %}
|
||||
{% set track_text = track_count > 0 ? track_count ~ ' tracks' : 'Track count unknown' %}
|
||||
<p class="text-secondary mb-2">
|
||||
Released {{ release_text }} • {{ track_text }}
|
||||
{% if album.source is defined and album.source == 'user' %}
|
||||
<br>
|
||||
<small>
|
||||
Added{{ albumOwner ? ' by ' ~ (albumOwner.displayName ?? albumOwner.userIdentifier) : '' }}
|
||||
{% if albumCreatedAt %}on {{ albumCreatedAt|date('Y-m-d') }}{% endif %}
|
||||
</small>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="mb-2"><strong>User score:</strong> {{ avg }}/10 ({{ count }})</p>
|
||||
{% if album.external_urls.spotify %}
|
||||
<a class="btn btn-outline-success btn-sm" href="{{ album.external_urls.spotify }}" target="_blank" rel="noopener">Open in Spotify</a>
|
||||
@@ -38,6 +50,46 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
{% if tracks is defined and tracks is not empty %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="h5 mb-0">Tracklist</h2>
|
||||
<span class="text-secondary">{{ tracks|length }} tracks</span>
|
||||
</div>
|
||||
<div class="mui-table-wrapper w-100">
|
||||
<table class="mui-table mui-table--compact mui-table--striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Title</th>
|
||||
<th scope="col" class="text-end">Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for track in tracks %}
|
||||
<tr>
|
||||
<td class="mui-table__number">{{ track.disc > 1 ? track.disc ~ '.' : '' }}{{ track.track }}</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="mui-table__title">{{ track.name }}</div>
|
||||
{% if track.preview_url %}
|
||||
<a class="mui-icon-button" href="{{ track.preview_url }}" target="_blank" rel="noopener" title="Preview track">
|
||||
►
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-end mui-table__metric">{{ track.duration_label }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h2 class="h5 mb-0">Reviews</h2>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user