1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 13:23:34 +00:00

[PM-22107] Update Remove Individual Vault policy dialog (#15323)

* WIP

* switch to signal

* fix ts strict errors

* clean up

* refactor policy list service

* implement vnext component

* refactor to include feature flag check in display()

* CR feedback

* refactor submit to cancel before request is built

* clean up

* Fix typo

---------

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
This commit is contained in:
Brandon Treston
2025-08-06 09:34:43 -04:00
committed by GitHub
parent 61cd0c4f51
commit 29e16fc5e0
17 changed files with 276 additions and 76 deletions

View File

@@ -1,12 +1,12 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Directive, Input, OnInit } from "@angular/core"; import { Directive, Input, OnInit } from "@angular/core";
import { UntypedFormControl, UntypedFormGroup } from "@angular/forms"; import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
import { Observable, of } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request"; import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request";
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response"; import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
export abstract class BasePolicy { export abstract class BasePolicy {
abstract name: string; abstract name: string;
@@ -14,38 +14,56 @@ export abstract class BasePolicy {
abstract type: PolicyType; abstract type: PolicyType;
abstract component: any; abstract component: any;
display(organization: Organization) { /**
return true; * If true, the description will be reused in the policy edit modal. Set this to false if you
* have more complex requirements that you will implement in your template instead.
**/
showDescription: boolean = true;
display(organization: Organization, configService: ConfigService): Observable<boolean> {
return of(true);
} }
} }
@Directive() @Directive()
export abstract class BasePolicyComponent implements OnInit { export abstract class BasePolicyComponent implements OnInit {
@Input() policyResponse: PolicyResponse; @Input() policyResponse: PolicyResponse | undefined;
@Input() policy: BasePolicy; @Input() policy: BasePolicy | undefined;
enabled = new UntypedFormControl(false); enabled = new UntypedFormControl(false);
data: UntypedFormGroup = null; data: UntypedFormGroup | undefined;
ngOnInit(): void { ngOnInit(): void {
this.enabled.setValue(this.policyResponse.enabled); this.enabled.setValue(this.policyResponse?.enabled);
if (this.policyResponse.data != null) { if (this.policyResponse?.data != null) {
this.loadData(); this.loadData();
} }
} }
buildRequest() { buildRequest() {
const request = new PolicyRequest(); if (!this.policy) {
request.enabled = this.enabled.value; throw new Error("Policy was not found");
request.type = this.policy.type; }
request.data = this.buildRequestData();
const request: PolicyRequest = {
type: this.policy.type,
enabled: this.enabled.value,
data: this.buildRequestData(),
};
return Promise.resolve(request); return Promise.resolve(request);
} }
/**
* Enable optional validation before sumitting a respose for policy submission
* */
confirm(): Promise<boolean> | boolean {
return true;
}
protected loadData() { protected loadData() {
this.data.patchValue(this.policyResponse.data ?? {}); this.data?.patchValue(this.policyResponse?.data ?? {});
} }
protected buildRequestData() { protected buildRequestData() {

View File

@@ -3,6 +3,7 @@ export { BasePolicy, BasePolicyComponent } from "./base-policy.component";
export { DisableSendPolicy } from "./disable-send.component"; export { DisableSendPolicy } from "./disable-send.component";
export { MasterPasswordPolicy } from "./master-password.component"; export { MasterPasswordPolicy } from "./master-password.component";
export { PasswordGeneratorPolicy } from "./password-generator.component"; export { PasswordGeneratorPolicy } from "./password-generator.component";
export { vNextOrganizationDataOwnershipPolicy } from "./vnext-organization-data-ownership.component";
export { OrganizationDataOwnershipPolicy } from "./organization-data-ownership.component"; export { OrganizationDataOwnershipPolicy } from "./organization-data-ownership.component";
export { RequireSsoPolicy } from "./require-sso.component"; export { RequireSsoPolicy } from "./require-sso.component";
export { ResetPasswordPolicy } from "./reset-password.component"; export { ResetPasswordPolicy } from "./reset-password.component";

View File

@@ -1,6 +1,10 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { map, Observable } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
@@ -9,6 +13,12 @@ export class OrganizationDataOwnershipPolicy extends BasePolicy {
description = "personalOwnershipPolicyDesc"; description = "personalOwnershipPolicyDesc";
type = PolicyType.OrganizationDataOwnership; type = PolicyType.OrganizationDataOwnership;
component = OrganizationDataOwnershipPolicyComponent; component = OrganizationDataOwnershipPolicyComponent;
display(organization: Organization, configService: ConfigService): Observable<boolean> {
return configService
.getFeatureFlag$(FeatureFlag.CreateDefaultLocation)
.pipe(map((enabled) => !enabled));
}
} }
@Component({ @Component({

View File

@@ -1,38 +1,45 @@
<app-header> <app-header>
@let organization = organization$ | async; @let organization = organization$ | async;
<button @if (isBreadcrumbingEnabled$ | async) {
bitBadge <button
class="!tw-align-middle" bitBadge
(click)="changePlan(organization)" class="!tw-align-middle"
*ngIf="isBreadcrumbingEnabled$ | async" (click)="changePlan(organization)"
slot="title-suffix" slot="title-suffix"
type="button" type="button"
variant="primary" variant="primary"
> >
{{ "upgrade" | i18n }} {{ "upgrade" | i18n }}
</button> </button>
}
</app-header> </app-header>
<bit-container> <bit-container>
<ng-container *ngIf="loading"> @if (loading) {
<i <i
class="bwi bwi-spinner bwi-spin tw-text-muted" class="bwi bwi-spinner bwi-spin tw-text-muted"
title="{{ 'loading' | i18n }}" title="{{ 'loading' | i18n }}"
aria-hidden="true" aria-hidden="true"
></i> ></i>
<span class="tw-sr-only">{{ "loading" | i18n }}</span> <span class="tw-sr-only">{{ "loading" | i18n }}</span>
</ng-container> }
<bit-table *ngIf="!loading"> @if (!loading) {
<ng-template body> <bit-table>
<tr bitRow *ngFor="let p of policies"> <ng-template body>
<td bitCell *ngIf="p.display(organization)" ngPreserveWhitespaces> @for (p of policies; track p.name) {
<button type="button" bitLink (click)="edit(p)">{{ p.name | i18n }}</button> @if (p.display(organization, configService) | async) {
<span bitBadge variant="success" *ngIf="policiesEnabledMap.get(p.type)">{{ <tr bitRow>
"on" | i18n <td bitCell ngPreserveWhitespaces>
}}</span> <button type="button" bitLink (click)="edit(p)">{{ p.name | i18n }}</button>
<small class="tw-text-muted tw-block">{{ p.description | i18n }}</small> @if (policiesEnabledMap.get(p.type)) {
</td> <span bitBadge variant="success">{{ "on" | i18n }}</span>
</tr> }
</ng-template> <small class="tw-text-muted tw-block">{{ p.description | i18n }}</small>
</bit-table> </td>
</tr>
}
}
</ng-template>
</bit-table>
}
</bit-container> </bit-container>

View File

@@ -15,7 +15,6 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response"; import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions"; import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
import { import {
@@ -25,7 +24,7 @@ import {
import { All } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model"; import { All } from "@bitwarden/web-vault/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model";
import { PolicyListService } from "../../core/policy-list.service"; import { PolicyListService } from "../../core/policy-list.service";
import { BasePolicy, RestrictedItemTypesPolicy } from "../policies"; import { BasePolicy } from "../policies";
import { CollectionDialogTabType } from "../shared/components/collection-dialog"; import { CollectionDialogTabType } from "../shared/components/collection-dialog";
import { PolicyEditComponent, PolicyEditDialogResult } from "./policy-edit.component"; import { PolicyEditComponent, PolicyEditDialogResult } from "./policy-edit.component";
@@ -53,7 +52,7 @@ export class PoliciesComponent implements OnInit {
private policyListService: PolicyListService, private policyListService: PolicyListService,
private organizationBillingService: OrganizationBillingServiceAbstraction, private organizationBillingService: OrganizationBillingServiceAbstraction,
private dialogService: DialogService, private dialogService: DialogService,
private configService: ConfigService, protected configService: ConfigService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@@ -71,35 +70,31 @@ export class PoliciesComponent implements OnInit {
await this.load(); await this.load();
// Handle policies component launch from Event message // Handle policies component launch from Event message
/* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */ this.route.queryParams
this.route.queryParams.pipe(first()).subscribe(async (qParams) => { .pipe(first())
if (qParams.policyId != null) { /* eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe */
const policyIdFromEvents: string = qParams.policyId; .subscribe(async (qParams) => {
for (const orgPolicy of this.orgPolicies) { if (qParams.policyId != null) {
if (orgPolicy.id === policyIdFromEvents) { const policyIdFromEvents: string = qParams.policyId;
for (let i = 0; i < this.policies.length; i++) { for (const orgPolicy of this.orgPolicies) {
if (this.policies[i].type === orgPolicy.type) { if (orgPolicy.id === policyIdFromEvents) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. for (let i = 0; i < this.policies.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises if (this.policies[i].type === orgPolicy.type) {
this.edit(this.policies[i]); // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
break; // eslint-disable-next-line @typescript-eslint/no-floating-promises
this.edit(this.policies[i]);
break;
}
} }
break;
} }
break;
} }
} }
} });
});
}); });
} }
async load() { async load() {
if (
(await this.configService.getFeatureFlag(FeatureFlag.RemoveCardItemTypePolicy)) &&
this.policyListService.getPolicies().every((p) => !(p instanceof RestrictedItemTypesPolicy))
) {
this.policyListService.addPolicies([new RestrictedItemTypesPolicy()]);
}
const response = await this.policyApiService.getPolicies(this.organizationId); const response = await this.policyApiService.getPolicies(this.organizationId);
this.orgPolicies = response.data != null && response.data.length > 0 ? response.data : []; this.orgPolicies = response.data != null && response.data.length > 0 ? response.data : [];
this.orgPolicies.forEach((op) => { this.orgPolicies.forEach((op) => {

View File

@@ -22,7 +22,9 @@
<span class="tw-sr-only">{{ "loading" | i18n }}</span> <span class="tw-sr-only">{{ "loading" | i18n }}</span>
</div> </div>
<div [hidden]="loading"> <div [hidden]="loading">
<p bitTypography="body1">{{ policy.description | i18n }}</p> @if (policy.showDescription) {
<p bitTypography="body1">{{ policy.description | i18n }}</p>
}
<ng-template #policyForm></ng-template> <ng-template #policyForm></ng-template>
</div> </div>
</ng-container> </ng-container>

View File

@@ -128,13 +128,20 @@ export class PolicyEditComponent implements AfterViewInit {
} }
submit = async () => { submit = async () => {
if ((await this.policyComponent.confirm()) == false) {
this.dialogRef.close();
return;
}
let request: PolicyRequest; let request: PolicyRequest;
try { try {
request = await this.policyComponent.buildRequest(); request = await this.policyComponent.buildRequest();
} catch (e) { } catch (e) {
this.toastService.showToast({ variant: "error", title: null, message: e.message }); this.toastService.showToast({ variant: "error", title: null, message: e.message });
return; return;
} }
await this.policyApiService.putPolicy(this.data.organizationId, this.data.policy.type, request); await this.policyApiService.putPolicy(this.data.organizationId, this.data.policy.type, request);
this.toastService.showToast({ this.toastService.showToast({
variant: "success", variant: "success",

View File

@@ -1,7 +1,9 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { of } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
@@ -11,8 +13,8 @@ export class RequireSsoPolicy extends BasePolicy {
type = PolicyType.RequireSso; type = PolicyType.RequireSso;
component = RequireSsoPolicyComponent; component = RequireSsoPolicyComponent;
display(organization: Organization) { display(organization: Organization, configService: ConfigService) {
return organization.useSso; return of(organization.useSso);
} }
} }

View File

@@ -1,6 +1,6 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms"; import { FormBuilder } from "@angular/forms";
import { firstValueFrom } from "rxjs"; import { firstValueFrom, of } from "rxjs";
import { import {
getOrganizationById, getOrganizationById,
@@ -10,6 +10,7 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
@@ -19,8 +20,8 @@ export class ResetPasswordPolicy extends BasePolicy {
type = PolicyType.ResetPassword; type = PolicyType.ResetPassword;
component = ResetPasswordPolicyComponent; component = ResetPasswordPolicyComponent;
display(organization: Organization) { display(organization: Organization, configService: ConfigService) {
return organization.useResetPassword; return of(organization.useResetPassword);
} }
} }
@@ -52,6 +53,10 @@ export class ResetPasswordPolicyComponent extends BasePolicyComponent implements
throw new Error("No user found."); throw new Error("No user found.");
} }
if (!this.policyResponse) {
throw new Error("Policies not found");
}
const organization = await firstValueFrom( const organization = await firstValueFrom(
this.organizationService this.organizationService
.organizations$(userId) .organizations$(userId)

View File

@@ -1,6 +1,10 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { Observable } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
@@ -9,6 +13,10 @@ export class RestrictedItemTypesPolicy extends BasePolicy {
description = "restrictedItemTypePolicyDesc"; description = "restrictedItemTypePolicyDesc";
type = PolicyType.RestrictedItemTypes; type = PolicyType.RestrictedItemTypes;
component = RestrictedItemTypesPolicyComponent; component = RestrictedItemTypesPolicyComponent;
display(organization: Organization, configService: ConfigService): Observable<boolean> {
return configService.getFeatureFlag$(FeatureFlag.RemoveCardItemTypePolicy);
}
} }
@Component({ @Component({

View File

@@ -20,6 +20,9 @@ export class SingleOrgPolicyComponent extends BasePolicyComponent implements OnI
async ngOnInit() { async ngOnInit() {
super.ngOnInit(); super.ngOnInit();
if (!this.policyResponse) {
throw new Error("Policies not found");
}
if (!this.policyResponse.canToggleState) { if (!this.policyResponse.canToggleState) {
this.enabled.disable(); this.enabled.disable();
} }

View File

@@ -0,0 +1,57 @@
<p>
{{ "organizationDataOwnershipContent" | i18n }}
<a
bitLink
href="https://bitwarden.com/resources/credential-lifecycle-management/"
target="_blank"
>
{{ "organizationDataOwnershipContentAnchor" | i18n }}.
</a>
</p>
<bit-form-control>
<input type="checkbox" bitCheckbox [formControl]="enabled" id="enabled" />
<bit-label>{{ "turnOn" | i18n }}</bit-label>
</bit-form-control>
<ng-template #dialog>
<bit-simple-dialog background="alt">
<span bitDialogTitle>{{ "organizationDataOwnershipWarningTitle" | i18n }}</span>
<ng-container bitDialogContent>
<div class="tw-text-left tw-overflow-hidden">
{{ "organizationDataOwnershipWarningContentTop" | i18n }}
<div class="tw-flex tw-flex-col tw-p-2">
<ul class="tw-list-disc tw-pl-5 tw-space-y-2 tw-break-words tw-mb-0">
<li>
{{ "organizationDataOwnershipWarning1" | i18n }}
</li>
<li>
{{ "organizationDataOwnershipWarning2" | i18n }}
</li>
<li>
{{ "organizationDataOwnershipWarning3" | i18n }}
</li>
</ul>
</div>
{{ "organizationDataOwnershipWarningContentBottom" | i18n }}
<a
bitLink
href="https://bitwarden.com/resources/credential-lifecycle-management/"
target="_blank"
>
{{ "organizationDataOwnershipContentAnchor" | i18n }}.
</a>
</div>
</ng-container>
<ng-container bitDialogFooter>
<span class="tw-flex tw-gap-2">
<button bitButton buttonType="primary" [bitDialogClose]="true" type="submit">
{{ "continue" | i18n }}
</button>
<button bitButton buttonType="secondary" [bitDialogClose]="false" type="button">
{{ "cancel" | i18n }}
</button>
</span>
</ng-container>
</bit-simple-dialog>
</ng-template>

View File

@@ -0,0 +1,50 @@
import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core";
import { lastValueFrom, Observable } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { DialogService } from "@bitwarden/components";
import { SharedModule } from "../../../shared";
import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
export class vNextOrganizationDataOwnershipPolicy extends BasePolicy {
name = "organizationDataOwnership";
description = "organizationDataOwnershipDesc";
type = PolicyType.OrganizationDataOwnership;
component = vNextOrganizationDataOwnershipPolicyComponent;
showDescription = false;
override display(organization: Organization, configService: ConfigService): Observable<boolean> {
return configService.getFeatureFlag$(FeatureFlag.CreateDefaultLocation);
}
}
@Component({
selector: "vnext-policy-organization-data-ownership",
templateUrl: "vnext-organization-data-ownership.component.html",
standalone: true,
imports: [SharedModule],
})
export class vNextOrganizationDataOwnershipPolicyComponent
extends BasePolicyComponent
implements OnInit
{
constructor(private dialogService: DialogService) {
super();
}
@ViewChild("dialog", { static: true }) warningContent!: TemplateRef<unknown>;
override async confirm(): Promise<boolean> {
if (this.policyResponse?.enabled && !this.enabled.value) {
const dialogRef = this.dialogService.open(this.warningContent);
const result = await lastValueFrom(dialogRef.closed);
return Boolean(result);
}
return true;
}
}

View File

@@ -35,12 +35,14 @@ import {
MasterPasswordPolicy, MasterPasswordPolicy,
PasswordGeneratorPolicy, PasswordGeneratorPolicy,
OrganizationDataOwnershipPolicy, OrganizationDataOwnershipPolicy,
vNextOrganizationDataOwnershipPolicy,
RequireSsoPolicy, RequireSsoPolicy,
ResetPasswordPolicy, ResetPasswordPolicy,
SendOptionsPolicy, SendOptionsPolicy,
SingleOrgPolicy, SingleOrgPolicy,
TwoFactorAuthenticationPolicy, TwoFactorAuthenticationPolicy,
RemoveUnlockWithPinPolicy, RemoveUnlockWithPinPolicy,
RestrictedItemTypesPolicy,
} from "./admin-console/organizations/policies"; } from "./admin-console/organizations/policies";
const BroadcasterSubscriptionId = "AppComponent"; const BroadcasterSubscriptionId = "AppComponent";
@@ -244,8 +246,10 @@ export class AppComponent implements OnDestroy, OnInit {
new SingleOrgPolicy(), new SingleOrgPolicy(),
new RequireSsoPolicy(), new RequireSsoPolicy(),
new OrganizationDataOwnershipPolicy(), new OrganizationDataOwnershipPolicy(),
new vNextOrganizationDataOwnershipPolicy(),
new DisableSendPolicy(), new DisableSendPolicy(),
new SendOptionsPolicy(), new SendOptionsPolicy(),
new RestrictedItemTypesPolicy(),
]); ]);
} }

View File

@@ -5429,6 +5429,37 @@
"organizationDataOwnership": { "organizationDataOwnership": {
"message": "Enforce organization data ownership" "message": "Enforce organization data ownership"
}, },
"organizationDataOwnershipDesc": {
"message": "Require all items to be owned by an organization, removing the option to store items at the account level.",
"description": "This is the policy description shown in the policy list."
},
"organizationDataOwnershipContent": {
"message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'"
},
"organizationDataOwnershipContentAnchor":{
"message": "credential lifecycle",
"description": "This will be used as a hyperlink"
},
"organizationDataOwnershipWarningTitle":{
"message": "Are you sure you want to proceed?"
},
"organizationDataOwnershipWarning1":{
"message": "will remain accessible to members"
},
"organizationDataOwnershipWarning2":{
"message": "will not be automatically selected when creating new items"
},
"organizationDataOwnershipWarning3":{
"message": "cannot be managed from the Admin Console until the user is offboarded"
},
"organizationDataOwnershipWarningContentTop":{
"message": "By turning this policy off, the default collection: "
},
"organizationDataOwnershipWarningContentBottom":{
"message": "Learn more about the ",
"description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Learn more about the credential lifecycle.'"
},
"personalOwnership": { "personalOwnership": {
"message": "Remove individual vault" "message": "Remove individual vault"
}, },

View File

@@ -1,7 +1,9 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { of } from "rxjs";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { import {
BasePolicy, BasePolicy,
BasePolicyComponent, BasePolicyComponent,
@@ -13,8 +15,8 @@ export class ActivateAutofillPolicy extends BasePolicy {
type = PolicyType.ActivateAutofill; type = PolicyType.ActivateAutofill;
component = ActivateAutofillPolicyComponent; component = ActivateAutofillPolicyComponent;
display(organization: Organization) { display(organization: Organization, configService: ConfigService) {
return organization.useActivateAutofillPolicy; return of(organization.useActivateAutofillPolicy);
} }
} }

View File

@@ -1,9 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { PolicyType } from "../../enums"; import { PolicyType } from "../../enums";
export class PolicyRequest { export type PolicyRequest = {
type: PolicyType; type: PolicyType;
enabled: boolean; enabled: boolean;
data: any; data: any;
} };