Skip to content
This repository was archived by the owner on Mar 15, 2024. It is now read-only.

Commit 66391b4

Browse files
addisonbeckeliykat
andauthored
[fix] Pull org admin vault collections directly from the API (#1700) (#1726)
* [fix] Pull org admin vault collections directly from the API * [refactor] Establish pattern for interfaces in module scoped services * [fix] Remove access modifiers from constructor params for an extended service * [fix] Rename skipFilterCollectionRefresh to firstLoaded * [fix] Simplify hiding unwanted filters in the org vault * Revert "[refactor] Establish pattern for interfaces in module scoped services" This reverts commit f1edae5. * Update src/app/modules/vault-filter/vault-filter.component.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * Update src/app/modules/vault-filter/organization-vault-filter.component.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * [fix] Ran prettier Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
1 parent 1c09629 commit 66391b4

8 files changed

+111
-57
lines changed

jslib

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Component, Input } from "@angular/core";
2+
3+
import { Organization } from "jslib-common/models/domain/organization";
4+
5+
import { VaultFilterComponent } from "./vault-filter.component";
6+
7+
@Component({
8+
selector: "app-organization-vault-filter",
9+
templateUrl: "vault-filter.component.html",
10+
})
11+
export class OrganizationVaultFilterComponent extends VaultFilterComponent {
12+
hideOrganizations = true;
13+
hideFavorites = true;
14+
hideFolders = true;
15+
16+
organization: Organization;
17+
18+
async initCollections() {
19+
if (this.organization.canEditAnyCollection) {
20+
return await this.vaultFilterService.buildAdminCollections(this.organization.id);
21+
}
22+
return await this.vaultFilterService.buildCollections(this.organization.id);
23+
}
24+
25+
async reloadCollectionsAndFolders() {
26+
this.collections = await this.initCollections();
27+
}
28+
}

src/app/modules/vault-filter/vault-filter.component.html

+2-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
appAutofocus
2828
/>
2929
<app-organization-filter
30-
*ngIf="showOrgFilter"
3130
[hide]="hideOrganizations"
3231
[activeFilter]="activeFilter"
3332
[collapsedFilterNodes]="collapsedFilterNodes"
@@ -39,7 +38,7 @@
3938
></app-organization-filter>
4039
<div class="filter">
4140
<app-status-filter
42-
[hideFavorites]="!showFavorites"
41+
[hideFavorites]="hideFavorites"
4342
[hideTrash]="hideTrash"
4443
[activeFilter]="activeFilter"
4544
(onFilterChange)="applyFilter($event)"
@@ -55,7 +54,7 @@
5554
</div>
5655
<div class="filter">
5756
<app-folder-filter
58-
[hide]="!showFolders"
57+
[hide]="hideFolders"
5958
[activeFilter]="activeFilter"
6059
[collapsedFilterNodes]="collapsedFilterNodes"
6160
[folderNodes]="folders"
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,22 @@
1-
import { Component, EventEmitter, Input, Output } from "@angular/core";
1+
import { Component, EventEmitter, Output } from "@angular/core";
22

