1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-31 23:53:37 +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

@@ -16,7 +16,7 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarde
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
@@ -27,6 +27,7 @@ import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstrac
import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service";
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction";
import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abstractions/system.service";
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service";
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
@@ -58,7 +59,7 @@ import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.s
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
import { OrganizationService } from "@bitwarden/common/services/organization.service";
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service";
import { PolicyService } from "@bitwarden/common/services/policy/policy.service";
@@ -68,6 +69,7 @@ import { SendService } from "@bitwarden/common/services/send.service";
import { SettingsService } from "@bitwarden/common/services/settings.service";
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
import { SyncService } from "@bitwarden/common/services/sync/sync.service";
import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service";
import { SystemService } from "@bitwarden/common/services/system.service";
import { TokenService } from "@bitwarden/common/services/token.service";
import { TotpService } from "@bitwarden/common/services/totp.service";
@@ -158,6 +160,7 @@ export default class MainBackground {
folderApiService: FolderApiServiceAbstraction;
policyApiService: PolicyApiServiceAbstraction;
userVerificationApiService: UserVerificationApiServiceAbstraction;
syncNotifierService: SyncNotifierServiceAbstraction;
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
backgroundWindow = window;
@@ -298,7 +301,8 @@ export default class MainBackground {
this.cryptoFunctionService,
this.stateService
);
this.organizationService = new OrganizationService(this.stateService);
this.syncNotifierService = new SyncNotifierService();
this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService);
this.policyService = new PolicyService(this.stateService, this.organizationService);
this.policyApiService = new PolicyApiService(
this.policyService,
@@ -388,9 +392,9 @@ export default class MainBackground {
this.logService,
this.keyConnectorService,
this.stateService,
this.organizationService,
this.providerService,
this.folderApiService,
this.syncNotifierService,
logoutCallback
);
this.eventService = new EventService(

View File

@@ -1,12 +1,17 @@
import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/services/organization.service";
import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { OrganizationService } from "@bitwarden/common/services/organization/organization.service";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
import {
syncNotifierServiceFactory,
SyncNotifierServiceInitOptions,
} from "./sync-notifier-service.factory";
type OrganizationServiceFactoryOptions = FactoryOptions;
export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions &
SyncNotifierServiceInitOptions &
StateServiceInitOptions;
export function organizationServiceFactory(
@@ -17,6 +22,10 @@ export function organizationServiceFactory(
cache,
"organizationService",
opts,
async () => new OrganizationService(await stateServiceFactory(cache, opts))
async () =>
new OrganizationService(
await stateServiceFactory(cache, opts),
await syncNotifierServiceFactory(cache, opts)
)
);
}

View File

@@ -0,0 +1,17 @@
import { SyncNotifierService as AbstractSyncNotifierService } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction";
import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
type SyncNotifierServiceFactoryOptions = FactoryOptions;
export type SyncNotifierServiceInitOptions = SyncNotifierServiceFactoryOptions;
export function syncNotifierServiceFactory(
cache: { syncNotifierService?: AbstractSyncNotifierService } & CachedServices,
opts: SyncNotifierServiceInitOptions
): Promise<AbstractSyncNotifierService> {
return factory(cache, "syncNotifierService", opts, () =>
Promise.resolve(new SyncNotifierService())
);
}

View File

@@ -26,7 +26,7 @@ import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";

View File

@@ -12,7 +12,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

@@ -10,7 +10,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.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 { SearchService } from "@bitwarden/common/abstractions/search.service";
import { CipherType } from "@bitwarden/common/enums/cipherType";
@@ -78,7 +78,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
async ngOnInit() {
this.searchTypeSearch = !this.platformUtilsService.isSafari();
this.showOrganizations = await this.organizationService.hasOrganizations();
this.showOrganizations = this.organizationService.hasOrganizations();
this.vaultFilter = this.vaultFilterService.getVaultFilter();
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.queryParams.pipe(first()).subscribe(async (params) => {

View File

@@ -4,7 +4,7 @@ import { Router } from "@angular/router";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.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 { SearchService } from "@bitwarden/common/abstractions/search.service";
@@ -219,7 +219,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
const otherTypes: CipherType[] = [];
const dontShowCards = await this.stateService.getDontShowCardsCurrentTab();
const dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab();
this.showOrganizations = await this.organizationService.hasOrganizations();
this.showOrganizations = this.organizationService.hasOrganizations();
if (!dontShowCards) {
otherTypes.push(CipherType.Card);
}

View File

@@ -1,70 +1,76 @@
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<header>
<div class="left">
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
</div>
<h1 class="center">
<span class="title">{{ "moveToOrganization" | i18n }}</span>
</h1>
<div class="right">
<button
type="submit"
[disabled]="form.loading || !canSave"
*ngIf="organizations && organizations.length"
>
<span [hidden]="form.loading">{{ "move" | i18n }}</span>
<i class="bwi bwi-spinner bwi-lg bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
</button>
</div>
</header>
<main tabindex="-1">
<div class="box">
<div class="box-content" *ngIf="!organizations || !organizations.length">
<div class="box-content-row padded no-hover">
{{ "noOrganizationsList" | i18n }}
</div>
<ng-container *ngIf="organizations$ | async as organizations">
<header>
<div class="left">
<button type="button" (click)="cancel()">{{ "cancel" | i18n }}</button>
</div>
<div class="box-content" *ngIf="organizations && organizations.length">
<div class="box-content-row" appBoxRow>
<label for="organization">{{ "organization" | i18n }}</label>
<select
id="organization"
name="OrganizationId"
[(ngModel)]="organizationId"
(change)="filterCollections()"
>
<option *ngFor="let o of organizations" [ngValue]="o.id">{{ o.name }}</option>
</select>
</div>
</div>
<div class="box-footer">
{{ "moveToOrgDesc" | i18n }}
</div>
</div>
<div class="box" *ngIf="organizations && organizations.length">
<h2 class="box-header">
{{ "collections" | i18n }}
</h2>
<div class="box-content" *ngIf="!collections || !collections.length">
<div class="box-content-row padded no-hover">
{{ "noCollectionsInList" | i18n }}
</div>
</div>
<div class="box-content" *ngIf="collections && collections.length">
<div
class="box-content-row box-content-row-checkbox"
*ngFor="let c of collections; let i = index"
appBoxRow
<h1 class="center">
<span class="title">{{ "moveToOrganization" | i18n }}</span>
</h1>
<div class="right">
<button
type="submit"
[disabled]="form.loading || !canSave"
*ngIf="organizations && organizations.length"
>
<label for="collection_{{ i }}">{{ c.name }}</label>
<input
id="collection_{{ i }}"
type="checkbox"
[(ngModel)]="c.checked"
name="Collection[{{ i }}].Checked"
/>
<span [hidden]="form.loading">{{ "move" | i18n }}</span>
<i
class="bwi bwi-spinner bwi-lg bwi-spin"
[hidden]="!form.loading"
aria-hidden="true"
></i>
</button>
</div>
</header>
<main tabindex="-1">
<div class="box">
<div class="box-content" *ngIf="!organizations || !organizations.length">
<div class="box-content-row padded no-hover">
{{ "noOrganizationsList" | i18n }}
</div>
</div>
<div class="box-content" *ngIf="organizations && organizations.length">
<div class="box-content-row" appBoxRow>
<label for="organization">{{ "organization" | i18n }}</label>
<select
id="organization"
name="OrganizationId"
[(ngModel)]="organizationId"
(change)="filterCollections()"
>
<option *ngFor="let o of organizations" [ngValue]="o.id">{{ o.name }}</option>
</select>
</div>
</div>
<div class="box-footer">
{{ "moveToOrgDesc" | i18n }}
</div>
</div>
</div>
</main>
<div class="box" *ngIf="organizations && organizations.length">
<h2 class="box-header">
{{ "collections" | i18n }}
</h2>
<div class="box-content" *ngIf="!collections || !collections.length">
<div class="box-content-row padded no-hover">
{{ "noCollectionsInList" | i18n }}
</div>
</div>
<div class="box-content" *ngIf="collections && collections.length">
<div
class="box-content-row box-content-row-checkbox"
*ngFor="let c of collections; let i = index"
appBoxRow
>
<label for="collection_{{ i }}">{{ c.name }}</label>
<input
id="collection_{{ i }}"
type="checkbox"
[(ngModel)]="c.checked"
name="Collection[{{ i }}].Checked"
/>
</div>
</div>
</div>
</main>
</ng-container>
</form>

View File

@@ -7,7 +7,7 @@ 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";
@Component({

View File

@@ -1,71 +1,70 @@
<div class="content org-filter-content" *ngIf="loaded && show">
<button
#toggleVaults
class="org-filter"
(click)="openOverlay()"
aria-haspopup="menu"
aria-controls="cdk-overlay-container"
[attr.aria-expanded]="isOpen"
[attr.aria-label]="vaultFilterDisplay"
>
{{ vaultFilterDisplay | ellipsis: 45 }}&nbsp;
<i
class="bwi bwi-sm"
aria-hidden="true"
[ngClass]="{ 'bwi-angle-down': !isOpen, 'bwi-chevron-up': isOpen }"
></i>
</button>
<ng-template class="vault-select-container" #vaultSelectorTemplate>
<div
class="vault-select"
[@transformPanel]="'open'"
cdkTrapFocus
cdkTrapFocusAutoCapture
role="dialog"
aria-modal="true"
>
<ng-container *ngIf="loaded && organizations$ | async as organizations">
<div class="content org-filter-content" *ngIf="loaded && shouldShow(organizations)">
<ng-container *ngIf="selectedVault$ | async as vaultFilterDisplay">
<button
appStopClick
(click)="selectAllVaults()"
[ngClass]="{ active: !myVaultOnly && !selectOrganizationId }"
appA11yTitle="{{ 'vault' | i18n }}: {{ 'allVaults' | i18n }}"
>
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
&nbsp;{{ "allVaults" | i18n }}
</button>
<button
*ngIf="!enforcePersonalOwnwership"
appStopClick
(click)="selectMyVault()"
appA11yTitle="{{ 'vault' | i18n }}: {{ 'myVault' | i18n }}"
>
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
&nbsp;{{ "myVault" | i18n }}
</button>
<button
*ngFor="let organization of organizations"
appStopClick
(click)="selectOrganization(organization)"
appA11yTitle="{{ 'vault' | i18n }}: {{ organization.name }}"
#toggleVaults
class="org-filter"
(click)="openOverlay()"
aria-haspopup="menu"
aria-controls="cdk-overlay-container"
[attr.aria-expanded]="isOpen"
[attr.aria-label]="vaultFilterDisplay"
>
{{ vaultFilterDisplay | ellipsis: 45 }}&nbsp;
<i
*ngIf="organization.planProductType !== 1"
class="bwi bwi-fw bwi-business"
class="bwi bwi-sm"
aria-hidden="true"
></i>
<i
*ngIf="organization.planProductType === 1"
class="bwi bwi-fw bwi-family"
aria-hidden="true"
></i>
<span>&nbsp;{{ organization.name | ellipsis: (organization.enabled ? 21 : 18):true }}</span>
<i
*ngIf="!organization.enabled"
class="bwi bwi-fw bwi-exclamation-triangle text-danger"
aria-label="{{ 'organizationIsDisabled' | i18n }}"
appA11yTitle="{{ 'organizationIsDisabled' | i18n }}"
[ngClass]="{ 'bwi-angle-down': !isOpen, 'bwi-chevron-up': isOpen }"
></i>
</button>
</div>
</ng-template>
</div>
</ng-container>
<ng-template class="vault-select-container" #vaultSelectorTemplate>
<div
class="vault-select"
[@transformPanel]="'open'"
cdkTrapFocus
cdkTrapFocusAutoCapture
role="dialog"
aria-modal="true"
>
<button
appStopClick
(click)="selectAllVaults()"
[ngClass]="{ active: !myVaultOnly && !selectOrganizationId }"
>
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
&nbsp;{{ "allVaults" | i18n }}
</button>
<button *ngIf="!enforcePersonalOwnwership" appStopClick (click)="selectMyVault()">
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
&nbsp;{{ "myVault" | i18n }}
</button>
<button
*ngFor="let organization of organizations"
appStopClick
(click)="selectOrganization(organization)"
>
<i
*ngIf="organization.planProductType !== 1"
class="bwi bwi-fw bwi-business"
aria-hidden="true"
></i>
<i
*ngIf="organization.planProductType === 1"
class="bwi bwi-fw bwi-family"
aria-hidden="true"
></i>
<span
>&nbsp;{{ organization.name | ellipsis: (organization.enabled ? 21 : 18):true }}</span
>
<i
*ngIf="!organization.enabled"
class="bwi bwi-fw bwi-exclamation-triangle text-danger"
aria-label="{{ 'organizationIsDisabled' | i18n }}"
appA11yTitle="{{ 'organizationIsDisabled' | i18n }}"
></i>
</button>
</div>
</ng-template>
</div>
</ng-container>

View File

@@ -5,19 +5,19 @@ import {
Component,
ElementRef,
EventEmitter,
NgZone,
OnInit,
Output,
TemplateRef,
ViewChild,
ViewContainerRef,
HostListener,
OnDestroy,
} from "@angular/core";
import { merge } from "rxjs";
import { BehaviorSubject, concatMap, map, merge, Observable, Subject, takeUntil } from "rxjs";
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { Organization } from "@bitwarden/common/models/domain/organization";
@@ -47,20 +47,22 @@ import { VaultFilterService } from "../../services/vaultFilter.service";
]),
],
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class VaultSelectComponent implements OnInit {
export class VaultSelectComponent implements OnInit, OnDestroy {
@Output() onVaultSelectionChanged = new EventEmitter();
@ViewChild("toggleVaults", { read: ElementRef })
buttonRef: ElementRef<HTMLButtonElement>;
@ViewChild("vaultSelectorTemplate", { read: TemplateRef }) templateRef: TemplateRef<HTMLElement>;
private _selectedVault = new BehaviorSubject<string>(null);
isOpen = false;
loaded = false;
organizations: Organization[];
organizations$: Observable<Organization[]>;
selectedVault$: Observable<string> = this._selectedVault.asObservable();
vaultFilter: VaultFilter = new VaultFilter();
vaultFilterDisplay = "";
enforcePersonalOwnwership = false;
enforcePersonalOwnership = false;
overlayPostition: ConnectedPosition[] = [
{
originX: "start",
@@ -71,22 +73,22 @@ export class VaultSelectComponent implements OnInit {
];
private overlayRef: OverlayRef;
private _destroy = new Subject<void>();
get show() {
shouldShow(organizations: Organization[]): boolean {
return (
(this.organizations.length > 0 && !this.enforcePersonalOwnwership) ||
(this.organizations.length > 1 && this.enforcePersonalOwnwership)
(organizations.length > 0 && !this.enforcePersonalOwnership) ||
(organizations.length > 1 && this.enforcePersonalOwnership)
);
}
constructor(
private vaultFilterService: VaultFilterService,
private i18nService: I18nService,
private ngZone: NgZone,
private broadcasterService: BroadcasterService,
private overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private platformUtilsService: PlatformUtilsService
private platformUtilsService: PlatformUtilsService,
private organizationService: OrganizationService
) {}
@HostListener("document:keydown.escape", ["$event"])
@@ -98,46 +100,45 @@ export class VaultSelectComponent implements OnInit {
}
async ngOnInit() {
await this.load();
this.broadcasterService.subscribe(this.constructor.name, (message: any) => {
this.ngZone.run(async () => {
switch (message.command) {
case "syncCompleted":
await this.load();
break;
default:
break;
}
});
});
this.organizations$ = this.organizationService.organizations$
.pipe(takeUntil(this._destroy))
.pipe(map((orgs) => orgs.sort((a, b) => a.name.localeCompare(b.name))));
this.organizations$
.pipe(
concatMap(async (organizations) => {
this.enforcePersonalOwnership =
await this.vaultFilterService.checkForPersonalOwnershipPolicy();
if (this.shouldShow(organizations)) {
if (this.enforcePersonalOwnership && !this.vaultFilter.myVaultOnly) {
const firstOrganization = organizations[0];
this._selectedVault.next(firstOrganization.name);
this.vaultFilterService.setVaultFilter(firstOrganization.id);
this.vaultFilter.selectedOrganizationId = firstOrganization.id;
} else if (this.vaultFilter.myVaultOnly) {
this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault));
} else if (this.vaultFilter.selectedOrganizationId != null) {
const selectedOrganization = organizations.find(
(o) => o.id === this.vaultFilter.selectedOrganizationId
);
this._selectedVault.next(selectedOrganization.name);
} else {
this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults));
}
}
})
)
.pipe(takeUntil(this._destroy))
.subscribe();
this.loaded = true;
}
async load() {
this.vaultFilter = this.vaultFilterService.getVaultFilter();
this.organizations = (await this.vaultFilterService.buildOrganizations()).sort((a, b) =>
a.name.localeCompare(b.name)
);
this.enforcePersonalOwnwership =
await this.vaultFilterService.checkForPersonalOwnershipPolicy();
if (this.show) {
if (this.enforcePersonalOwnwership && !this.vaultFilter.myVaultOnly) {
this.vaultFilterService.setVaultFilter(this.organizations[0].id);
this.vaultFilter.selectedOrganizationId = this.organizations[0].id;
this.vaultFilterDisplay = this.organizations.find(
(o) => o.id === this.vaultFilter.selectedOrganizationId
).name;
} else if (this.vaultFilter.myVaultOnly) {
this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault);
} else if (this.vaultFilter.selectedOrganizationId != null) {
this.vaultFilterDisplay = this.organizations.find(
(o) => o.id === this.vaultFilter.selectedOrganizationId
).name;
} else {
this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults);
}
}
this.loaded = true;
ngOnDestroy(): void {
this._destroy.next();
this._destroy.complete();
this._selectedVault.complete();
}
openOverlay() {
@@ -191,20 +192,20 @@ export class VaultSelectComponent implements OnInit {
this.i18nService.t("disabledOrganizationFilterError")
);
} else {
this.vaultFilterDisplay = organization.name;
this._selectedVault.next(organization.name);
this.vaultFilterService.setVaultFilter(organization.id);
this.onVaultSelectionChanged.emit();
this.close();
}
}
selectAllVaults() {
this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults);
this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults));
this.vaultFilterService.setVaultFilter(this.vaultFilterService.allVaults);
this.onVaultSelectionChanged.emit();
this.close();
}
selectMyVault() {
this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault);
this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault));
this.vaultFilterService.setVaultFilter(this.vaultFilterService.myVault);
this.onVaultSelectionChanged.emit();
this.close();

View File

@@ -3,7 +3,7 @@ import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { CipherView } from "@bitwarden/common/models/view/cipherView";