mirror of
https://github.com/bitwarden/web
synced 2025-12-23 03:33:31 +00:00
PS-515 Fix/org users list performance (#1673)
* [PS-515] Use virtual scroll to speed up long user lists WIP: this is currently showing a large blank area under the last user. Need to figure out why virtual-scroll-spacer is sized too large. * Fix cdk-virtual-scroll styling * Format csp for readability * Set Viewport height The viewport height was * Calculate viewport height from item size Virtual scroll viewports need set heights, we can emulate the old modal behavior by calculating an approximate height required by the viewport to display all items. It will not go beyond the window due to the `.modal-dialog-scrollable` class * Remove modal css changes * pr review
This commit is contained in:
180
src/app/modules/organizations/manage/entity-users.component.html
Normal file
180
src/app/modules/organizations/manage/entity-users.component.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="userAccessTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<form
|
||||
class="modal-content"
|
||||
#form
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
ngNativeValidate
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="userAccessTitle">
|
||||
{{ "userAccess" | i18n }}
|
||||
<small>{{ entityName }}</small>
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
appA11yTitle="{{ 'close' | i18n }}"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" *ngIf="loading || !users">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</div>
|
||||
<cdk-virtual-scroll-viewport
|
||||
itemSize="46"
|
||||
minBufferPx="600"
|
||||
maxBufferPx="1200"
|
||||
[style]="scrollViewportStyle"
|
||||
>
|
||||
<div class="modal-body" *ngIf="!loading && users && searchedUsers">
|
||||
<div class="d-flex">
|
||||
<div class="mr-3">
|
||||
<label class="sr-only" for="search">{{ "search" | i18n }}</label>
|
||||
<input
|
||||
type="search"
|
||||
class="form-control form-control-sm"
|
||||
id="search"
|
||||
placeholder="{{ 'search' | i18n }}"
|
||||
name="SearchText"
|
||||
[(ngModel)]="searchText"
|
||||
/>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
[ngClass]="{ active: !showSelected }"
|
||||
(click)="filterSelected(false)"
|
||||
>
|
||||
{{ "all" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
[ngClass]="{ active: showSelected }"
|
||||
(click)="filterSelected(true)"
|
||||
>
|
||||
{{ "selected" | i18n }}
|
||||
<span class="badge badge-pill badge-info" *ngIf="selectedCount">{{
|
||||
selectedCount
|
||||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="!searchedUsers.length">
|
||||
<hr />
|
||||
{{ "noUsersInList" | i18n }}
|
||||
</ng-container>
|
||||
<table class="table table-hover table-list mb-0" [hidden]="!searchedUsers.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th> </th>
|
||||
<th>{{ "name" | i18n }}</th>
|
||||
<th *ngIf="entity === 'collection'"> </th>
|
||||
<th>{{ "userType" | i18n }}</th>
|
||||
<th width="100" class="text-center" *ngIf="entity === 'collection'">
|
||||
{{ "hidePasswords" | i18n }}
|
||||
</th>
|
||||
<th width="100" class="text-center" *ngIf="entity === 'collection'">
|
||||
{{ "readOnly" | i18n }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *cdkVirtualFor="let u of searchedUsers" class="">
|
||||
<td class="table-list-checkbox" (click)="check(u)">
|
||||
<input
|
||||
type="checkbox"
|
||||
[(ngModel)]="u.checked"
|
||||
name="{{ u.id.substr(0, 8) }}_Checked"
|
||||
[disabled]="entity === 'collection' && u.accessAll"
|
||||
(change)="selectedChanged(u)"
|
||||
appStopProp
|
||||
/>
|
||||
</td>
|
||||
<td width="30" (click)="check(u)">
|
||||
<app-avatar
|
||||
[data]="u | userName"
|
||||
[email]="u.email"
|
||||
size="25"
|
||||
[circle]="true"
|
||||
[fontSize]="14"
|
||||
>
|
||||
</app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{ u.email }}
|
||||
<span
|
||||
class="badge badge-secondary"
|
||||
*ngIf="u.status === organizationUserStatusType.Invited"
|
||||
>{{ "invited" | i18n }}</span
|
||||
>
|
||||
<span
|
||||
class="badge badge-warning"
|
||||
*ngIf="u.status === organizationUserStatusType.Accepted"
|
||||
>{{ "accepted" | i18n }}</span
|
||||
>
|
||||
<small class="text-muted d-block" *ngIf="u.name">{{ u.name }}</small>
|
||||
</td>
|
||||
<td *ngIf="entity === 'collection'">
|
||||
<ng-container *ngIf="u.accessAll">
|
||||
<i
|
||||
class="bwi bwi-filter"
|
||||
title="{{ 'userAccessAllItems' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "userAccessAllItems" | i18n }}</span>
|
||||
</ng-container>
|
||||
</td>
|
||||
<td>
|
||||
<span *ngIf="u.type === organizationUserType.Owner">{{ "owner" | i18n }}</span>
|
||||
<span *ngIf="u.type === organizationUserType.Admin">{{ "admin" | i18n }}</span>
|
||||
<span *ngIf="u.type === organizationUserType.Manager">{{
|
||||
"manager" | i18n
|
||||
}}</span>
|
||||
<span *ngIf="u.type === organizationUserType.User">{{ "user" | i18n }}</span>
|
||||
<span *ngIf="u.type === organizationUserType.Custom">{{ "custom" | i18n }}</span>
|
||||
</td>
|
||||
<td class="text-center" *ngIf="entity === 'collection'">
|
||||
<input
|
||||
type="checkbox"
|
||||
[(ngModel)]="u.hidePasswords"
|
||||
name="{{ u.id.substr(0, 8) }}_HidePasswords"
|
||||
[disabled]="u.accessAll || !u.checked"
|
||||
/>
|
||||
</td>
|
||||
<td class="text-center" *ngIf="entity === 'collection'">
|
||||
<input
|
||||
type="checkbox"
|
||||
[(ngModel)]="u.readOnly"
|
||||
name="{{ u.id.substr(0, 8) }}_ReadOnly"
|
||||
[disabled]="u.accessAll || !u.checked"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||
<span>{{ "save" | i18n }}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
||||
{{ "close" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user