Kavita/UI/Web/src/app/admin/manage-users/manage-users.component.html
2025-07-01 23:32:57 +02:00

116 lines
5.3 KiB
HTML

<ng-container *transloco="let t; read: 'manage-users'">
<div class="position-relative">
<button class="btn btn-outline-primary position-absolute custom-position" (click)="inviteUser()">
<i class="fa fa-plus" aria-hidden="true"></i><span class="phone-hidden">&nbsp;{{t('invite')}}</span>
</button>
</div>
<table class="table table-striped">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">{{t('name-header')}}</th>
<th scope="col">{{t('last-active-header')}}</th>
<th scope="col">{{t('sharing-header')}}</th>
<th scope="col">{{t('roles-header')}}</th>
<th scope="col">{{t('actions-header')}}</th>
</tr>
</thead>
<tbody>
@for(member of members; track member.username + member.lastActiveUtc + member.roles.length; let idx = $index) {
<tr>
<td>
<div class="-flex flex-row justify-content-center align-items-center">
<app-owner-icon [owner]="member.owner" />
</div>
</td>
<td id="username--{{idx}}">
<span class="member-name" id="member-name--{{idx}}" [ngClass]="{'highlight': member.username === loggedInUsername}">{{member.username | titlecase}}</span>
@if (member.isPending) {
<span class="badge bg-secondary text-dark ms-1 pending-badge" [ngbTooltip]="t('pending-tooltip')">{{t('pending-title')}}</span>
}
</td>
<td>
<span [ngbTooltip]="member.lastActiveUtc | utcToLocalTime | defaultDate">
@if ((messageHub.onlineUsers$ | async)?.includes(member.username)) {
{{t('online-now-tooltip')}}
} @else {
{{member.lastActiveUtc | utcToLocaleDate | timeAgo | sentenceCase | defaultDate}}
}
</span>
</td>
<td>
@if (member.libraries.length > 0) {
@if (hasAdminRole(member) || member.libraries.length === libraryCount) {
{{t('all-libraries')}}
} @else {
@if (member.libraries.length > 5) {
{{t('too-many-libraries')}}
}
@else {
@for(lib of member.libraries; track lib.name) {
<app-tag-badge class="col-auto">{{lib.name}}</app-tag-badge>
}
}
}
} @else {
{{null | defaultValue}}
}
</td>
<td>
@if (getRoles(member); as roles) {
<div>
@if (roles.length === 0) {
<span>{{null | defaultValue}}</span>
} @else {
@if (hasAdminRole(member)) {
<app-tag-badge class="col-auto">{{Role.Admin | roleLocalized}}</app-tag-badge>
} @else {
@for (role of roles; track role) {
<app-tag-badge class="col-auto">{{role | roleLocalized}}</app-tag-badge>
}
}
}
</div>
} @else {
{{null | defaultValue}}
}
</td>
<td>
<div class="btn-container">
@if (canEditMember(member)) {
<button class="btn btn-danger btn-sm me-2 mb-2" (click)="deleteUser(member)"
placement="top" [ngbTooltip]="t('delete-user-tooltip')" [attr.aria-label]="t('delete-user-alt', {user: member.username | titlecase})">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
<button class="btn btn-primary btn-sm me-2 mb-2" (click)="openEditUser(member)"
placement="top" [ngbTooltip]="t('edit-user-tooltip')" [attr.aria-label]="t('edit-user-alt', {user: member.username | titlecase})">
<i class="fa fa-pen" aria-hidden="true"></i>
</button>
@if (member.isPending) {
<button class="btn btn-secondary btn-sm me-2 mb-2" (click)="resendEmail(member)"
placement="top" [ngbTooltip]="t('resend-invite-tooltip')" [attr.aria-label]="t('resend-invite-alt', {user: member.username | titlecase})"><i class="fa-solid fa-share-from-square" aria-hidden="true"></i></button>
<button class="btn btn-secondary btn-sm me-2 mb-2" (click)="setup(member)"
placement="top" [ngbTooltip]="t('setup-user-tooltip')" [attr.aria-label]="t('setup-user-alt', {user: member.username | titlecase})"><i class="fa-solid fa-sliders" aria-hidden="true"></i></button>
} @else {
<button class="btn btn-secondary btn-sm me-2 mb-2" (click)="updatePassword(member)"
placement="top" [ngbTooltip]="t('change-password-tooltip')" [attr.aria-label]="t('change-password-alt', {user: member.username | titlecase})"><i class="fa fa-key" aria-hidden="true"></i></button>
}
}
</div>
</td>
</tr>
}
@empty {
@if (loadingMembers) {
<tr><td colspan="4" style="text-align: center;"><app-loading [loading]="loadingMembers"></app-loading></td></tr>
} @else {
<tr><td colspan="4" style="text-align: center;">{{t('no-data')}}</td></tr>
}
}
</tbody>
</table>
</ng-container>