324 lines
12 KiB
HTML
324 lines
12 KiB
HTML
<div class="container page-content">
|
|
<div class="tw-mb-4 tw-flex tw-flex-col tw-space-y-4">
|
|
<h1>{{ "members" | i18n }}</h1>
|
|
<div class="tw-flex tw-items-center tw-justify-end tw-space-x-3">
|
|
<bit-toggle-group
|
|
[selected]="status"
|
|
(selectedChange)="filter($event)"
|
|
[attr.aria-label]="'memberStatusFilter' | i18n"
|
|
>
|
|
<bit-toggle [value]="null">
|
|
{{ "all" | i18n }} <span bitBadge badgeType="info" *ngIf="allCount">{{ allCount }}</span>
|
|
</bit-toggle>
|
|
|
|
<bit-toggle [value]="userStatusType.Invited">
|
|
{{ "invited" | i18n }}
|
|
<span bitBadge badgeType="info" *ngIf="invitedCount">{{ invitedCount }}</span>
|
|
</bit-toggle>
|
|
|
|
<bit-toggle [value]="userStatusType.Accepted">
|
|
{{ "needsConfirmation" | i18n }}
|
|
<span bitBadge badgeType="info" *ngIf="acceptedCount">{{ acceptedCount }}</span>
|
|
</bit-toggle>
|
|
|
|
<bit-toggle [value]="userStatusType.Revoked">
|
|
{{ "revoked" | i18n }}
|
|
<span bitBadge badgeType="info" *ngIf="revokedCount">{{ revokedCount }}</span>
|
|
</bit-toggle>
|
|
</bit-toggle-group>
|
|
|
|
<app-search-input
|
|
class="tw-grow"
|
|
[(ngModel)]="searchText"
|
|
[placeholder]="'searchMembers' | i18n"
|
|
>
|
|
</app-search-input>
|
|
|
|
<button type="button" bitButton buttonType="primary" (click)="invite()">
|
|
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
|
{{ "inviteMember" | i18n }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<ng-container *ngIf="loading">
|
|
<i
|
|
class="bwi bwi-spinner bwi-spin text-muted"
|
|
title="{{ 'loading' | i18n }}"
|
|
aria-hidden="true"
|
|
></i>
|
|
<span class="sr-only">{{ "loading" | i18n }}</span>
|
|
</ng-container>
|
|
<ng-container
|
|
*ngIf="
|
|
!loading &&
|
|
(isPaging() ? pagedUsers : (users | search: searchText:'name':'email':'id')) as searchedUsers
|
|
"
|
|
>
|
|
<p *ngIf="!searchedUsers.length">{{ "noMembersInList" | i18n }}</p>
|
|
<ng-container *ngIf="searchedUsers.length">
|
|
<app-callout
|
|
type="info"
|
|
title="{{ 'confirmUsers' | i18n }}"
|
|
icon="bwi bwi-check-circle"
|
|
*ngIf="showConfirmUsers"
|
|
>
|
|
{{ "usersNeedConfirmed" | i18n }}
|
|
</app-callout>
|
|
<bit-table
|
|
infinite-scroll
|
|
[infiniteScrollDistance]="1"
|
|
[infiniteScrollDisabled]="!isPaging()"
|
|
(scrolled)="loadMore()"
|
|
>
|
|
<ng-container header>
|
|
<tr>
|
|
<th bitCell class="tw-w-20">
|
|
<input
|
|
type="checkbox"
|
|
class="tw-mr-1"
|
|
(change)="selectAll($any($event.target).checked)"
|
|
id="selectAll"
|
|
/>
|
|
<label class="tw-mb-0 !tw-font-bold !tw-text-muted" for="selectAll">{{
|
|
"all" | i18n
|
|
}}</label>
|
|
</th>
|
|
<th bitCell>{{ "name" | i18n }}</th>
|
|
<th bitCell>{{ (organization.useGroups ? "groups" : "collections") | i18n }}</th>
|
|
<th bitCell>{{ "role" | i18n }}</th>
|
|
<th bitCell>{{ "policies" | i18n }}</th>
|
|
<th bitCell class="tw-w-10">
|
|
<button
|
|
[bitMenuTriggerFor]="headerMenu"
|
|
type="button"
|
|
bitIconButton="bwi-ellipsis-v"
|
|
size="small"
|
|
appA11yTitle="{{ 'options' | i18n }}"
|
|
></button>
|
|
|
|
<bit-menu #headerMenu>
|
|
<button type="button" bitMenuItem (click)="bulkReinvite()">
|
|
<i class="bwi bwi-fw bwi-envelope" aria-hidden="true"></i>
|
|
{{ "reinviteSelected" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="bulkConfirm()"
|
|
*ngIf="showBulkConfirmUsers"
|
|
>
|
|
<span class="tw-text-success">
|
|
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
|
{{ "confirmSelected" | i18n }}
|
|
</span>
|
|
</button>
|
|
<button type="button" bitMenuItem (click)="bulkRestore()">
|
|
<i class="bwi bwi-fw bwi-plus-circle" aria-hidden="true"></i>
|
|
{{ "restoreAccess" | i18n }}
|
|
</button>
|
|
<button type="button" bitMenuItem (click)="bulkRevoke()">
|
|
<i class="bwi bwi-fw bwi-minus-circle" aria-hidden="true"></i>
|
|
{{ "revokeAccess" | i18n }}
|
|
</button>
|
|
<button type="button" bitMenuItem (click)="bulkRemove()">
|
|
<span class="tw-text-danger">
|
|
<i aria-hidden="true" class="bwi bwi-close"></i>
|
|
{{ "remove" | i18n }}
|
|
</span>
|
|
</button>
|
|
</bit-menu>
|
|
</th>
|
|
</tr>
|
|
</ng-container>
|
|
<ng-template body>
|
|
<tr bitRow *ngFor="let u of searchedUsers" alignContent="middle">
|
|
<td bitCell (click)="checkUser(u)">
|
|
<input type="checkbox" [(ngModel)]="$any(u).checked" />
|
|
</td>
|
|
<td bitCell (click)="edit(u)" class="tw-cursor-pointer">
|
|
<div class="tw-flex tw-items-center">
|
|
<bit-avatar
|
|
size="small"
|
|
[text]="u | userName"
|
|
[id]="u.userId"
|
|
class="tw-mr-3"
|
|
></bit-avatar>
|
|
<div class="tw-flex tw-flex-col">
|
|
<div>
|
|
<button bitLink>
|
|
{{ u.name ?? u.email }}
|
|
</button>
|
|
<span
|
|
bitBadge
|
|
class="tw-text-xs"
|
|
badgeType="secondary"
|
|
*ngIf="u.status === userStatusType.Invited"
|
|
>{{ "invited" | i18n }}</span
|
|
>
|
|
<span
|
|
bitBadge
|
|
class="tw-text-xs"
|
|
badgeType="warning"
|
|
*ngIf="u.status === userStatusType.Accepted"
|
|
>{{ "needsConfirmation" | i18n }}</span
|
|
>
|
|
<span
|
|
bitBadge
|
|
class="tw-text-xs"
|
|
badgeType="secondary"
|
|
*ngIf="u.status === userStatusType.Revoked"
|
|
>{{ "revoked" | i18n }}</span
|
|
>
|
|
</div>
|
|
<div class="tw-text-sm tw-text-muted" *ngIf="u.name">
|
|
{{ u.email }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
|
|
<td
|
|
bitCell
|
|
(click)="edit(u, organization.useGroups ? memberTab.Groups : memberTab.Collections)"
|
|
class="tw-cursor-pointer"
|
|
>
|
|
<bit-badge-list
|
|
*ngIf="organization.useGroups || !u.accessAll"
|
|
[items]="organization.useGroups ? u.groupNames : u.collectionNames"
|
|
[maxItems]="3"
|
|
badgeType="secondary"
|
|
></bit-badge-list>
|
|
<span *ngIf="!organization.useGroups && u.accessAll">{{ "all" | i18n }}</span>
|
|
</td>
|
|
|
|
<td
|
|
bitCell
|
|
(click)="edit(u, memberTab.Role)"
|
|
class="tw-cursor-pointer tw-text-sm tw-text-muted"
|
|
>
|
|
{{ u.type | userType }}
|
|
</td>
|
|
|
|
<td bitCell class="tw-text-muted">
|
|
<ng-container *ngIf="u.twoFactorEnabled">
|
|
<i
|
|
class="bwi bwi-lock"
|
|
title="{{ 'userUsingTwoStep' | i18n }}"
|
|
aria-hidden="true"
|
|
></i>
|
|
<span class="tw-sr-only">{{ "userUsingTwoStep" | i18n }}</span>
|
|
</ng-container>
|
|
<ng-container *ngIf="showEnrolledStatus($any(u))">
|
|
<i
|
|
class="bwi bwi-key"
|
|
title="{{ 'enrolledPasswordReset' | i18n }}"
|
|
aria-hidden="true"
|
|
></i>
|
|
<span class="tw-sr-only">{{ "enrolledPasswordReset" | i18n }}</span>
|
|
</ng-container>
|
|
</td>
|
|
<td bitCell>
|
|
<button
|
|
[bitMenuTriggerFor]="rowMenu"
|
|
type="button"
|
|
bitIconButton="bwi-ellipsis-v"
|
|
size="small"
|
|
appA11yTitle="{{ 'options' | i18n }}"
|
|
></button>
|
|
|
|
<bit-menu #rowMenu>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="reinvite(u)"
|
|
*ngIf="u.status === userStatusType.Invited"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-envelope"></i>
|
|
{{ "resendInvitation" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="confirm(u)"
|
|
*ngIf="u.status === userStatusType.Accepted"
|
|
>
|
|
<span class="tw-text-success">
|
|
<i aria-hidden="true" class="bwi bwi-check"></i> {{ "confirm" | i18n }}
|
|
</span>
|
|
</button>
|
|
<bit-menu-divider
|
|
*ngIf="
|
|
u.status === userStatusType.Accepted || u.status === userStatusType.Invited
|
|
"
|
|
></bit-menu-divider>
|
|
<button type="button" bitMenuItem (click)="edit(u, memberTab.Role)">
|
|
<i aria-hidden="true" class="bwi bwi-user"></i> {{ "memberRole" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="edit(u, memberTab.Groups)"
|
|
*ngIf="organization.useGroups"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-users"></i> {{ "groups" | i18n }}
|
|
</button>
|
|
<button type="button" bitMenuItem (click)="edit(u, memberTab.Collections)">
|
|
<i aria-hidden="true" class="bwi bwi-collection"></i> {{ "collections" | i18n }}
|
|
</button>
|
|
<bit-menu-divider></bit-menu-divider>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="events(u)"
|
|
*ngIf="organization.useEvents && u.status === userStatusType.Confirmed"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-file-text"></i> {{ "eventLogs" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="resetPassword(u)"
|
|
*ngIf="allowResetPassword(u)"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-key"></i> {{ "resetPassword" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="restore(u)"
|
|
*ngIf="u.status === userStatusType.Revoked"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-plus-circle"></i>
|
|
{{ "restoreAccess" | i18n }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
bitMenuItem
|
|
(click)="revoke(u)"
|
|
*ngIf="u.status !== userStatusType.Revoked"
|
|
>
|
|
<i aria-hidden="true" class="bwi bwi-minus-circle"></i>
|
|
{{ "revokeAccess" | i18n }}
|
|
</button>
|
|
<button type="button" bitMenuItem (click)="remove(u)">
|
|
<span class="tw-text-danger">
|
|
<i aria-hidden="true" class="bwi bwi-close"></i> {{ "remove" | i18n }}
|
|
</span>
|
|
</button>
|
|
</bit-menu>
|
|
</td>
|
|
</tr>
|
|
</ng-template>
|
|
</bit-table>
|
|
</ng-container>
|
|
</ng-container>
|
|
<ng-template #addEdit></ng-template>
|
|
<ng-template #groupsTemplate></ng-template>
|
|
<ng-template #eventsTemplate></ng-template>
|
|
<ng-template #confirmTemplate></ng-template>
|
|
<ng-template #resetPasswordTemplate></ng-template>
|
|
<ng-template #bulkStatusTemplate></ng-template>
|
|
<ng-template #bulkConfirmTemplate></ng-template>
|
|
<ng-template #bulkRemoveTemplate></ng-template>
|
|
</div>
|