1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-1925][PM-2741][AC-1334] flexible collections export page (#5759)

* Use bitTypography for page title

* Replaced app-callout with bit-callout

* Replace button with bit-button

* Update radio buttons to use CL

* Use searchable select for fileFormat dropdown

* Remove unneeded divs (old styling)

* pm-1826 remove eslint-disable tailwindcss/no-custom-classname

* Removed for-attribute from bit-labels

* Removed bitInput from bit-selects

* Removed name-attribute from bit-selects

* Make format a required field

* Removed unused dependency on cryptoService

* Remove unused dependency on BroadcasterService

* Removed dependency on window

* Moved organizationId into BaseExportComponent

* Add vaultSelector

Add organizationService as new dependency
Retrieve organizations a user has access to
Add vaultSelector dropdown
Add `export from` label
Add exportFromHint

* Removed hint as discussed by product&design

* Add function to check for import/export permission

* Export callout should listen to changes

Even though the organizationId was changed, the Input did not trigger changing the scope

* Reading FlexibleCollections feature flag to show the vault-selector on export (#7196)

---------

Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>
This commit is contained in:
Daniel James Smith
2023-12-14 13:55:54 +01:00
committed by GitHub
parent 12de4b1386
commit 60d9f3d150
8 changed files with 180 additions and 158 deletions

View File

@@ -8,8 +8,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
templateUrl: "export-scope-callout.component.html",
})
export class ExportScopeCalloutComponent implements OnInit {
@Input() organizationId: string = null;
show = false;
scopeConfig: {
title: string;
@@ -17,6 +15,17 @@ export class ExportScopeCalloutComponent implements OnInit {
scopeIdentifier: string;
};
private _organizationId: string;
get organizationId(): string {
return this._organizationId;
}
@Input() set organizationId(value: string) {
this._organizationId = value;
this.getScopeMessage(this._organizationId);
}
constructor(
protected organizationService: OrganizationService,
protected stateService: StateService,
@@ -26,18 +35,23 @@ export class ExportScopeCalloutComponent implements OnInit {
if (!this.organizationService.hasOrganizations()) {
return;
}
await this.getScopeMessage(this.organizationId);
this.show = true;
}
private async getScopeMessage(organizationId: string) {
this.scopeConfig =
this.organizationId != null
organizationId != null
? {
title: "exportingOrganizationVaultTitle",
description: "exportingOrganizationVaultDesc",
scopeIdentifier: this.organizationService.get(this.organizationId).name,
scopeIdentifier: this.organizationService.get(organizationId).name,
}
: {
title: "exportingPersonalVaultTitle",
description: "exportingIndividualVaultDescription",
scopeIdentifier: await this.stateService.getEmail(),
};
this.show = true;
}
}

View File

@@ -1,17 +1,22 @@
import { Directive, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from "@angular/core";
import { UntypedFormBuilder, Validators } from "@angular/forms";
import { merge, startWith, Subject, takeUntil } from "rxjs";
import { concat, map, merge, Observable, startWith, Subject, takeUntil } from "rxjs";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import {
OrganizationService,
canAccessImportExport,
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
import { EventType } from "@bitwarden/common/enums";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncryptedExportType } from "@bitwarden/common/tools/enums/encrypted-export-type.enum";
import { DialogService } from "@bitwarden/components";
import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export";
@@ -26,13 +31,22 @@ export class ExportComponent implements OnInit, OnDestroy {
filePasswordValue: string = null;
formPromise: Promise<string>;
private _disabledByPolicy = false;
protected organizationId: string = null;
organizations$: Observable<Organization[]>;
protected get disabledByPolicy(): boolean {
return this._disabledByPolicy;
}
exportForm = this.formBuilder.group({
format: ["json"],
vaultSelector: [
"myVault",
{
nonNullable: true,
validators: [Validators.required],
},
],
format: ["json", Validators.required],
secret: [""],
filePassword: ["", Validators.required],
confirmFilePassword: ["", Validators.required],
@@ -48,21 +62,27 @@ export class ExportComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
constructor(
protected cryptoService: CryptoService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected exportService: VaultExportServiceAbstraction,
protected eventCollectionService: EventCollectionService,
private policyService: PolicyService,
protected win: Window,
private logService: LogService,
private userVerificationService: UserVerificationService,
private formBuilder: UntypedFormBuilder,
protected fileDownloadService: FileDownloadService,
protected dialogService: DialogService,
protected organizationService: OrganizationService,
) {}
async ngOnInit() {
this.organizations$ = concat(
this.organizationService.memberOrganizations$.pipe(
canAccessImportExport(this.i18nService),
map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))),
),
);
this.policyService
.policyAppliesToActiveUser$(PolicyType.DisablePersonalVaultExport)
.pipe(takeUntil(this.destroy$))
@@ -73,6 +93,19 @@ export class ExportComponent implements OnInit, OnDestroy {
}
});
if (this.organizationId) {
this.exportForm.controls.vaultSelector.patchValue(this.organizationId);
this.exportForm.controls.vaultSelector.disable();
} else {
this.exportForm.controls.vaultSelector.valueChanges
.pipe(takeUntil(this.destroy$))
.subscribe((value) => {
this.organizationId = value != "myVault" ? value : undefined;
});
this.exportForm.controls.vaultSelector.setValue("myVault");
}
merge(
this.exportForm.get("format").valueChanges,
this.exportForm.get("fileEncryptionType").valueChanges,