mirror of
https://github.com/bitwarden/browser
synced 2026-02-27 18:13:29 +00:00
[PM-25627] convert policy dialogs to drawer (#18534)
* Enhance policy edit dialogs by updating dialog size to large for improved layout and switching to openDrawer method for better user experience. * Enhance policy edit dialogs by adding policy status badges to indicate if a policy is enabled, improving user visibility and experience. * Update dialog component styles to enhance drawer behavior by changing height to full screen and adding sticky footer for improved layout and user experience. * Refactor policy display layout by wrapping buttons and badges in a flex container for improved alignment and spacing. * Refactor password policy forms in admin console for improved layout - Simplified the structure of form fields in `master-password.component.html` and `password-generator.component.html` by removing unnecessary div wrappers. - Updated the label for the password type policy override in `messages.json` for clarity. * Update dialog size in policy edit component for consistency - Changed the dialog size from 'large' to 'default' in `policy-edit-dialog.component.html` to align with design standards. * refactor(dialog): update dialog component styles for drawer layout - Adjusted height class for drawer dialogs from 'tw-h-screen' to 'tw-h-full' for better layout management. - Removed sticky positioning for footer in drawer mode to improve visual consistency. * refactor(dialog): enhance form layout for policy edit dialogs - Added classes for full height and flex column layout to the form elements in policy edit dialogs for improved visual consistency and usability.
This commit is contained in:
@@ -19,12 +19,14 @@
|
|||||||
@if (p.display$(organization, configService) | async) {
|
@if (p.display$(organization, configService) | async) {
|
||||||
<tr bitRow>
|
<tr bitRow>
|
||||||
<td bitCell ngPreserveWhitespaces>
|
<td bitCell ngPreserveWhitespaces>
|
||||||
<button type="button" bitLink (click)="edit(p, organizationId)">
|
<div class="tw-flex tw-items-center tw-gap-2">
|
||||||
{{ p.name | i18n }}
|
<button type="button" bitLink (click)="edit(p, organizationId)">
|
||||||
</button>
|
{{ p.name | i18n }}
|
||||||
@if (policiesEnabledMap.get(p.type)) {
|
</button>
|
||||||
<span bitBadge variant="success">{{ "on" | i18n }}</span>
|
@if (policiesEnabledMap.get(p.type)) {
|
||||||
}
|
<span bitBadge variant="success">{{ "on" | i18n }}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
<small class="tw-text-muted tw-block">{{ p.description | i18n }}</small>
|
<small class="tw-text-muted tw-block">{{ p.description | i18n }}</small>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -13,29 +13,24 @@
|
|||||||
<bit-label>{{ "enforceOnLoginDesc" | i18n }}</bit-label>
|
<bit-label>{{ "enforceOnLoginDesc" | i18n }}</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
|
|
||||||
<div class="tw-flex tw-space-x-4">
|
<bit-form-field>
|
||||||
<bit-form-field class="tw-flex-auto">
|
<bit-label>{{ "minComplexityScore" | i18n }}</bit-label>
|
||||||
<bit-label>{{ "minComplexityScore" | i18n }}</bit-label>
|
<bit-select formControlName="minComplexity" id="minComplexity">
|
||||||
<bit-select formControlName="minComplexity" id="minComplexity">
|
<bit-option *ngFor="let o of passwordScores" [value]="o.value" [label]="o.name"></bit-option>
|
||||||
<bit-option
|
</bit-select>
|
||||||
*ngFor="let o of passwordScores"
|
</bit-form-field>
|
||||||
[value]="o.value"
|
|
||||||
[label]="o.name"
|
<bit-form-field>
|
||||||
></bit-option>
|
<bit-label>{{ "minLength" | i18n }}</bit-label>
|
||||||
</bit-select>
|
<input
|
||||||
</bit-form-field>
|
bitInput
|
||||||
<bit-form-field class="tw-flex-auto">
|
type="number"
|
||||||
<bit-label>{{ "minLength" | i18n }}</bit-label>
|
formControlName="minLength"
|
||||||
<input
|
id="minLength"
|
||||||
bitInput
|
[min]="MinPasswordLength"
|
||||||
type="number"
|
[max]="MaxPasswordLength"
|
||||||
formControlName="minLength"
|
/>
|
||||||
id="minLength"
|
</bit-form-field>
|
||||||
[min]="MinPasswordLength"
|
|
||||||
[max]="MaxPasswordLength"
|
|
||||||
/>
|
|
||||||
</bit-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<bit-form-control class="!tw-mb-2">
|
<bit-form-control class="!tw-mb-2">
|
||||||
<input type="checkbox" bitCheckbox formControlName="requireUpper" id="requireUpper" />
|
<input type="checkbox" bitCheckbox formControlName="requireUpper" id="requireUpper" />
|
||||||
|
|||||||
@@ -4,56 +4,50 @@
|
|||||||
<bit-label>{{ "turnOn" | i18n }}</bit-label>
|
<bit-label>{{ "turnOn" | i18n }}</bit-label>
|
||||||
</bit-form-control>
|
</bit-form-control>
|
||||||
|
|
||||||
<div class="tw-grid tw-grid-cols-12 tw-gap-4">
|
<bit-form-field>
|
||||||
<bit-form-field class="tw-col-span-6 tw-mb-0">
|
<bit-label>{{ "passwordTypePolicyOverride" | i18n }}</bit-label>
|
||||||
<bit-label>{{ "overridePasswordTypePolicy" | i18n }}</bit-label>
|
<bit-select formControlName="overridePasswordType" id="overrideType">
|
||||||
<bit-select formControlName="overridePasswordType" id="overrideType">
|
<bit-option
|
||||||
<bit-option
|
*ngFor="let o of overridePasswordTypeOptions"
|
||||||
*ngFor="let o of overridePasswordTypeOptions"
|
[value]="o.value"
|
||||||
[value]="o.value"
|
[label]="o.name"
|
||||||
[label]="o.name"
|
></bit-option>
|
||||||
></bit-option>
|
</bit-select>
|
||||||
</bit-select>
|
</bit-form-field>
|
||||||
</bit-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- password-specific policies -->
|
<!-- password-specific policies -->
|
||||||
<div *ngIf="showPasswordPolicies$ | async">
|
<div *ngIf="showPasswordPolicies$ | async">
|
||||||
<h3 bitTypography="h3" class="tw-mt-4">{{ "password" | i18n }}</h3>
|
<h3 bitTypography="h3" class="tw-mt-4">{{ "password" | i18n }}</h3>
|
||||||
<div class="tw-grid tw-grid-cols-12 tw-gap-4">
|
<bit-form-field>
|
||||||
<bit-form-field class="tw-col-span-6">
|
<bit-label>{{ "minLength" | i18n }}</bit-label>
|
||||||
<bit-label>{{ "minLength" | i18n }}</bit-label>
|
<input
|
||||||
<input
|
bitInput
|
||||||
bitInput
|
type="number"
|
||||||
type="number"
|
[min]="minLengthMin"
|
||||||
[min]="minLengthMin"
|
[max]="minLengthMax"
|
||||||
[max]="minLengthMax"
|
formControlName="minLength"
|
||||||
formControlName="minLength"
|
/>
|
||||||
/>
|
</bit-form-field>
|
||||||
</bit-form-field>
|
<bit-form-field>
|
||||||
</div>
|
<bit-label>{{ "minNumbers" | i18n }}</bit-label>
|
||||||
<div class="tw-grid tw-grid-cols-12 tw-gap-4">
|
<input
|
||||||
<bit-form-field class="tw-col-span-6">
|
bitInput
|
||||||
<bit-label>{{ "minNumbers" | i18n }}</bit-label>
|
type="number"
|
||||||
<input
|
[min]="minNumbersMin"
|
||||||
bitInput
|
[max]="minNumbersMax"
|
||||||
type="number"
|
formControlName="minNumbers"
|
||||||
[min]="minNumbersMin"
|
/>
|
||||||
[max]="minNumbersMax"
|
</bit-form-field>
|
||||||
formControlName="minNumbers"
|
<bit-form-field>
|
||||||
/>
|
<bit-label>{{ "minSpecial" | i18n }}</bit-label>
|
||||||
</bit-form-field>
|
<input
|
||||||
<bit-form-field class="tw-col-span-6">
|
bitInput
|
||||||
<bit-label>{{ "minSpecial" | i18n }}</bit-label>
|
type="number"
|
||||||
<input
|
[min]="minSpecialMin"
|
||||||
bitInput
|
[max]="minSpecialMax"
|
||||||
type="number"
|
formControlName="minSpecial"
|
||||||
[min]="minSpecialMin"
|
/>
|
||||||
[max]="minSpecialMax"
|
</bit-form-field>
|
||||||
formControlName="minSpecial"
|
|
||||||
/>
|
|
||||||
</bit-form-field>
|
|
||||||
</div>
|
|
||||||
<bit-form-control>
|
<bit-form-control>
|
||||||
<input type="checkbox" bitCheckbox formControlName="useUpper" id="useUpper" />
|
<input type="checkbox" bitCheckbox formControlName="useUpper" id="useUpper" />
|
||||||
<bit-label>{{ "uppercaseLabel" | i18n }}</bit-label>
|
<bit-label>{{ "uppercaseLabel" | i18n }}</bit-label>
|
||||||
@@ -79,18 +73,16 @@
|
|||||||
<!-- passphrase-specific policies -->
|
<!-- passphrase-specific policies -->
|
||||||
<div *ngIf="showPassphrasePolicies$ | async">
|
<div *ngIf="showPassphrasePolicies$ | async">
|
||||||
<h3 bitTypography="h3" class="tw-mt-4">{{ "passphrase" | i18n }}</h3>
|
<h3 bitTypography="h3" class="tw-mt-4">{{ "passphrase" | i18n }}</h3>
|
||||||
<div class="tw-grid tw-grid-cols-12 tw-gap-4">
|
<bit-form-field>
|
||||||
<bit-form-field class="tw-col-span-6">
|
<bit-label>{{ "minimumNumberOfWords" | i18n }}</bit-label>
|
||||||
<bit-label>{{ "minimumNumberOfWords" | i18n }}</bit-label>
|
<input
|
||||||
<input
|
bitInput
|
||||||
bitInput
|
type="number"
|
||||||
type="number"
|
[min]="minNumberWordsMin"
|
||||||
[min]="minNumberWordsMin"
|
[max]="minNumberWordsMax"
|
||||||
[max]="minNumberWordsMax"
|
formControlName="minNumberWords"
|
||||||
formControlName="minNumberWords"
|
/>
|
||||||
/>
|
</bit-form-field>
|
||||||
</bit-form-field>
|
|
||||||
</div>
|
|
||||||
<bit-form-control>
|
<bit-form-control>
|
||||||
<input type="checkbox" bitCheckbox formControlName="capitalize" id="capitalize" />
|
<input type="checkbox" bitCheckbox formControlName="capitalize" id="capitalize" />
|
||||||
<bit-label>{{ "capitalize" | i18n }}</bit-label>
|
<bit-label>{{ "capitalize" | i18n }}</bit-label>
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
<form [formGroup]="formGroup" [bitSubmit]="submit" class="tw-h-full tw-flex tw-flex-col">
|
||||||
<bit-dialog [loading]="loading" [title]="'editPolicy' | i18n" [subtitle]="policy.name | i18n">
|
<bit-dialog dialogSize="default" [loading]="loading">
|
||||||
|
<ng-container bitDialogTitle>
|
||||||
|
<span class="tw-flex tw-items-center tw-gap-2">
|
||||||
|
{{ policy.name | i18n }}
|
||||||
|
@if (isPolicyEnabled) {
|
||||||
|
<span bitBadge variant="success">{{ "on" | i18n }}</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
<ng-container bitDialogContent>
|
<ng-container bitDialogContent>
|
||||||
<div *ngIf="loading">
|
<div *ngIf="loading">
|
||||||
<i
|
<i
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ export class PolicyEditDialogComponent implements AfterViewInit {
|
|||||||
return this.data.policy;
|
return this.data.policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isPolicyEnabled(): boolean {
|
||||||
|
return this.policyComponent?.policyResponse?.enabled ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type guard to check if the policy component has the buildVNextRequest method.
|
* Type guard to check if the policy component has the buildVNextRequest method.
|
||||||
*/
|
*/
|
||||||
@@ -196,6 +200,9 @@ export class PolicyEditDialogComponent implements AfterViewInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
static open = (dialogService: DialogService, config: DialogConfig<PolicyEditDialogData>) => {
|
static open = (dialogService: DialogService, config: DialogConfig<PolicyEditDialogData>) => {
|
||||||
return dialogService.open<PolicyEditDialogResult>(PolicyEditDialogComponent, config);
|
return dialogService.openDrawer<PolicyEditDialogResult, PolicyEditDialogData>(
|
||||||
|
PolicyEditDialogComponent,
|
||||||
|
config,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
<form [formGroup]="formGroup" [bitSubmit]="submit" class="tw-h-full tw-flex tw-flex-col">
|
||||||
<bit-dialog [loading]="loading">
|
<bit-dialog dialogSize="large" [loading]="loading">
|
||||||
<ng-container bitDialogTitle>
|
<ng-container bitDialogTitle>
|
||||||
@let title = (multiStepSubmit | async)[currentStep()]?.titleContent();
|
@let title = (multiStepSubmit | async)[currentStep()]?.titleContent();
|
||||||
@if (title) {
|
@if (title) {
|
||||||
@@ -40,13 +40,16 @@
|
|||||||
@if (showBadge) {
|
@if (showBadge) {
|
||||||
<span bitBadge variant="info" class="tw-w-[99px] tw-my-2"> {{ "availableNow" | i18n }}</span>
|
<span bitBadge variant="info" class="tw-w-[99px] tw-my-2"> {{ "availableNow" | i18n }}</span>
|
||||||
}
|
}
|
||||||
<span>
|
<span class="tw-flex tw-items-center tw-gap-2">
|
||||||
{{ (showBadge ? "autoConfirm" : "editPolicy") | i18n }}
|
{{ (showBadge ? "autoConfirm" : "editPolicy") | i18n }}
|
||||||
@if (!showBadge) {
|
@if (!showBadge) {
|
||||||
<span class="tw-text-muted tw-font-normal tw-text-sm">
|
<span class="tw-text-muted tw-font-normal tw-text-sm">
|
||||||
{{ policy.name | i18n }}
|
{{ policy.name | i18n }}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
@if (isPolicyEnabled) {
|
||||||
|
<span bitBadge variant="success">{{ "on" | i18n }}</span>
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -287,6 +287,9 @@ export class AutoConfirmPolicyDialogComponent
|
|||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
config: DialogConfig<AutoConfirmPolicyDialogData>,
|
config: DialogConfig<AutoConfirmPolicyDialogData>,
|
||||||
) => {
|
) => {
|
||||||
return dialogService.open<PolicyEditDialogResult>(AutoConfirmPolicyDialogComponent, config);
|
return dialogService.openDrawer<PolicyEditDialogResult, AutoConfirmPolicyDialogData>(
|
||||||
|
AutoConfirmPolicyDialogComponent,
|
||||||
|
config,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
<form [formGroup]="formGroup" [bitSubmit]="submit" class="tw-h-full tw-flex tw-flex-col">
|
||||||
<bit-dialog [loading]="loading">
|
<bit-dialog dialogSize="large" [loading]="loading">
|
||||||
<ng-container bitDialogTitle>
|
<ng-container bitDialogTitle>
|
||||||
@let title = multiStepSubmit()[currentStep()]?.titleContent();
|
@let title = multiStepSubmit()[currentStep()]?.titleContent();
|
||||||
@if (title) {
|
@if (title) {
|
||||||
@@ -35,7 +35,12 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<ng-template #step0Title>
|
<ng-template #step0Title>
|
||||||
{{ policy.name | i18n }}
|
<span class="tw-flex tw-items-center tw-gap-2">
|
||||||
|
{{ policy.name | i18n }}
|
||||||
|
@if (isPolicyEnabled) {
|
||||||
|
<span bitBadge variant="success">{{ "on" | i18n }}</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #step1Title>
|
<ng-template #step1Title>
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export class OrganizationDataOwnershipPolicyDialogComponent
|
|||||||
};
|
};
|
||||||
|
|
||||||
static open = (dialogService: DialogService, config: DialogConfig<PolicyEditDialogData>) => {
|
static open = (dialogService: DialogService, config: DialogConfig<PolicyEditDialogData>) => {
|
||||||
return dialogService.open<PolicyEditDialogResult>(
|
return dialogService.openDrawer<PolicyEditDialogResult, PolicyEditDialogData>(
|
||||||
OrganizationDataOwnershipPolicyDialogComponent,
|
OrganizationDataOwnershipPolicyDialogComponent,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5394,8 +5394,8 @@
|
|||||||
"minimumNumberOfWords": {
|
"minimumNumberOfWords": {
|
||||||
"message": "Minimum number of words"
|
"message": "Minimum number of words"
|
||||||
},
|
},
|
||||||
"overridePasswordTypePolicy": {
|
"passwordTypePolicyOverride": {
|
||||||
"message": "Password Type",
|
"message": "Password type",
|
||||||
"description": "Name of the password generator policy that overrides the user's password/passphrase selection."
|
"description": "Name of the password generator policy that overrides the user's password/passphrase selection."
|
||||||
},
|
},
|
||||||
"userPreference": {
|
"userPreference": {
|
||||||
|
|||||||
Reference in New Issue
Block a user