mirror of
https://github.com/bitwarden/browser
synced 2026-02-27 10:03:23 +00:00
338 lines
12 KiB
HTML
338 lines
12 KiB
HTML
<ng-container>
|
|
<bit-table
|
|
*ngIf="filteredCiphers.length || filteredCollections.length"
|
|
infiniteScroll
|
|
[infiniteScrollDistance]="1"
|
|
[infiniteScrollDisabled]="!isPaging()"
|
|
(scrolled)="loadMore()"
|
|
>
|
|
<ng-container header>
|
|
<tr>
|
|
<th bitCell class="tw-min-w-fit" colspan="2">
|
|
<input
|
|
class="tw-mr-2"
|
|
type="checkbox"
|
|
id="checkAll"
|
|
(change)="checkAll($any($event.target).checked)"
|
|
[(ngModel)]="isAllChecked"
|
|
/>
|
|
<label class="tw-mb-0 !tw-font-bold !tw-text-muted" for="checkAll">{{
|
|
"all" | i18n
|
|
}}</label>
|
|
</th>
|
|
<th bitCell class="tw-w-1/2">{{ "name" | i18n }}</th>
|
|
<th bitCell class="tw-w-max">
|
|
<ng-container *ngIf="!organization">{{ "owner" | i18n }}</ng-container>
|
|
<ng-container *ngIf="organization">
|
|
{{ (activeFilter.selectedCollectionNode ? "groups" : "collections") | i18n }}
|
|
</ng-container>
|
|
</th>
|
|
<th bitCell class="tw-min-w-fit tw-text-right">
|
|
<button
|
|
[bitMenuTriggerFor]="headerMenu"
|
|
bitIconButton="bwi-ellipsis-v"
|
|
size="small"
|
|
type="button"
|
|
appA11yTitle="{{ 'options' | i18n }}"
|
|
></button>
|
|
<bit-menu #headerMenu>
|
|
<ng-container>
|
|
<button
|
|
class="dropdown-item"
|
|
appStopClick
|
|
(click)="bulkMove()"
|
|
*ngIf="!activeFilter.isDeleted && !organization"
|
|
>
|
|
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
|
{{ "moveSelected" | i18n }}
|
|
</button>
|
|
<button
|
|
class="dropdown-item"
|
|
appStopClick
|
|
(click)="bulkShare()"
|
|
*ngIf="!activeFilter.isDeleted && !organization"
|
|
>
|
|
<i class="bwi bwi-fw bwi-arrow-circle-right" aria-hidden="true"></i>
|
|
{{ "moveSelectedToOrg" | i18n }}
|
|
</button>
|
|
<button class="dropdown-item" (click)="bulkRestore()" *ngIf="activeFilter.isDeleted">
|
|
<i class="bwi bwi-fw bwi-undo" aria-hidden="true"></i>
|
|
{{ "restoreSelected" | i18n }}
|
|
</button>
|
|
<button class="dropdown-item text-danger" (click)="bulkDelete()">
|
|
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>
|
|
{{
|
|
(activeFilter.isDeleted ? "permanentlyDeleteSelected" : "deleteSelected") | i18n
|
|
}}
|
|
</button>
|
|
</ng-container>
|
|
</bit-menu>
|
|
</th>
|
|
</tr>
|
|
</ng-container>
|
|
<ng-template body>
|
|
<tr
|
|
bitRow
|
|
*ngFor="let col of filteredCollections"
|
|
(click)="navigateCollection(col)"
|
|
class="tw-cursor-pointer"
|
|
alignContent="middle"
|
|
>
|
|
<td bitCell (click)="checkRow(col)" appStopProp>
|
|
<input
|
|
*ngIf="canDeleteCollection(col.node)"
|
|
class="tw-cursor-pointer"
|
|
type="checkbox"
|
|
[(ngModel)]="$any(col).checked"
|
|
appStopProp
|
|
/>
|
|
</td>
|
|
<td bitCell>
|
|
<div class="icon" aria-hidden="true">
|
|
<i class="bwi bwi-fw bwi-lg bwi-collection"></i>
|
|
</div>
|
|
</td>
|
|
<td bitCell>
|
|
<button
|
|
bitLink
|
|
class="tw-text-start"
|
|
linkType="secondary"
|
|
(click)="navigateCollection(col)"
|
|
>
|
|
{{ col.node.name }}
|
|
</button>
|
|
</td>
|
|
<td bitCell>
|
|
<ng-container *ngIf="!organization">
|
|
<app-org-badge
|
|
organizationName="{{ col.node.organizationId | orgNameFromId: organizations }}"
|
|
[profileName]="profileName"
|
|
(onOrganizationClicked)="onOrganizationClicked(col.node.organizationId)"
|
|
appStopProp
|
|
>
|
|
</app-org-badge>
|
|
</ng-container>
|
|
<ng-container *ngIf="organization && activeFilter.selectedCollectionNode">
|
|
<app-group-badge
|
|
*ngIf="col.node.groups"
|
|
[selectedGroups]="col.node.groups"
|
|
[allGroups]="groups"
|
|
></app-group-badge>
|
|
</ng-container>
|
|
</td>
|
|
<td bitCell class="tw-text-right">
|
|
<button
|
|
*ngIf="canEditCollection(col.node) || canDeleteCollection(col.node)"
|
|
[bitMenuTriggerFor]="collectionOptions"
|
|
size="small"
|
|
bitIconButton="bwi-ellipsis-v"
|
|
type="button"
|
|
appA11yTitle="{{ 'options' | i18n }}"
|
|
appStopProp
|
|
></button>
|
|
<bit-menu #collectionOptions>
|
|
<button
|
|
*ngIf="canEditCollection(col.node)"
|
|
bitMenuItem
|
|
(click)="editCollection(col.node, 'info')"
|
|
>
|
|
<i class="bwi bwi-fw bwi-pencil-square" aria-hidden="true"></i>
|
|
{{ "editInfo" | i18n }}
|
|
</button>
|
|
<button
|
|
*ngIf="canEditCollection(col.node)"
|
|
bitMenuItem
|
|
(click)="editCollection(col.node, 'access')"
|
|
>
|
|
<i class="bwi bwi-fw bwi-users" aria-hidden="true"></i>
|
|
{{ "access" | i18n }}
|
|
</button>
|
|
<button
|
|
*ngIf="canDeleteCollection(col.node)"
|
|
bitMenuItem
|
|
(click)="deleteCollection(col.node)"
|
|
>
|
|
<span class="tw-text-danger">
|
|
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>
|
|
{{ "delete" | i18n }}
|
|
</span>
|
|
</button>
|
|
</bit-menu>
|
|
</td>
|
|
</tr>
|
|
<tr
|
|
bitRow
|
|
*ngFor="let c of filteredCiphers"
|
|
class="tw-cursor-pointer"
|
|
(click)="selectCipher(c)"
|
|
alignContent="middle"
|
|
>
|
|
<td bitCell (click)="checkRow(c)" appStopProp>
|
|
<input type="checkbox" [(ngModel)]="$any(c).checked" appStopProp />
|
|
</td>
|
|
<td bitCell>
|
|
<app-vault-icon [cipher]="c"></app-vault-icon>
|
|
</td>
|
|
<td bitCell class="tw-break-all">
|
|
<button
|
|
bitLink
|
|
class="tw-text-start"
|
|
[routerLink]="[]"
|
|
[queryParams]="{ itemId: c.id }"
|
|
queryParamsHandling="merge"
|
|
title="{{ 'editItem' | i18n }}"
|
|
>
|
|
{{ c.name }}
|
|
</button>
|
|
<ng-container *ngIf="c.hasAttachments">
|
|
<i
|
|
class="bwi bwi-paperclip"
|
|
appStopProp
|
|
title="{{ 'attachments' | i18n }}"
|
|
aria-hidden="true"
|
|
></i>
|
|
<span class="sr-only">{{ "attachments" | i18n }}</span>
|
|
<ng-container *ngIf="showFixOldAttachments(c)">
|
|
<i
|
|
class="bwi bwi-exclamation-triangle text-warning"
|
|
appStopProp
|
|
title="{{ 'attachmentsNeedFix' | i18n }}"
|
|
aria-hidden="true"
|
|
></i>
|
|
<span class="sr-only">{{ "attachmentsNeedFix" | i18n }}</span>
|
|
</ng-container>
|
|
</ng-container>
|
|
<br />
|
|
<span class="tw-text-sm tw-text-muted" appStopProp>{{ c.subTitle }}</span>
|
|
</td>
|
|
<td bitCell>
|
|
<ng-container *ngIf="!organization">
|
|
<app-org-badge
|
|
organizationName="{{ c.organizationId | orgNameFromId: organizations }}"
|
|
profileName="{{ profileName }}"
|
|
(onOrganizationClicked)="onOrganizationClicked(c.organizationId)"
|
|
appStopProp
|
|
>
|
|
</app-org-badge>
|
|
</ng-container>
|
|
<ng-container *ngIf="organization && !activeFilter.selectedCollectionNode">
|
|
<app-collection-badge
|
|
*ngIf="c.collectionIds"
|
|
[collectionIds]="c.collectionIds"
|
|
[collections]="vaultFilterService.filteredCollections$ | async"
|
|
></app-collection-badge>
|
|
</ng-container>
|
|
</td>
|
|
<td bitCell class="tw-text-right">
|
|
<button
|
|
[bitMenuTriggerFor]="cipherOptions"
|
|
size="small"
|
|
bitIconButton="bwi-ellipsis-v"
|
|
type="button"
|
|
appA11yTitle="{{ 'options' | i18n }}"
|
|
appStopProp
|
|
></button>
|
|
<bit-menu #cipherOptions>
|
|
<ng-container *ngIf="c.type === cipherType.Login && !c.isDeleted">
|
|
<button bitMenuItem (click)="copy(c, c.login.username, 'username', 'Username')">
|
|
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
|
{{ "copyUsername" | i18n }}
|
|
</button>
|
|
<button
|
|
bitMenuItem
|
|
(click)="copy(c, c.login.password, 'password', 'Password')"
|
|
*ngIf="c.viewPassword"
|
|
>
|
|
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
|
{{ "copyPassword" | i18n }}
|
|
</button>
|
|
<button
|
|
bitMenuItem
|
|
(click)="copy(c, c.login.totp, 'verificationCodeTotp', 'TOTP')"
|
|
*ngIf="displayTotpCopyButton(c)"
|
|
>
|
|
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
|
{{ "copyVerificationCode" | i18n }}
|
|
</button>
|
|
<button bitMenuItem *ngIf="c.login.canLaunch" (click)="launch(c.login.launchUri)">
|
|
<i class="bwi bwi-fw bwi-share-square" aria-hidden="true"></i>
|
|
{{ "launch" | i18n }}
|
|
</button>
|
|
</ng-container>
|
|
<button bitMenuItem (click)="attachments(c)">
|
|
<i class="bwi bwi-fw bwi-paperclip" aria-hidden="true"></i>
|
|
{{ "attachments" | i18n }}
|
|
</button>
|
|
<button
|
|
bitMenuItem
|
|
*ngIf="((!organization && !c.organizationId) || organization) && !c.isDeleted"
|
|
(click)="clone(c)"
|
|
>
|
|
<i class="bwi bwi-fw bwi-files" aria-hidden="true"></i>
|
|
{{ "clone" | i18n }}
|
|
</button>
|
|
<button
|
|
bitMenuItem
|
|
*ngIf="!organization && !c.organizationId && !c.isDeleted"
|
|
(click)="share(c)"
|
|
>
|
|
<i class="bwi bwi-fw bwi-arrow-circle-right" aria-hidden="true"></i>
|
|
{{ "moveToOrganization" | i18n }}
|
|
</button>
|
|
<button
|
|
bitMenuItem
|
|
*ngIf="c.organizationId && !c.isDeleted"
|
|
(click)="editCipherCollections(c)"
|
|
>
|
|
<i class="bwi bwi-fw bwi-collection" aria-hidden="true"></i>
|
|
{{ "collections" | i18n }}
|
|
</button>
|
|
<button bitMenuItem *ngIf="c.organizationId && accessEvents" (click)="events(c)">
|
|
<i class="bwi bwi-fw bwi-file-text" aria-hidden="true"></i>
|
|
{{ "eventLogs" | i18n }}
|
|
</button>
|
|
<button bitMenuItem (click)="restore(c)" *ngIf="c.isDeleted">
|
|
<i class="bwi bwi-fw bwi-undo" aria-hidden="true"></i>
|
|
{{ "restore" | i18n }}
|
|
</button>
|
|
<button bitMenuItem (click)="deleteCipher(c)">
|
|
<span class="tw-text-danger">
|
|
<i class="bwi bwi-fw bwi-trash" aria-hidden="true"></i>
|
|
{{ (c.isDeleted ? "permanentlyDelete" : "delete") | i18n }}
|
|
</span>
|
|
</button>
|
|
</bit-menu>
|
|
</td>
|
|
</tr>
|
|
</ng-template>
|
|
</bit-table>
|
|
<div
|
|
class="tw-mt-6 tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-start"
|
|
*ngIf="
|
|
showMissingCollectionPermissionMessage ||
|
|
(!filteredCiphers.length && !filteredCollections.length)
|
|
"
|
|
>
|
|
<ng-container *ngIf="!loaded">
|
|
<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="loaded">
|
|
<bit-icon [icon]="noItemIcon" aria-hidden="true"></bit-icon>
|
|
<ng-container *ngIf="showMissingCollectionPermissionMessage">
|
|
<p>{{ "noPermissionToViewAllCollectionItems" | i18n }}</p>
|
|
</ng-container>
|
|
<ng-container *ngIf="!showMissingCollectionPermissionMessage">
|
|
<p>{{ "noItemsInList" | i18n }}</p>
|
|
<button (click)="addCipher()" class="btn btn-outline-primary" *ngIf="showAddNew">
|
|
<i class="bwi bwi-plus bwi-fw"></i>{{ "addItem" | i18n }}
|
|
</button>
|
|
</ng-container>
|
|
</ng-container>
|
|
</div>
|
|
</ng-container>
|