diff --git a/.gitignore b/.gitignore
index 0fa968aa47c..0f609335b63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ Thumbs.db
*.launch
.settings/
*.sublime-workspace
+.claude
# Visual Studio Code
.vscode/*
diff --git a/apps/web/src/app/admin-console/core/policy-list.service.ts b/apps/web/src/app/admin-console/core/policy-list.service.ts
deleted file mode 100644
index bb207006906..00000000000
--- a/apps/web/src/app/admin-console/core/policy-list.service.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { BasePolicy } from "../organizations/policies";
-
-export class PolicyListService {
- private policies: BasePolicy[] = [];
-
- addPolicies(policies: BasePolicy[]) {
- this.policies.push(...policies);
- }
-
- getPolicies(): BasePolicy[] {
- return this.policies;
- }
-}
diff --git a/apps/web/src/app/admin-console/organizations/policies/README.md b/apps/web/src/app/admin-console/organizations/policies/README.md
new file mode 100644
index 00000000000..e3b4efdbbf7
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/README.md
@@ -0,0 +1,234 @@
+# Adding a New Policy in Admin Console
+
+This README explains how to add a new policy type to the Admin Console. Policies are used to control organizational behavior and security settings for their members.
+
+This README does not cover checking the policy status in order to enforce it in the domain code.
+
+## Overview
+
+Each policy consists of three main components:
+
+1. **Policy Type Enum** - Defines the policy type identifier
+2. **Policy Definition & Component** - Implements the UI and business logic
+3. **Registration** - Registers the policy in the application
+
+## Step 1: Adding the Enum
+
+Add your new policy type to the `PolicyType` enum.
+
+**Important**: You must also add the corresponding PolicyType enum value on the server.
+
+Example:
+
+```typescript
+export enum PolicyType {
+ // ... existing policies
+ YourNewPolicy = 21, // Use the next available number
+}
+```
+
+## Step 2: Creating the Policy Definition and Component
+
+### Policy Licensing and Location
+
+The location where you create your policy depends on its licensing:
+
+- **Open Source (OSS) Policies**: Create in `apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/`
+- **Bitwarden Licensed Policies**: Create in `bitwarden_license/bit-web/src/app/admin-console/policies/`
+
+Most policies should be OSS licensed unless they specifically relate to premium/enterprise features that are part of Bitwarden's commercial offerings.
+
+Create a new component file in the appropriate `policy-edit-definitions/` folder following the naming pattern `your-policy-name.component.ts`.
+
+**Note:** you may also create the policy files in your own team's code if you prefer to own your own definition. The same licensing considerations apply.
+
+### Basic Structure
+
+```typescript
+import { Component } from "@angular/core";
+import { PolicyType } from "@bitwarden/common/admin-console/enums";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
+
+// Policy Definition Class
+export class YourNewPolicy extends BasePolicyEditDefinition {
+ name = "yourPolicyNameTitle"; // i18n key for title
+ description = "yourPolicyNameDesc"; // i18n key for description
+ type = PolicyType.YourNewPolicy; // Reference to enum
+ component = YourNewPolicyComponent; // Reference to component
+}
+
+// Policy Component Class
+@Component({
+ templateUrl: "your-policy-name.component.html",
+ imports: [SharedModule],
+})
+export class YourNewPolicyComponent extends BasePolicyEditComponent {
+ // Component implementation
+}
+```
+
+### Common Use Cases
+
+#### Simple Toggle Policy (No Additional Configuration)
+
+For policies that only need an enabled/disabled state:
+
+```typescript
+export class SimpleTogglePolicy extends BasePolicyEditDefinition {
+ name = "simpleTogglePolicyTitle";
+ description = "simpleTogglePolicyDesc";
+ type = PolicyType.SimpleToggle;
+ component = SimpleTogglePolicyComponent;
+}
+
+@Component({
+ templateUrl: "simple-toggle.component.html",
+ imports: [SharedModule],
+})
+export class SimpleTogglePolicyComponent extends BasePolicyEditComponent {}
+```
+
+Template (`simple-toggle.component.html`):
+
+```html
+
+
+ {{ "turnOn" | i18n }}
+
+```
+
+#### Policy with Configuration Data
+
+For policies requiring additional settings beyond just enabled/disabled, you'll need to define a custom `data` FormGroup to handle the policy's configuration options:
+
+```typescript
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { ControlsOf } from "@bitwarden/angular/types/controls-of";
+
+interface YourPolicyOptions {
+ minLength: number;
+ requireSpecialChar: boolean;
+}
+
+@Component({
+ templateUrl: "your-policy.component.html",
+ imports: [SharedModule],
+})
+export class YourPolicyComponent extends BasePolicyEditComponent implements OnInit {
+ data: FormGroup> = this.formBuilder.group({
+ minLength: [8, [Validators.min(1)]],
+ requireSpecialChar: [false],
+ });
+
+ constructor(private formBuilder: FormBuilder) {
+ super();
+ }
+
+ async ngOnInit() {
+ super.ngOnInit();
+ // Additional initialization logic
+ }
+}
+```
+
+Template (`your-policy.component.html`):
+
+```html
+
+
+ {{ "turnOn" | i18n }}
+
+
+
+
+ {{ "minimumLength" | i18n }}
+
+
+
+
+
+ {{ "requireSpecialCharacter" | i18n }}
+
+
+```
+
+#### Feature Flagged Policy
+
+To hide a policy behind a feature flag using ConfigService:
+
+```typescript
+import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
+import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
+
+export class NewPolicyBeta extends BasePolicyEditDefinition {
+ name = "newPolicyTitle";
+ description = "newPolicyDesc";
+ type = PolicyType.NewPolicy;
+ component = NewPolicyComponent;
+
+ // Only show if feature flag is enabled
+ display$(organization: Organization, configService: ConfigService) {
+ return configService.getFeatureFlag$(FeatureFlag.YourNewPolicyFeature);
+ }
+}
+```
+
+#### Policy related to Organization Features
+
+To show a policy only when the organization has a specific plan feature:
+
+```typescript
+import { of } from "rxjs";
+import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
+
+export class RequireSsoPolicy extends BasePolicyEditDefinition {
+ name = "requireSsoTitle";
+ description = "requireSsoDesc";
+ type = PolicyType.RequireSso;
+ component = RequireSsoPolicyComponent;
+
+ // Only show if organization has SSO enabled
+ display$(organization: Organization, configService: ConfigService) {
+ return of(organization.useSso);
+ }
+}
+```
+
+## Step 3: Registering the Policy
+
+### Export from Index File
+
+Add your policy to the barrel file in its folder:
+
+```typescript
+export { YourNewPolicy } from "./your-policy-name.component";
+```
+
+### Register in Policy Register
+
+Add your policy to the appropriate register in `policy-edit-register.ts`:
+
+```typescript
+import {
+ // ... existing imports
+ YourNewPolicy,
+} from "./policy-edit-definitions";
+
+export const ossPolicyEditRegister: BasePolicyEditDefinition[] = [
+ // ... existing policies
+ new YourNewPolicy(),
+];
+```
+
+**Note**: Use `ossPolicyEditRegister` for open-source policies and `bitPolicyEditRegister` for Bitwarden Licensed policies.
+
+## Testing Your Policy
+
+1. Build and run the application
+2. Navigate to Admin Console → Policies
+3. Verify your policy appears in the list
+4. Test the policy configuration UI
+5. Verify policy data saves correctly
diff --git a/apps/web/src/app/admin-console/organizations/policies/base-policy-edit.component.ts b/apps/web/src/app/admin-console/organizations/policies/base-policy-edit.component.ts
new file mode 100644
index 00000000000..2e5faea4702
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/base-policy-edit.component.ts
@@ -0,0 +1,119 @@
+import { Directive, Input, OnInit } from "@angular/core";
+import { FormControl, UntypedFormGroup } from "@angular/forms";
+import { Observable, of } from "rxjs";
+import { Constructor } from "type-fest";
+
+import { PolicyType } from "@bitwarden/common/admin-console/enums";
+import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
+import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request";
+import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
+
+/**
+ * A metadata class that defines how a policy is displayed in the Admin Console Policies page for editing.
+ * Add this to the `ossPolicyRegister` or `bitPolicyRegister` file to register it in the application.
+ */
+export abstract class BasePolicyEditDefinition {
+ /**
+ * i18n string for the policy name.
+ */
+ abstract name: string;
+ /**
+ * i18n string for the policy description.
+ * This is shown in the list of policies.
+ */
+ abstract description: string;
+ /**
+ * The PolicyType enum that this policy represents.
+ */
+ abstract type: PolicyType;
+ /**
+ * The component used to edit this policy. See {@link BasePolicyEditComponent}.
+ */
+ abstract component: Constructor;
+
+ /**
+ * If true, the {@link 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;
+
+ /**
+ * A method that determines whether to display this policy in the Admin Console Policies page.
+ * The default implementation will always display the policy.
+ * This can be used to hide the policy based on the organization's plan features or a feature flag value.
+ * Note: this only hides the policy for editing in Admin Console, it does not affect its enforcement
+ * if it has already been turned on. Enforcement should be feature flagged separately.
+ */
+ display$(organization: Organization, configService: ConfigService): Observable {
+ return of(true);
+ }
+}
+
+/**
+ * A component used to edit the policy settings in Admin Console. It is rendered inside the PolicyEditDialogComponent.
+ * This should contain the form controls used to edit the policy (including the Enabled checkbox) and any additional
+ * warnings or callouts.
+ * See existing implementations as a guide.
+ */
+@Directive()
+export abstract class BasePolicyEditComponent implements OnInit {
+ @Input() policyResponse: PolicyResponse | undefined;
+ @Input() policy: BasePolicyEditDefinition | undefined;
+
+ /**
+ * Whether the policy is enabled.
+ */
+ enabled = new FormControl(false);
+
+ /**
+ * An optional FormGroup for additional policy configuration. Required for more complex policies only.
+ */
+ data: UntypedFormGroup | undefined;
+
+ ngOnInit(): void {
+ this.enabled.setValue(this.policyResponse?.enabled ?? false);
+
+ if (this.policyResponse?.data != null) {
+ this.loadData();
+ }
+ }
+
+ buildRequest() {
+ if (!this.policy) {
+ throw new Error("Policy was not found");
+ }
+
+ const request: PolicyRequest = {
+ type: this.policy.type,
+ enabled: this.enabled.value ?? false,
+ data: this.buildRequestData(),
+ };
+
+ return Promise.resolve(request);
+ }
+
+ /**
+ * This is called before the policy is saved. If it returns false, it will not be saved
+ * and the user will remain on the policy edit dialog.
+ * This can be used to trigger an additional confirmation modal before saving.
+ * */
+ confirm(): Promise | boolean {
+ return true;
+ }
+
+ protected loadData() {
+ this.data?.patchValue(this.policyResponse?.data ?? {});
+ }
+
+ /**
+ * Transforms the {@link data} FormGroup to the policy data model for saving.
+ */
+ protected buildRequestData() {
+ if (this.data != null) {
+ return this.data.value;
+ }
+
+ return null;
+ }
+}
diff --git a/apps/web/src/app/admin-console/organizations/policies/base-policy.component.ts b/apps/web/src/app/admin-console/organizations/policies/base-policy.component.ts
deleted file mode 100644
index 3af99644dd2..00000000000
--- a/apps/web/src/app/admin-console/organizations/policies/base-policy.component.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { Directive, Input, OnInit } from "@angular/core";
-import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
-import { Observable, of } from "rxjs";
-
-import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
-import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request";
-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 {
- abstract name: string;
- abstract description: string;
- abstract type: PolicyType;
- abstract component: any;
-
- /**
- * 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 {
- return of(true);
- }
-}
-
-@Directive()
-export abstract class BasePolicyComponent implements OnInit {
- @Input() policyResponse: PolicyResponse | undefined;
- @Input() policy: BasePolicy | undefined;
-
- enabled = new UntypedFormControl(false);
- data: UntypedFormGroup | undefined;
-
- ngOnInit(): void {
- this.enabled.setValue(this.policyResponse?.enabled);
-
- if (this.policyResponse?.data != null) {
- this.loadData();
- }
- }
-
- buildRequest() {
- if (!this.policy) {
- throw new Error("Policy was not found");
- }
-
- const request: PolicyRequest = {
- type: this.policy.type,
- enabled: this.enabled.value,
- data: this.buildRequestData(),
- };
-
- return Promise.resolve(request);
- }
-
- /**
- * Enable optional validation before sumitting a respose for policy submission
- * */
- confirm(): Promise | boolean {
- return true;
- }
-
- protected loadData() {
- this.data?.patchValue(this.policyResponse?.data ?? {});
- }
-
- protected buildRequestData() {
- if (this.data != null) {
- return this.data.value;
- }
-
- return null;
- }
-}
diff --git a/apps/web/src/app/admin-console/organizations/policies/index.ts b/apps/web/src/app/admin-console/organizations/policies/index.ts
index 6b6b2303b2f..624e5132faf 100644
--- a/apps/web/src/app/admin-console/organizations/policies/index.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/index.ts
@@ -1,15 +1,4 @@
-export * from "./policies.module";
-export { BasePolicy, BasePolicyComponent } from "./base-policy.component";
-export { DisableSendPolicy } from "./disable-send.component";
-export { MasterPasswordPolicy } from "./master-password.component";
-export { PasswordGeneratorPolicy } from "./password-generator.component";
-export { vNextOrganizationDataOwnershipPolicy } from "./vnext-organization-data-ownership.component";
-export { OrganizationDataOwnershipPolicy } from "./organization-data-ownership.component";
-export { RequireSsoPolicy } from "./require-sso.component";
-export { ResetPasswordPolicy } from "./reset-password.component";
-export { SendOptionsPolicy } from "./send-options.component";
-export { SingleOrgPolicy } from "./single-org.component";
-export { TwoFactorAuthenticationPolicy } from "./two-factor-authentication.component";
export { PoliciesComponent } from "./policies.component";
-export { RemoveUnlockWithPinPolicy } from "./remove-unlock-with-pin.component";
-export { RestrictedItemTypesPolicy } from "./restricted-item-types.component";
+export { ossPolicyEditRegister } from "./policy-edit-register";
+export { BasePolicyEditDefinition, BasePolicyEditComponent } from "./base-policy-edit.component";
+export { POLICY_EDIT_REGISTER } from "./policy-register-token";
diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.component.html b/apps/web/src/app/admin-console/organizations/policies/policies.component.html
index 843d1d18d59..ea14986749f 100644
--- a/apps/web/src/app/admin-console/organizations/policies/policies.component.html
+++ b/apps/web/src/app/admin-console/organizations/policies/policies.component.html
@@ -14,7 +14,7 @@
@for (p of policies; track p.name) {
- @if (p.display(organization, configService) | async) {
+ @if (p.display$(organization, configService) | async) {
diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.component.ts b/apps/web/src/app/admin-console/organizations/policies/policies.component.ts
index 094f0262629..45383133687 100644
--- a/apps/web/src/app/admin-console/organizations/policies/policies.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policies.component.ts
@@ -16,22 +16,31 @@ import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { DialogService } from "@bitwarden/components";
+import { safeProvider } from "@bitwarden/ui-common";
-import { PolicyListService } from "../../core/policy-list.service";
-import { BasePolicy } from "../policies";
+import { HeaderModule } from "../../../layouts/header/header.module";
+import { SharedModule } from "../../../shared";
-import { PolicyEditComponent, PolicyEditDialogResult } from "./policy-edit.component";
+import { BasePolicyEditDefinition } from "./base-policy-edit.component";
+import { PolicyEditDialogComponent } from "./policy-edit-dialog.component";
+import { PolicyListService } from "./policy-list.service";
+import { POLICY_EDIT_REGISTER } from "./policy-register-token";
@Component({
- selector: "app-org-policies",
templateUrl: "policies.component.html",
- standalone: false,
+ imports: [SharedModule, HeaderModule],
+ providers: [
+ safeProvider({
+ provide: PolicyListService,
+ deps: [POLICY_EDIT_REGISTER],
+ }),
+ ],
})
export class PoliciesComponent implements OnInit {
loading = true;
organizationId: string;
- policies: BasePolicy[];
- organization$: Observable;
+ policies: readonly BasePolicyEditDefinition[];
+ protected organization$: Observable;
private orgPolicies: PolicyResponse[];
protected policiesEnabledMap: Map = new Map();
@@ -97,8 +106,8 @@ export class PoliciesComponent implements OnInit {
this.loading = false;
}
- async edit(policy: BasePolicy) {
- const dialogRef = PolicyEditComponent.open(this.dialogService, {
+ async edit(policy: BasePolicyEditDefinition) {
+ const dialogRef = PolicyEditDialogComponent.open(this.dialogService, {
data: {
policy: policy,
organizationId: this.organizationId,
@@ -106,7 +115,7 @@ export class PoliciesComponent implements OnInit {
});
const result = await lastValueFrom(dialogRef.closed);
- if (result === PolicyEditDialogResult.Saved) {
+ if (result == "saved") {
await this.load();
}
}
diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.module.ts b/apps/web/src/app/admin-console/organizations/policies/policies.module.ts
deleted file mode 100644
index 95b22497eba..00000000000
--- a/apps/web/src/app/admin-console/organizations/policies/policies.module.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { NgModule } from "@angular/core";
-
-import { HeaderModule } from "../../../layouts/header/header.module";
-import { SharedModule } from "../../../shared";
-
-import { DisableSendPolicyComponent } from "./disable-send.component";
-import { MasterPasswordPolicyComponent } from "./master-password.component";
-import { OrganizationDataOwnershipPolicyComponent } from "./organization-data-ownership.component";
-import { PasswordGeneratorPolicyComponent } from "./password-generator.component";
-import { PoliciesComponent } from "./policies.component";
-import { PolicyEditComponent } from "./policy-edit.component";
-import { RemoveUnlockWithPinPolicyComponent } from "./remove-unlock-with-pin.component";
-import { RequireSsoPolicyComponent } from "./require-sso.component";
-import { ResetPasswordPolicyComponent } from "./reset-password.component";
-import { RestrictedItemTypesPolicyComponent } from "./restricted-item-types.component";
-import { SendOptionsPolicyComponent } from "./send-options.component";
-import { SingleOrgPolicyComponent } from "./single-org.component";
-import { TwoFactorAuthenticationPolicyComponent } from "./two-factor-authentication.component";
-
-@NgModule({
- imports: [SharedModule, HeaderModule],
- declarations: [
- DisableSendPolicyComponent,
- MasterPasswordPolicyComponent,
- PasswordGeneratorPolicyComponent,
- OrganizationDataOwnershipPolicyComponent,
- RequireSsoPolicyComponent,
- ResetPasswordPolicyComponent,
- SendOptionsPolicyComponent,
- SingleOrgPolicyComponent,
- TwoFactorAuthenticationPolicyComponent,
- PoliciesComponent,
- PolicyEditComponent,
- RemoveUnlockWithPinPolicyComponent,
- RestrictedItemTypesPolicyComponent,
- ],
- exports: [
- DisableSendPolicyComponent,
- MasterPasswordPolicyComponent,
- PasswordGeneratorPolicyComponent,
- OrganizationDataOwnershipPolicyComponent,
- RequireSsoPolicyComponent,
- ResetPasswordPolicyComponent,
- SendOptionsPolicyComponent,
- SingleOrgPolicyComponent,
- TwoFactorAuthenticationPolicyComponent,
- PoliciesComponent,
- PolicyEditComponent,
- RemoveUnlockWithPinPolicyComponent,
- ],
-})
-export class PoliciesModule {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/disable-send.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/disable-send.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/disable-send.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/disable-send.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/disable-send.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/disable-send.component.ts
similarity index 50%
rename from apps/web/src/app/admin-console/organizations/policies/disable-send.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/disable-send.component.ts
index b323ac00d34..3b4df75e555 100644
--- a/apps/web/src/app/admin-console/organizations/policies/disable-send.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/disable-send.component.ts
@@ -2,9 +2,10 @@ import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class DisableSendPolicy extends BasePolicy {
+export class DisableSendPolicy extends BasePolicyEditDefinition {
name = "disableSend";
description = "disableSendPolicyDesc";
type = PolicyType.DisableSend;
@@ -12,8 +13,7 @@ export class DisableSendPolicy extends BasePolicy {
}
@Component({
- selector: "policy-disable-send",
templateUrl: "disable-send.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class DisableSendPolicyComponent extends BasePolicyComponent {}
+export class DisableSendPolicyComponent extends BasePolicyEditComponent {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/index.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/index.ts
new file mode 100644
index 00000000000..13f29ab68f7
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/index.ts
@@ -0,0 +1,15 @@
+export { DisableSendPolicy } from "./disable-send.component";
+export { MasterPasswordPolicy } from "./master-password.component";
+export { OrganizationDataOwnershipPolicy } from "./organization-data-ownership.component";
+export { PasswordGeneratorPolicy } from "./password-generator.component";
+export { RemoveUnlockWithPinPolicy } from "./remove-unlock-with-pin.component";
+export { RequireSsoPolicy } from "./require-sso.component";
+export { ResetPasswordPolicy } from "./reset-password.component";
+export { RestrictedItemTypesPolicy } from "./restricted-item-types.component";
+export { SendOptionsPolicy } from "./send-options.component";
+export { SingleOrgPolicy } from "./single-org.component";
+export { TwoFactorAuthenticationPolicy } from "./two-factor-authentication.component";
+export {
+ vNextOrganizationDataOwnershipPolicy,
+ vNextOrganizationDataOwnershipPolicyComponent,
+} from "./vnext-organization-data-ownership.component";
diff --git a/apps/web/src/app/admin-console/organizations/policies/master-password.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/master-password.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/master-password.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/master-password.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/master-password.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/master-password.component.ts
similarity index 88%
rename from apps/web/src/app/admin-console/organizations/policies/master-password.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/master-password.component.ts
index 54cf1be88fc..fe3d76a0907 100644
--- a/apps/web/src/app/admin-console/organizations/policies/master-password.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/master-password.component.ts
@@ -16,9 +16,10 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class MasterPasswordPolicy extends BasePolicy {
+export class MasterPasswordPolicy extends BasePolicyEditDefinition {
name = "masterPassPolicyTitle";
description = "masterPassPolicyDesc";
type = PolicyType.MasterPassword;
@@ -26,11 +27,10 @@ export class MasterPasswordPolicy extends BasePolicy {
}
@Component({
- selector: "policy-master-password",
templateUrl: "master-password.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class MasterPasswordPolicyComponent extends BasePolicyComponent implements OnInit {
+export class MasterPasswordPolicyComponent extends BasePolicyEditComponent implements OnInit {
MinPasswordLength = Utils.minimumPasswordLength;
data: FormGroup> = this.formBuilder.group({
diff --git a/apps/web/src/app/admin-console/organizations/policies/organization-data-ownership.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/organization-data-ownership.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/organization-data-ownership.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/organization-data-ownership.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/organization-data-ownership.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/organization-data-ownership.component.ts
similarity index 70%
rename from apps/web/src/app/admin-console/organizations/policies/organization-data-ownership.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/organization-data-ownership.component.ts
index beb9fd5752a..94094b76f69 100644
--- a/apps/web/src/app/admin-console/organizations/policies/organization-data-ownership.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/organization-data-ownership.component.ts
@@ -6,15 +6,16 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
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 { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class OrganizationDataOwnershipPolicy extends BasePolicy {
+export class OrganizationDataOwnershipPolicy extends BasePolicyEditDefinition {
name = "organizationDataOwnership";
description = "personalOwnershipPolicyDesc";
type = PolicyType.OrganizationDataOwnership;
component = OrganizationDataOwnershipPolicyComponent;
- display(organization: Organization, configService: ConfigService): Observable {
+ display$(organization: Organization, configService: ConfigService): Observable {
return configService
.getFeatureFlag$(FeatureFlag.CreateDefaultLocation)
.pipe(map((enabled) => !enabled));
@@ -22,8 +23,7 @@ export class OrganizationDataOwnershipPolicy extends BasePolicy {
}
@Component({
- selector: "policy-organization-data-ownership",
templateUrl: "organization-data-ownership.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class OrganizationDataOwnershipPolicyComponent extends BasePolicyComponent {}
+export class OrganizationDataOwnershipPolicyComponent extends BasePolicyEditComponent {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/password-generator.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/password-generator.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/password-generator.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/password-generator.component.ts
similarity index 94%
rename from apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/password-generator.component.ts
index 26f87f333eb..e26d37bfdf2 100644
--- a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/password-generator.component.ts
@@ -9,9 +9,10 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { BuiltIn, Profile } from "@bitwarden/generator-core";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class PasswordGeneratorPolicy extends BasePolicy {
+export class PasswordGeneratorPolicy extends BasePolicyEditDefinition {
name = "passwordGenerator";
description = "passwordGeneratorPolicyDesc";
type = PolicyType.PasswordGenerator;
@@ -19,11 +20,10 @@ export class PasswordGeneratorPolicy extends BasePolicy {
}
@Component({
- selector: "policy-password-generator",
templateUrl: "password-generator.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class PasswordGeneratorPolicyComponent extends BasePolicyComponent {
+export class PasswordGeneratorPolicyComponent extends BasePolicyEditComponent {
// these properties forward the application default settings to the UI
// for HTML attribute bindings
protected readonly minLengthMin =
diff --git a/apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.spec.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.spec.ts
similarity index 86%
rename from apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.spec.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.spec.ts
index 9058cd22f3e..f6df56cd83a 100644
--- a/apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.spec.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.spec.ts
@@ -1,11 +1,8 @@
-import { CommonModule } from "@angular/common";
import { NO_ERRORS_SCHEMA } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
-import { ReactiveFormsModule } from "@angular/forms";
import { By } from "@angular/platform-browser";
import { mock } from "jest-mock-extended";
-import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -33,8 +30,6 @@ describe("RemoveUnlockWithPinPolicyComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
- imports: [CommonModule, ReactiveFormsModule],
- declarations: [RemoveUnlockWithPinPolicyComponent, I18nPipe],
providers: [
{ provide: I18nService, useValue: mock() },
{ provide: I18nService, useValue: i18nService },
@@ -102,9 +97,6 @@ describe("RemoveUnlockWithPinPolicyComponent", () => {
const bitLabelElement = fixture.debugElement.query(By.css("bit-label"));
expect(bitLabelElement).not.toBeNull();
- const textNodes = bitLabelElement.childNodes
- .filter((node) => node.nativeNode.nodeType === Node.TEXT_NODE)
- .map((node) => node.nativeNode.wholeText?.trim());
- expect(textNodes).toContain("Turn on");
+ expect(bitLabelElement.nativeElement.textContent.trim()).toBe("Turn on");
});
});
diff --git a/apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.ts
similarity index 61%
rename from apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.ts
index 0d0f42b603e..e95ef8a1422 100644
--- a/apps/web/src/app/admin-console/organizations/policies/remove-unlock-with-pin.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/remove-unlock-with-pin.component.ts
@@ -2,9 +2,10 @@ import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class RemoveUnlockWithPinPolicy extends BasePolicy {
+export class RemoveUnlockWithPinPolicy extends BasePolicyEditDefinition {
name = "removeUnlockWithPinPolicyTitle";
description = "removeUnlockWithPinPolicyDesc";
type = PolicyType.RemoveUnlockWithPin;
@@ -12,8 +13,7 @@ export class RemoveUnlockWithPinPolicy extends BasePolicy {
}
@Component({
- selector: "remove-unlock-with-pin",
templateUrl: "remove-unlock-with-pin.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class RemoveUnlockWithPinPolicyComponent extends BasePolicyComponent {}
+export class RemoveUnlockWithPinPolicyComponent extends BasePolicyEditComponent {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/require-sso.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/require-sso.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/require-sso.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/require-sso.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/require-sso.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/require-sso.component.ts
similarity index 59%
rename from apps/web/src/app/admin-console/organizations/policies/require-sso.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/require-sso.component.ts
index 3a0d196c593..3f28c0cb068 100644
--- a/apps/web/src/app/admin-console/organizations/policies/require-sso.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/require-sso.component.ts
@@ -5,22 +5,22 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
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 { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class RequireSsoPolicy extends BasePolicy {
+export class RequireSsoPolicy extends BasePolicyEditDefinition {
name = "requireSso";
description = "requireSsoPolicyDesc";
type = PolicyType.RequireSso;
component = RequireSsoPolicyComponent;
- display(organization: Organization, configService: ConfigService) {
+ display$(organization: Organization, configService: ConfigService) {
return of(organization.useSso);
}
}
@Component({
- selector: "policy-require-sso",
templateUrl: "require-sso.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class RequireSsoPolicyComponent extends BasePolicyComponent {}
+export class RequireSsoPolicyComponent extends BasePolicyEditComponent {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/reset-password.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/reset-password.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/reset-password.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/reset-password.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/reset-password.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/reset-password.component.ts
similarity index 82%
rename from apps/web/src/app/admin-console/organizations/policies/reset-password.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/reset-password.component.ts
index 93a42285fbc..fafb0b32398 100644
--- a/apps/web/src/app/admin-console/organizations/policies/reset-password.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/reset-password.component.ts
@@ -12,25 +12,25 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
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 { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class ResetPasswordPolicy extends BasePolicy {
+export class ResetPasswordPolicy extends BasePolicyEditDefinition {
name = "accountRecoveryPolicy";
description = "accountRecoveryPolicyDesc";
type = PolicyType.ResetPassword;
component = ResetPasswordPolicyComponent;
- display(organization: Organization, configService: ConfigService) {
+ display$(organization: Organization, configService: ConfigService) {
return of(organization.useResetPassword);
}
}
@Component({
- selector: "policy-reset-password",
templateUrl: "reset-password.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class ResetPasswordPolicyComponent extends BasePolicyComponent implements OnInit {
+export class ResetPasswordPolicyComponent extends BasePolicyEditComponent implements OnInit {
data = this.formBuilder.group({
autoEnrollEnabled: false,
});
diff --git a/apps/web/src/app/admin-console/organizations/policies/restricted-item-types.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/restricted-item-types.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/restricted-item-types.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.ts
similarity index 70%
rename from apps/web/src/app/admin-console/organizations/policies/restricted-item-types.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.ts
index 6cad0fc0170..51cba689693 100644
--- a/apps/web/src/app/admin-console/organizations/policies/restricted-item-types.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/restricted-item-types.component.ts
@@ -6,25 +6,25 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
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 { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class RestrictedItemTypesPolicy extends BasePolicy {
+export class RestrictedItemTypesPolicy extends BasePolicyEditDefinition {
name = "restrictedItemTypePolicy";
description = "restrictedItemTypePolicyDesc";
type = PolicyType.RestrictedItemTypes;
component = RestrictedItemTypesPolicyComponent;
- display(organization: Organization, configService: ConfigService): Observable {
+ display$(organization: Organization, configService: ConfigService): Observable {
return configService.getFeatureFlag$(FeatureFlag.RemoveCardItemTypePolicy);
}
}
@Component({
- selector: "policy-restricted-item-types",
templateUrl: "restricted-item-types.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class RestrictedItemTypesPolicyComponent extends BasePolicyComponent {
+export class RestrictedItemTypesPolicyComponent extends BasePolicyEditComponent {
constructor() {
super();
}
diff --git a/apps/web/src/app/admin-console/organizations/policies/send-options.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/send-options.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/send-options.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/send-options.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/send-options.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/send-options.component.ts
similarity index 62%
rename from apps/web/src/app/admin-console/organizations/policies/send-options.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/send-options.component.ts
index 9a0a8871296..e581ed2f4c7 100644
--- a/apps/web/src/app/admin-console/organizations/policies/send-options.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/send-options.component.ts
@@ -3,9 +3,10 @@ import { UntypedFormBuilder } from "@angular/forms";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class SendOptionsPolicy extends BasePolicy {
+export class SendOptionsPolicy extends BasePolicyEditDefinition {
name = "sendOptions";
description = "sendOptionsPolicyDesc";
type = PolicyType.SendOptions;
@@ -13,11 +14,10 @@ export class SendOptionsPolicy extends BasePolicy {
}
@Component({
- selector: "policy-send-options",
templateUrl: "send-options.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class SendOptionsPolicyComponent extends BasePolicyComponent {
+export class SendOptionsPolicyComponent extends BasePolicyEditComponent {
data = this.formBuilder.group({
disableHideEmail: false,
});
diff --git a/apps/web/src/app/admin-console/organizations/policies/single-org.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/single-org.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/single-org.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/single-org.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/single-org.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/single-org.component.ts
similarity index 61%
rename from apps/web/src/app/admin-console/organizations/policies/single-org.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/single-org.component.ts
index 613253ef8d9..ecaa86b03bc 100644
--- a/apps/web/src/app/admin-console/organizations/policies/single-org.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/single-org.component.ts
@@ -2,9 +2,10 @@ import { Component, OnInit } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class SingleOrgPolicy extends BasePolicy {
+export class SingleOrgPolicy extends BasePolicyEditDefinition {
name = "singleOrg";
description = "singleOrgPolicyDesc";
type = PolicyType.SingleOrg;
@@ -12,11 +13,10 @@ export class SingleOrgPolicy extends BasePolicy {
}
@Component({
- selector: "policy-single-org",
templateUrl: "single-org.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class SingleOrgPolicyComponent extends BasePolicyComponent implements OnInit {
+export class SingleOrgPolicyComponent extends BasePolicyEditComponent implements OnInit {
async ngOnInit() {
super.ngOnInit();
diff --git a/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/two-factor-authentication.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/two-factor-authentication.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/two-factor-authentication.component.ts
similarity index 60%
rename from apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/two-factor-authentication.component.ts
index 691e12c72f6..13b7660c4e7 100644
--- a/apps/web/src/app/admin-console/organizations/policies/two-factor-authentication.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/two-factor-authentication.component.ts
@@ -2,9 +2,10 @@ import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
-export class TwoFactorAuthenticationPolicy extends BasePolicy {
+export class TwoFactorAuthenticationPolicy extends BasePolicyEditDefinition {
name = "twoStepLoginPolicyTitle";
description = "twoStepLoginPolicyDesc";
type = PolicyType.TwoFactorAuthentication;
@@ -12,8 +13,7 @@ export class TwoFactorAuthenticationPolicy extends BasePolicy {
}
@Component({
- selector: "policy-two-factor-authentication",
templateUrl: "two-factor-authentication.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class TwoFactorAuthenticationPolicyComponent extends BasePolicyComponent {}
+export class TwoFactorAuthenticationPolicyComponent extends BasePolicyEditComponent {}
diff --git a/apps/web/src/app/admin-console/organizations/policies/vnext-organization-data-ownership.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/vnext-organization-data-ownership.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/vnext-organization-data-ownership.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/vnext-organization-data-ownership.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/vnext-organization-data-ownership.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/vnext-organization-data-ownership.component.ts
similarity index 88%
rename from apps/web/src/app/admin-console/organizations/policies/vnext-organization-data-ownership.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/vnext-organization-data-ownership.component.ts
index 89964e94395..2234d5c7437 100644
--- a/apps/web/src/app/admin-console/organizations/policies/vnext-organization-data-ownership.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-definitions/vnext-organization-data-ownership.component.ts
@@ -12,9 +12,8 @@ import { OrgKey } from "@bitwarden/common/types/key";
import { DialogService } from "@bitwarden/components";
import { EncString } from "@bitwarden/sdk-internal";
-import { SharedModule } from "../../../shared";
-
-import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
+import { SharedModule } from "../../../../shared";
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "../base-policy-edit.component";
interface VNextPolicyRequest {
policy: PolicyRequest;
@@ -23,26 +22,24 @@ interface VNextPolicyRequest {
};
}
-export class vNextOrganizationDataOwnershipPolicy extends BasePolicy {
+export class vNextOrganizationDataOwnershipPolicy extends BasePolicyEditDefinition {
name = "organizationDataOwnership";
description = "organizationDataOwnershipDesc";
type = PolicyType.OrganizationDataOwnership;
component = vNextOrganizationDataOwnershipPolicyComponent;
showDescription = false;
- override display(organization: Organization, configService: ConfigService): Observable {
+ override display$(organization: Organization, configService: ConfigService): Observable {
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
+ extends BasePolicyEditComponent
implements OnInit
{
constructor(
@@ -74,7 +71,7 @@ export class vNextOrganizationDataOwnershipPolicyComponent
const request: VNextPolicyRequest = {
policy: {
type: this.policy.type,
- enabled: this.enabled.value,
+ enabled: this.enabled.value ?? false,
data: this.buildRequestData(),
},
metadata: {
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.html b/apps/web/src/app/admin-console/organizations/policies/policy-edit-dialog.component.html
similarity index 100%
rename from apps/web/src/app/admin-console/organizations/policies/policy-edit.component.html
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-dialog.component.html
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-dialog.component.ts
similarity index 67%
rename from apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts
rename to apps/web/src/app/admin-console/organizations/policies/policy-edit-dialog.component.ts
index ad1099af3cd..f0672d0f861 100644
--- a/apps/web/src/app/admin-console/organizations/policies/policy-edit.component.ts
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-dialog.component.ts
@@ -1,5 +1,3 @@
-// FIXME: Update this file to be type safe and remove this and next line
-// @ts-strict-ignore
import {
AfterViewInit,
ChangeDetectorRef,
@@ -9,7 +7,7 @@ import {
ViewContainerRef,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
-import { Observable, map, firstValueFrom, switchMap } from "rxjs";
+import { Observable, map, firstValueFrom, switchMap, filter, of } from "rxjs";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
@@ -29,37 +27,38 @@ import {
} from "@bitwarden/components";
import { KeyService } from "@bitwarden/key-management";
-import { BasePolicy, BasePolicyComponent } from "../policies";
-import { vNextOrganizationDataOwnershipPolicyComponent } from "../policies/vnext-organization-data-ownership.component";
+import { SharedModule } from "../../../shared";
+
+import { BasePolicyEditDefinition, BasePolicyEditComponent } from "./base-policy-edit.component";
+import { vNextOrganizationDataOwnershipPolicyComponent } from "./policy-edit-definitions";
export type PolicyEditDialogData = {
- /** Returns policy abstracts. */
- policy: BasePolicy;
- /** Returns a unique organization id */
+ /**
+ * The metadata containing information about how to display and edit the policy.
+ */
+ policy: BasePolicyEditDefinition;
+ /**
+ * The organization ID for the policy.
+ */
organizationId: string;
};
-// FIXME: update to use a const object instead of a typescript enum
-// eslint-disable-next-line @bitwarden/platform/no-enums
-export enum PolicyEditDialogResult {
- Saved = "saved",
-}
+export type PolicyEditDialogResult = "saved";
+
@Component({
- selector: "app-policy-edit",
- templateUrl: "policy-edit.component.html",
- standalone: false,
+ templateUrl: "policy-edit-dialog.component.html",
+ imports: [SharedModule],
})
-export class PolicyEditComponent implements AfterViewInit {
+export class PolicyEditDialogComponent implements AfterViewInit {
@ViewChild("policyForm", { read: ViewContainerRef, static: true })
- policyFormRef: ViewContainerRef;
+ policyFormRef: ViewContainerRef | undefined;
policyType = PolicyType;
loading = true;
enabled = false;
- saveDisabled$: Observable;
- policyComponent: BasePolicyComponent;
+ saveDisabled$: Observable = of(false);
+ policyComponent: BasePolicyEditComponent | undefined;
- private policyResponse: PolicyResponse;
formGroup = this.formBuilder.group({
enabled: [this.enabled],
});
@@ -75,35 +74,43 @@ export class PolicyEditComponent implements AfterViewInit {
private configService: ConfigService,
private keyService: KeyService,
) {}
- get policy(): BasePolicy {
+
+ get policy(): BasePolicyEditDefinition {
return this.data.policy;
}
+ /**
+ * Instantiates the child policy component and inserts it into the view.
+ */
async ngAfterViewInit() {
- await this.load();
+ const policyResponse = await this.load();
this.loading = false;
- this.policyComponent = this.policyFormRef.createComponent(this.data.policy.component)
- .instance as BasePolicyComponent;
- this.policyComponent.policy = this.data.policy;
- this.policyComponent.policyResponse = this.policyResponse;
+ if (!this.policyFormRef) {
+ throw new Error("Template not initialized.");
+ }
- this.saveDisabled$ = this.policyComponent.data.statusChanges.pipe(
- map((status) => status !== "VALID" || !this.policyResponse.canToggleState),
- );
+ this.policyComponent = this.policyFormRef.createComponent(this.data.policy.component).instance;
+ this.policyComponent.policy = this.data.policy;
+ this.policyComponent.policyResponse = policyResponse;
+
+ if (this.policyComponent.data) {
+ // If the policy has additional configuration, disable the save button if the form state is invalid
+ this.saveDisabled$ = this.policyComponent.data.statusChanges.pipe(
+ map((status) => status !== "VALID" || !policyResponse.canToggleState),
+ );
+ }
this.cdr.detectChanges();
}
async load() {
try {
- this.policyResponse = await this.policyApiService.getPolicy(
- this.data.organizationId,
- this.data.policy.type,
- );
- } catch (e) {
+ return await this.policyApiService.getPolicy(this.data.organizationId, this.data.policy.type);
+ } catch (e: any) {
+ // No policy exists yet, instantiate an empty one
if (e.statusCode === 404) {
- this.policyResponse = new PolicyResponse({ Enabled: false });
+ return new PolicyResponse({ Enabled: false });
} else {
throw e;
}
@@ -111,6 +118,10 @@ export class PolicyEditComponent implements AfterViewInit {
}
submit = async () => {
+ if (!this.policyComponent) {
+ throw new Error("PolicyComponent not initialized.");
+ }
+
if ((await this.policyComponent.confirm()) == false) {
this.dialogRef.close();
return;
@@ -128,14 +139,12 @@ export class PolicyEditComponent implements AfterViewInit {
this.toastService.showToast({
variant: "success",
- title: null,
message: this.i18nService.t("editedPolicyId", this.i18nService.t(this.data.policy.name)),
});
- this.dialogRef.close(PolicyEditDialogResult.Saved);
- } catch (error) {
+ this.dialogRef.close("saved");
+ } catch (error: any) {
this.toastService.showToast({
variant: "error",
- title: null,
message: error.message,
});
}
@@ -150,6 +159,10 @@ export class PolicyEditComponent implements AfterViewInit {
}
private async handleStandardSubmission(): Promise {
+ if (!this.policyComponent) {
+ throw new Error("PolicyComponent not initialized.");
+ }
+
const request = await this.policyComponent.buildRequest();
await this.policyApiService.putPolicy(this.data.organizationId, this.data.policy.type, request);
}
@@ -161,10 +174,8 @@ export class PolicyEditComponent implements AfterViewInit {
this.accountService.activeAccount$.pipe(
getUserId,
switchMap((userId) => this.keyService.orgKeys$(userId)),
- map(
- (orgKeys: { [key: OrganizationId]: any }) =>
- orgKeys[this.data.organizationId as OrganizationId] ?? null,
- ),
+ filter((orgKeys) => orgKeys != null),
+ map((orgKeys) => orgKeys[this.data.organizationId as OrganizationId] ?? null),
),
);
@@ -181,6 +192,6 @@ export class PolicyEditComponent implements AfterViewInit {
);
}
static open = (dialogService: DialogService, config: DialogConfig) => {
- return dialogService.open(PolicyEditComponent, config);
+ return dialogService.open(PolicyEditDialogComponent, config);
};
}
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-edit-register.ts b/apps/web/src/app/admin-console/organizations/policies/policy-edit-register.ts
new file mode 100644
index 00000000000..3a4ba9a710f
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-edit-register.ts
@@ -0,0 +1,34 @@
+import { BasePolicyEditDefinition } from "./base-policy-edit.component";
+import {
+ DisableSendPolicy,
+ MasterPasswordPolicy,
+ OrganizationDataOwnershipPolicy,
+ PasswordGeneratorPolicy,
+ RemoveUnlockWithPinPolicy,
+ RequireSsoPolicy,
+ ResetPasswordPolicy,
+ RestrictedItemTypesPolicy,
+ SendOptionsPolicy,
+ SingleOrgPolicy,
+ TwoFactorAuthenticationPolicy,
+ vNextOrganizationDataOwnershipPolicy,
+} from "./policy-edit-definitions";
+
+/**
+ * The policy register for OSS policies.
+ * Add your policy definition here if it is under the OSS license.
+ */
+export const ossPolicyEditRegister: BasePolicyEditDefinition[] = [
+ new TwoFactorAuthenticationPolicy(),
+ new MasterPasswordPolicy(),
+ new RemoveUnlockWithPinPolicy(),
+ new ResetPasswordPolicy(),
+ new PasswordGeneratorPolicy(),
+ new SingleOrgPolicy(),
+ new RequireSsoPolicy(),
+ new OrganizationDataOwnershipPolicy(),
+ new vNextOrganizationDataOwnershipPolicy(),
+ new DisableSendPolicy(),
+ new SendOptionsPolicy(),
+ new RestrictedItemTypesPolicy(),
+];
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-list.service.ts b/apps/web/src/app/admin-console/organizations/policies/policy-list.service.ts
new file mode 100644
index 00000000000..0434338f2f0
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-list.service.ts
@@ -0,0 +1,13 @@
+import { BasePolicyEditDefinition } from "./base-policy-edit.component";
+
+export class PolicyListService {
+ private policies: readonly BasePolicyEditDefinition[];
+
+ constructor(policies: BasePolicyEditDefinition[]) {
+ this.policies = Object.freeze([...policies]);
+ }
+
+ getPolicies() {
+ return this.policies;
+ }
+}
diff --git a/apps/web/src/app/admin-console/organizations/policies/policy-register-token.ts b/apps/web/src/app/admin-console/organizations/policies/policy-register-token.ts
new file mode 100644
index 00000000000..3c46af32e88
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/policies/policy-register-token.ts
@@ -0,0 +1,7 @@
+import { SafeInjectionToken } from "@bitwarden/ui-common";
+
+import { BasePolicyEditDefinition } from "./base-policy-edit.component";
+
+export const POLICY_EDIT_REGISTER = new SafeInjectionToken(
+ "POLICY_EDIT_REGISTER",
+);
diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts
index 7065e8e799c..27a6226f964 100644
--- a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts
+++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts
@@ -7,7 +7,6 @@ import { DangerZoneComponent } from "../../../auth/settings/account/danger-zone.
import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared";
import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component";
-import { PoliciesModule } from "../../organizations/policies";
import { AccountComponent } from "./account.component";
import { OrganizationSettingsRoutingModule } from "./organization-settings-routing.module";
@@ -16,7 +15,6 @@ import { TwoFactorSetupComponent } from "./two-factor-setup.component";
@NgModule({
imports: [
SharedModule,
- PoliciesModule,
OrganizationSettingsRoutingModule,
AccountFingerprintComponent,
DangerZoneComponent,
diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
index 1cb95250611..60911173308 100644
--- a/apps/web/src/app/app.component.ts
+++ b/apps/web/src/app/app.component.ts
@@ -30,22 +30,6 @@ import { SearchService } from "@bitwarden/common/vault/abstractions/search.servi
import { DialogService, ToastService } from "@bitwarden/components";
import { KeyService, BiometricStateService } from "@bitwarden/key-management";
-import { PolicyListService } from "./admin-console/core/policy-list.service";
-import {
- DisableSendPolicy,
- MasterPasswordPolicy,
- PasswordGeneratorPolicy,
- OrganizationDataOwnershipPolicy,
- vNextOrganizationDataOwnershipPolicy,
- RequireSsoPolicy,
- ResetPasswordPolicy,
- SendOptionsPolicy,
- SingleOrgPolicy,
- TwoFactorAuthenticationPolicy,
- RemoveUnlockWithPinPolicy,
- RestrictedItemTypesPolicy,
-} from "./admin-console/organizations/policies";
-
const BroadcasterSubscriptionId = "AppComponent";
const IdleTimeout = 60000 * 10; // 10 minutes
@@ -79,7 +63,6 @@ export class AppComponent implements OnDestroy, OnInit {
private serverNotificationsService: ServerNotificationsService,
private stateService: StateService,
private eventUploadService: EventUploadService,
- protected policyListService: PolicyListService,
protected configService: ConfigService,
private dialogService: DialogService,
private biometricStateService: BiometricStateService,
@@ -238,21 +221,6 @@ export class AppComponent implements OnDestroy, OnInit {
}
});
});
-
- this.policyListService.addPolicies([
- new TwoFactorAuthenticationPolicy(),
- new MasterPasswordPolicy(),
- new RemoveUnlockWithPinPolicy(),
- new ResetPasswordPolicy(),
- new PasswordGeneratorPolicy(),
- new SingleOrgPolicy(),
- new RequireSsoPolicy(),
- new OrganizationDataOwnershipPolicy(),
- new vNextOrganizationDataOwnershipPolicy(),
- new DisableSendPolicy(),
- new SendOptionsPolicy(),
- new RestrictedItemTypesPolicy(),
- ]);
}
ngOnDestroy() {
diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts
index 22386144732..b3ce39d5021 100644
--- a/apps/web/src/app/core/core.module.ts
+++ b/apps/web/src/app/core/core.module.ts
@@ -113,7 +113,10 @@ import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarde
import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service";
import { flagEnabled } from "../../utils/flags";
-import { PolicyListService } from "../admin-console/core/policy-list.service";
+import {
+ POLICY_EDIT_REGISTER,
+ ossPolicyEditRegister,
+} from "../admin-console/organizations/policies";
import {
WebChangePasswordService,
WebRegistrationFinishService,
@@ -152,7 +155,10 @@ const safeProviders: SafeProvider[] = [
safeProvider(InitService),
safeProvider(RouterService),
safeProvider(EventService),
- safeProvider(PolicyListService),
+ safeProvider({
+ provide: POLICY_EDIT_REGISTER,
+ useValue: ossPolicyEditRegister,
+ }),
safeProvider({
provide: DEFAULT_VAULT_TIMEOUT,
deps: [PlatformUtilsService],
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/index.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/index.ts
new file mode 100644
index 00000000000..c2cd83f838c
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/index.ts
@@ -0,0 +1 @@
+export { bitPolicyEditRegister } from "./policy-edit-register";
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/activate-autofill.component.html
similarity index 100%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/activate-autofill.component.html
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/activate-autofill.component.ts
similarity index 71%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.ts
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/activate-autofill.component.ts
index 821509b43e2..17efc017136 100644
--- a/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.ts
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/activate-autofill.component.ts
@@ -5,11 +5,12 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import {
- BasePolicy,
- BasePolicyComponent,
-} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
+ BasePolicyEditDefinition,
+ BasePolicyEditComponent,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+import { SharedModule } from "@bitwarden/web-vault/app/shared";
-export class ActivateAutofillPolicy extends BasePolicy {
+export class ActivateAutofillPolicy extends BasePolicyEditDefinition {
name = "activateAutofill";
description = "activateAutofillPolicyDesc";
type = PolicyType.ActivateAutofill;
@@ -21,8 +22,7 @@ export class ActivateAutofillPolicy extends BasePolicy {
}
@Component({
- selector: "policy-activate-autofill",
templateUrl: "activate-autofill.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class ActivateAutofillPolicyComponent extends BasePolicyComponent {}
+export class ActivateAutofillPolicyComponent extends BasePolicyEditComponent {}
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/automatic-app-login.component.html b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/automatic-app-login.component.html
similarity index 100%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/automatic-app-login.component.html
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/automatic-app-login.component.html
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/automatic-app-login.component.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/automatic-app-login.component.ts
similarity index 76%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/automatic-app-login.component.ts
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/automatic-app-login.component.ts
index 1a478fb4393..7dadc04c6f4 100644
--- a/bitwarden_license/bit-web/src/app/admin-console/policies/automatic-app-login.component.ts
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/automatic-app-login.component.ts
@@ -5,11 +5,12 @@ import { FormBuilder, FormControl } from "@angular/forms";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import {
- BasePolicy,
- BasePolicyComponent,
-} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
+ BasePolicyEditDefinition,
+ BasePolicyEditComponent,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+import { SharedModule } from "@bitwarden/web-vault/app/shared";
-export class AutomaticAppLoginPolicy extends BasePolicy {
+export class AutomaticAppLoginPolicy extends BasePolicyEditDefinition {
name = "automaticAppLogin";
description = "automaticAppLoginDesc";
type = PolicyType.AutomaticAppLogIn;
@@ -17,11 +18,10 @@ export class AutomaticAppLoginPolicy extends BasePolicy {
}
@Component({
- selector: "policy-automatic-app-login",
templateUrl: "automatic-app-login.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class AutomaticAppLoginPolicyComponent extends BasePolicyComponent {
+export class AutomaticAppLoginPolicyComponent extends BasePolicyEditComponent {
data = this.formBuilder.group({
idpHost: new FormControl(null),
});
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/disable-personal-vault-export.component.html b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/disable-personal-vault-export.component.html
similarity index 100%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/disable-personal-vault-export.component.html
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/disable-personal-vault-export.component.html
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/disable-personal-vault-export.component.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/disable-personal-vault-export.component.ts
similarity index 75%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/disable-personal-vault-export.component.ts
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/disable-personal-vault-export.component.ts
index c274e58ccac..d93fb50b0e2 100644
--- a/bitwarden_license/bit-web/src/app/admin-console/policies/disable-personal-vault-export.component.ts
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/disable-personal-vault-export.component.ts
@@ -2,11 +2,12 @@ import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import {
- BasePolicy,
- BasePolicyComponent,
-} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
+ BasePolicyEditDefinition,
+ BasePolicyEditComponent,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+import { SharedModule } from "@bitwarden/web-vault/app/shared";
-export class DisablePersonalVaultExportPolicy extends BasePolicy {
+export class DisablePersonalVaultExportPolicy extends BasePolicyEditDefinition {
name = "disablePersonalVaultExport";
description = "disablePersonalVaultExportDescription";
type = PolicyType.DisablePersonalVaultExport;
@@ -14,8 +15,7 @@ export class DisablePersonalVaultExportPolicy extends BasePolicy {
}
@Component({
- selector: "policy-disable-personal-vault-export",
templateUrl: "disable-personal-vault-export.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class DisablePersonalVaultExportPolicyComponent extends BasePolicyComponent {}
+export class DisablePersonalVaultExportPolicyComponent extends BasePolicyEditComponent {}
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/index.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/index.ts
new file mode 100644
index 00000000000..8c4be2eeea1
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/index.ts
@@ -0,0 +1,4 @@
+export { ActivateAutofillPolicy } from "./activate-autofill.component";
+export { AutomaticAppLoginPolicy } from "./automatic-app-login.component";
+export { DisablePersonalVaultExportPolicy } from "./disable-personal-vault-export.component";
+export { MaximumVaultTimeoutPolicy } from "./maximum-vault-timeout.component";
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/maximum-vault-timeout.component.html b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/maximum-vault-timeout.component.html
similarity index 100%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/maximum-vault-timeout.component.html
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/maximum-vault-timeout.component.html
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/maximum-vault-timeout.component.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/maximum-vault-timeout.component.ts
similarity index 90%
rename from bitwarden_license/bit-web/src/app/admin-console/policies/maximum-vault-timeout.component.ts
rename to bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/maximum-vault-timeout.component.ts
index a5b9ad47f6e..160ce9aeb20 100644
--- a/bitwarden_license/bit-web/src/app/admin-console/policies/maximum-vault-timeout.component.ts
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-definitions/maximum-vault-timeout.component.ts
@@ -8,11 +8,12 @@ import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/po
import { VaultTimeoutAction } from "@bitwarden/common/key-management/vault-timeout";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import {
- BasePolicy,
- BasePolicyComponent,
-} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
+ BasePolicyEditDefinition,
+ BasePolicyEditComponent,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+import { SharedModule } from "@bitwarden/web-vault/app/shared";
-export class MaximumVaultTimeoutPolicy extends BasePolicy {
+export class MaximumVaultTimeoutPolicy extends BasePolicyEditDefinition {
name = "maximumVaultTimeout";
description = "maximumVaultTimeoutDesc";
type = PolicyType.MaximumVaultTimeout;
@@ -20,11 +21,10 @@ export class MaximumVaultTimeoutPolicy extends BasePolicy {
}
@Component({
- selector: "policy-maximum-timeout",
templateUrl: "maximum-vault-timeout.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class MaximumVaultTimeoutPolicyComponent extends BasePolicyComponent {
+export class MaximumVaultTimeoutPolicyComponent extends BasePolicyEditComponent {
vaultTimeoutActionOptions: { name: string; value: string }[];
data = this.formBuilder.group({
hours: new FormControl(null),
diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-register.ts b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-register.ts
new file mode 100644
index 00000000000..3438e706f10
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/admin-console/policies/policy-edit-register.ts
@@ -0,0 +1,28 @@
+import {
+ ossPolicyEditRegister,
+ BasePolicyEditDefinition,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+
+import { FreeFamiliesSponsorshipPolicy } from "../../billing/policies/free-families-sponsorship.component";
+
+import {
+ ActivateAutofillPolicy,
+ AutomaticAppLoginPolicy,
+ DisablePersonalVaultExportPolicy,
+ MaximumVaultTimeoutPolicy,
+} from "./policy-edit-definitions";
+
+/**
+ * The policy register for Bitwarden Licensed policies.
+ * Add your policy definition here if it is under the Bitwarden License.
+ * It will not appear in the web vault when running in OSS mode.
+ */
+const policyEditRegister: BasePolicyEditDefinition[] = [
+ new MaximumVaultTimeoutPolicy(),
+ new DisablePersonalVaultExportPolicy(),
+ new FreeFamiliesSponsorshipPolicy(),
+ new ActivateAutofillPolicy(),
+ new AutomaticAppLoginPolicy(),
+];
+
+export const bitPolicyEditRegister = ossPolicyEditRegister.concat(policyEditRegister);
diff --git a/bitwarden_license/bit-web/src/app/app.component.ts b/bitwarden_license/bit-web/src/app/app.component.ts
index ca6a5ea8f62..abfb79b8f18 100644
--- a/bitwarden_license/bit-web/src/app/app.component.ts
+++ b/bitwarden_license/bit-web/src/app/app.component.ts
@@ -1,31 +1,10 @@
-import { Component, OnInit } from "@angular/core";
+import { Component } from "@angular/core";
import { AppComponent as BaseAppComponent } from "@bitwarden/web-vault/app/app.component";
-import { ActivateAutofillPolicy } from "./admin-console/policies/activate-autofill.component";
-import { AutomaticAppLoginPolicy } from "./admin-console/policies/automatic-app-login.component";
-import { DisablePersonalVaultExportPolicy } from "./admin-console/policies/disable-personal-vault-export.component";
-import { MaximumVaultTimeoutPolicy } from "./admin-console/policies/maximum-vault-timeout.component";
-import { FreeFamiliesSponsorshipPolicy } from "./billing/policies/free-families-sponsorship.component";
-
@Component({
selector: "app-root",
templateUrl: "../../../../apps/web/src/app/app.component.html",
standalone: false,
})
-export class AppComponent extends BaseAppComponent implements OnInit {
- ngOnInit() {
- super.ngOnInit();
-
- this.policyListService.addPolicies([
- new MaximumVaultTimeoutPolicy(),
- new DisablePersonalVaultExportPolicy(),
- new FreeFamiliesSponsorshipPolicy(),
- new ActivateAutofillPolicy(),
- ]);
-
- if (!this.policyListService.getPolicies().some((p) => p instanceof AutomaticAppLoginPolicy)) {
- this.policyListService.addPolicies([new AutomaticAppLoginPolicy()]);
- }
- }
-}
+export class AppComponent extends BaseAppComponent {}
diff --git a/bitwarden_license/bit-web/src/app/app.module.ts b/bitwarden_license/bit-web/src/app/app.module.ts
index b665dee3b17..e9696a4549f 100644
--- a/bitwarden_license/bit-web/src/app/app.module.ts
+++ b/bitwarden_license/bit-web/src/app/app.module.ts
@@ -6,19 +6,17 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { RouterModule } from "@angular/router";
import { JslibModule } from "@bitwarden/angular/jslib.module";
+import { safeProvider } from "@bitwarden/ui-common";
+import { POLICY_EDIT_REGISTER } from "@bitwarden/web-vault/app/admin-console/organizations/policies";
import { CoreModule } from "@bitwarden/web-vault/app/core";
import { OssRoutingModule } from "@bitwarden/web-vault/app/oss-routing.module";
import { OssModule } from "@bitwarden/web-vault/app/oss.module";
import { WildcardRoutingModule } from "@bitwarden/web-vault/app/wildcard-routing.module";
import { OrganizationsModule } from "./admin-console/organizations/organizations.module";
-import { ActivateAutofillPolicyComponent } from "./admin-console/policies/activate-autofill.component";
-import { AutomaticAppLoginPolicyComponent } from "./admin-console/policies/automatic-app-login.component";
-import { DisablePersonalVaultExportPolicyComponent } from "./admin-console/policies/disable-personal-vault-export.component";
-import { MaximumVaultTimeoutPolicyComponent } from "./admin-console/policies/maximum-vault-timeout.component";
+import { bitPolicyEditRegister } from "./admin-console/policies";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
-import { FreeFamiliesSponsorshipPolicyComponent } from "./billing/policies/free-families-sponsorship.component";
import { AccessIntelligenceModule } from "./dirt/access-intelligence/access-intelligence.module";
/**
@@ -44,14 +42,13 @@ import { AccessIntelligenceModule } from "./dirt/access-intelligence/access-inte
RouterModule,
WildcardRoutingModule, // Needs to be last to catch all non-existing routes
],
- declarations: [
- AppComponent,
- DisablePersonalVaultExportPolicyComponent,
- MaximumVaultTimeoutPolicyComponent,
- ActivateAutofillPolicyComponent,
- AutomaticAppLoginPolicyComponent,
- FreeFamiliesSponsorshipPolicyComponent,
- ],
+ declarations: [AppComponent],
bootstrap: [AppComponent],
+ providers: [
+ safeProvider({
+ provide: POLICY_EDIT_REGISTER,
+ useValue: bitPolicyEditRegister,
+ }),
+ ],
})
export class AppModule {}
diff --git a/bitwarden_license/bit-web/src/app/billing/policies/free-families-sponsorship.component.ts b/bitwarden_license/bit-web/src/app/billing/policies/free-families-sponsorship.component.ts
index dd808300988..db5ef3ba62f 100644
--- a/bitwarden_license/bit-web/src/app/billing/policies/free-families-sponsorship.component.ts
+++ b/bitwarden_license/bit-web/src/app/billing/policies/free-families-sponsorship.component.ts
@@ -2,11 +2,12 @@ import { Component } from "@angular/core";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import {
- BasePolicy,
- BasePolicyComponent,
-} from "@bitwarden/web-vault/app/admin-console/organizations/policies/base-policy.component";
+ BasePolicyEditDefinition,
+ BasePolicyEditComponent,
+} from "@bitwarden/web-vault/app/admin-console/organizations/policies";
+import { SharedModule } from "@bitwarden/web-vault/app/shared";
-export class FreeFamiliesSponsorshipPolicy extends BasePolicy {
+export class FreeFamiliesSponsorshipPolicy extends BasePolicyEditDefinition {
name = "freeFamiliesSponsorship";
description = "freeFamiliesSponsorshipPolicyDesc";
type = PolicyType.FreeFamiliesSponsorshipPolicy;
@@ -14,8 +15,7 @@ export class FreeFamiliesSponsorshipPolicy extends BasePolicy {
}
@Component({
- selector: "policy-free-families-sponsorship",
templateUrl: "free-families-sponsorship.component.html",
- standalone: false,
+ imports: [SharedModule],
})
-export class FreeFamiliesSponsorshipPolicyComponent extends BasePolicyComponent {}
+export class FreeFamiliesSponsorshipPolicyComponent extends BasePolicyEditComponent {}