1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 21:33:27 +00:00
Files
browser/apps/web/src/app/admin-console/organizations/policies/base-policy-edit.component.ts
Oscar Hinton 3790e09673 AC - Prefer signal & change detection (#16948)
* Modernize Angular

* Remove conflicted files
2025-10-23 11:25:48 -04:00

144 lines
4.9 KiB
TypeScript

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";
import { DialogConfig, DialogRef, DialogService } from "@bitwarden/components";
import type { PolicyEditDialogData, PolicyEditDialogResult } from "./policy-edit-dialog.component";
/**
* Interface for policy dialog components.
* Any component that implements this interface can be used as a custom policy edit dialog.
*/
export interface PolicyDialogComponent {
open: (
dialogService: DialogService,
config: DialogConfig<PolicyEditDialogData>,
) => DialogRef<PolicyEditDialogResult>;
}
/**
* 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<BasePolicyEditComponent>;
/**
* The dialog component that will be opened when editing this policy.
* This allows customizing the look and feel of each policy's dialog contents.
*/
editDialogComponent?: PolicyDialogComponent;
/**
* 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<boolean> {
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 {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() policyResponse: PolicyResponse | undefined;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@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> | 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;
}
}