mirror of
https://github.com/bitwarden/web
synced 2025-12-06 00:03:28 +00:00
Web is in lock-step to server version. We do not need fallbacks
since we're sure the server version will support collection permissions split.
(cherry picked from commit 1de569e64d)
262 lines
16 KiB
HTML
262 lines
16 KiB
HTML
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="userAddEditTitle">
|
|
<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="userAddEditTitle">
|
|
{{title}}
|
|
<small class="text-muted" *ngIf="name">{{name}}</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">
|
|
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
|
<span class="sr-only">{{'loading' | i18n}}</span>
|
|
</div>
|
|
<div class="modal-body" *ngIf="!loading">
|
|
<ng-container *ngIf="!editMode">
|
|
<p>{{'inviteUserDesc' | i18n}}</p>
|
|
<div class="form-group mb-4">
|
|
<label for="emails">{{'email' | i18n}}</label>
|
|
<input id="emails" class="form-control" type="text" name="Emails" [(ngModel)]="emails" required
|
|
appAutoFocus>
|
|
<small class="text-muted">{{'inviteMultipleEmailDesc' | i18n : '20'}}</small>
|
|
</div>
|
|
</ng-container>
|
|
<h3>
|
|
{{'userType' | i18n}}
|
|
<a target="_blank" rel="noopener" appA11yTitle="{{'learnMore' | i18n}}"
|
|
href="https://bitwarden.com/help/article/user-types-access-control/#user-types">
|
|
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
|
|
</a>
|
|
</h3>
|
|
<div class="form-check mt-2 form-check-block">
|
|
<input class="form-check-input" type="radio" name="userType" id="userTypeUser"
|
|
[value]="organizationUserType.User" [(ngModel)]="type">
|
|
<label class="form-check-label" for="userTypeUser">
|
|
{{'user' | i18n}}
|
|
<small>{{'userDesc' | i18n}}</small>
|
|
</label>
|
|
</div>
|
|
<div class="form-check mt-2 form-check-block">
|
|
<input class="form-check-input" type="radio" name="userType" id="userTypeManager"
|
|
[value]="organizationUserType.Manager" [(ngModel)]="type">
|
|
<label class="form-check-label" for="userTypeManager">
|
|
{{'manager' | i18n}}
|
|
<small>{{'managerDesc' | i18n}}</small>
|
|
</label>
|
|
</div>
|
|
<div class="form-check mt-2 form-check-block">
|
|
<input class="form-check-input" type="radio" name="userType" id="userTypeAdmin"
|
|
[value]="organizationUserType.Admin" [(ngModel)]="type">
|
|
<label class="form-check-label" for="userTypeAdmin">
|
|
{{'admin' | i18n}}
|
|
<small>{{'adminDesc' | i18n}}</small>
|
|
</label>
|
|
</div>
|
|
<div class="form-check mt-2 form-check-block">
|
|
<input class="form-check-input" type="radio" name="userType" id="userTypeOwner"
|
|
[value]="organizationUserType.Owner" [(ngModel)]="type">
|
|
<label class="form-check-label" for="userTypeOwner">
|
|
{{'owner' | i18n}}
|
|
<small>{{'ownerDesc' | i18n}}</small>
|
|
</label>
|
|
</div>
|
|
<div class="form-check mt-2 form-check-block">
|
|
<input class="form-check-input" type="radio" name="userType" id="userTypeCustom"
|
|
[value]="organizationUserType.Custom" [(ngModel)]="type">
|
|
<label class="form-check-label" for="userTypeCustom">
|
|
{{'custom' | i18n}}
|
|
<small>{{'customDesc' | i18n}}</small>
|
|
</label>
|
|
</div>
|
|
<ng-container *ngIf="customUserTypeSelected">
|
|
<h3 class="mt-4 d-flex">
|
|
{{'permissions' | i18n}}
|
|
</h3>
|
|
<div class="row">
|
|
<div class="col-6">
|
|
<div class="mb-3">
|
|
<label class="font-weight-bold mb-0">Manager Permissions</label>
|
|
<hr class="my-0 mr-2" />
|
|
<app-nested-checkbox parentId="manageAssignedCollections"
|
|
[checkboxes]="manageAssignedCollectionsCheckboxes">
|
|
</app-nested-checkbox>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="mb-3">
|
|
<label class="font-weight-bold mb-0">Admin Permissions</label>
|
|
<hr class="my-0 mr-2" />
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="accessEventLogs"
|
|
id="accessEventLogs" [(ngModel)]="permissions.accessEventLogs">
|
|
<label class="form-check-label font-weight-normal" for="accessEventLogs">
|
|
{{'accessEventLogs' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="accessImportExport"
|
|
id="accessImportExport" [(ngModel)]="permissions.accessImportExport">
|
|
<label class="form-check-label font-weight-normal" for="accessImportExport">
|
|
{{'accessImportExport' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="accessReports"
|
|
id="accessReports" [(ngModel)]="permissions.accessReports">
|
|
<label class="form-check-label font-weight-normal" for="accessReports">
|
|
{{'accessReports' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<app-nested-checkbox parentId="manageAllCollections"
|
|
[checkboxes]="manageAllCollectionsCheckboxes">
|
|
</app-nested-checkbox>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="manageGroups"
|
|
id="manageGroups" [(ngModel)]="permissions.manageGroups">
|
|
<label class="form-check-label font-weight-normal" for="manageGroups">
|
|
{{'manageGroups' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="manageSso"
|
|
id="managePolicies" [(ngModel)]="permissions.manageSso">
|
|
<label class="form-check-label font-weight-normal" for="manageSso">
|
|
{{'manageSso' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="managePolicies"
|
|
id="managePolicies" [(ngModel)]="permissions.managePolicies">
|
|
<label class="form-check-label font-weight-normal" for="managePolicies">
|
|
{{'managePolicies' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="manageUsers"
|
|
id="manageUsers" [(ngModel)]="permissions.manageUsers"
|
|
(change)="handleDependentPermissions()">
|
|
<label class="form-check-label font-weight-normal" for="manageUsers">
|
|
{{'manageUsers' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<div class="form-check mt-1 form-check-block">
|
|
<input class="form-check-input" type="checkbox" name="manageResetPassword"
|
|
id="manageResetPassword" [(ngModel)]="permissions.manageResetPassword"
|
|
(change)="handleDependentPermissions()">
|
|
<label class="form-check-label font-weight-normal" for="manageResetPassword">
|
|
{{'manageResetPassword' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-container>
|
|
<h3 class="mt-4 d-flex">
|
|
<div class="mb-3">
|
|
{{'accessControl' | i18n}}
|
|
<a target="_blank" rel="noopener" appA11yTitle="{{'learnMore' | i18n}}"
|
|
href="https://bitwarden.com/help/article/user-types-access-control/#access-control">
|
|
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
|
|
</a>
|
|
</div>
|
|
<div class="ml-auto" *ngIf="access === 'selected' && collections && collections.length">
|
|
<button type="button" (click)="selectAll(true)" class="btn btn-link btn-sm py-0">
|
|
{{'selectAll' | i18n}}
|
|
</button>
|
|
<button type="button" (click)="selectAll(false)" class="btn btn-link btn-sm py-0">
|
|
{{'unselectAll' | i18n}}
|
|
</button>
|
|
</div>
|
|
</h3>
|
|
<div class="form-group" [ngClass]="{'mb-0': access !== 'selected'}">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="access" id="accessAll" value="all"
|
|
[(ngModel)]="access">
|
|
<label class="form-check-label" for="accessAll">
|
|
{{'userAccessAllItems' | i18n}}
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="access" id="accessSelected" value="selected"
|
|
[(ngModel)]="access">
|
|
<label class="form-check-label" for="accessSelected">
|
|
{{'userAccessSelectedCollections' | i18n}}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<ng-container *ngIf="access === 'selected'">
|
|
<div *ngIf="!collections || !collections.length">
|
|
{{'noCollectionsInList' | i18n}}
|
|
</div>
|
|
<table class="table table-hover table-list mb-0" *ngIf="collections && collections.length">
|
|
<thead>
|
|
<tr>
|
|
<th> </th>
|
|
<th>{{'name' | i18n}}</th>
|
|
<th width="100" class="text-center">{{'hidePasswords' | i18n}}</th>
|
|
<th width="100" class="text-center">{{'readOnly' | i18n}}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngFor="let c of collections; let i = index">
|
|
<td class="table-list-checkbox" (click)="check(c)">
|
|
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked"
|
|
appStopProp>
|
|
</td>
|
|
<td (click)="check(c)">
|
|
{{c.name}}
|
|
</td>
|
|
<td class="text-center">
|
|
<input type="checkbox" [(ngModel)]="c.hidePasswords"
|
|
name="Collection[{{i}}].HidePasswords" [disabled]="!c.checked">
|
|
</td>
|
|
<td class="text-center">
|
|
<input type="checkbox" [(ngModel)]="c.readOnly" name="Collection[{{i}}].ReadOnly"
|
|
[disabled]="!c.checked">
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</ng-container>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
|
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
|
<span>{{'save' | i18n}}</span>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
|
{{'cancel' | i18n}}
|
|
</button>
|
|
<div class="ml-auto">
|
|
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger"
|
|
appA11yTitle="{{'delete' | i18n}}" *ngIf="editMode" [disabled]="deleteBtn.loading"
|
|
[appApiAction]="deletePromise">
|
|
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading" aria-hidden="true"></i>
|
|
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading"
|
|
title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|