1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

[PS-1092] Organization Service Observables (#3462)

* Update imports

* Implement observables in a few places

* Add tests

* Get all clients working

* Use _destroy

* Address PR feedback

* Address PR feedback

* Address feedback
This commit is contained in:
Justin Baur
2022-09-27 16:25:19 -04:00
committed by GitHub
parent 2c68518f87
commit c6dccc354c
100 changed files with 1225 additions and 813 deletions

View File

@@ -9,7 +9,7 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";

View File

@@ -1,6 +1,6 @@
import { Component, Input, OnInit } from "@angular/core";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service";
@Component({
@@ -23,7 +23,7 @@ export class ExportScopeCalloutComponent implements OnInit {
) {}
async ngOnInit(): Promise<void> {
if (!(await this.organizationService.hasOrganizations())) {
if (!this.organizationService.hasOrganizations()) {
return;
}
this.scopeConfig =
@@ -31,7 +31,7 @@ export class ExportScopeCalloutComponent implements OnInit {
? {
title: "exportingOrganizationVaultTitle",
description: "exportingOrganizationVaultDescription",
scopeIdentifier: (await this.organizationService.get(this.organizationId)).name,
scopeIdentifier: this.organizationService.get(this.organizationId).name,
}
: {
title: "exportingPersonalVaultTitle",

View File

@@ -1,7 +1,6 @@
import { Directive, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
@@ -23,7 +22,6 @@ export class RemovePasswordComponent implements OnInit {
constructor(
private router: Router,
private stateService: StateService,
private apiService: ApiService,
private syncService: SyncService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
@@ -70,9 +68,7 @@ export class RemovePasswordComponent implements OnInit {
try {
this.leaving = true;
this.actionPromise = this.organizationApiService.leave(this.organization.id).then(() => {
return this.syncService.fullSync(true);
});
this.actionPromise = this.organizationApiService.leave(this.organization.id);
await this.actionPromise;
this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization"));
await this.keyConnectorService.removeConvertAccountRequired();

View File

@@ -1,29 +1,33 @@
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
import { Utils } from "@bitwarden/common/misc/utils";
import { Organization } from "@bitwarden/common/models/domain/organization";
import { CipherView } from "@bitwarden/common/models/view/cipherView";
import { CollectionView } from "@bitwarden/common/models/view/collectionView";
import { Checkable, isChecked } from "@bitwarden/common/types/checkable";
@Directive()
export class ShareComponent implements OnInit {
export class ShareComponent implements OnInit, OnDestroy {
@Input() cipherId: string;
@Input() organizationId: string;
@Output() onSharedCipher = new EventEmitter();
formPromise: Promise<any>;
formPromise: Promise<void>;
cipher: CipherView;
collections: CollectionView[] = [];
organizations: Organization[] = [];
collections: Checkable<CollectionView>[] = [];
organizations$: Observable<Organization[]>;
protected writeableCollections: CollectionView[] = [];
protected writeableCollections: Checkable<CollectionView>[] = [];
private _destroy = new Subject<void>();
constructor(
protected collectionService: CollectionService,
@@ -38,24 +42,37 @@ export class ShareComponent implements OnInit {
await this.load();
}
ngOnDestroy(): void {
this._destroy.next();
this._destroy.complete();
}
async load() {
const allCollections = await this.collectionService.getAllDecrypted();
this.writeableCollections = allCollections.map((c) => c).filter((c) => !c.readOnly);
const orgs = await this.organizationService.getAll();
this.organizations = orgs
.sort(Utils.getSortFunction(this.i18nService, "name"))
.filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed);
this.organizations$ = this.organizationService.organizations$.pipe(
map((orgs) => {
return orgs
.filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed)
.sort(Utils.getSortFunction(this.i18nService, "name"));
})
);
this.organizations$.pipe(takeUntil(this._destroy)).subscribe((orgs) => {
if (this.organizationId == null && orgs.length > 0) {
this.organizationId = orgs[0].id;
}
});
const cipherDomain = await this.cipherService.get(this.cipherId);
this.cipher = await cipherDomain.decrypt();
if (this.organizationId == null && this.organizations.length > 0) {
this.organizationId = this.organizations[0].id;
}
this.filterCollections();
}
filterCollections() {
this.writeableCollections.forEach((c) => ((c as any).checked = false));
this.writeableCollections.forEach((c) => (c.checked = false));
if (this.organizationId == null || this.writeableCollections.length === 0) {
this.collections = [];
} else {
@@ -66,9 +83,7 @@ export class ShareComponent implements OnInit {
}
async submit(): Promise<boolean> {
const selectedCollectionIds = this.collections
.filter((c) => !!(c as any).checked)
.map((c) => c.id);
const selectedCollectionIds = this.collections.filter(isChecked).map((c) => c.id);
if (selectedCollectionIds.length === 0) {
this.platformUtilsService.showToast(
"error",
@@ -80,9 +95,9 @@ export class ShareComponent implements OnInit {
const cipherDomain = await this.cipherService.get(this.cipherId);
const cipherView = await cipherDomain.decrypt();
const orgs = await firstValueFrom(this.organizations$);
const orgName =
this.organizations.find((o) => o.id === this.organizationId)?.name ??
this.i18nService.t("organization");
orgs.find((o) => o.id === this.organizationId)?.name ?? this.i18nService.t("organization");
try {
this.formPromise = this.cipherService
@@ -106,7 +121,7 @@ export class ShareComponent implements OnInit {
get canSave() {
if (this.collections != null) {
for (let i = 0; i < this.collections.length; i++) {
if ((this.collections[i] as any).checked) {
if (this.collections[i].checked) {
return true;
}
}