]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: NVMeoF namespace create form should show subsystem selection first 68175/head
authorSagar Gopale <sagar.gopale@ibm.com>
Thu, 2 Apr 2026 08:06:37 +0000 (13:36 +0530)
committerSagar Gopale <sagar.gopale@ibm.com>
Wed, 15 Apr 2026 07:16:09 +0000 (12:46 +0530)
Fixes: https://tracker.ceph.com/issues/75846
Signed-off-by: Sagar Gopale <sagar.gopale@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-form/nvmeof-namespaces-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/nvmeof-namespaces-form/nvmeof-namespaces-form.component.ts

index c87e889e42eada174ce25c3baf4d601f67e83f7d..370db1c726d6dd0fe72e5eca1ff98a43891e6407 100644 (file)
         </cd-help-text>
       </div>
 
+      <!-- Subsystem -->
+      <div cdsRow
+           class="form-item">
+        <div cdsCol>
+          <cds-select
+            formControlName="subsystem"
+            cdValidate
+            #subsystemRef="cdValidate"
+            label="Select subsystem"
+            [invalid]="subsystemRef.isInvalid"
+            invalidText="This field is required"
+            i18n-label
+            i18n-invalidText>
+            @if (!subsystems) {
+            <option
+              [ngValue]="null"
+              disabled>Loading...</option>
+            }
+            @if (subsystems && subsystems.length === 0) {
+            <option
+              [ngValue]="null"
+              disabled>-- No subsystems available --</option>
+            }
+            @if (subsystems && subsystems.length > 0) {
+            <option
+              selectionFeedback="top-after-reopen"
+              value=""
+              selected>Select a subsystem</option>
+            }
+            @for (subsystem of subsystems; track subsystem.nqn) {
+            <option
+              [value]="subsystem.nqn">{{ subsystem.nqn }}</option>
+            }
+          </cds-select>
+        </div>
+      </div>
+
       <!-- Namespace Count (Create only) -->
       <div cdsRow
            class="form-item">
         <div cdsCol>
           <cds-number
             formControlName="nsCount"
+            cdValidate
+            #nsCountRef="cdValidate"
             label="Number of namespaces"
             helperText="No. of namespaces to generate. Value must be between 1 and 5."
             [min]="MIN_NAMESPACE_CREATE"
             [max]="MAX_NAMESPACE_CREATE"
-            [invalid]="nsForm.controls['nsCount'].invalid && (nsForm.controls['nsCount'].dirty || nsForm.controls['nsCount'].touched)"
+            [invalid]="nsCountRef.isInvalid"
             [invalidText]="nsForm.getError('required', 'nsCount') ? requiredInvalidText : nsCountInvalidText"
             i18n-label
             i18n-helperText>
         <div cdsCol>
           <cds-number
             formControlName="namespace_size"
+            cdValidate
+            #namespaceSizeRef="cdValidate"
             label="Namespace size (GiB)"
             helperText="Specify the size to expose to hosts. Leave blank for full device/file."
             placeholder="e.g. 100"
             [min]="0"
-            [invalid]="nsForm.controls['namespace_size'].invalid && (nsForm.controls['namespace_size'].dirty || nsForm.controls['namespace_size'].touched)"
+            [invalid]="namespaceSizeRef.isInvalid"
             [invalidText]="namespaceSizeError"
             i18n-label
             i18n-helperText>
       </div>
       }
 
-      <!-- Subsystem -->
-      <div cdsRow
-           class="form-item">
-        <div cdsCol>
-          <cds-select
-            formControlName="subsystem"
-            label="Select subsystem"
-            [invalid]="nsForm.controls['subsystem'].invalid && (nsForm.controls['subsystem'].dirty || nsForm.controls['subsystem'].touched)"
-            invalidText="This field is required"
-            i18n-label
-            i18n-invalidText>
-            @if (subsystems === undefined) {
-            <option
-              [ngValue]="null"
-              disabled>Loading...</option>
-            }
-            @if (subsystems && subsystems.length === 0) {
-            <option
-              [ngValue]="null"
-              disabled>-- No subsystems available --</option>
-            }
-            @if (subsystems && subsystems.length > 0) {
-            <option
-              selectionFeedback="top-after-reopen"
-              value=""
-              selected>Select a subsystem</option>
-            }
-            @for (subsystem of subsystems; track subsystem.nqn) {
-            <option
-              [value]="subsystem.nqn">{{ subsystem.nqn }}</option>
-            }
-          </cds-select>
-        </div>
-      </div>
-
       <!-- Pool -->
       <div cdsRow
            class="form-item">
         <div cdsCol>
           <cds-select
             formControlName="pool"
