From 81023d996b00c257672760b42ad64aab42c579eb Mon Sep 17 00:00:00 2001 From: pujashahu Date: Tue, 10 Sep 2024 16:35:34 +0530 Subject: [PATCH] mgr/dashboard: carbonize user management form Fixes: https://tracker.ceph.com/issues/67979 Signed-off-by: Puja Shahu --- .../frontend/src/app/core/auth/auth.module.ts | 47 +- .../auth/user-form/user-form-role.model.ts | 9 +- .../auth/user-form/user-form.component.html | 432 ++++++++---------- .../auth/user-form/user-form.component.ts | 20 +- .../date-time-picker.component.html | 43 +- .../date-time-picker.component.scss | 3 + .../date-time-picker.component.ts | 16 +- .../components/helper/helper.component.html | 3 +- .../frontend/src/styles/themes/_content.scss | 1 + 9 files changed, 298 insertions(+), 276 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/auth.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/auth.module.ts index c0e0517896c..f1f04f7c2f0 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/auth.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/auth.module.ts @@ -17,13 +17,48 @@ import { UserFormComponent } from './user-form/user-form.component'; import { UserListComponent } from './user-list/user-list.component'; import { UserPasswordFormComponent } from './user-password-form/user-password-form.component'; import { UserTabsComponent } from './user-tabs/user-tabs.component'; -import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-components-angular'; + +import { + ButtonModule, + CheckboxModule, + DatePickerModule, + GridModule, + IconModule, + IconService, + InputModule, + ModalModule, + NumberModule, + RadioModule, + SelectModule, + UIShellModule, + TimePickerModule, + ComboBoxModule +} from 'carbon-components-angular'; +// Icons +import ChevronDown from '@carbon/icons/es/chevron--down/16'; +import Close from '@carbon/icons/es/close/32'; +import AddFilled from '@carbon/icons/es/add--filled/32'; +import SubtractFilled from '@carbon/icons/es/subtract--filled/32'; +import Reset from '@carbon/icons/es/reset/32'; +import EyeIcon from '@carbon/icons/es/view/16'; @NgModule({ imports: [ CommonModule, FormsModule, ReactiveFormsModule, SharedModule, + UIShellModule, + InputModule, + GridModule, + ButtonModule, + IconModule, + CheckboxModule, + RadioModule, + SelectModule, + NumberModule, + ModalModule, + DatePickerModule, + TimePickerModule, NgbNavModule, NgbPopoverModule, NgxPipeFunctionModule, @@ -31,8 +66,8 @@ import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-compon NgbModule, IconModule, GridModule, - ButtonModule, - InputModule + InputModule, + ComboBoxModule ], declarations: [ LoginComponent, @@ -46,7 +81,11 @@ import { ButtonModule, GridModule, IconModule, InputModule } from 'carbon-compon UserPasswordFormComponent ] }) -export class AuthModule {} +export class AuthModule { + constructor(private iconService: IconService) { + this.iconService.registerAll([ChevronDown, Close, AddFilled, SubtractFilled, Reset, EyeIcon]); + } +} const routes: Routes = [ { path: '', redirectTo: 'users', pathMatch: 'full' }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form-role.model.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form-role.model.ts index 2d323b04ea5..abf529196f6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form-role.model.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form-role.model.ts @@ -4,11 +4,12 @@ export class UserFormRoleModel implements SelectOption { name: string; description: string; selected = false; - scopes_permissions: object; - enabled = true; - - constructor(name: string, description: string) { + scopes_permissions?: object; + enabled: boolean; + content: string; + constructor(name: string, description: string, content: string) { this.name = name; this.description = description; + this.content = content; } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html index 4169d54c39f..d2e52158473 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html @@ -1,249 +1,205 @@ -
-
-
+
+ +
{{ action | titlecase }} {{ resource | upperFirst }}
-
+ class="form-header">{{ action | titlecase }} {{ resource | upperFirst }} +
+ +
+ Username + + + + + + This field is required. + + + + + The username already exists. + + + +
+ +
+ Password + + + + + + Password confirmation doesn't match the password. + + This field is required. + + {{ passwordValuation }} + + +
- -
- -
- - This field is required. - The username already exists. -
-
- - -
- -
-
- - -
-
-
-
-
- This field is required. - - {{ passwordValuation }} - -
-
- - -
- -
-
- - - Password confirmation doesn't match the password. -
- This field is required. -
-
- - -
-
- - + +
+ + Email + + + + Invalid email. + + +
+ +
+ + + +
+ +
+ Enabled + +
+ +
+ User must change password at next logon + +
+ + + + +
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts index 7c02b86eae0..009d4c193e4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts @@ -55,7 +55,8 @@ export class UserFormComponent extends CdForm implements OnInit { icons = Icons; pwdExpirationSettings: CdPwdExpirationSettings; pwdExpirationFormat = 'YYYY-MM-DD'; - + selectedRole: string[]; + passwordexp: boolean = false; constructor( private authService: AuthService, private authStorageService: AuthStorageService, @@ -91,6 +92,7 @@ export class UserFormComponent extends CdForm implements OnInit { password: [ '', [], + [ CdValidators.passwordPolicy( this.userService, @@ -105,7 +107,7 @@ export class UserFormComponent extends CdForm implements OnInit { ] ], confirmpassword: [''], - pwdExpirationDate: [undefined], + pwdExpirationDate: [''], email: ['', [CdValidators.email]], roles: [[]], enabled: [true, [Validators.required]], @@ -121,8 +123,10 @@ export class UserFormComponent extends CdForm implements OnInit { if (this.router.url.startsWith('/user-management/users/edit')) { this.mode = this.userFormMode.editing; this.action = this.actionLabels.EDIT; + this.passwordexp = false; } else { this.action = this.actionLabels.CREATE; + this.passwordexp = true; } const observables = [this.roleService.list(), this.settingsService.getStandardSettings()]; @@ -130,6 +134,7 @@ export class UserFormComponent extends CdForm implements OnInit { (result: [UserFormRoleModel[], CdPwdExpirationSettings]) => { this.allRoles = _.map(result[0], (role) => { role.enabled = true; + role.content = `${role.name}, ${role.description}`; return role; }); this.pwdExpirationSettings = new CdPwdExpirationSettings(result[1]); @@ -158,7 +163,6 @@ export class UserFormComponent extends CdForm implements OnInit { this.userService.get(username).subscribe((userFormModel: UserFormModel) => { this.response = _.cloneDeep(userFormModel); this.setResponse(userFormModel); - this.loadingReady(); }); }); @@ -173,20 +177,28 @@ export class UserFormComponent extends CdForm implements OnInit { this.userForm.get(key).setValue(response[key]) ); const expirationDate = response['pwdExpirationDate']; + if (expirationDate) { + this.passwordexp = false; this.userForm .get('pwdExpirationDate') .setValue(moment(expirationDate * 1000).format(this.pwdExpirationFormat)); + } else { + this.passwordexp = true; } } getRequest(): UserFormModel { const userFormModel = new UserFormModel(); + ['username', 'password', 'name', 'email', 'roles', 'enabled', 'pwdUpdateRequired'].forEach( - (key) => (userFormModel[key] = this.userForm.get(key).value) + (key) => { + userFormModel[key] = this.userForm.get(key).value; + } ); const expirationDate = this.userForm.get('pwdExpirationDate').value; if (expirationDate) { + this.passwordexp = false; const mom = moment(expirationDate, this.pwdExpirationFormat); if ( this.mode !== this.userFormMode.editing || diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.html index 328e72cc595..ccdb70e39e4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.html @@ -1,22 +1,23 @@ -
-
- - +
+
+ {{name}} + + + Select a time + @@ -24,5 +25,7 @@ value="AM">AM -
+ + +
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.scss index e69de29bb2d..39f2a7115a1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.scss +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.scss @@ -0,0 +1,3 @@ +.form-item-append { + margin-top: 1rem; +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.ts index 4841d2ed92d..3458d9171a7 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/date-time-picker/date-time-picker.component.ts @@ -25,7 +25,8 @@ export class DateTimePickerComponent implements OnInit { @Input() helperText = ''; - + @Input() + placeHolder = ''; @Input() disabled = false; @@ -39,9 +40,8 @@ export class DateTimePickerComponent implements OnInit { date: { [key: number]: string }[] = []; time: string; ampm: string; - sub: Subscription; - + @Input() defaultDate: boolean = false; constructor(private calendar: NgbCalendar) {} ngOnInit() { @@ -59,8 +59,12 @@ export class DateTimePickerComponent implements OnInit { if (!mom.isValid() || mom.isBefore(moment())) { mom = moment(); } + if (this.defaultDate) { + this.date.push([]); + } else { + this.date.push(mom.format('YYYY-MM-DD')); + } - this.date.push(mom.format('YYYY-MM-DD')); const time = mom.format('HH:mm:ss'); this.time = mom.format('hh:mm'); this.ampm = mom.hour() >= 12 ? 'PM' : 'AM'; @@ -76,7 +80,9 @@ export class DateTimePickerComponent implements OnInit { onModelChange(event?: any) { if (event) { - if (Array.isArray(event)) { + if (event.length === 0) { + this.datetime.date = { date: null, time: null, ampm: null }; + } else if (Array.isArray(event)) { this.datetime.date = moment(event[0]).format('YYYY-MM-DD'); } else if (event && ['AM', 'PM'].includes(event)) { const initialMoment = moment(this.datetime.time, 'hh:mm:ss A'); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html index da1a4800f7f..81ad90914b6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/components/helper/helper.component.html @@ -5,7 +5,8 @@ - + diff --git a/src/pybind/mgr/dashboard/frontend/src/styles/themes/_content.scss b/src/pybind/mgr/dashboard/frontend/src/styles/themes/_content.scss index 37f89aba17f..0725b63dbfd 100644 --- a/src/pybind/mgr/dashboard/frontend/src/styles/themes/_content.scss +++ b/src/pybind/mgr/dashboard/frontend/src/styles/themes/_content.scss @@ -33,6 +33,7 @@ $content-theme: map-merge( text-primary: vv.$dark, text-secondary: vv.$dark, text-disabled: vv.$gray-500, + icon-secondary: vv.$gray-800, field-01: colors.$gray-10, interactive: vv.$primary )