mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
Merge branch 'feature/sm-billing' into AC-1418-add-secrets-manager-manage-subscription-component
This commit is contained in:
@@ -952,7 +952,7 @@
|
||||
"message": "Server URL"
|
||||
},
|
||||
"apiUrl": {
|
||||
"message": "API Server URL"
|
||||
"message": "API server URL"
|
||||
},
|
||||
"webVaultUrl": {
|
||||
"message": "Web vault server URL"
|
||||
|
||||
@@ -7,8 +7,6 @@ import { NotificationsService as NotificationsServiceAbstraction } from "@bitwar
|
||||
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
|
||||
import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service";
|
||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
||||
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification-api.service.abstraction";
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { InternalOrganizationService as InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -21,6 +19,8 @@ import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/ab
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction";
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||
|
||||
@@ -15,7 +15,6 @@ import { NotificationsService } from "@bitwarden/common/abstractions/notificatio
|
||||
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
|
||||
import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
|
||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -31,6 +30,7 @@ import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-con
|
||||
import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { LoginService } from "@bitwarden/common/auth/services/login.service";
|
||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Router } from "@angular/router";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
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";
|
||||
|
||||
@@ -6,8 +6,8 @@ import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"urls": {
|
||||
"icons": "https://icons.eudevtest.bitwarden.pw",
|
||||
"notifications": "https://notifications.eudevtest.bitwarden.pw",
|
||||
"scim": "https://scim.eudevtest.bitwarden.pw"
|
||||
},
|
||||
"flags": {
|
||||
"secretsManager": true,
|
||||
"showPasswordless": true
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"urls": {
|
||||
"icons": "https://icons.bitwarden.net",
|
||||
"icons": "https://icons.bitwarden.eu",
|
||||
"notifications": "https://notifications.bitwarden.eu",
|
||||
"scim": "https://scim.bitwarden.eu"
|
||||
},
|
||||
|
||||
11
apps/web/config/euqa.json
Normal file
11
apps/web/config/euqa.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"urls": {
|
||||
"icons": "https://icons.euqa.bitwarden.pw",
|
||||
"notifications": "https://notifications.euqa.bitwarden.pw",
|
||||
"scim": "https://scim.euqa.bitwarden.pw"
|
||||
},
|
||||
"flags": {
|
||||
"secretsManager": true,
|
||||
"showPasswordless": true
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
"build:bit:dev:watch": "cross-env ENV=development npm run build:bit:watch",
|
||||
"build:bit:qa": "cross-env NODE_ENV=production ENV=qa npm run build:bit",
|
||||
"build:bit:euprd": "cross-env NODE_ENV=production ENV=euprd npm run build:bit",
|
||||
"build:bit:eudevtest": "cross-env NODE_ENV=production ENV=eudevtest npm run build:bit",
|
||||
"build:bit:euqa": "cross-env NODE_ENV=production ENV=euqa npm run build:bit",
|
||||
"build:bit:cloud": "cross-env NODE_ENV=production ENV=cloud npm run build:bit",
|
||||
"build:oss:selfhost:watch": "cross-env ENV=selfhosted npm run build:oss:watch",
|
||||
"build:bit:selfhost:watch": "cross-env ENV=selfhosted npm run build:bit:watch",
|
||||
|
||||
@@ -4,10 +4,10 @@ import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||
import { combineLatest, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
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";
|
||||
@@ -17,7 +17,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import { UserVerificationModule } from "../../../../shared/components/user-verification";
|
||||
import { UserVerificationModule } from "../../../../auth/shared/components/user-verification";
|
||||
import { SharedModule } from "../../../../shared/shared.module";
|
||||
|
||||
class CountBasedLocalizationKey {
|
||||
|
||||
@@ -3,10 +3,9 @@ import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
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";
|
||||
@@ -35,7 +34,6 @@ export class OrganizationExportComponent extends ExportComponent {
|
||||
userVerificationService: UserVerificationService,
|
||||
formBuilder: UntypedFormBuilder,
|
||||
fileDownloadService: FileDownloadService,
|
||||
modalService: ModalService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
@@ -49,7 +47,6 @@ export class OrganizationExportComponent extends ExportComponent {
|
||||
userVerificationService,
|
||||
formBuilder,
|
||||
fileDownloadService,
|
||||
modalService,
|
||||
dialogService
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
import { ModalConfig } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
||||
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/abstractions/organization-user/requests";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ScrollingModule } from "@angular/cdk/scrolling";
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { UserVerificationModule } from "../../../auth/shared/components/user-verification";
|
||||
import { LooseComponentsModule, SharedModule } from "../../../shared";
|
||||
import { UserVerificationModule } from "../../../shared/components/user-verification";
|
||||
|
||||
import { EnrollMasterPasswordReset } from "./enroll-master-password-reset.component";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request";
|
||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Directive, EventEmitter, Output } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { UpdateTwoFactorDuoRequest } from "@bitwarden/common/auth/models/request/update-two-factor-duo.request";
|
||||
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
|
||||
import { UpdateTwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/update-two-factor-email.request";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, NgZone } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
import { UpdateTwoFactorWebAuthnDeleteRequest } from "@bitwarden/common/auth/models/request/update-two-factor-web-authn-delete.request";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { UpdateTwoFactorYubioOtpRequest } from "@bitwarden/common/auth/models/request/update-two-factor-yubio-otp.request";
|
||||
import { TwoFactorYubiKeyResponse } from "@bitwarden/common/auth/models/response/two-factor-yubi-key.response";
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from "./user-verification.module";
|
||||
export * from "./user-verification-prompt.component";
|
||||
export * from "./user-verification.component";
|
||||
export * from "./user-verification-prompt.component";
|
||||
@@ -0,0 +1,20 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog>
|
||||
<span bitDialogTitle>{{ modalTitle | i18n }}</span>
|
||||
<ng-container bitDialogContent>
|
||||
<p bitTypography="body1">{{ confirmDescription | i18n }}</p>
|
||||
<app-user-verification
|
||||
[(invalidSecret)]="invalidSecret"
|
||||
formControlName="secret"
|
||||
></app-user-verification>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||
{{ confirmButtonText | i18n }}
|
||||
</button>
|
||||
<button type="button" bitButton bitFormButton buttonType="secondary" bitDialogClose>
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
</form>
|
||||
@@ -0,0 +1,60 @@
|
||||
import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
|
||||
import { UserVerificationPromptComponent as BaseUserVerificationPrompt } from "@bitwarden/angular/auth/components/user-verification-prompt.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ModalConfig } from "@bitwarden/angular/services/modal.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
export interface UserVerificationPromptParams {
|
||||
confirmDescription: string;
|
||||
confirmButtonText: string;
|
||||
modalTitle: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "user-verification-prompt.component.html",
|
||||
})
|
||||
export class UserVerificationPromptComponent extends BaseUserVerificationPrompt {
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) data: UserVerificationPromptParams,
|
||||
private dialogRef: DialogRef<boolean>,
|
||||
userVerificationService: UserVerificationService,
|
||||
formBuilder: FormBuilder,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
i18nService: I18nService
|
||||
) {
|
||||
// TODO: Remove when BaseUserVerificationPrompt has support for CL
|
||||
const modalConfig: ModalConfig = { data };
|
||||
super(
|
||||
null,
|
||||
modalConfig,
|
||||
userVerificationService,
|
||||
formBuilder,
|
||||
platformUtilsService,
|
||||
i18nService
|
||||
);
|
||||
}
|
||||
|
||||
override close(success: boolean) {
|
||||
this.dialogRef.close(success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strongly typed helper to open a UserVerificationPrompt
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param config Configuration for the dialog
|
||||
*/
|
||||
export const openUserVerificationPrompt = (
|
||||
dialogService: DialogServiceAbstraction,
|
||||
config: DialogConfig<UserVerificationPromptParams>
|
||||
) => {
|
||||
return dialogService.open<boolean, UserVerificationPromptParams>(
|
||||
UserVerificationPromptComponent,
|
||||
config
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<ng-container *ngIf="!usesKeyConnector">
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "masterPass" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
id="masterPassword"
|
||||
type="password"
|
||||
name="MasterPasswordHash"
|
||||
[formControl]="secret"
|
||||
appAutofocus
|
||||
appInputVerbatim
|
||||
/>
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="usesKeyConnector">
|
||||
<div class="tw-mb-6">
|
||||
<label class="tw-block">{{ "sendVerificationCode" | i18n }}</label>
|
||||
<button type="button" bitButton buttonType="secondary" [bitAction]="requestOTP" appAutofocus>
|
||||
{{ "sendCode" | i18n }}
|
||||
</button>
|
||||
<span class="tw-ml-2 tw-text-success" role="alert" @sent *ngIf="sentCode">
|
||||
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
|
||||
{{ "codeSent" | i18n }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "verificationCode" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
type="text"
|
||||
id="verificationCode"
|
||||
name="verificationCode"
|
||||
[formControl]="secret"
|
||||
appInputVerbatim
|
||||
/>
|
||||
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</ng-container>
|
||||
@@ -1,12 +1,13 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import { SharedModule } from "../../shared.module";
|
||||
import { SharedModule } from "../../../../shared/shared.module";
|
||||
|
||||
import { UserVerificationPromptComponent } from "./user-verification-prompt.component";
|
||||
import { UserVerificationComponent } from "./user-verification.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule],
|
||||
imports: [SharedModule, FormsModule, ReactiveFormsModule],
|
||||
declarations: [UserVerificationComponent, UserVerificationPromptComponent],
|
||||
exports: [UserVerificationComponent, UserVerificationPromptComponent],
|
||||
})
|
||||
@@ -4,8 +4,8 @@ import { Router } from "@angular/router";
|
||||
import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "@bitwarden/angular/auth/components/update-password.component";
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
||||
@@ -2,10 +2,10 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { ModalConfig } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationApiKeyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { OrganizationApiKeyRequest } from "@bitwarden/common/admin-console/models/request/organization-api-key.request";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { ApiKeyResponse } from "@bitwarden/common/auth/models/response/api-key.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { UserVerificationModule } from "../../auth/shared/components/user-verification";
|
||||
import { LooseComponentsModule, SharedModule } from "../../shared";
|
||||
import { UserVerificationModule } from "../../shared/components/user-verification";
|
||||
|
||||
import { AdjustSubscription } from "./adjust-subscription.component";
|
||||
import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
import { ApiKeyResponse } from "@bitwarden/common/auth/models/response/api-key.response";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, Input } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
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";
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="confirmUserTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()">
|
||||
<h2 class="tw-my-6 tw-px-3.5 tw-font-semibold" id="modalTitle | i18n ">
|
||||
{{ modalTitle | i18n | uppercase }}
|
||||
</h2>
|
||||
<div class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-p-3.5">
|
||||
{{ confirmDescription | i18n }}
|
||||
</div>
|
||||
<div class="tw-p-3.5">
|
||||
<app-user-verification ngDefaultControl [formControl]="secret" name="secret">
|
||||
</app-user-verification>
|
||||
</div>
|
||||
<div
|
||||
class="tw-border-0 tw-border-t tw-border-solid tw-border-secondary-300 tw-bg-background-alt tw-p-3.5"
|
||||
>
|
||||
<button type="button" bitButton buttonType="primary" type="submit" appBlurClick>
|
||||
<span>{{ confirmButtonText | i18n }}</span>
|
||||
</button>
|
||||
<button type="button" bitButton buttonType="secondary" data-dismiss="modal">
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { UserVerificationPromptComponent as BaseUserVerificationPrompt } from "@bitwarden/angular/auth/components/user-verification-prompt.component";
|
||||
|
||||
@Component({
|
||||
templateUrl: "user-verification-prompt.component.html",
|
||||
})
|
||||
export class UserVerificationPromptComponent extends BaseUserVerificationPrompt {}
|
||||
@@ -1,46 +0,0 @@
|
||||
<ng-container *ngIf="!usesKeyConnector">
|
||||
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
|
||||
<input
|
||||
id="masterPassword"
|
||||
type="password"
|
||||
name="MasterPasswordHash"
|
||||
class="form-control"
|
||||
[formControl]="secret"
|
||||
required
|
||||
appAutofocus
|
||||
appInputVerbatim
|
||||
/>
|
||||
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="usesKeyConnector">
|
||||
<div class="form-group">
|
||||
<label class="d-block">{{ "sendVerificationCode" | i18n }}</label>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
(click)="requestOTP()"
|
||||
[disabled]="disableRequestOTP"
|
||||
>
|
||||
{{ "sendCode" | i18n }}
|
||||
</button>
|
||||
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
|
||||
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
|
||||
{{ "codeSent" | i18n }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="verificationCode">{{ "verificationCode" | i18n }}</label>
|
||||
<input
|
||||
id="verificationCode"
|
||||
type="input"
|
||||
name="verificationCode"
|
||||
class="form-control"
|
||||
[formControl]="secret"
|
||||
required
|
||||
appAutofocus
|
||||
appInputVerbatim
|
||||
/>
|
||||
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
@@ -43,6 +43,7 @@ import { TwoFactorVerifyComponent } from "../auth/settings/two-factor-verify.com
|
||||
import { TwoFactorWebAuthnComponent } from "../auth/settings/two-factor-webauthn.component";
|
||||
import { TwoFactorYubiKeyComponent } from "../auth/settings/two-factor-yubikey.component";
|
||||
import { VerifyEmailComponent } from "../auth/settings/verify-email.component";
|
||||
import { UserVerificationModule } from "../auth/shared/components/user-verification";
|
||||
import { SsoComponent } from "../auth/sso.component";
|
||||
import { TwoFactorOptionsComponent } from "../auth/two-factor-options.component";
|
||||
import { TwoFactorComponent } from "../auth/two-factor.component";
|
||||
@@ -109,7 +110,6 @@ import { AttachmentsComponent as OrgAttachmentsComponent } from "../vault/org-va
|
||||
import { CollectionsComponent as OrgCollectionsComponent } from "../vault/org-vault/collections.component";
|
||||
|
||||
import { AccountFingerprintComponent } from "./components/account-fingerprint/account-fingerprint.component";
|
||||
import { UserVerificationModule } from "./components/user-verification";
|
||||
import { SharedModule } from "./shared.module";
|
||||
|
||||
// Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left.
|
||||
@@ -234,6 +234,7 @@ import { SharedModule } from "./shared.module";
|
||||
LowKdfComponent,
|
||||
],
|
||||
exports: [
|
||||
UserVerificationModule,
|
||||
PremiumBadgeComponent,
|
||||
AcceptEmergencyComponent,
|
||||
AcceptOrganizationComponent,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ExportComponent as BaseExportComponent } from "@bitwarden/angular/tools/export/components/export.component";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { EncryptedExportType } 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";
|
||||
@@ -15,7 +15,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export";
|
||||
|
||||
import { UserVerificationPromptComponent } from "../../shared/components/user-verification";
|
||||
import { openUserVerificationPrompt } from "../../auth/shared/components/user-verification";
|
||||
|
||||
@Component({
|
||||
selector: "app-export",
|
||||
@@ -37,7 +37,6 @@ export class ExportComponent extends BaseExportComponent {
|
||||
userVerificationService: UserVerificationService,
|
||||
formBuilder: UntypedFormBuilder,
|
||||
fileDownloadService: FileDownloadService,
|
||||
private modalService: ModalService,
|
||||
dialogService: DialogServiceAbstraction
|
||||
) {
|
||||
super(
|
||||
@@ -101,8 +100,7 @@ export class ExportComponent extends BaseExportComponent {
|
||||
confirmDescription = "encExportKeyWarningDesc";
|
||||
}
|
||||
|
||||
const ref = this.modalService.open(UserVerificationPromptComponent, {
|
||||
allowMultipleModals: true,
|
||||
const ref = openUserVerificationPrompt(this.dialogService, {
|
||||
data: {
|
||||
confirmDescription: confirmDescription,
|
||||
confirmButtonText: "exportVault",
|
||||
@@ -114,7 +112,7 @@ export class ExportComponent extends BaseExportComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
return ref.onClosedPromise();
|
||||
return firstValueFrom(ref.closed);
|
||||
}
|
||||
|
||||
get isFileEncryptedExport() {
|
||||
|
||||
@@ -22,6 +22,19 @@
|
||||
<input bitInput appAutofocus formControlName="name" />
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field *ngIf="showOrgSelector">
|
||||
<bit-label>{{ "organization" | i18n }}</bit-label>
|
||||
<bit-select bitInput formControlName="selectedOrg">
|
||||
<bit-option
|
||||
*ngFor="let org of organizations$ | async"
|
||||
icon="bwi-business"
|
||||
[value]="org.id"
|
||||
[label]="org.name"
|
||||
>
|
||||
</bit-option>
|
||||
</bit-select>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "externalId" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="externalId" />
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { combineLatest, of, shareReplay, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import {
|
||||
combineLatest,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
shareReplay,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
|
||||
import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog";
|
||||
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
|
||||
@@ -10,6 +19,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CollectionResponse } from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { BitValidators } from "@bitwarden/components";
|
||||
|
||||
@@ -35,9 +46,16 @@ export interface CollectionDialogParams {
|
||||
organizationId: string;
|
||||
initialTab?: CollectionDialogTabType;
|
||||
parentCollectionId?: string;
|
||||
showOrgSelector?: boolean;
|
||||
collectionIds?: string[];
|
||||
}
|
||||
|
||||
export enum CollectionDialogResult {
|
||||
export interface CollectionDialogResult {
|
||||
action: CollectionDialogAction;
|
||||
collection: CollectionResponse;
|
||||
}
|
||||
|
||||
export enum CollectionDialogAction {
|
||||
Saved = "saved",
|
||||
Canceled = "canceled",
|
||||
Deleted = "deleted",
|
||||
@@ -48,6 +66,7 @@ export enum CollectionDialogResult {
|
||||
})
|
||||
export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
protected organizations$: Observable<Organization[]>;
|
||||
|
||||
protected tabIndex: CollectionDialogTabType;
|
||||
protected loading = true;
|
||||
@@ -56,11 +75,13 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
protected nestOptions: CollectionView[] = [];
|
||||
protected accessItems: AccessItemView[] = [];
|
||||
protected deletedParentName: string | undefined;
|
||||
protected showOrgSelector = false;
|
||||
protected formGroup = this.formBuilder.group({
|
||||
name: ["", [Validators.required, BitValidators.forbiddenCharacters(["/"])]],
|
||||
externalId: "",
|
||||
parent: undefined as string | undefined,
|
||||
access: [[] as AccessItemValue[]],
|
||||
selectedOrg: "",
|
||||
});
|
||||
protected PermissionMode = PermissionMode;
|
||||
|
||||
@@ -79,8 +100,31 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.tabIndex = params.initialTab ?? CollectionDialogTabType.Info;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const organization$ = of(this.organizationService.get(this.params.organizationId)).pipe(
|
||||
async ngOnInit() {
|
||||
// Opened from the individual vault
|
||||
if (this.params.showOrgSelector) {
|
||||
this.showOrgSelector = true;
|
||||
this.formGroup.controls.selectedOrg.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((id) => this.loadOrg(id, this.params.collectionIds));
|
||||
this.organizations$ = this.organizationService.organizations$.pipe(
|
||||
map((orgs) =>
|
||||
orgs
|
||||
.filter((o) => o.canCreateNewCollections)
|
||||
.sort(Utils.getSortFunction(this.i18nService, "name"))
|
||||
)
|
||||
);
|
||||
// patchValue will trigger a call to loadOrg() in this case, so no need to call it again here
|
||||
this.formGroup.patchValue({ selectedOrg: this.params.organizationId });
|
||||
} else {
|
||||
// Opened from the org vault
|
||||
this.formGroup.patchValue({ selectedOrg: this.params.organizationId });
|
||||
this.loadOrg(this.params.organizationId, this.params.collectionIds);
|
||||
}
|
||||
}
|
||||
|
||||
async loadOrg(orgId: string, collectionIds: string[]) {
|
||||
const organization$ = of(this.organizationService.get(orgId)).pipe(
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
);
|
||||
const groups$ = organization$.pipe(
|
||||
@@ -89,20 +133,19 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
return of([] as GroupView[]);
|
||||
}
|
||||
|
||||
return this.groupService.getAll(this.params.organizationId);
|
||||
return this.groupService.getAll(orgId);
|
||||
})
|
||||
);
|
||||
|
||||
combineLatest({
|
||||
organization: organization$,
|
||||
collections: this.collectionService.getAll(this.params.organizationId),
|
||||
collections: this.collectionService.getAll(orgId),
|
||||
collectionDetails: this.params.collectionId
|
||||
? this.collectionService.get(this.params.organizationId, this.params.collectionId)
|
||||
? this.collectionService.get(orgId, this.params.collectionId)
|
||||
: of(null),
|
||||
groups: groups$,
|
||||
users: this.organizationUserService.getAllUsers(this.params.organizationId),
|
||||
users: this.organizationUserService.getAllUsers(orgId),
|
||||
})
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.pipe(takeUntil(this.formGroup.controls.selectedOrg.valueChanges), takeUntil(this.destroy$))
|
||||
.subscribe(({ organization, collections, collectionDetails, groups, users }) => {
|
||||
this.organization = organization;
|
||||
this.accessItems = [].concat(
|
||||
@@ -110,6 +153,10 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
users.data.map(mapUserToAccessItemView)
|
||||
);
|
||||
|
||||
if (collectionIds) {
|
||||
collections = collections.filter((c) => collectionIds.includes(c.id));
|
||||
}
|
||||
|
||||
if (this.params.collectionId) {
|
||||
this.collection = collections.find((c) => c.id === this.collectionId);
|
||||
this.nestOptions = collections.filter((c) => c.id !== this.collectionId);
|
||||
@@ -149,7 +196,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
protected async cancel() {
|
||||
this.close(CollectionDialogResult.Canceled);
|
||||
this.close(CollectionDialogAction.Canceled);
|
||||
}
|
||||
|
||||
protected submit = async () => {
|
||||
@@ -168,7 +215,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
const collectionView = new CollectionAdminView();
|
||||
collectionView.id = this.params.collectionId;
|
||||
collectionView.organizationId = this.params.organizationId;
|
||||
collectionView.organizationId = this.formGroup.controls.selectedOrg.value;
|
||||
collectionView.externalId = this.formGroup.controls.externalId.value;
|
||||
collectionView.groups = this.formGroup.controls.access.value
|
||||
.filter((v) => v.type === AccessItemType.Group)
|
||||
@@ -184,7 +231,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
collectionView.name = this.formGroup.controls.name.value;
|
||||
}
|
||||
|
||||
await this.collectionService.save(collectionView);
|
||||
const savedCollection = await this.collectionService.save(collectionView);
|
||||
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
@@ -195,7 +242,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
)
|
||||
);
|
||||
|
||||
this.close(CollectionDialogResult.Saved);
|
||||
this.close(CollectionDialogAction.Saved, savedCollection);
|
||||
};
|
||||
|
||||
protected delete = async () => {
|
||||
@@ -217,7 +264,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.i18nService.t("deletedCollectionId", this.collection?.name)
|
||||
);
|
||||
|
||||
this.close(CollectionDialogResult.Deleted);
|
||||
this.close(CollectionDialogAction.Deleted);
|
||||
};
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@@ -225,8 +272,8 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
private close(result: CollectionDialogResult) {
|
||||
this.dialogRef.close(result);
|
||||
private close(action: CollectionDialogAction, collection?: CollectionResponse) {
|
||||
this.dialogRef.close({ action, collection } as CollectionDialogResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export class CollectionAdminService {
|
||||
return view;
|
||||
}
|
||||
|
||||
async save(collection: CollectionAdminView): Promise<unknown> {
|
||||
async save(collection: CollectionAdminView): Promise<CollectionResponse> {
|
||||
const request = await this.encrypt(collection);
|
||||
|
||||
let response: CollectionResponse;
|
||||
@@ -61,9 +61,7 @@ export class CollectionAdminService {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Implement upsert when in PS-1083: Collection Service refactors
|
||||
// await this.collectionService.upsert(data);
|
||||
return;
|
||||
return response;
|
||||
}
|
||||
|
||||
async delete(organizationId: string, collectionId: string): Promise<void> {
|
||||
|
||||
@@ -32,7 +32,6 @@ import { OrganizationOptionsComponent } from "./organization-options.component";
|
||||
export class VaultFilterComponent implements OnInit, OnDestroy {
|
||||
filters?: VaultFilterList;
|
||||
@Input() activeFilter: VaultFilter = new VaultFilter();
|
||||
@Output() onAddFolder = new EventEmitter<never>();
|
||||
@Output() onEditFolder = new EventEmitter<FolderFilter>();
|
||||
|
||||
@Input() searchText = "";
|
||||
@@ -142,10 +141,6 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
||||
filter.selectedCollectionNode = collectionNode;
|
||||
};
|
||||
|
||||
addFolder = async (): Promise<void> => {
|
||||
this.onAddFolder.emit();
|
||||
};
|
||||
|
||||
editFolder = async (folder: FolderFilter): Promise<void> => {
|
||||
this.onEditFolder.emit(folder);
|
||||
};
|
||||
@@ -249,10 +244,6 @@ export class VaultFilterComponent implements OnInit, OnDestroy {
|
||||
text: "editFolder",
|
||||
action: this.editFolder,
|
||||
},
|
||||
add: {
|
||||
text: "Add Folder",
|
||||
action: this.addFolder,
|
||||
},
|
||||
};
|
||||
return folderFilterSection;
|
||||
}
|
||||
|
||||
@@ -34,16 +34,6 @@
|
||||
<h3 *ngIf="!headerInfo.isSelectable" class="filter-title">
|
||||
{{ headerNode.node.name | i18n }}
|
||||
</h3>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
*ngIf="showAddButton"
|
||||
(click)="onAdd()"
|
||||
class="text-muted ml-auto add-button"
|
||||
appA11yTitle="{{ addInfo.text | i18n }}"
|
||||
>
|
||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<ul
|
||||
id="{{ headerNode.node.name }}-filters"
|
||||
|
||||
@@ -87,10 +87,6 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy {
|
||||
return this.section.add;
|
||||
}
|
||||
|
||||
get showAddButton() {
|
||||
return this.section.add && !this.section.add.route;
|
||||
}
|
||||
|
||||
get showAddLink() {
|
||||
return this.section.add && this.section.add.route;
|
||||
}
|
||||
|
||||
@@ -40,9 +40,31 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="filter.type !== 'trash'" class="tw-shrink-0">
|
||||
<button type="button" bitButton buttonType="primary" (click)="addCipher()">
|
||||
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
|
||||
{{ "newItem" | i18n }}
|
||||
</button>
|
||||
<div appListDropdown>
|
||||
<button
|
||||
bitButton
|
||||
buttonType="primary"
|
||||
type="button"
|
||||
[bitMenuTriggerFor]="addOptions"
|
||||
id="newItemDropdown"
|
||||
appA11yTitle="{{ 'new' | i18n }}"
|
||||
>
|
||||
{{ "new" | i18n }}<i class="bwi bwi-angle-down tw-ml-2" aria-hidden="true"></i>
|
||||
</button>
|
||||
<bit-menu #addOptions aria-labelledby="newItemDropdown">
|
||||
<button type="button" bitMenuItem (click)="addCipher()">
|
||||
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>
|
||||
{{ "item" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitMenuItem (click)="addFolder()">
|
||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
||||
{{ "folder" | i18n }}
|
||||
</button>
|
||||
<button *ngIf="canCreateCollections" type="button" bitMenuItem (click)="addCollection()">
|
||||
<i class="bwi bwi-fw bwi-collection" aria-hidden="true"></i>
|
||||
{{ "collection" | i18n }}
|
||||
</button>
|
||||
</bit-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,11 +39,26 @@ export class VaultHeaderComponent {
|
||||
*/
|
||||
@Input() collection?: TreeNode<CollectionView>;
|
||||
|
||||
/**
|
||||
* Whether 'Collection' option is shown in the 'New' dropdown
|
||||
*/
|
||||
@Input() canCreateCollections: boolean;
|
||||
|
||||
/**
|
||||
* Emits an event when the new item button is clicked in the header
|
||||
*/
|
||||
@Output() onAddCipher = new EventEmitter<void>();
|
||||
|
||||
/**
|
||||
* Emits an event when the new collection button is clicked in the 'New' dropdown menu
|
||||
*/
|
||||
@Output() onAddCollection = new EventEmitter<null>();
|
||||
|
||||
/**
|
||||
* Emits an event when the new folder button is clicked in the 'New' dropdown menu
|
||||
*/
|
||||
@Output() onAddFolder = new EventEmitter<null>();
|
||||
|
||||
constructor(private i18nService: I18nService) {}
|
||||
|
||||
/**
|
||||
@@ -115,4 +130,12 @@ export class VaultHeaderComponent {
|
||||
protected addCipher() {
|
||||
this.onAddCipher.emit();
|
||||
}
|
||||
|
||||
async addFolder(): Promise<void> {
|
||||
this.onAddFolder.emit();
|
||||
}
|
||||
|
||||
async addCollection(): Promise<void> {
|
||||
this.onAddCollection.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
[activeFilter]="activeFilter"
|
||||
[searchText]="currentSearchText$ | async"
|
||||
(searchTextChanged)="filterSearchText($event)"
|
||||
(onAddFolder)="addFolder()"
|
||||
(onEditFolder)="editFolder($event)"
|
||||
></app-vault-filter>
|
||||
</div>
|
||||
@@ -21,8 +20,11 @@
|
||||
[filter]="filter"
|
||||
[loading]="refreshing && !performingInitialLoad"
|
||||
[organizations]="allOrganizations"
|
||||
[canCreateCollections]="canCreateCollections"
|
||||
[collection]="selectedCollection"
|
||||
(onAddCipher)="addCipher()"
|
||||
(onAddCollection)="addCollection()"
|
||||
(onAddFolder)="addFolder()"
|
||||
></app-vault-header>
|
||||
<app-callout type="warning" *ngIf="activeFilter.isDeleted" icon="bwi-exclamation-triangle">
|
||||
{{ trashCleanupWarning }}
|
||||
|
||||
@@ -54,11 +54,14 @@ import { CollectionService } from "@bitwarden/common/vault/abstractions/collecti
|
||||
import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
|
||||
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
||||
import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { Icons } from "@bitwarden/components";
|
||||
|
||||
import { UpdateKeyComponent } from "../../settings/update-key.component";
|
||||
import { CollectionDialogAction, openCollectionDialog } from "../components/collection-dialog";
|
||||
import { VaultItemEvent } from "../components/vault-items/vault-item-event";
|
||||
import { getNestedCollectionTree } from "../utils/collection-utils";
|
||||
|
||||
@@ -140,6 +143,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected collections: CollectionView[];
|
||||
protected isEmpty: boolean;
|
||||
protected selectedCollection: TreeNode<CollectionView> | undefined;
|
||||
protected canCreateCollections = false;
|
||||
protected currentSearchText$: Observable<string>;
|
||||
|
||||
private searchText$ = new Subject<string>();
|
||||
@@ -234,12 +238,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
const canAccessPremium$ = Utils.asyncToObservable(() =>
|
||||
this.stateService.getCanAccessPremium()
|
||||
).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
const allCollections$ = Utils.asyncToObservable(() =>
|
||||
this.collectionService.getAllDecrypted()
|
||||
).pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
const allCollections$ = Utils.asyncToObservable(() => this.collectionService.getAllDecrypted());
|
||||
const nestedCollections$ = allCollections$.pipe(
|
||||
map((collections) => getNestedCollectionTree(collections)),
|
||||
shareReplay({ refCount: true, bufferSize: 1 })
|
||||
map((collections) => getNestedCollectionTree(collections))
|
||||
);
|
||||
|
||||
this.searchText$
|
||||
@@ -384,6 +385,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.collections = collections;
|
||||
this.selectedCollection = selectedCollection;
|
||||
|
||||
this.canCreateCollections = allOrganizations?.some((o) => o.canCreateNewCollections);
|
||||
|
||||
this.showBulkMove =
|
||||
filter.type !== "trash" &&
|
||||
(filter.organizationId === undefined || filter.organizationId === Unassigned);
|
||||
@@ -639,6 +642,32 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
return childComponent;
|
||||
}
|
||||
|
||||
async addCollection() {
|
||||
const dialog = openCollectionDialog(this.dialogService, {
|
||||
data: {
|
||||
organizationId: this.allOrganizations
|
||||
.filter((o) => o.canCreateNewCollections)
|
||||
.sort(Utils.getSortFunction(this.i18nService, "name"))[0].id,
|
||||
parentCollectionId: this.filter.collectionId,
|
||||
showOrgSelector: true,
|
||||
collectionIds: this.allCollections.map((c) => c.id),
|
||||
},
|
||||
});
|
||||
const result = await lastValueFrom(dialog.closed);
|
||||
if (result.action === CollectionDialogAction.Saved) {
|
||||
if (result.collection) {
|
||||
// Update CollectionService with the new collection
|
||||
const c = new CollectionData(result.collection as CollectionDetailsResponse);
|
||||
await this.collectionService.upsert(c);
|
||||
}
|
||||
this.refresh();
|
||||
} else if (result.action === CollectionDialogAction.Deleted) {
|
||||
// TODO: Remove collection from collectionService when collection
|
||||
// deletion is implemented in the individual vault in AC-1347
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
async cloneCipher(cipher: CipherView) {
|
||||
const component = await this.editCipher(cipher);
|
||||
component.cloneMode = true;
|
||||
|
||||
@@ -60,7 +60,7 @@ import { openEntityEventsDialog } from "../../admin-console/organizations/manage
|
||||
import { VaultFilterService } from "../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service";
|
||||
import { VaultFilter } from "../../vault/individual-vault/vault-filter/shared/models/vault-filter.model";
|
||||
import {
|
||||
CollectionDialogResult,
|
||||
CollectionDialogAction,
|
||||
CollectionDialogTabType,
|
||||
openCollectionDialog,
|
||||
} from "../components/collection-dialog";
|
||||
@@ -866,7 +866,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
const result = await lastValueFrom(dialog.closed);
|
||||
if (result === CollectionDialogResult.Saved || result === CollectionDialogResult.Deleted) {
|
||||
if (
|
||||
result.action === CollectionDialogAction.Saved ||
|
||||
result.action === CollectionDialogAction.Deleted
|
||||
) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
@@ -877,7 +880,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
const result = await lastValueFrom(dialog.closed);
|
||||
if (result === CollectionDialogResult.Saved || result === CollectionDialogResult.Deleted) {
|
||||
if (
|
||||
result.action === CollectionDialogAction.Saved ||
|
||||
result.action === CollectionDialogAction.Deleted
|
||||
) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -964,8 +964,14 @@
|
||||
"confirmVaultExport": {
|
||||
"message": "Confirm vault export"
|
||||
},
|
||||
"confirmSecretsExport": {
|
||||
"message": "Confirm secrets export"
|
||||
},
|
||||
"exportWarningDesc": {
|
||||
"message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it."
|
||||
},
|
||||
"exportSecretsWarningDesc": {
|
||||
"message": "This export contains your secrets data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it."
|
||||
},
|
||||
"encExportKeyWarningDesc": {
|
||||
"message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file."
|
||||
@@ -979,6 +985,9 @@
|
||||
"exportVault": {
|
||||
"message": "Export vault"
|
||||
},
|
||||
"exportSecrets": {
|
||||
"message": "Export secrets"
|
||||
},
|
||||
"fileFormat": {
|
||||
"message": "File format"
|
||||
},
|
||||
@@ -2657,6 +2666,12 @@
|
||||
"failedLogin2fa": {
|
||||
"message": "Login attempt failed with incorrect two-step login."
|
||||
},
|
||||
"incorrectPassword": {
|
||||
"message": "Incorrect password"
|
||||
},
|
||||
"incorrectCode": {
|
||||
"message": "Incorrect code"
|
||||
},
|
||||
"exportedVault": {
|
||||
"message": "Vault exported"
|
||||
},
|
||||
@@ -6182,10 +6197,6 @@
|
||||
"message": "Access token created and copied to clipboard",
|
||||
"description": "Notification to inform the user that the access token has been created and copied to the clipboard."
|
||||
},
|
||||
"accessTokenPermissionsBetaNotification": {
|
||||
"message": "Permissions management is unavailable for beta.",
|
||||
"description": "Notification to inform the user that the feature for managing access token permissions is not available in the beta version."
|
||||
},
|
||||
"revokeAccessToken": {
|
||||
"message": "Revoke access token",
|
||||
"description": "Invalidates / cancels an access token and as such removes access to secrets for the client application."
|
||||
|
||||
Reference in New Issue
Block a user