33
import { VaultFilterComponent as BaseVaultFilterComponent } from "jslib-angular/modules/vault-filter/vault-filter.component";
4-
import { VaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
5-
import { Organization } from "jslib-common/models/domain/organization";
4+
5+
import { VaultFilterService } from "./vault-filter.service";
66

77
@Component({
88
selector: "app-vault-filter",
99
templateUrl: "vault-filter.component.html",
1010
})
1111
export class VaultFilterComponent extends BaseVaultFilterComponent {
12-
@Input() showOrgFilter = true;
13-
@Input() showFolders = true;
14-
@Input() showFavorites = true;
15-
1612
@Output() onSearchTextChanged = new EventEmitter<string>();
1713

1814
searchPlaceholder: string;
1915
searchText = "";
2016

21-
organization: Organization;
22-
23-
constructor(vaultFilterService: VaultFilterService) {
17+
constructor(protected vaultFilterService: VaultFilterService) {
18+
// This empty constructor is required to provide the web vaultFilterService subclass to super()
19+
// TODO: refactor this to use proper dependency injection
2420
super(vaultFilterService);
2521
}
2622

@@ -37,8 +33,4 @@ export class VaultFilterComponent extends BaseVaultFilterComponent {
3733
this.activeSingleOrganizationPolicy =
3834
await this.vaultFilterService.checkForSingleOrganizationPolicy();
3935
}
40-
41-
async initCollections() {
42-
return await this.vaultFilterService.buildCollections(this.organization?.id);
43-
}
4436
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
import { NgModule } from "@angular/core";
22

3-
import { VaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
4-
import { CipherService } from "jslib-common/abstractions/cipher.service";
5-
import { CollectionService } from "jslib-common/abstractions/collection.service";
6-
import { FolderService } from "jslib-common/abstractions/folder.service";
7-
import { OrganizationService } from "jslib-common/abstractions/organization.service";
8-
import { PolicyService } from "jslib-common/abstractions/policy.service";
9-
import { StateService } from "jslib-common/abstractions/state.service";
10-
113
import { SharedModule } from "../shared.module";
124

135
import { CollectionFilterComponent } from "./components/collection-filter.component";
@@ -17,7 +9,9 @@ import { OrganizationFilterComponent } from "./components/organization-filter.co
179
import { OrganizationOptionsComponent } from "./components/organization-options.component";
1810
import { StatusFilterComponent } from "./components/status-filter.component";
1911
import { TypeFilterComponent } from "./components/type-filter.component";
12+
import { OrganizationVaultFilterComponent } from "./organization-vault-filter.component";
2013
import { VaultFilterComponent } from "./vault-filter.component";
14+
import { VaultFilterService } from "./vault-filter.service";
2115

2216
@NgModule({
2317
imports: [SharedModule],
@@ -29,22 +23,10 @@ import { VaultFilterComponent } from "./vault-filter.component";
2923
OrganizationOptionsComponent,
3024
StatusFilterComponent,
3125
TypeFilterComponent,
26+
OrganizationVaultFilterComponent,
3227
LinkSsoComponent,
3328
],
34-
exports: [VaultFilterComponent],
35-
providers: [
36-
{
37-
provide: VaultFilterService,
38-
useClass: VaultFilterService,
39-
deps: [
40-
StateService,
41-
OrganizationService,
42-
FolderService,
43-
CipherService,
44-
CollectionService,
45-
PolicyService,
46-
],
47-
},
48-
],
29+
exports: [VaultFilterComponent, OrganizationVaultFilterComponent],
30+
providers: [VaultFilterService],
4931
})
5032
export class VaultFilterModule {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
1+
import { Injectable } from "@angular/core";
2+
3+
import { DynamicTreeNode } from "jslib-angular/modules/vault-filter/models/dynamic-tree-node.model";
14
import { VaultFilterService as BaseVaultFilterService } from "jslib-angular/modules/vault-filter/vault-filter.service";
5+
import { ApiService } from "jslib-common/abstractions/api.service";
6+
import { CipherService } from "jslib-common/abstractions/cipher.service";
7+
import { CollectionService } from "jslib-common/abstractions/collection.service";
8+
import { FolderService } from "jslib-common/abstractions/folder.service";
9+
import { OrganizationService } from "jslib-common/abstractions/organization.service";
10+
import { PolicyService } from "jslib-common/abstractions/policy.service";
11+
import { StateService } from "jslib-common/abstractions/state.service";
12+
import { CollectionData } from "jslib-common/models/data/collectionData";
13+
import { Collection } from "jslib-common/models/domain/collection";
14+
import { CollectionDetailsResponse } from "jslib-common/models/response/collectionResponse";
15+
import { CollectionView } from "jslib-common/models/view/collectionView";
16+
17+
@Injectable()
18+
export class VaultFilterService extends BaseVaultFilterService {
19+
constructor(
20+
stateService: StateService,
21+
organizationService: OrganizationService,
22+
folderService: FolderService,
23+
cipherService: CipherService,
24+
collectionService: CollectionService,
25+
policyService: PolicyService,
26+
protected apiService: ApiService
27+
) {
28+
super(
29+
stateService,
30+
organizationService,
31+
folderService,
32+
cipherService,
33+
collectionService,
34+
policyService
35+
);
36+
}
37+
38+
async buildAdminCollections(organizationId: string) {
39+
let result: CollectionView[] = [];
40+
const collectionResponse = await this.apiService.getCollections(organizationId);
41+
if (collectionResponse?.data != null && collectionResponse.data.length) {
42+
const collectionDomains = collectionResponse.data.map(
43+
(r: CollectionDetailsResponse) => new Collection(new CollectionData(r))
44+
);
45+
result = await this.collectionService.decryptMany(collectionDomains);
46+
}
247

3-
export class VaultFilterService extends BaseVaultFilterService {}
48+
const nestedCollections = await this.collectionService.getAllNested(result);
49+
return new DynamicTreeNode<CollectionView>({
50+
fullList: result,
51+
nestedList: nestedCollections,
52+
});
53+
}
54+
}

src/app/modules/vault/modules/organization-vault/organization-vault.component.html

+2-5
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@
44
<div class="groupings">
55
<div class="content">
66
<div class="inner-content">
7-
<app-vault-filter
7+
<app-organization-vault-filter
88
#vaultFilter
9-
[showFolders]="false"
10-
[showFavorites]="false"
119
[activeFilter]="activeFilter"
12-
[showOrgFilter]="false"
1310
(onFilterChange)="applyVaultFilter($event)"
1411
(onSearchTextChanged)="filterSearchText($event)"
15-
></app-vault-filter>
12+
></app-organization-vault-filter>
1613
</div>
1714
</div>
1815
</div>

src/app/modules/vault/modules/organization-vault/organization-vault.component.ts

+15-10
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { AddEditComponent } from "../../../../organizations/vault/add-edit.compo
2929
import { AttachmentsComponent } from "../../../../organizations/vault/attachments.component";
3030
import { CiphersComponent } from "../../../../organizations/vault/ciphers.component";
3131
import { CollectionsComponent } from "../../../../organizations/vault/collections.component";
32-
import { VaultFilterComponent } from "../../../vault-filter/vault-filter.component";
32+
import { OrganizationVaultFilterComponent } from "../../../vault-filter/organization-vault-filter.component";
3333
import { VaultService } from "../../vault.service";
3434

3535
const BroadcasterSubscriptionId = "OrgVaultComponent";
@@ -39,7 +39,8 @@ const BroadcasterSubscriptionId = "OrgVaultComponent";
3939
templateUrl: "organization-vault.component.html",
4040
})
4141
export class OrganizationVaultComponent implements OnInit, OnDestroy {
42-
@ViewChild("vaultFilter", { static: true }) vaultFilterComponent: VaultFilterComponent;
42+
@ViewChild("vaultFilter", { static: true })
43+
vaultFilterComponent: OrganizationVaultFilterComponent;
4344
@ViewChild(CiphersComponent, { static: true }) ciphersComponent: CiphersComponent;
4445
@ViewChild("attachments", { read: ViewContainerRef, static: true })
4546
attachmentsModalRef: ViewContainerRef;
@@ -57,6 +58,11 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
5758
trashCleanupWarning: string = null;
5859
activeFilter: VaultFilter = new VaultFilter();
5960

61+
// This is a hack to avoid redundant api calls that fetch OrganizationVaultFilterComponent collections
62+
// When it makes sense to do so we should leverage some other communication method for change events that isn't directly tied to the query param for organizationId
63+
// i.e. exposing the VaultFiltersService to the OrganizationSwitcherComponent to make relevant updates from a change event instead of just depending on the router
64+
firstLoaded = true;
65+
6066
constructor(
6167
private route: ActivatedRoute,
6268
private organizationService: OrganizationService,
@@ -95,11 +101,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
95101
case "syncCompleted":
96102
if (message.successfully) {
97103
await Promise.all([
98-
this.vaultFilterComponent.reloadCollectionsAndFolders(
99-
new VaultFilter({
100-
selectedOrganizationId: this.organization.id,
101-
} as Partial<VaultFilter>)
102-
),
104+
this.vaultFilterComponent.reloadCollectionsAndFolders(),
103105
this.ciphersComponent.refresh(),
104106
]);
105107
this.changeDetectorRef.detectChanges();
@@ -109,9 +111,12 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
109111
});
110112
});
111113
}
112-
await this.vaultFilterComponent.reloadCollectionsAndFolders(
113-
new VaultFilter({ selectedOrganizationId: this.organization.id } as Partial<VaultFilter>)
114-
);
114+
115+
if (!this.firstLoaded) {
116+
await this.vaultFilterComponent.reloadCollectionsAndFolders();
117+
}
118+
this.firstLoaded = false;
119+
115120
await this.ciphersComponent.reload();
116121

117122
if (qParams.viewEvents != null) {

0 commit comments

Comments
 (0)