]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: Carbonize the Change Password Form
authorAfreen Misbah <afreen@ibm.com>
Tue, 21 Oct 2025 16:37:46 +0000 (22:07 +0530)
committerAfreen Misbah <afreen@ibm.com>
Mon, 24 Nov 2025 09:10:20 +0000 (14:40 +0530)
Fixes https://tracker.ceph.com/issues/73193

-  using carbon based stylings, typography and components
-  used grid layout for form arrangement
-  breadcrumb is slightly off, which needs to be fixed by applying grid layout to the app shell

Signed-off-by: Afreen Misbah <afreen@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-password-form/user-password-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-password-form/user-password-form.component.scss
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-password-form/user-password-form.component.ts
src/pybind/mgr/dashboard/frontend/src/styles/ceph-custom/_forms.scss

index e09907aeb85d81865799953b8aae112e217d3a58..438aee155a8ae4dde83e7decde896ff1bb7d23dd 100644 (file)
-<div class="cd-col-form">
-  <form #frm="ngForm"
-        [formGroup]="userForm"
-        novalidate>
-    <div class="card">
-      <div i18n="form title"
-           class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
-
-      <div class="card-body">
-        <!-- Old password -->
-        <div class="form-group row">
-          <label class="cd-col-form-label required"
-                 for="oldpassword"
-                 i18n>Old password</label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     type="password"
-                     placeholder="Old password..."
-                     id="oldpassword"
-                     formControlName="oldpassword"
-                     autocomplete="new-password"
-                     autofocus>
-              <button class="btn btn-light"
-                      cdPasswordButton="oldpassword">
-              </button>
-            </div>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('oldpassword', frm, 'required')"
-                  i18n>This field is required.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('oldpassword', frm, 'notmatch')"
-                  i18n>The old and new passwords must be different.</span>
-          </div>
-        </div>
-
-        <!-- New password -->
-        <div class="form-group row">
-          <label class="cd-col-form-label"
-                 for="newpassword">
-            <span class="required"
-                  i18n>New password</span>
-            <cd-helper *ngIf="passwordPolicyHelpText.length > 0"
-                       class="text-pre-wrap"
-                       html="{{ passwordPolicyHelpText }}">
-            </cd-helper>
-          </label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     type="password"
-                     placeholder="Password..."
-                     id="newpassword"
-                     autocomplete="new-password"
-                     formControlName="newpassword">
-              <button type="button"
-                      class="btn btn-light"
-                      cdPasswordButton="newpassword">
-              </button>
-            </div>
-            <div class="password-strength-level">
-              <div class="{{ passwordStrengthLevelClass }}"
-                   data-toggle="tooltip"
-                   title="{{ passwordValuation }}">
-              </div>
-            </div>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('newpassword', frm, 'required')"
-                  i18n>This field is required.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('newpassword', frm, 'notmatch')"
-                  i18n>The old and new passwords must be different.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('newpassword', frm, 'passwordPolicy')">
-              {{ passwordValuation }}
-            </span>
-          </div>
-        </div>
-
-        <!-- Confirm new password -->
-        <div class="form-group row">
-          <label class="cd-col-form-label required"
-                 for="confirmnewpassword"
-                 i18n>Confirm new password</label>
-          <div class="cd-col-form-input">
-            <div class="input-group">
-              <input class="form-control"
-                     type="password"
-                     autocomplete="new-password"
-                     placeholder="Confirm new password..."
-                     id="confirmnewpassword"
-                     formControlName="confirmnewpassword">
-              <button class="btn btn-light"
-                      cdPasswordButton="confirmnewpassword">
-              </button>
-            </div>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('confirmnewpassword', frm, 'required')"
-                  i18n>This field is required.</span>
-            <span class="invalid-feedback"
-                  *ngIf="userForm.showError('confirmnewpassword', frm, 'match')"
-                  i18n>Password confirmation doesn't match the new password.</span>
-          </div>
-        </div>
+<form [formGroup]="userForm"
+      novalidate>
+  <div cdsGrid
+       [useCssGrid]="true"
+       [narrow]="true"
+       [fullWidth]="true">
+    <div cdsCol
+         [columnNumbers]="{sm: 4, md: 8}">
+      <div cdsRow
+           class="form-heading">
+        <h3>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+        <cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
       </div>
