1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 00:03:56 +00:00
Files
browser/apps/web/src/app/vault/vault-items.component.html
Jake Fink f9a89916a2 [EC-14] Part II: Add Collection Rows to Vault List (#3875)
* [EC-14] initial refactoring of vault filter

* [EC-14] return observable trees for all filters with head node

* [EC-14] Remove bindings on callbacks

* [EC-14] fix formatting on disabled orgs

* [EC-14] hide MyVault if personal org policy

* [EC-14] add check for single org policy

* [EC-14] add policies to org and change node constructor

* [EC-14] don't show options if personal vault policy

* [EC-14] default to all vaults

* [EC-14] add default selection to filters

* [EC-14] finish filter model callbacks

* [EC-14] finish filter functionality and begin cleaning up

* [EC-14] clean up old components and start on org vault

* [EC-14] loop through filters for presentation

* [EC-14] refactor VaultFilterService and put filter presentation data back into Vault Filter component. Remove VaultService

* [EC-14] begin refactoring org vault

* [EC-14] Refactor Vault Filter Service to use observables

* [EC-14] finish org vault filter

* [EC-14] fix vault model tests

* [EC-14] fix org service calls

* [EC-14] pull refactor out of shared code

* [EC-14] include head node for collections even if collections aren't loaded yet

* [EC-14] fix url params for vaults

* [EC-14] remove comments

* [EC-14] Remove unnecesary getter for org on vault filter

* [EC-14] fix linter

* [EC-14] fix prettier

* [EC-14] add deprecated methods to collection service for desktop and browser

* [EC-14] simplify cipher type node check

* [EC-14] add getters to vault filter model

* [EC-14] refactor how we build the filter list into methods

* [EC-14] add getters to build filter method

* [EC-14] start adding header and collection rows

* [EC-14] remove param ids if false

* [EC-14] Make collection rows navigatable

* [EC-14] fix collapsing nodes

* [EC-14] add specific type to search placeholder

* [EC-14] remove extra constructor and comment from org vault filter

* [EC-14] extract subscription callback to methods

* [EC-14] Remove unecessary await

* [EC-14] Remove ternary operators while building org filter

* [EC-14] remove unnecessary deps array in vault filter service declaration

* [EC-14] consolidate new models into one file

* [EC-14] change name of edit collections method

* [EC-14] add collection badges to item rows

* [EC-14] show groups badge on collection rows

* [EC-14] add bulk actions to header menu button

* [EC-14] initialize nested observable inside of service

Signed-off-by: Jacob Fink <jfink@bitwarden.com>

* [EC-14] change how we load orgs into the vault filter and select the default filter

* [EC-14] remove get from getters name

* [EC-14] remove eslint-disable comment

* [EC-14] move vault filter service abstraction to angular folder and separate

* [EC-14] rename filter types and delete VaultFilterLabel

* [EC-14] remove changes to workspace file

* [EC-14] remove deprecated service from jslib module

* [EC-14] remove any remaining files from common code

* [EC-14] consolidate vault filter components into components folder

* [EC-14] simplify method call

* [EC-14] refactor the vault filter service
- orgs now have observable property
- BehaviorSubjects have been migrated to ReplaySubjects if they don't need starting value
- added unit tests
- fix small error when selecting org badge of personal vault
- renamed some properties

* [EC-14] replace mergeMap with switchMap in vault filter service

* [EC-14] early return to prevent nesting

* [EC-14] clean up filterCollections method

* [EC-14] use isDeleted helper in html

* [EC-14] add jsdoc comments to ServiceUtils

* [EC-14] fix linter

* [EC-14] use array.slice instead of setting length

* [EC-14] resolve merge conflicts

* [EC-14] remove checkbox from end user vault collection rows

* [EC-14] add owner column to collections in end user vault

* [EC-14] add a11y titles for vault filters

* Update apps/web/src/app/vault/vault-filter/services/vault-filter.service.ts

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

* [EC-14] add missing high level jsdoc description

* [EC-14] fix storybook absolute imports

* [EC-14] delete vault-shared.module

* [EC-14] change search placeholder text to getter and add missing strings

* [EC-14] remove two way binding from search text in vault filter

* [EC-14] removed all binding from search text and just use input event

* [EC-14] remove async from apply vault filter

* [EC-14] remove circular observable calls in vault filter service

Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com>

* [EC-14] move collapsed nodes to vault filter section

* [EC-14] deconstruct filter section inside component

* [EC-14] fix merge conflicts and introduce refactored organization service to vault filter service

* [EC-14] remove mutation from filter builders

* [EC-14] fix styling on buildFolderTree

* [EC-14] remove leftover folder-filters reference and use ternary for collapse icon

* [EC-14] remove unecessary checks

* [EC-14] stop rebuilding filters when the organization changes

* [EC-14] Move subscription out of setter in vault filter section

* [EC-14] remove extra policy service methods from vault filter service

* [EC-14] remove new methods from old vault-filter.service

* [EC-14] Use vault filter service in vault components

* [EC-14] reload collections from vault now that we have vault filter service

* [EC-14] remove currentFilterCollections in vault filter component

* [EC-14] change VaultFilterType to more specific OrganizationFilter in organization-options

* [EC-14] include org check in isNodeSelected

* [EC-14] add getters to filter function, fix storybook, and add test for All Collections

* [EC-14] Resolve merge conflicts

* [EC-14] fix merge conflicts

* [EC-14] fix merge conflicts: org service protected and remove absolute path

* [EC-14] separate org vault filter service observables

* [EC-14] remove folder subject in vault filter service

* [EC-14] remove collections subject from vault filter service

* [EC-14] change collection api call name
- getCollectionsWithDetails to getManyCollectionsWithDetails

* [EC-14] add collection functionality
- add endpoint to bulk delete collections
- add logic to bulk delete both ciphers and collections
- refresh ciphers list after making collection changes
- stop making api calls from ciphers list each time a filter changes

* [EC-14] get collections from vault filter service
- for badge, instead of passing through @Input variable

* [EC-14] only bulk delete collections if passed

* [EC-14] fix deleting ciphers in org vault
- reuse same logic from end user vault
- call different api endpoints

* [EC-14] include collections in MaxCheckedCount

* [EC-14] add paging to collections

* [EC-14] hide collections if searching

* [EC-14] change vault table to new table component
- removed a lot of scss classes to use tailwind alternatives
- added getters for arrays in component that template can reference
- imported and used new bitIconButton for options button

* [EC-14] remove cursor pointer when checkbox not available

* [EC-14] stop reloading cipher list too early

* [EC-14] stop setting cipher component to loaded too early
- loaded variable on cipher component hides the loaded indicator
- when setting the default filter, we were triggering that variable
- instead, we'll just set the active filter and let it grab the filter when ready

* [EC-14] check/navigate collection when clicked

* [EC-14] rename edit collections callback
- used to be onEditCollection
- renamed to onEditCipherCollections

* [EC-14] remove showOrganizationBadge property
- property used to tell template whether it was org vault or end user
- replace with check for organization property

* [EC-14] replace || with ?? in load function of ciphers

* [EC-14] remove nested subscriptions
- nested subscriptions = bad
- the only dependency any of the subscriptions have is on the organization
- use withLatestFrom to verify that the org has been set before firing

* [EC-14] add getters and rename method

* [EC-14] add null check in bulk delete component
- some input variables can be null, so we can't just check the length

* [EC-14] add ItemRow type
- ItemRow can be either CipherView or CollectionFilter
- Consolidated a large portion of selection logic

* [EC-14] remove extra applyFilter override
- Removed extra applyFIlter, allCiphers has already been filtered by org
- Also reordered some of the methods to make more sense

* [EC-14] remove extra collections uncheck

* [EC-14] transition bulk delete to dialog service

* [EC-14] transition bulk restore to dialog service

* [EC-14] transition bulk move to dialog service

* [EC-14] transition bulk share to dialog service

* [EC-14] remove modal references

* [EC-14] reload cipher list when changing orgs

* [EC-14] add helper method to bulk delete dialog
- Gives us built in typing instead of having to redeclare

* [EC-14] add helper to open bulk restore dialog
- Gives us typing without redeclaring

* [EC-14] add open helper to bulk move dialog

* [EC-14] add open helper to bulk share dialog
- Adds typing to data
- also removed the component refs from bulk actions

* [EC-14] remove modal service from bulk actions

* [EC-14] introduce VaultItemRow to combine cipher and collections

* [EC-14] show loading indicator while switching orgs

* [EC-14] remove indexing every time filter changes
- also reverted back to using setter for changing org

* [EC-14] allow searching by function in search pipe
- this allows us to search parent properties in objects

Co-authored-by: Andreas Coroiu <andreas@andreascoroiu.com>

* [EC-14] make collections searchable
- used search pipe to filter based on search text

* [EC-14] consolidate bulk dialogs in single module

* [EC-14] remove form promise from bulk dialogs

* [EC-14] stop casting dialog return type
- we now have a helper function that gives us typing on result

* [EC-14] add length check to array guard

* [EC-14] remove extra false assignment

* [EC-14] move to sentence case

* [EC-14] address pr feedback

* [EC-14] add back the default assignment to deleted
- we need this default assignment to check for null or undefined values

* [EC-14] remove optional chaining
- everything is initialized to an empty array so it should never be null

* [EC-14] remove manager check to show org vault
- this is fixed upstream in a more comprehensive way

* [EC-686] add tests and comments to serviceUtils (#4092)

* [EC-686] add tests and comments to serviceUtls

* [EC-686] whitelist spec filename from linter

* [EC-686] fix prettier

* [EC-14] use new collection admin service

* [EC-14] fix groups searching

* [EC-14] use new groups service and models

* [EC-14] fix shared module

* [EC-14] remove leftover empty vault filter service

* [EC-14] remove CollectionGroupDetailsView models

* [EC-14] replace GroupDetails with AdminView
- Collections in vault filter now use admin view to get access details
- Collections shown in cipher list use admin view for access details

* [EC-14] add back the dialog to shared module

* [EC-14] hide org vault if lacking permissions

* [EC-14] add edit collection dialog to vault

* [EC-14] add screen reader label to share dialog

* [EC-14] moved sync call below subscription
- the subscription gives a callback for when we finish a sync
- by awaiting the sync before we weren't using the callback to refresh

* [EC-14] move cipher params check to switchMap
- we want to avoid async subscriptions

* [EC-14] clean up subscriptions in org vault
- added takeUntil
- use combineLatest

* [EC-14] clean up vault subscriptions
- remove nested subscriptions
- use takeUntil

* [EC-14] init ciphers component first

* [EC-14] fix view vault tab permissions
- CanViewAssignedCollections doesn't include CanViewAllCollections
- CanViewAssignedCollections does include IsManager

* [EC-14] reduce nesting

* [EC-14] rename bulk action dialogs selectors

* [EC-14] fix permissions for collection management
- users with custom admin permissions should be able to edit as well

* [EC-14] prettier

* [EC-14] use percentages for table columns widths

* [EC-14] use GetCollectionAccessDetails in cli
- renamed api call

Signed-off-by: Jacob Fink <jfink@bitwarden.com>
Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
Co-authored-by: Thomas Rittson <eliykat@users.noreply.github.com>
Co-authored-by: Andreas Coroiu <andreas@andreascoroiu.com>
2022-12-19 12:40:00 -05:00

306 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-1/2">
<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">
<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-container body>
<tr bitRow *ngFor="let col of filteredCollections">
<td bitCell (click)="selectRow(col)">
<input
*ngIf="organization && col.node.id !== null"
class="tw-cursor-pointer"
type="checkbox"
[(ngModel)]="$any(col).checked"
appStopProp
/>
</td>
<td bitCell (click)="selectRow(col)">
<div class="icon" aria-hidden="true">
<i class="bwi bwi-fw bwi-lg bwi-collection"></i>
</div>
</td>
<td bitCell class="tw-font-bold" (click)="selectRow(col)">
<button bitLink linkType="secondary" (click)="navigateCollection(col)">
{{ col.node.name }}
</button>
</td>
<td bitCell (click)="selectRow(col)">
<ng-container *ngIf="!organization">
<app-org-badge
organizationName="{{ col.node.organizationId | orgNameFromId: organizations }}"
[profileName]="profileName"
(onOrganizationClicked)="onOrganizationClicked(col.node.organizationId)"
>
</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>
<button
*ngIf="organization && col.node.id !== null"
[bitMenuTriggerFor]="collectionOptions"
size="small"
bitIconButton="bwi-ellipsis-v"
type="button"
appA11yTitle="{{ 'options' | i18n }}"
></button>
<bit-menu #collectionOptions>
<button
*ngIf="organization?.canEditAssignedCollections || organization?.canEditAnyCollection"
bitMenuItem
(click)="editCollection(col.node, 'info')"
>
<i class="bwi bwi-fw bwi-pencil-square" aria-hidden="true"></i>
{{ "editInfo" | i18n }}
</button>
<button
*ngIf="organization?.canEditAssignedCollections || organization?.canEditAnyCollection"
bitMenuItem
(click)="editCollection(col.node, 'access')"
>
<i class="bwi bwi-fw bwi-users" aria-hidden="true"></i>
{{ "access" | i18n }}
</button>
<button
*ngIf="
organization?.canDeleteAssignedCollections || organization?.canDeleteAnyCollection
"
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">
<td bitCell (click)="selectRow(c)">
<input type="checkbox" [(ngModel)]="$any(c).checked" appStopProp />
</td>
<td bitCell (click)="selectRow(c)">
<app-vault-icon [cipher]="c"></app-vault-icon>
</td>
<td bitCell (click)="selectRow(c)">
<a
appStopProp
[routerLink]="[]"
[queryParams]="{ itemId: c.id }"
queryParamsHandling="merge"
title="{{ 'editItem' | i18n }}"
>{{ c.name }}</a
>
<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 />
<small appStopProp>{{ c.subTitle }}</small>
</td>
<td bitCell>
<ng-container *ngIf="!organization">
<app-org-badge
organizationName="{{ c.organizationId | orgNameFromId: organizations }}"
profileName="{{ profileName }}"
(onOrganizationClicked)="onOrganizationClicked(c.organizationId)"
>
</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>
<button
[bitMenuTriggerFor]="cipherOptions"
size="small"
bitIconButton="bwi-ellipsis-v"
type="button"
appA11yTitle="{{ 'options' | i18n }}"
></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-container>
</bit-table>
<div class="no-items" *ngIf="!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>
<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>
</div>
</ng-container>