]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: [Dashboard] Incorrect action button label "Edit User" instead of ... 68845/head
authorpujaoshahu <pshahu@redhat.com>
Mon, 11 May 2026 13:07:53 +0000 (18:37 +0530)
committerpujashahu <pshahu@redhat.com>
Wed, 22 Jul 2026 09:04:06 +0000 (14:34 +0530)
Fixes: https://tracker.ceph.com/issues/76507
Signed-off-by: pujaoshahu <pshahu@redhat.com>
Summary: Updated submit button labels in edit forms to display "Save" instead of "Edit User", "Edit Pool", or "Edit Host" for better UX consistency, while keeping form titles unchanged.

Modified Files
role-form.component.ts: Added submitAction property to control submit button label by mode; edit mode uses Save changes, create mode uses Create Role.

role-form.component.html: Submit button now binds to submitAction instead of action/resource text.

role-form.component.spec.ts: Added tests for submitAction behavior in create and edit modes.

user-form.component.ts: Uses submitAction property; edit mode label updated to Save changes.

user-form.component.html: Submit button uses submitAction binding.

user-form.component.spec.ts: Added/updated tests covering submitAction behavior.

pool-form.component.ts: Uses submitAction property; edit mode label updated to Save changes.

pool-form.component.html: Submit button uses submitAction binding.

pool-form.component.spec.ts: Updated submit label test expectation for edit mode.

hosts.component.ts: Edit host modal submit button text changed to Save changes.

hosts.component.spec.ts: Updated test to match Save changes button text.

app.constants.ts: In the current workspace snapshot, there is no SAVE constant added under ActionLabelsI18n.

Signed-off-by: pujaoshahu <pshahu@redhat.com>
Signed-off-by: pujashahu <pshahu@redhat.com>
16 files changed:
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/role-form/role-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/core/auth/user-form/user-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/services/host-action.service.ts

index 55ce961fed9921af8f0ee916f9c9ef4df86464c8..7046fcc2bfbea7c85236cca791105aa68dd6090b 100644 (file)
       <cd-form-button-panel
         (submitActionEvent)="submit()"
         [form]="formDir"