-
-      <div class="card-footer">
+      <div cdsRow
+           class="form-item">
+        <cds-password-label
+          [invalid]="!userForm.controls.oldpassword.valid && userForm.controls.oldpassword.dirty"
+          [invalidText]="oldPasswordInvalid">
+          Old Password
+          <input cdsPassword
+                 formControlName="oldpassword"
+                 autocomplete="oldpassword"
+                 [invalid]="!userForm.controls.oldpassword.valid && userForm.controls.oldpassword.dirty"
+                 id="oldpassword"
+                 autofocus>
+        </cds-password-label>
+      </div>
+      <div cdsRow
+           class="form-item">
+        <cds-password-label
+          [invalid]="!userForm.controls.newpassword.valid && userForm.controls.newpassword.dirty"
+          [invalidText]="newPasswordInvalid"
+          [helperText]="passwordPolicyHelpText">
+          New Password
+          <input cdsPassword
+                 formControlName="newpassword"
+                 autocomplete="newpassword"
+                 [invalid]="!userForm.controls.newpassword.valid && userForm.controls.newpassword.dirty"
+                 id="newpassword">
+        </cds-password-label>
+      </div>
+      <div cdsRow
+           class="form-item">
+        <cds-password-label
+          [invalid]="!userForm.controls.confirmnewpassword.valid && userForm.controls.confirmnewpassword.dirty"
+          [invalidText]="confirmNewPasswordInvalid">
+          Confirm New Password
+          <input cdsPassword
+                 formControlName="confirmnewpassword"
+                 autocomplete="confirmnewpassword"
+                 [invalid]="!userForm.controls.confirmnewpassword.valid && userForm.controls.confirmnewpassword.dirty"
+                 id="confirmnewpassword">
+        </cds-password-label>
+      </div>
+      <div cdsRow>
         <cd-form-button-panel (submitActionEvent)="onSubmit()"
                               [form]="userForm"
                               [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
-                              wrappingClass="text-right"></cd-form-button-panel>
+                              wrappingClass="text-right form-button"></cd-form-button-panel>
       </div>
     </div>
-  </form>
-</div>
+  </div>
+</form>
+
+<ng-template #oldPasswordInvalid>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('oldpassword', null, 'required')"
+        i18n>{{INVALID_TEXTS['required']}}</span>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('oldpassword', null, 'notmatch')"
+        i18n>{{INVALID_TEXTS['notmatch']}}</span>
+</ng-template>
+
+<ng-template #newPasswordInvalid>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('newpassword', null, 'required')"
+        i18n>{{INVALID_TEXTS['required']}}</span>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('newpassword', null, 'notmatch')"
+        i18n>{{INVALID_TEXTS['notmatch']}}</span>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('newpassword', null, 'passwordPolicy')"
+        i18n>{{INVALID_TEXTS['passwordPolicy']}}</span>
+</ng-template>
+
+<ng-template #confirmNewPasswordInvalid>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('confirmnewpassword', null, 'required')"
+        i18n>{{INVALID_TEXTS['required']}}</span>
+  <span class="invalid-feedback"
+        *ngIf="userForm.showError('confirmnewpassword', null, 'match')"
+        i18n>{{INVALID_TEXTS['match']}}</span>
+</ng-template>
index dffb927ac16ec64b9449077df4c5dfabc5c7b24a..bb2c47a27187cd66f9fea94247652a241d4ca876 100644 (file)
@@ -28,6 +28,12 @@ export class UserPasswordFormComponent {
   passwordStrengthLevelClass: string;
   passwordValuation: string;
   icons = Icons;
+  INVALID_TEXTS = {
+    required: 'This field is required',
+    notmatch: 'The old and new passwords must be different',
+    match: "Password confirmation doesn't match the new password.",
+    passwordPolicy: ''
+  };
 
   constructor(
     public actionLabels: ActionLabelsI18n,
@@ -76,11 +82,17 @@ export class UserPasswordFormComponent {
             CdValidators.passwordPolicy(
               this.userService,
               () => this.authStorageService.getUsername(),
-              (_valid: boolean, credits: number, valuation: string) => {
+              (_valid: boolean, credits, valuation: string) => {
+                /* `passwordStrengthLevelClass` and `passwordValuation` is used in LoginPasswordFormComponent
+                 * These values are not needed in this component after carbonization.
+                 * @TODO: Need to remove once the LoginPasswordFormComponent is carbonized.
+                 */
                 this.passwordStrengthLevelClass = this.passwordPolicyService.mapCreditsToCssClass(
                   credits
                 );
                 this.passwordValuation = _.defaultTo(valuation, '');
+
+                this.INVALID_TEXTS['passwordPolicy'] = _.defaultTo(valuation, '');
               }
             )
           ]
index ce6e8e6843923c27c0cb426cb6699337280f99dc..7d209ca2b9ca87c98f3ecaa373623a3c696c52b8 100644 (file)
@@ -111,12 +111,36 @@ Carbon Overrides
 /******************************************
 Form Controls
 ******************************************/
+
+// Ref: https://carbondesignsystem.com/components/form/style/#recommended-for-default-forms/
+
+form {
+  // Overriding to remove extra space which is getting added when cdsGrid is used.
+  // If we use grid in app shell, then we dont need to set this.
+  // @TODO: Add grid layout for the app shell
+  .cds--grid {
+    padding-inline: 0;
+  }
+}
+
+.form-heading {
+  h3 {
+    @include type.type-style('heading-03');
+  }
+
+  display: block;
+  margin-bottom: var(--cds-spacing-08);
+}
+
 .form-item {
   @extend .cds--form-item;
 
   display: block;
-  margin-bottom: 32px;
-  margin-top: 32px;
+  margin-bottom: var(--cds-spacing-07);
+}
+
+.form-button {
+  margin-top: var(--cds-spacing-09);
 }
 
 .form-item-append {