bitwarden-browser/apps/web/src/app/organizations/members/people.component.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>