-        [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+        [submitText]="submitAction"
         wrappingClass="text-right"
       ></cd-form-button-panel>
     </form>
index ce30293655663dba714317d6c4be362b785573cb..932edad3c16d7f900e9192ead919d036ab602e28 100644 (file)
@@ -119,6 +119,7 @@ export class RbdFormComponent extends CdForm implements OnInit {
 
   action: string;
   resource: string;
+  submitAction: string;
   private rbdImage = new ReplaySubject(1);
   private routerUrl: string;
 
@@ -352,17 +353,21 @@ export class RbdFormComponent extends CdForm implements OnInit {
     if (url.startsWith('/block/rbd/edit')) {
       this.mode = this.rbdFormMode.editing;
       this.action = this.actionLabels.EDIT;
+      this.submitAction = this.actionLabels.SAVE_CHANGES;
       this.disableForEdit();
     } else if (url.startsWith('/block/rbd/clone')) {
       this.mode = this.rbdFormMode.cloning;
       this.disableForClone();
       this.action = this.actionLabels.CLONE;
+      this.submitAction = `${this.action} ${this.resource}`;
     } else if (url.startsWith('/block/rbd/copy')) {
       this.mode = this.rbdFormMode.copying;
       this.action = this.actionLabels.COPY;
+      this.submitAction = `${this.action} ${this.resource}`;
       this.disableForCopy();
     } else {
       this.action = this.actionLabels.CREATE;
+      this.submitAction = `${this.action} ${this.resource}`;
     }
     _.each(this.features, (feature) => {
       this.rbdForm
index 21375beb0ba3951e4db65a9a5d9453b4102765ed..b9e9494e4e676efa8308eafa95b59a579b6c7f84 100644 (file)
@@ -11,6 +11,7 @@ import { CephSharedModule } from '~/app/ceph/shared/ceph-shared.module';
 import { CoreModule } from '~/app/core/core.module';
 import { HostService } from '~/app/shared/api/host.service';
 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
 import { TableActionsComponent } from '~/app/shared/datatable/table-actions/table-actions.component';
 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
@@ -274,6 +275,21 @@ describe('HostsComponent', () => {
     expect(showForceMaintenanceModal.showModal).toBeFalsy();
   });
 
+  it('should set host edit modal submit label to Save changes', () => {
+    const hostService = TestBed.inject(HostService);
+    const modalService = TestBed.inject(ModalCdsService);
+    spyOn(hostService, 'getLabels').and.returnValue(of([]));
+    const showSpy = spyOn(modalService, 'show').and.stub();
+
+    component.selection = new CdTableSelection();
+    component.selection.selected = [{ hostname: 'host-test', labels: [] }];
+
+    component.editAction();
+
+    expect(showSpy).toHaveBeenCalled();
+    expect(showSpy.calls.mostRecent().args[1].submitButtonText).toBe('Save changes');
+  });
+
   describe('table actions', () => {
     const fakeHosts = require('./fixtures/host_list_response.json');
 
index ba3b673cac4e826dd64db79ec03c6214c5a9cc5f..b94aec974a21333431b024834cef79208cb69365 100644 (file)
   <cd-form-button-panel
     (submitActionEvent)="onSubmit()"
     [form]="serviceForm"
-    [submitText]="(action | titlecase) + ' ' + resource"
+    [submitText]="submitAction"
     [modalForm]="true"
   ></cd-form-button-panel>
 </cds-modal>
index ef80a1ca4cbdcd3d2e0f228815679583b67bb1b8..26927c6d4efa3f8e2f85d52d34ea67188bcac4d3 100644 (file)
@@ -81,6 +81,7 @@ export class ServiceFormComponent extends CdForm implements OnInit {
   serviceForm: CdFormGroup;
   action: string;
   resource: string;
+  submitAction: string;
   serviceTypes: string[] = [];
   serviceIds: string[] = [];
   selectedHosts: string[] = [];
@@ -697,6 +698,7 @@ export class ServiceFormComponent extends CdForm implements OnInit {
   ngOnInit(): void {
     this.open = true;
     this.action = this.actionLabels.CREATE;
+    this.submitAction = `${this.action} ${this.resource}`;
     this.resolveRoute();
     this.getRgwModuleStatus();
     this.mgrModuleService.updateCompleted$.subscribe(() => this.getRgwModuleStatus());
@@ -738,6 +740,8 @@ export class ServiceFormComponent extends CdForm implements OnInit {
 
     if (this.editing) {
       this.action = this.actionLabels.EDIT;
+      this.submitAction = this.actionLabels.SAVE_CHANGES;
+      this.disableForEditing(this.serviceType);
       this.cephServiceService
         .list(new HttpParams({ fromObject: { limit: -1, offset: 0 } }), this.serviceName)
         .observable.subscribe((response: CephServiceSpec[]) => {
index 2b2b09d6dfd4670e19508f32390f75f7152d8e76..d0ade1b8b5ab1fb35a1dcbf6d469fd97e2e4afea 100644 (file)
       <cd-form-button-panel
         (submitActionEvent)="submit()"
         [form]="form"
-        [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+        [submitText]="submitAction"
         wrappingClass="text-right form-button"
       >
       </cd-form-button-panel>
index 928205b8479216c82207f4e8d638c8325ee717ee..c07552605424564eaf8033e2f67be29a94f17a15 100644 (file)
@@ -174,6 +174,23 @@ describe('PoolFormComponent', () => {
     expect(component).toBeTruthy();
   });
 
+  describe('submit label', () => {
+    it('should set submit label to Create Pool in create mode', () => {
+      expect(component.submitAction).toBe('Create Pool');
+    });
+
+    it('should set submit label to Save changes in edit mode', () => {
+      fixture.destroy();
+      Object.defineProperty(router, 'url', {
+        get: () => '/pool/edit/somePoolName',
+        configurable: true
+      });
+      setUpPoolComponent();
+
+      expect(component.submitAction).toBe('Save changes');
+    });
+  });
+
   describe('throws error for not allowed users', () => {
     const expectError = (redirected: boolean) => {
       navigationSpy.calls.reset();
index 5f1e32eccd4db3249d6090d3853b8ca801296cb5..dfd02d41d266796ebe82ba232837054603890f2e 100644 (file)
@@ -115,6 +115,7 @@ export class PoolFormComponent extends CdForm implements OnInit {
   currentConfigurationValues: { [configKey: string]: any } = {};
   action: string;
   resource: string;
+  submitAction: string;
   icons = Icons;
   pgAutoscaleModes: string[];
   crushUsage: string[] = undefined; // Will only be set if a rule is used by some pool
@@ -153,6 +154,9 @@ export class PoolFormComponent extends CdForm implements OnInit {
     this.editing = this.router.url.startsWith(`/pool/${URLVerbs.EDIT}`);
     this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
     this.resource = $localize`pool`;
+    this.submitAction = this.editing
+      ? this.actionLabels.SAVE_CHANGES
+      : `${this.action} ${_.upperFirst(this.resource)}`;
     this.authenticate();
     this.createForm();
   }
index e24e718a5e18fd3290047d3d15200a84138f7da6..f42cc2ab21ecff1d458864361815bd6574def3b5 100644 (file)
@@ -79,7 +79,7 @@
         <cd-form-button-panel
           (submitActionEvent)="submit()"
           [form]="roleForm"
-          [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+          [submitText]="submitAction"
           wrappingClass="text-right"
         >
         </cd-form-button-panel>
index f10e315e5df2e4173e9758b93065e882e40dcb56..83cd1c919b8ef5e02d1465b724e8a43a1d12c4f6 100644 (file)
@@ -82,6 +82,10 @@ describe('RoleFormComponent', () => {
       expect(component.mode).toBeUndefined();
     });
 
+    it('should set submit action to Create Role', () => {
+      expect(component.submitAction).toBe('Create Role');
+    });
+
     it('should submit', () => {
       const role: RoleFormModel = {
         name: 'role1',
@@ -138,6 +142,10 @@ describe('RoleFormComponent', () => {
       expect(component.mode).toBe('editing');
     });
 
+    it('should set submit action to Save changes', () => {
+      expect(component.submitAction).toBe('Save changes');
+    });
+
     it('should submit', () => {
       formHelper.setValue('scopes_permissions', {
         osd: ['read', 'update'],
index 18649b2e59f05c7a08749e414a5c756428adf93a..9bbfefcc64b03301ea2a4c1e7f32c59cc678be30 100644 (file)
@@ -37,6 +37,7 @@ export class RoleFormComponent extends CdForm implements OnInit {
 
   action: string;
   resource: string;
+  submitAction: string;
 
   constructor(
     private route: ActivatedRoute,
@@ -98,8 +99,10 @@ export class RoleFormComponent extends CdForm implements OnInit {
     if (this.router.url.startsWith('/user-management/roles/edit')) {
       this.mode = this.roleFormMode.editing;
       this.action = this.actionLabels.EDIT;
+      this.submitAction = this.actionLabels.SAVE_CHANGES;
     } else {
       this.action = this.actionLabels.CREATE;
+      this.submitAction = `${this.action} ${_.upperFirst(this.resource)}`;
     }
     if (this.mode === this.roleFormMode.editing) {
       this.initEdit();
index bc163105c83858f30e1fa63d3d164c6ff386f20a..84a5bf740d2dcb20ae8ef7a0c09bfcae39a4130d 100644 (file)
       <cd-form-button-panel
         (submitActionEvent)="submit()"
         [form]="userForm"
-        [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+        [submitText]="submitAction"
         wrappingClass="text-right"
       >
       </cd-form-button-panel>
index d68e2e9be5399bceef25c0f00be8be19968c41da..86312e26a25b242ce249055839798ef18ab1c6d1 100644 (file)
@@ -86,6 +86,10 @@ describe('UserFormComponent', () => {
       component.ngOnInit();
     });
 
+    it('should set submit label to Create User', () => {
+      expect(component.submitAction).toBe('Create User');
+    });
+
     it('should not disable fields', () => {
       [
         'username',
@@ -268,6 +272,10 @@ describe('UserFormComponent', () => {
       expect(form.getValue('roles')).toContain('administrator');
     });
 
+    it('should set submit label to Save changes', () => {
+      expect(component.submitAction).toBe('Save changes');
+    });
+
     it('should alert if user is removing needed role permission', () => {
       let modalBodyTpl = null;
       spyOn(modalService, 'show').and.callFake((_content, initialState) => {
index 4200797334053a089d7bfae7eb9efb62084f2889..65d40743041066c22f6087f5242ae63b8462bd52 100644 (file)
@@ -53,6 +53,7 @@ export class UserFormComponent extends CdForm implements OnInit {
   messages = new SelectMessages({ empty: $localize`There are no roles.` });
   action: string;
   resource: string;
+  submitAction: string;
   passwordPolicyHelpText = '';
   passwordStrengthLevelClass: string;
   passwordValuation: string;
@@ -146,9 +147,11 @@ 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.submitAction = this.actionLabels.SAVE_CHANGES;
       this.passwordexp = false;
     } else {
       this.action = this.actionLabels.CREATE;
+      this.submitAction = `${this.action} ${_.upperFirst(this.resource)}`;
       this.passwordexp = true;
     }
     this.userForm.get('password').updateValueAndValidity();
index 41891d9b8432bce73fcd8865df9a90934366ee77..bc8b457f8bc47eae5b2601ca14734b51b5f624a4 100644 (file)
@@ -170,6 +170,7 @@ export class ActionLabelsI18n {
   NFS_EXPORT: string;
   VIEW: string;
   EDIT_GATEWAYS_GROUP: string;
+  SAVE_CHANGES: string;
   constructor() {
     /* Create a new item */
     this.CREATE = $localize`Create`;
@@ -263,6 +264,7 @@ export class ActionLabelsI18n {
     this.NFS_EXPORT = $localize`Create NFS Share`;
     this.VIEW = $localize`View`;
     this.EDIT_GATEWAYS_GROUP = $localize`Edit gateways group`;
+    this.SAVE_CHANGES = $localize`Save changes`;
   }
 }
 
index f2ae91dd1b2a2b8c8ed926a372153c7b23718a32..93af02328c33c723a51db504a1eece09b1fdc9dd 100644 (file)
@@ -44,7 +44,7 @@ export class HostActionService {
       this.cdsModalService.show(FormModalComponent, {
         titleText: $localize`Edit Host: ${host.hostname}`,
         fields: [labelsField],
-        submitButtonText: $localize`Edit Host`,
+        submitButtonText: $localize`Save changes`,
         onSubmit: (values: { labels: string[] }) => {
           this.submitHostLabelUpdate(host.hostname, values.labels, onSuccess);
         }