From 4852992662deb70bf455936fd51bfce5a20a36f4 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 18 Apr 2023 08:04:39 +0200 Subject: [PATCH] [AC-779] [Defect] Event log links for policies groups users and items not working (#5212) * [AC-779] fix: policy link * [AC-779] fix: search string set by url not showing in input field * [AC-779] fix: navigation to cipher events * [AC-779] fix: collection link * [AC-779] chore: clean up old components * [AC-779] chore: remove some copy pasta --- .../manage/collections.component.html | 106 ------- .../manage/collections.component.ts | 298 ------------------ .../manage/manage.component.html | 38 --- .../organizations/manage/manage.component.ts | 23 -- .../organization-routing.module.ts | 15 - apps/web/src/app/core/event.service.ts | 12 +- .../src/app/shared/loose-components.module.ts | 6 - .../components/vault-filter.component.html | 3 +- .../components/vault-filter.component.ts | 9 +- .../individual-vault/vault.component.html | 3 +- .../vault/individual-vault/vault.component.ts | 18 +- .../app/vault/org-vault/vault.component.html | 3 +- .../app/vault/org-vault/vault.component.ts | 45 ++- 13 files changed, 67 insertions(+), 512 deletions(-) delete mode 100644 apps/web/src/app/admin-console/organizations/manage/collections.component.html delete mode 100644 apps/web/src/app/admin-console/organizations/manage/collections.component.ts delete mode 100644 apps/web/src/app/admin-console/organizations/manage/manage.component.html delete mode 100644 apps/web/src/app/admin-console/organizations/manage/manage.component.ts diff --git a/apps/web/src/app/admin-console/organizations/manage/collections.component.html b/apps/web/src/app/admin-console/organizations/manage/collections.component.html deleted file mode 100644 index 8f33e706b6..0000000000 --- a/apps/web/src/app/admin-console/organizations/manage/collections.component.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - {{ "loading" | i18n }} - - -

{{ "noCollectionsInList" | i18n }}

- - - - - - - -
- {{ c.name }} - - -
-
- - diff --git a/apps/web/src/app/admin-console/organizations/manage/collections.component.ts b/apps/web/src/app/admin-console/organizations/manage/collections.component.ts deleted file mode 100644 index 8026ee4a37..0000000000 --- a/apps/web/src/app/admin-console/organizations/manage/collections.component.ts +++ /dev/null @@ -1,298 +0,0 @@ -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { firstValueFrom, lastValueFrom } from "rxjs"; -import { first } from "rxjs/operators"; - -import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { - CollectionDetailsResponse, - CollectionResponse, -} from "@bitwarden/common/admin-console/models/response/collection.response"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; -import { ProductType } from "@bitwarden/common/enums"; -import { ListResponse } from "@bitwarden/common/models/response/list.response"; -import { - DialogService, - SimpleDialogCloseType, - SimpleDialogOptions, - SimpleDialogType, -} from "@bitwarden/components"; - -import { EntityUsersComponent } from "../manage/entity-users.component"; -import { - CollectionDialogResult, - openCollectionDialog, -} from "../shared/components/collection-dialog"; - -@Component({ - selector: "app-org-manage-collections", - templateUrl: "collections.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class CollectionsComponent implements OnInit { - @ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef; - @ViewChild("usersTemplate", { read: ViewContainerRef, static: true }) - usersModalRef: ViewContainerRef; - - loading = true; - organization: Organization; - canCreate = false; - organizationId: string; - collections: CollectionView[]; - assignedCollections: CollectionView[]; - pagedCollections: CollectionView[]; - searchText: string; - - protected didScroll = false; - protected pageSize = 100; - - private pagedCollectionsCount = 0; - - constructor( - private apiService: ApiService, - private route: ActivatedRoute, - private collectionService: CollectionService, - private modalService: ModalService, - private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, - private searchService: SearchService, - private logService: LogService, - private organizationService: OrganizationService, - private dialogService: DialogService, - private router: Router - ) {} - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.parent.parent.params.subscribe(async (params) => { - this.organizationId = params.organizationId; - await this.load(); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe - this.route.queryParams.pipe(first()).subscribe(async (qParams) => { - this.searchText = qParams.search; - }); - }); - } - - async load() { - this.organization = await this.organizationService.get(this.organizationId); - this.canCreate = this.organization.canCreateNewCollections; - - const decryptCollections = async (r: ListResponse) => { - const collections = r.data - .filter((c) => c.organizationId === this.organizationId) - .map((d) => new Collection(new CollectionData(d as CollectionDetailsResponse))); - return await this.collectionService.decryptMany(collections); - }; - - if (this.organization.canViewAssignedCollections) { - const response = await this.apiService.getUserCollections(); - this.assignedCollections = await decryptCollections(response); - } - - if (this.organization.canViewAllCollections) { - const response = await this.apiService.getCollections(this.organizationId); - this.collections = await decryptCollections(response); - } else { - this.collections = this.assignedCollections; - } - - this.resetPaging(); - this.loading = false; - } - - loadMore() { - if (!this.collections || this.collections.length <= this.pageSize) { - return; - } - const pagedLength = this.pagedCollections.length; - let pagedSize = this.pageSize; - if (pagedLength === 0 && this.pagedCollectionsCount > this.pageSize) { - pagedSize = this.pagedCollectionsCount; - } - if (this.collections.length > pagedLength) { - this.pagedCollections = this.pagedCollections.concat( - this.collections.slice(pagedLength, pagedLength + pagedSize) - ); - } - this.pagedCollectionsCount = this.pagedCollections.length; - this.didScroll = this.pagedCollections.length > this.pageSize; - } - - async edit(collection?: CollectionView) { - const canCreate = collection == undefined && this.canCreate; - const canEdit = collection != undefined && this.canEdit(collection); - const canDelete = collection != undefined && this.canDelete(collection); - - if (!(canCreate || canEdit || canDelete)) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("missingPermissions")); - return; - } - - if ( - !collection && - this.organization.planProductType === ProductType.Free && - this.collections.length === this.organization.maxCollections - ) { - // Show org upgrade modal - // It might be worth creating a simple - // org upgrade dialog service to launch the dialog here and in the people.comp - // once the enterprise pod is done w/ their organization module refactor. - const orgUpgradeSimpleDialogOpts: SimpleDialogOptions = { - title: this.i18nService.t("upgradeOrganization"), - content: this.i18nService.t( - this.organization.canEditSubscription - ? "freeOrgMaxCollectionReachedManageBilling" - : "freeOrgMaxCollectionReachedNoManageBilling", - this.organization.maxCollections - ), - type: SimpleDialogType.PRIMARY, - }; - - if (this.organization.canEditSubscription) { - orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("upgrade"); - } else { - orgUpgradeSimpleDialogOpts.acceptButtonText = this.i18nService.t("ok"); - orgUpgradeSimpleDialogOpts.cancelButtonText = null; // hide secondary btn - } - - const simpleDialog = this.dialogService.openSimpleDialog(orgUpgradeSimpleDialogOpts); - - firstValueFrom(simpleDialog.closed).then((result: SimpleDialogCloseType | undefined) => { - if (!result) { - return; - } - - if (result == SimpleDialogCloseType.ACCEPT && this.organization.canEditSubscription) { - this.router.navigate( - ["/organizations", this.organization.id, "billing", "subscription"], - { queryParams: { upgrade: true } } - ); - } - }); - - return; - } - - const dialog = openCollectionDialog(this.dialogService, { - data: { collectionId: collection?.id, organizationId: this.organizationId }, - }); - - const result = await lastValueFrom(dialog.closed); - if (result === CollectionDialogResult.Saved || result === CollectionDialogResult.Deleted) { - this.load(); - } - } - - add() { - this.edit(null); - } - - async delete(collection: CollectionView) { - const confirmed = await this.platformUtilsService.showDialog( - this.i18nService.t("deleteCollectionConfirmation"), - collection.name, - this.i18nService.t("yes"), - this.i18nService.t("no"), - "warning" - ); - if (!confirmed) { - return false; - } - - try { - await this.apiService.deleteCollection(this.organizationId, collection.id); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("deletedCollectionId", collection.name) - ); - this.removeCollection(collection); - } catch (e) { - this.logService.error(e); - this.platformUtilsService.showToast("error", null, this.i18nService.t("missingPermissions")); - } - } - - async users(collection: CollectionView) { - const [modal] = await this.modalService.openViewRef( - EntityUsersComponent, - this.usersModalRef, - (comp) => { - comp.organizationId = this.organizationId; - comp.entity = "collection"; - comp.entityId = collection.id; - comp.entityName = collection.name; - - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - comp.onEditedUsers.subscribe(() => { - this.load(); - modal.close(); - }); - } - ); - } - - async resetPaging() { - this.pagedCollections = []; - this.loadMore(); - } - - isSearching() { - return this.searchService.isSearchable(this.searchText); - } - - isPaging() { - const searching = this.isSearching(); - if (searching && this.didScroll) { - this.resetPaging(); - } - return !searching && this.collections && this.collections.length > this.pageSize; - } - - canEdit(collection: CollectionView) { - if (this.organization.canEditAnyCollection) { - return true; - } - - if ( - this.organization.canEditAssignedCollections && - this.assignedCollections.some((c) => c.id === collection.id) - ) { - return true; - } - return false; - } - - canDelete(collection: CollectionView) { - if (this.organization.canDeleteAnyCollection) { - return true; - } - - if ( - this.organization.canDeleteAssignedCollections && - this.assignedCollections.some((c) => c.id === collection.id) - ) { - return true; - } - return false; - } - - private removeCollection(collection: CollectionView) { - const index = this.collections.indexOf(collection); - if (index > -1) { - this.collections.splice(index, 1); - this.resetPaging(); - } - } -} diff --git a/apps/web/src/app/admin-console/organizations/manage/manage.component.html b/apps/web/src/app/admin-console/organizations/manage/manage.component.html deleted file mode 100644 index da1090063d..0000000000 --- a/apps/web/src/app/admin-console/organizations/manage/manage.component.html +++ /dev/null @@ -1,38 +0,0 @@ - diff --git a/apps/web/src/app/admin-console/organizations/manage/manage.component.ts b/apps/web/src/app/admin-console/organizations/manage/manage.component.ts deleted file mode 100644 index 8f07c27e47..0000000000 --- a/apps/web/src/app/admin-console/organizations/manage/manage.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; - -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; - -@Component({ - selector: "app-org-manage", - templateUrl: "manage.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class ManageComponent implements OnInit { - organization: Organization; - - constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {} - - ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.parent.params.subscribe(async (params) => { - this.organization = await this.organizationService.get(params.organizationId); - }); - } -} diff --git a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts index 43b7e8d510..dca1b18530 100644 --- a/apps/web/src/app/admin-console/organizations/organization-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/organization-routing.module.ts @@ -15,9 +15,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { OrganizationPermissionsGuard } from "../../admin-console/organizations/guards/org-permissions.guard"; import { OrganizationRedirectGuard } from "../../admin-console/organizations/guards/org-redirect.guard"; import { OrganizationLayoutComponent } from "../../admin-console/organizations/layouts/organization-layout.component"; -import { CollectionsComponent } from "../../admin-console/organizations/manage/collections.component"; import { GroupsComponent } from "../../admin-console/organizations/manage/groups.component"; -import { ManageComponent } from "../../admin-console/organizations/manage/manage.component"; import { VaultModule } from "../../vault/org-vault/vault.module"; const routes: Routes = [ @@ -62,19 +60,6 @@ const routes: Routes = [ organizationPermissions: canAccessGroupsTab, }, }, - { - path: "manage", - component: ManageComponent, - children: [ - { - path: "collections", - component: CollectionsComponent, - data: { - titleId: "collections", - }, - }, - ], - }, { path: "reporting", loadChildren: () => diff --git a/apps/web/src/app/core/event.service.ts b/apps/web/src/app/core/event.service.ts index 82c8c755d6..f5259dc144 100644 --- a/apps/web/src/app/core/event.service.ts +++ b/apps/web/src/app/core/event.service.ts @@ -487,12 +487,7 @@ export class EventService { const a = this.makeAnchor(shortId); a.setAttribute( "href", - "#/organizations/" + - ev.organizationId + - "/vault?search=" + - shortId + - "&viewEvents=" + - ev.cipherId + `#/organizations/${ev.organizationId}/vault?search=${shortId}&viewEvents=${ev.cipherId}&type=all` ); return a.outerHTML; } @@ -507,10 +502,9 @@ export class EventService { private formatCollectionId(ev: EventResponse) { const shortId = this.getShortId(ev.collectionId); const a = this.makeAnchor(shortId); - // TODO: Update view/edit collection link after EC-14 is completed a.setAttribute( "href", - "#/organizations/" + ev.organizationId + "/manage/collections?search=" + shortId + `#/organizations/${ev.organizationId}/vault?collectionId=${ev.collectionId}` ); return a.outerHTML; } @@ -557,7 +551,7 @@ export class EventService { const a = this.makeAnchor(shortId); a.setAttribute( "href", - "#/organizations/" + ev.organizationId + "/manage/policies?policyId=" + ev.policyId + "#/organizations/" + ev.organizationId + "/settings/policies?policyId=" + ev.policyId ); return a.outerHTML; } diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 29cef004ae..0013a79952 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -36,10 +36,8 @@ import { VerifyRecoverDeleteComponent } from "../../auth/verify-recover-delete.c import { OrganizationSwitcherComponent } from "../admin-console/components/organization-switcher.component"; import { OrganizationCreateModule } from "../admin-console/organizations/create/organization-create.module"; import { OrganizationLayoutComponent } from "../admin-console/organizations/layouts/organization-layout.component"; -import { CollectionsComponent as OrgManageCollectionsComponent } from "../admin-console/organizations/manage/collections.component"; import { EntityEventsComponent as OrgEntityEventsComponent } from "../admin-console/organizations/manage/entity-events.component"; import { EventsComponent as OrgEventsComponent } from "../admin-console/organizations/manage/events.component"; -import { ManageComponent as OrgManageComponent } from "../admin-console/organizations/manage/manage.component"; import { UserConfirmComponent as OrgUserConfirmComponent } from "../admin-console/organizations/manage/user-confirm.component"; import { AcceptFamilySponsorshipComponent } from "../admin-console/organizations/sponsorships/accept-family-sponsorship.component"; import { FamiliesForEnterpriseSetupComponent } from "../admin-console/organizations/sponsorships/families-for-enterprise-setup.component"; @@ -172,8 +170,6 @@ import { SharedModule } from "./shared.module"; OrgEventsComponent, OrgExposedPasswordsReportComponent, OrgInactiveTwoFactorReportComponent, - OrgManageCollectionsComponent, - OrgManageComponent, OrgReusedPasswordsReportComponent, OrgToolsComponent, OrgUnsecuredWebsitesReportComponent, @@ -281,8 +277,6 @@ import { SharedModule } from "./shared.module"; OrgEventsComponent, OrgExposedPasswordsReportComponent, OrgInactiveTwoFactorReportComponent, - OrgManageCollectionsComponent, - OrgManageComponent, OrgReusedPasswordsReportComponent, OrgToolsComponent, OrgUnsecuredWebsitesReportComponent, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.html b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.html index cd61551af2..e115c62974 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.html +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.html @@ -21,7 +21,8 @@ placeholder="{{ searchPlaceholder | i18n }}" id="search" class="form-control" - (input)="searchTextChanged($any($event.target).value)" + [ngModel]="searchText" + (ngModelChange)="onSearchTextChanged($event)" autocomplete="off" appAutofocus /> diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts index 94bfa86116..b0076f664d 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts @@ -32,12 +32,13 @@ import { OrganizationOptionsComponent } from "./organization-options.component"; export class VaultFilterComponent implements OnInit, OnDestroy { filters?: VaultFilterList; @Input() activeFilter: VaultFilter = new VaultFilter(); - @Output() onSearchTextChanged = new EventEmitter(); @Output() onAddFolder = new EventEmitter(); @Output() onEditFolder = new EventEmitter(); + @Input() searchText = ""; + @Output() searchTextChanged = new EventEmitter(); + isLoaded = false; - searchText = ""; protected destroy$: Subject = new Subject(); @@ -99,9 +100,9 @@ export class VaultFilterComponent implements OnInit, OnDestroy { this.destroy$.complete(); } - searchTextChanged(t: string) { + onSearchTextChanged(t: string) { this.searchText = t; - this.onSearchTextChanged.emit(t); + this.searchTextChanged.emit(t); } applyOrganizationFilter = async (orgNode: TreeNode): Promise => { diff --git a/apps/web/src/app/vault/individual-vault/vault.component.html b/apps/web/src/app/vault/individual-vault/vault.component.html index 0e7333940d..9e8d9ab7b4 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.html +++ b/apps/web/src/app/vault/individual-vault/vault.component.html @@ -7,7 +7,8 @@ diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 28bfc95431..c779418009 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -8,7 +8,14 @@ import { ViewContainerRef, } from "@angular/core"; import { ActivatedRoute, Params, Router } from "@angular/router"; -import { BehaviorSubject, combineLatest, firstValueFrom, lastValueFrom, Subject } from "rxjs"; +import { + BehaviorSubject, + combineLatest, + firstValueFrom, + lastValueFrom, + Observable, + Subject, +} from "rxjs"; import { concatMap, debounceTime, @@ -131,9 +138,10 @@ export class VaultComponent implements OnInit, OnDestroy { protected collections: CollectionView[]; protected isEmpty: boolean; protected selectedCollection: TreeNode | undefined; + protected currentSearchText$: Observable; - private refresh$ = new BehaviorSubject(null); private searchText$ = new Subject(); + private refresh$ = new BehaviorSubject(null); private destroy$ = new Subject(); constructor( @@ -242,12 +250,12 @@ export class VaultComponent implements OnInit, OnDestroy { }) ); - const querySearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search)); + this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search)); const ciphers$ = combineLatest([ Utils.asyncToObservable(() => this.cipherService.getAllDecrypted()), filter$, - querySearchText$, + this.currentSearchText$, ]).pipe( filter(([ciphers, filter]) => ciphers != undefined && filter != undefined), concatMap(async ([ciphers, filter, searchText]) => { @@ -262,7 +270,7 @@ export class VaultComponent implements OnInit, OnDestroy { shareReplay({ refCount: true, bufferSize: 1 }) ); - const collections$ = combineLatest([nestedCollections$, filter$, querySearchText$]).pipe( + const collections$ = combineLatest([nestedCollections$, filter$, this.currentSearchText$]).pipe( filter(([collections, filter]) => collections != undefined && filter != undefined), map(([collections, filter, searchText]) => { if (filter.collectionId === undefined || filter.collectionId === Unassigned) { diff --git a/apps/web/src/app/vault/org-vault/vault.component.html b/apps/web/src/app/vault/org-vault/vault.component.html index 807a10ebf1..5af1cc31e8 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.html +++ b/apps/web/src/app/vault/org-vault/vault.component.html @@ -10,7 +10,8 @@ #vaultFilter [organization]="organization" [activeFilter]="activeFilter" - (onSearchTextChanged)="filterSearchText($event)" + [searchText]="currentSearchText$ | async" + (searchTextChanged)="filterSearchText($event)" > diff --git a/apps/web/src/app/vault/org-vault/vault.component.ts b/apps/web/src/app/vault/org-vault/vault.component.ts index 7a8bdb7c70..32f22ed409 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -8,7 +8,14 @@ import { ViewContainerRef, } from "@angular/core"; import { ActivatedRoute, Params, Router } from "@angular/router"; -import { BehaviorSubject, combineLatest, firstValueFrom, lastValueFrom, Subject } from "rxjs"; +import { + BehaviorSubject, + combineLatest, + firstValueFrom, + lastValueFrom, + Observable, + Subject, +} from "rxjs"; import { concatMap, debounceTime, @@ -123,9 +130,10 @@ export class VaultComponent implements OnInit, OnDestroy { protected selectedCollection: TreeNode | undefined; protected isEmpty: boolean; protected showMissingCollectionPermissionMessage: boolean; + protected currentSearchText$: Observable; - private refresh$ = new BehaviorSubject(null); private searchText$ = new Subject(); + private refresh$ = new BehaviorSubject(null); private destroy$ = new Subject(); constructor( @@ -219,7 +227,7 @@ export class VaultComponent implements OnInit, OnDestroy { }) ); - const querySearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search)); + this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search)); const allCollectionsWithoutUnassigned$ = organizationId$.pipe( switchMap((orgId) => this.collectionAdminService.getAll(orgId)), @@ -256,7 +264,7 @@ export class VaultComponent implements OnInit, OnDestroy { }) ); - const ciphers$ = combineLatest([allCiphers$, filter$, querySearchText$]).pipe( + const ciphers$ = combineLatest([allCiphers$, filter$, this.currentSearchText$]).pipe( filter(([ciphers, filter]) => ciphers != undefined && filter != undefined), concatMap(async ([ciphers, filter, searchText]) => { if (filter.collectionId === undefined && filter.type === undefined) { @@ -279,7 +287,7 @@ export class VaultComponent implements OnInit, OnDestroy { shareReplay({ refCount: true, bufferSize: 1 }) ); - const collections$ = combineLatest([nestedCollections$, filter$, querySearchText$]).pipe( + const collections$ = combineLatest([nestedCollections$, filter$, this.currentSearchText$]).pipe( filter(([collections, filter]) => collections != undefined && filter != undefined), map(([collections, filter, searchText]) => { if ( @@ -379,6 +387,33 @@ export class VaultComponent implements OnInit, OnDestroy { ) .subscribe(); + firstSetup$ + .pipe( + switchMap(() => combineLatest([this.route.queryParams, organization$, allCiphers$])), + switchMap(async ([qParams, organization, allCiphers$]) => { + const cipherId = qParams.viewEvents; + if (!cipherId) { + return; + } + const cipher = allCiphers$.find((c) => c.id === cipherId); + if (organization.useEvents && cipher != undefined) { + this.viewEvents(cipher); + } else { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("unknownCipher") + ); + this.router.navigate([], { + queryParams: { viewEvents: null }, + queryParamsHandling: "merge", + }); + } + }), + takeUntil(this.destroy$) + ) + .subscribe(); + firstSetup$ .pipe( switchMap(() => this.refresh$),