]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix rbd form mirroring toggle
authorNizamudeen A <nia@redhat.com>
Wed, 17 Sep 2025 03:39:54 +0000 (09:09 +0530)
committerNizamudeen A <nia@redhat.com>
Wed, 17 Sep 2025 11:18:16 +0000 (16:48 +0530)
- fix the toggle not working while editing the image
- the rbd form mirroring toggle doesn't disable/enable the mirror mode
when you change the pool.

- also re-arrange the form in a way that the required fields are together.
- disable mirroring when selecting the namespace

Fixes: https://tracker.ceph.com/issues/72458
Signed-off-by: Nizamudeen A <nia@redhat.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-contants.ts
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

index c5b251915946f60032e1d79448a1b50ec3a7c637..abc78f7612dcb80548e220516abc4fea7ee5f514 100644 (file)
@@ -12,3 +12,13 @@ export const RBDActionHelpers = {
   journalTooltipText: $localize`'Ensures reliable replication by logging changes before updating the image, but doubles write time, impacting performance. Not recommended for high-speed data processing tasks.`,
   snapshotTooltipText: $localize`This mode replicates RBD images between clusters using snapshots, efficiently copying data changes but requiring complete delta syncing during failover. Ideal for less demanding tasks due to its less granular approach compared to journaling.`
 };
+
+export const RBDPoolMirrorModes = {
+  pool: 'pool',
+  image: 'image'
+}
+
+export const RBDMirroringModes = {
+  journal: 'journal',
+  snapshot: 'snapshot'
+}
index a6675bc0898d2d0ea3d7668c6ccbeca402c5d082..225c52510814adfadfa28cb29f114c1df5cb1b2d 100644 (file)
@@ -75,6 +75,7 @@
                     cdRequiredField="Pool"
                     [invalid]="!rbdForm.controls['pool'].valid && (rbdForm.controls['pool'].dirty)"
                     [invalidText]="poolError"
+                    (valueChange)="setPoolMirrorMode()"
                     *ngIf="mode !== 'editing' && poolPermission.read">
           <option *ngIf="pools === null"
                   [ngValue]="null"
         </ng-template>
       </div>
 