+            cdValidate
+            #poolRef="cdValidate"
             label="RBD image pool"
-            [invalid]="nsForm.controls['pool'].invalid && (nsForm.controls['pool'].dirty || nsForm.controls['pool'].touched)"
+            [invalid]="poolRef.isInvalid"
             invalidText="This field is required"
             helperText="Pool where the backing Ceph block device resides."
             i18n-label
               i18n>Image name (optional)</label>
             <cds-text-label
               helperText="Provide a name for the images. For bulk creation, this will be used as the base prefix with numeric suffixes (e.g., img-1, img-2). Leave blank to auto-generate."
-              [invalid]="nsForm.controls['rbd_image_name'].invalid && (nsForm.controls['rbd_image_name'].dirty || nsForm.controls['rbd_image_name'].touched)"
+              [invalid]="rbdImageNameRef.isInvalid"
               [invalidText]="nsForm.getError('rbdImageName', 'rbd_image_name') ? 'Image name contains invalid characters' : ''"
               i18n-helperText
               i18n-invalidText>
               <input cdsText
+                     cdValidate
+                     #rbdImageNameRef="cdValidate"
                      placeholder="Enter a name"
                      formControlName="rbd_image_name" />
             </cds-text-label>
         <div cdsCol>
           <cds-select
             formControlName="rbd_image_name"
+            cdValidate
+            #rbdImageSelectRef="cdValidate"
             label="RBD Image"
-            [invalid]="nsForm.controls['rbd_image_name'].invalid && (nsForm.controls['rbd_image_name'].dirty || nsForm.controls['rbd_image_name'].touched)"
+            [invalid]="rbdImageSelectRef.isInvalid"
             invalidText="This field is required"
             helperText="Select an existing RBD image from the pool to expose as a namespace."
             i18n-label
           <cds-text-label
             label="Image size (GiB)"
             helperText="The size of the namespace image."
-            [invalid]="nsForm.controls['image_size'].invalid && (nsForm.controls['image_size'].dirty || nsForm.controls['image_size'].touched)"
+            [invalid]="imageSizeRef.isInvalid"
             [invalidText]="sizeError"
             cdRequiredField="Image Size"
             i18n-label
             i18n-helperText>
             <input cdsText
+                   cdValidate
+                   #imageSizeRef="cdValidate"
                    type="text"
                    placeholder="e.g. 100 GiB"
                    id="image_size"
                    formControlName="image_size"
                    defaultUnit="GiB"
                    [min]="0"
-                   [invalid]="nsForm.controls['image_size'].invalid && (nsForm.controls['image_size'].dirty || nsForm.controls['image_size'].touched)"
+                   [invalid]="imageSizeRef.isInvalid"
                    cdDimlessBinary>
           </cds-text-label>
           <ng-template #sizeError>
     </div>
   </div>
 </form>
-
index f3488cb68adce383cd696e7b240669f1a63b457c..63b1b5fb56668ea2d5a14b38a26689e42ebd6981 100644 (file)
@@ -45,7 +45,7 @@ export class NvmeofNamespacesFormComponent implements OnInit {
 
   nsForm: CdFormGroup;
   subsystemNQN: string;
-  subsystems: NvmeofSubsystem[] = [];
+  subsystems: NvmeofSubsystem[] | null = null;
   rbdPools: Array<Pool> = null;
   rbdImages: any[] = [];
   initiatorCandidates: { content: string; selected: boolean }[] = [];