1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-21 20:04:02 +00:00

add support for export-scope-callout.component to conditionally render organizational export message

• use config service to capture feature flag status
• use platform service and routing to determine admin console context
• use the above two variables to conditionally render export descriptions added to locale files
This commit is contained in:
John Harrington
2025-09-23 08:14:25 -07:00
parent 3ca1395472
commit 389c7a57f5
5 changed files with 111 additions and 25 deletions

View File

@@ -3193,6 +3193,24 @@
}
}
},
"exportingOrganizationVaultFromPasswordManagerWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"exportingOrganizationVaultFromAdminConsoleWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported. My items collection will not be included.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"error": {
"message": "Error"
},

View File

@@ -2654,6 +2654,24 @@
}
}
},
"exportingOrganizationVaultFromPasswordManagerWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"exportingOrganizationVaultFromAdminConsoleWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported. My items collection will not be included.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"locked": {
"message": "Locked"
},

View File

@@ -6972,6 +6972,24 @@
}
}
},
"exportingOrganizationVaultFromPasswordManagerWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"exportingOrganizationVaultFromAdminConsoleWithDataOwnershipDesc": {
"message": "Only the organization vault associated with $ORGANIZATION$ will be exported. My items collection will not be included.",
"placeholders": {
"organization": {
"content": "$1",
"example": "My Org Name"
}
}
},
"accessDenied": {
"message": "Access denied. You do not have permission to view this page."
},

View File

@@ -74,7 +74,7 @@ const FALSE = false as boolean;
*/
export const DefaultFeatureFlagValue = {
/* Admin Console Team */
[FeatureFlag.CreateDefaultLocation]: FALSE,
[FeatureFlag.CreateDefaultLocation]: true,
[FeatureFlag.CollectionVaultRefactor]: FALSE,
/* Autofill */

View File

@@ -1,7 +1,8 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, effect, input } from "@angular/core";
import { Component, Optional, effect, input } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom, map } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
@@ -11,6 +12,10 @@ import {
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { ClientType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { CalloutModule } from "@bitwarden/components";
@Component({
@@ -34,6 +39,9 @@ export class ExportScopeCalloutComponent {
constructor(
protected organizationService: OrganizationService,
protected accountService: AccountService,
private configService: ConfigService,
private platformUtilsService: PlatformUtilsService,
@Optional() private router?: Router,
) {
effect(async () => {
this.show = false;
@@ -42,30 +50,54 @@ export class ExportScopeCalloutComponent {
});
}
private get isAdminConsoleContext(): boolean {
const isWeb = this.platformUtilsService.getClientType?.() === ClientType.Web;
if (!isWeb || !this.router) {
return false;
}
try {
const url = this.router.url ?? "";
return url.includes("/organizations/");
} catch {
return false;
}
}
private async getScopeMessage(organizationId: string, exportFormat: string): Promise<void> {
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
this.scopeConfig =
organizationId != null
? {
title: "exportingOrganizationVaultTitle",
description: "exportingOrganizationVaultDesc",
scopeIdentifier: (
await firstValueFrom(
this.organizationService
.organizations$(userId)
.pipe(getOrganizationById(organizationId)),
)
).name,
}
: {
title: "exportingPersonalVaultTitle",
description:
exportFormat == "zip"
? "exportingIndividualVaultWithAttachmentsDescription"
: "exportingIndividualVaultDescription",
scopeIdentifier: await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.email)),
),
};
const enforceOrgDataOwnershipPolicyEnabled = await this.configService.getFeatureFlag(
FeatureFlag.CreateDefaultLocation,
);
const orgExportDescription = enforceOrgDataOwnershipPolicyEnabled
? this.isAdminConsoleContext
? "exportingOrganizationVaultFromAdminConsoleWithDataOwnershipDesc"
: "exportingOrganizationVaultFromPasswordManagerWithDataOwnershipDesc"
: "exportingOrganizationVaultDesc";
if (organizationId != null) {
// exporting from organizational vault
const org = await firstValueFrom(
this.organizationService.organizations$(userId).pipe(getOrganizationById(organizationId)),
);
this.scopeConfig = {
title: "exportingOrganizationVaultTitle",
description: orgExportDescription,
scopeIdentifier: org?.name ?? "",
};
} else {
this.scopeConfig = {
// exporting from individual vault
title: "exportingPersonalVaultTitle",
description:
exportFormat === "zip"
? "exportingIndividualVaultWithAttachmentsDescription"
: "exportingIndividualVaultDescription",
scopeIdentifier:
(await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.email)))) ??
"",
};
}
}
}