+      <!-- Size -->
+      <div class="form-item">
+        <cds-text-label for="size"
+                        i18n
+                        [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
+                        [invalidText]="sizeError"
+                        cdRequiredField="Size">Size
+          <input cdsText
+                 type="text"
+                 placeholder="e.g., 10GiB"
+                 id="size"
+                 name="size"
+                 formControlName="size"
+                 defaultUnit="GiB"
+                 [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
+                 cdDimlessBinary>
+        </cds-text-label>
+        <ng-template #sizeError>
+          <span class="invalid-feedback"
+                *ngIf="rbdForm.showError('size', formDir, 'required')"
+                i18n>This field is required.</span>
+          <span class="invalid-feedback"
+                *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
+                i18n>You have to increase the size.</span>
+          <span *ngIf="rbdForm.showError('size', formDir, 'pattern')"
+                class="invalid-feedback"
+                i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+        </ng-template>
+      </div>
+
+      <!-- Namespace -->
+      <!-- Skeleton-->
+      <div class="form-item"
+           *ngIf="mode !== 'editing' && rbdForm.getValue('pool') && namespaces === null">
+        <cds-select label="Namespace"
+                    for="namespace"
+                    name="namespace"
+                    id="namespace"
+                    [skeleton]="true"
+                    formControlName="namespace">
+          <option [ngValue]="null"
+                  i18n>Loading...</option>
+        </cds-select>
+      </div>
+
+      <div class="form-item"
+           *ngIf="(mode === 'editing' && rbdForm.getValue('namespace')) || mode !== 'editing' && (namespaces && namespaces.length > 0 || !poolPermission.read)">
+        <cds-text-label label="Namespace"
+                        id="namespace"
+                        [helperText]="namespaceHelperTpl"
+                        *ngIf="mode === 'editing' || !poolPermission.read"
+                        i18n>Namespace
+          <input cdsText
+                 id="namespace"
+                 formControlName="namespace">
+        </cds-text-label>
+
+        <cds-select label="Namespace"
+                    [helperText]="namespaceHelperTpl"
+                    for="namespace"
+                    name="namespace"
+                    id="namespace"
+                    formControlName="namespace"
+                    (valueChange)="disableMirroring($event)"
+                    *ngIf="mode !== 'editing' && poolPermission.read">
+          <option *ngIf="namespaces === null"
+                  [ngValue]="null"
+                  i18n>Loading...</option>
+          <option *ngIf="namespaces !== null && namespaces.length === 0"
+                  [ngValue]="null"
+                  i18n>-- No namespaces available --</option>
+          <option *ngIf="namespaces !== null && namespaces.length > 0"
+                  value=""
+                  i18n>-- Select a namespace --</option>
+          <option *ngFor="let namespace of namespaces"
+                  [value]="namespace">{{ namespace }}</option>
+        </cds-select>
+
+        <ng-template #namespaceHelperTpl>
+          Namespace allows you to logically group RBD images within your Ceph Cluster.Choosing a namespace makes it easier to locate and manage related RBD images efficiently.
+        </ng-template>
+      </div>
+
       <!-- Mirroring -->
       <div class="form-item">
         <cds-checkbox id="mirroring"
         </ng-template>
       </div>
 
-      <!-- Namespace -->
-      <!-- Skeleton-->
-      <div class="form-item"
-           *ngIf="mode !== 'editing' && rbdForm.getValue('pool') && namespaces === null">
-        <cds-select label="Namespace"
-                    for="namespace"
-                    name="namespace"
-                    id="namespace"
-                    [skeleton]="true"
-                    formControlName="namespace">
-          <option [ngValue]="null"
-                  i18n>Loading...</option>
-        </cds-select>
-      </div>
-
-      <div class="form-item">
-        <cds-select label="Namespace"
-                    helperText="Namespace allows you to logically group RBD images within your Ceph Cluster.Choosing a namespace makes it easier to locate and manage related RBD images efficiently"
-                    for="namespace"
-                    name="namespace"
-                    id="namespace"
-                    formControlName="namespace"
-                    *ngIf="(mode === 'editing' && rbdForm.getValue('namespace')) || mode !== 'editing' && (namespaces && namespaces.length > 0 || !poolPermission.read)">
-          <option *ngIf="namespaces === null"
-                  [ngValue]="null"
-                  i18n>Loading...</option>
-          <option *ngIf="namespaces !== null && namespaces.length === 0"
-                  [ngValue]="null"
-                  i18n>-- No namespaces available --</option>
-          <option *ngIf="namespaces !== null && namespaces.length > 0"
-                  [ngValue]="null"
-                  i18n>-- Select a namespace --</option>
-          <option *ngFor="let namespace of namespaces"
-                  [value]="namespace">{{ namespace }}</option>
-        </cds-select>
-      </div>
-
-      <!-- Size -->
-      <div class="form-item">
-        <cds-text-label for="size"
-                        i18n
-                        [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
-                        [invalidText]="sizeError"
-                        cdRequiredField="Size">Size
-          <input cdsText
-                 type="text"
-                 placeholder="e.g., 10GiB"
-                 id="size"
-                 name="size"
-                 formControlName="size"
-                 defaultUnit="GiB"
-                 [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
-                 cdDimlessBinary>
-        </cds-text-label>
-        <ng-template #sizeError>
-          <span class="invalid-feedback"
-                *ngIf="rbdForm.showError('size', formDir, 'required')"
-                i18n>This field is required.</span>
-          <span class="invalid-feedback"
-                *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
-                i18n>You have to increase the size.</span>
-          <span *ngIf="rbdForm.showError('size', formDir, 'pattern')"
-                class="invalid-feedback"
-                i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
-        </ng-template>
-      </div>
-
       <!-- Advanced Section -->
       <cd-form-advanced-fieldset>
         <!-- Features -->
index 84652ebd6c1175d84e3601a975bd7e1e962a13aa..fdc6d35cc01474f8f5ed993f2c49217055288261 100644 (file)
@@ -298,7 +298,7 @@ export class RbdFormComponent extends CdForm implements OnInit {
     });
   }
 
-  setPoolMirrorMode() {
+  setPoolMirrorMode(namespace?: string) {
     this.currentPoolName =
       this.mode === this.rbdFormMode.editing
         ? this.response?.pool_name
@@ -309,7 +309,11 @@ export class RbdFormComponent extends CdForm implements OnInit {
         const pool = data.content_data.pools.find((o: any) => o.name === this.currentPoolName);
         this.currentPoolMirrorMode = pool.mirror_mode;
         if (this.mode === this.rbdFormMode.editing) {
-          if (this.currentPoolMirrorMode === 'pool') {
+          if (namespace) {
+            this.mirroring = false;
+            this.rbdForm.get('mirroring').disable();
+          }
+          if (this.currentPoolMirrorMode === this.rbdPoolMirrorModes.pool) {
             this.showMirrorDisableMessage = true;
           } else {
             this.showMirrorDisableMessage = false;
@@ -668,7 +672,7 @@ export class RbdFormComponent extends CdForm implements OnInit {
         this.mirroring = false;
         this.rbdForm.get('mirroring').setValue(this.mirroring);
       }
-      this.setPoolMirrorMode();
+      this.setPoolMirrorMode(response.namespace);
     }
     this.rbdForm.get('pool').setValue(response.pool_name);
     this.onPoolChange(response.pool_name);
@@ -852,7 +856,18 @@ export class RbdFormComponent extends CdForm implements OnInit {
   }
 
   shouldDisable(option: string): boolean {
-    return this.currentPoolMirrorMode === 'pool' && option === 'snapshot' ? true : null;
+    return this.currentPoolMirrorMode === 'pool' && option === 'snapshot' ? true : false;
+  }
+
+  disableMirroring(namespace: string) {
+    const mirroringControl = this.rbdForm.get('mirroring');
+    if (namespace) {
+      this.mirroring = false;
+      mirroringControl.disable();
+    } else {
+      this.mirroring = true;
+      mirroringControl.enable();
+    }
   }
 
   submit() {