mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-15154] Domain verification copy update (#12217)
* refactor: update domain verification terminology to claimed domains * feat: add description for claimed domains in domain verification * Add informational link to claimed domains description in domain verification component * Update domain verification references to claimed domains in organization layout and SSO component * Add validation message for invalid domain name format in domain verification * Add domain claim messages and descriptions to localization files * Update domain verification navigation text based on feature flag * Update domain verification dialog to support account deprovisioning feature flag * Update domain verification component to support account deprovisioning feature flag * Refactor domain verification dialog to use synchronous feature flag for account deprovisioning * Refactor domain verification routing to resolve title based on account deprovisioning feature flag * Update SSO component to conditionally display domain verification link based on account deprovisioning feature flag * Update event service to conditionally display domain verification messages based on account deprovisioning feature flag * Update domain verification warning message * Refactor domain verification navigation text handling based on account deprovisioning feature flag * Refactor domain verification dialog to use observable for account deprovisioning feature flag * Refactor domain verification component to use observable for account deprovisioning feature flag
This commit is contained in:
@@ -6,24 +6,37 @@
|
||||
<bit-dialog [dialogSize]="'default'" [disablePadding]="false">
|
||||
<span bitDialogTitle>
|
||||
<span *ngIf="!data.orgDomain">{{ "newDomain" | i18n }}</span>
|
||||
<span *ngIf="data.orgDomain"> {{ "verifyDomain" | i18n }}</span>
|
||||
<span *ngIf="data.orgDomain">
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain") | i18n
|
||||
}}</span
|
||||
>
|
||||
|
||||
<span *ngIf="data.orgDomain" class="tw-text-xs tw-text-muted">{{
|
||||
data.orgDomain.domainName
|
||||
}}</span>
|
||||
|
||||
<span *ngIf="data?.orgDomain && !data.orgDomain?.verifiedDate" bitBadge variant="warning">{{
|
||||
"domainStatusUnverified" | i18n
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusUnderVerification"
|
||||
: "domainStatusUnverified"
|
||||
) | i18n
|
||||
}}</span>
|
||||
<span *ngIf="data?.orgDomain && data?.orgDomain?.verifiedDate" bitBadge variant="success">{{
|
||||
"domainStatusVerified" | i18n
|
||||
((accountDeprovisioningEnabled$ | async) ? "domainStatusClaimed" : "domainStatusVerified")
|
||||
| i18n
|
||||
}}</span>
|
||||
</span>
|
||||
<div bitDialogContent>
|
||||
<bit-form-field>
|
||||
<bit-label>{{ "domainName" | i18n }}</bit-label>
|
||||
<input bitInput appAutofocus formControlName="domainName" [showErrorsWhenDisabled]="true" />
|
||||
<bit-hint>{{ "domainNameInputHint" | i18n }}</bit-hint>
|
||||
<bit-hint>{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "claimDomainNameInputHint"
|
||||
: "domainNameInputHint"
|
||||
) | i18n
|
||||
}}</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field *ngIf="data?.orgDomain">
|
||||
@@ -42,18 +55,29 @@
|
||||
<bit-callout
|
||||
*ngIf="data?.orgDomain && !data?.orgDomain?.verifiedDate"
|
||||
type="info"
|
||||
title="{{ 'automaticDomainVerification' | i18n }}"
|
||||
title="{{
|
||||
(accountDeprovisioningEnabled$ | async)
|
||||
? ('automaticClaimedDomains' | i18n | uppercase)
|
||||
: ('automaticDomainVerification' | i18n)
|
||||
}}"
|
||||
>
|
||||
{{ "automaticDomainVerificationProcess" | i18n }}
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "automaticDomainClaimProcess"
|
||||
: "automaticDomainVerificationProcess"
|
||||
) | i18n
|
||||
}}
|
||||
</bit-callout>
|
||||
</div>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||
<span *ngIf="!data?.orgDomain">{{ "next" | i18n }}</span>
|
||||
<span *ngIf="data?.orgDomain && !data?.orgDomain?.verifiedDate">{{
|
||||
"verifyDomain" | i18n
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain") | i18n
|
||||
}}</span>
|
||||
<span *ngIf="data?.orgDomain?.verifiedDate">{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "reclaimDomain" : "reverifyDomain") | i18n
|
||||
}}</span>
|
||||
<span *ngIf="data?.orgDomain?.verifiedDate">{{ "reverifyDomain" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton buttonType="secondary" (click)="dialogRef.close()" type="button">
|
||||
{{ "cancel" | i18n }}
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { Subject, takeUntil, Observable, firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||
import { OrgDomainServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
|
||||
import { OrganizationDomainResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain.response";
|
||||
import { OrganizationDomainRequest } from "@bitwarden/common/admin-console/services/organization-domain/requests/organization-domain.request";
|
||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -31,20 +33,8 @@ export interface DomainAddEditDialogData {
|
||||
export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
private componentDestroyed$: Subject<void> = new Subject();
|
||||
|
||||
domainForm: FormGroup = this.formBuilder.group({
|
||||
domainName: [
|
||||
"",
|
||||
[
|
||||
Validators.required,
|
||||
domainNameValidator(this.i18nService.t("invalidDomainNameMessage")),
|
||||
uniqueInArrayValidator(
|
||||
this.data.existingDomainNames,
|
||||
this.i18nService.t("duplicateDomainError"),
|
||||
),
|
||||
],
|
||||
],
|
||||
txt: [{ value: null, disabled: true }],
|
||||
});
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
domainForm: FormGroup;
|
||||
|
||||
get domainNameCtrl(): FormControl {
|
||||
return this.domainForm.controls.domainName as FormControl;
|
||||
@@ -69,11 +59,34 @@ export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
private validationService: ValidationService,
|
||||
private dialogService: DialogService,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
|
||||
// Angular Method Implementations
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.domainForm = this.formBuilder.group({
|
||||
domainName: [
|
||||
"",
|
||||
[
|
||||
Validators.required,
|
||||
domainNameValidator(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? this.i18nService.t("invalidDomainNameClaimMessage")
|
||||
: this.i18nService.t("invalidDomainNameMessage"),
|
||||
),
|
||||
uniqueInArrayValidator(
|
||||
this.data.existingDomainNames,
|
||||
this.i18nService.t("duplicateDomainError"),
|
||||
),
|
||||
],
|
||||
],
|
||||
txt: [{ value: null, disabled: true }],
|
||||
});
|
||||
// If we have data.orgDomain, then editing, otherwise creating new domain
|
||||
await this.populateForm();
|
||||
}
|
||||
@@ -211,13 +224,22 @@ export class DomainAddEditDialogComponent implements OnInit, OnDestroy {
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("domainVerified"),
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainClaimed"
|
||||
: "domainVerified",
|
||||
),
|
||||
});
|
||||
this.dialogRef.close();
|
||||
} else {
|
||||
this.domainNameCtrl.setErrors({
|
||||
errorPassthrough: {
|
||||
message: this.i18nService.t("domainNotVerified", this.domainNameCtrl.value),
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainNotClaimed"
|
||||
: "domainNotVerified",
|
||||
this.domainNameCtrl.value,
|
||||
),
|
||||
},
|
||||
});
|
||||
// For the case where user opens dialog and reverifies when domain name formControl disabled.
|
||||
|
||||
@@ -4,6 +4,20 @@
|
||||
</button>
|
||||
</app-header>
|
||||
|
||||
<p class="tw-text-muted tw-w-1/3" *ngIf="accountDeprovisioningEnabled$ | async">
|
||||
{{ "claimedDomainsDesc" | i18n }}
|
||||
<a
|
||||
bitLink
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
appA11yTitle="{{ 'learnMore' | i18n }}"
|
||||
href="https://bitwarden.com/help/claimed-accounts/"
|
||||
slot="end"
|
||||
>
|
||||
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<ng-container *ngIf="loading">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin text-muted"
|
||||
@@ -40,10 +54,16 @@
|
||||
</td>
|
||||
<td bitCell>
|
||||
<span *ngIf="!orgDomain?.verifiedDate" bitBadge variant="warning">{{
|
||||
"domainStatusUnverified" | i18n
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusUnderVerification"
|
||||
: "domainStatusUnverified"
|
||||
) | i18n
|
||||
}}</span>
|
||||
<span *ngIf="orgDomain?.verifiedDate" bitBadge variant="success">{{
|
||||
"domainStatusVerified" | i18n
|
||||
((accountDeprovisioningEnabled$ | async)
|
||||
? "domainStatusClaimed"
|
||||
: "domainStatusVerified"
|
||||
) | i18n
|
||||
}}</span>
|
||||
</td>
|
||||
<td bitCell class="tw-text-muted">
|
||||
@@ -70,7 +90,10 @@
|
||||
type="button"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-check" aria-hidden="true"></i>
|
||||
{{ "verifyDomain" | i18n }}
|
||||
{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimDomain" : "verifyDomain")
|
||||
| i18n
|
||||
}}
|
||||
</button>
|
||||
<button bitMenuItem (click)="deleteDomain(orgDomain.id)" type="button">
|
||||
<span class="tw-text-danger">
|
||||
|
||||
@@ -43,6 +43,7 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
|
||||
organizationId: string;
|
||||
orgDomains$: Observable<OrganizationDomainResponse[]>;
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
@@ -54,7 +55,11 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
private policyApiService: PolicyApiServiceAbstraction,
|
||||
) {}
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
async ngOnInit() {
|
||||
@@ -105,7 +110,7 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
organizationDomains.every((domain) => domain.verifiedDate === null)
|
||||
) {
|
||||
await this.dialogService.openSimpleDialog({
|
||||
title: { key: "verified-domain-single-org-warning" },
|
||||
title: { key: "claim-domain-single-org-warning" },
|
||||
content: { key: "single-org-revoked-user-warning" },
|
||||
cancelButtonText: { key: "cancel" },
|
||||
acceptButtonText: { key: "confirm" },
|
||||
@@ -169,13 +174,22 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("domainVerified"),
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainClaimed"
|
||||
: "domainVerified",
|
||||
),
|
||||
});
|
||||
} else {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("domainNotVerified", domainName),
|
||||
message: this.i18nService.t(
|
||||
(await firstValueFrom(this.accountDeprovisioningEnabled$))
|
||||
? "domainNotClaimed"
|
||||
: "domainNotVerified",
|
||||
domainName,
|
||||
),
|
||||
});
|
||||
// Update this item so the last checked date gets updated.
|
||||
await this.updateOrgDomain(orgDomainId);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { inject, NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { authGuard } from "@bitwarden/angular/auth/guards";
|
||||
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { isEnterpriseOrgGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/is-enterprise-org.guard";
|
||||
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
||||
import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-console/organizations/layouts/organization-layout.component";
|
||||
@@ -26,8 +28,13 @@ const routes: Routes = [
|
||||
path: "domain-verification",
|
||||
component: DomainVerificationComponent,
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canManageDomainVerification)],
|
||||
data: {
|
||||
titleId: "domainVerification",
|
||||
resolve: {
|
||||
titleId: async () => {
|
||||
const configService = inject(ConfigService);
|
||||
return (await configService.getFeatureFlag(FeatureFlag.AccountDeprovisioning))
|
||||
? "claimedDomains"
|
||||
: "domainVerification";
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
<input bitInput type="text" formControlName="ssoIdentifier" />
|
||||
<bit-hint>
|
||||
{{ "ssoIdentifierHintPartOne" | i18n }}
|
||||
<a bitLink routerLink="../domain-verification">{{ "domainVerification" | i18n }}</a>
|
||||
<a bitLink routerLink="../domain-verification">{{
|
||||
((accountDeprovisioningEnabled$ | async) ? "claimedDomains" : "domainVerification")
|
||||
| i18n
|
||||
}}</a>
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
Validators,
|
||||
} from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, Subject, takeUntil } from "rxjs";
|
||||
import { concatMap, Observable, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ControlsOf } from "@bitwarden/angular/types/controls-of";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -28,6 +28,7 @@ import { SsoConfigApi } from "@bitwarden/common/auth/models/api/sso-config.api";
|
||||
import { OrganizationSsoRequest } from "@bitwarden/common/auth/models/request/organization-sso.request";
|
||||
import { OrganizationSsoResponse } from "@bitwarden/common/auth/models/response/organization-sso.response";
|
||||
import { SsoConfigView } from "@bitwarden/common/auth/models/view/sso-config.view";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -185,6 +186,8 @@ export class SsoComponent implements OnInit, OnDestroy {
|
||||
return this.ssoConfigForm?.controls?.configType as FormControl;
|
||||
}
|
||||
|
||||
accountDeprovisioningEnabled$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private route: ActivatedRoute,
|
||||
@@ -195,7 +198,11 @@ export class SsoComponent implements OnInit, OnDestroy {
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private configService: ConfigService,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
) {
|
||||
this.accountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.enabledCtrl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((enabled) => {
|
||||
|
||||
Reference in New Issue
Block a user