]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix some linting issues. 62926/head
authorAnkit <51ankitkp@gmail.com>
Wed, 23 Apr 2025 05:44:25 +0000 (11:14 +0530)
committerAnkit <51ankitkp@gmail.com>
Wed, 7 May 2025 11:55:57 +0000 (17:25 +0530)
Fixes: https://tracker.ceph.com/issues/66995
Signed-off-by: Ankit Kumar <51ankitkp@gmail.com>
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

index b76e45225f689f2ca4fa7b1f0a2db627949ef757..5b081cc27320076c1c696ad99a86268d79ac5ae7 100644 (file)
@@ -16,7 +16,6 @@
                  i18n>Name</label>
           <div class="cd-col-form-input">
             <input id="name"
-                   name="name"
                    type="text"
                    class="form-control"
                    placeholder="Name..."
@@ -47,8 +46,7 @@
           <div class="cd-col-form-input">
             <select class="form-select"
                     id="poolType"
-                    formControlName="poolType"
-                    name="poolType">
+                    formControlName="poolType">
               <option ngValue=""
                       i18n>-- Select a pool type --</option>
               <option *ngFor="let poolType of data.poolTypes"
@@ -71,7 +69,6 @@
             <div class="cd-col-form-input">
               <select class="form-select"
                       id="pgAutoscaleMode"
-                      name="pgAutoscaleMode"
                       formControlName="pgAutoscaleMode">
                 <option *ngFor="let mode of pgAutoscaleModes"
                         [value]="mode">
@@ -90,7 +87,6 @@
             <div class="cd-col-form-input">
               <input class="form-control"
                      id="pgNum"
-                     name="pgNum"
                      formControlName="pgNum"
                      min="1"
                      type="number"
                      id="size"
                      [max]="getMaxSize()"
                      [min]="getMinSize()"
-                     name="size"
                      type="number"
                      formControlName="size">
               <span class="invalid-feedback"
           </label>
           <div class="cd-col-form-input">
             <cd-select-badges id="applications"
-                              name="applications"
                               [customBadges]="true"
                               [customBadgeValidators]="data.applications.validators"
                               [messages]="data.applications.messages"
             <div class="custom-control custom-checkbox">
               <input class="custom-control-input"
                      id="rbdMirroring"
-                     name="rbdMirroring"
                      type="checkbox"
                      formControlName="rbdMirroring">
               <label class="custom-control-label"
               <div class="input-group mb-1">
                 <select class="form-select"
                         id="erasureProfile"
-                        name="erasureProfile"
                         formControlName="erasureProfile"
                         (change)="erasureProfileChange()">
                   <option *ngIf="!ecProfiles"
                 <div class="input-group">
                   <select class="form-select"
                           id="crushRule"
-                          formControlName="crushRule"
-                          name="crushSet">
+                          formControlName="crushRule">
                     <option [ngValue]="null"
                             i18n>-- Select a crush rule --</option>
                     <option *ngFor="let rule of current.rules"
             <div class="cd-col-form-input">
               <select class="form-select"
                       id="mode"
-                      name="mode"
                       formControlName="mode">
                 <option *ngFor="let mode of info.compression_modes"
                         [value]="mode">
               <div class="cd-col-form-input">
                 <select class="form-select"
                         id="algorithm"
-                        name="algorithm"
                         formControlName="algorithm">
                   <option *ngIf="!info.compression_algorithms"
                           ngValue=""
                 <ng-container i18n>Minimum blob size</ng-container>
               </label>
               <div class="cd-col-form-input">
-                <input id="minBlobSize"
-                       name="minBlobSize"
-                       formControlName="minBlobSize"
-                       type="text"
-                       min="0"
-                       class="form-control"
-                       i18n-placeholder
-                       placeholder="e.g., 128KiB"
-                       defaultUnit="KiB"
-                       cdDimlessBinary>
+                <div class="input-group mb-1">
+                  <input id="minBlobSize"
+                         formControlName="minBlobSize"
+                         type="text"
+                         min="0"
+                         class="form-control"
+                         i18n-placeholder
+                         placeholder="e.g., 128">
+                  <select id="minUnit"
+                          class="form-input form-select"
+                          formControlName="minBlobSizeUnit">
+                    <option *ngFor="let u of blobUnits"
+                            [value]="u">
+                      {{ u }}
+                    </option>
+                  </select>
+                </div>
                 <cd-help-text>
                   <span i18n>Chunks smaller than Minimum blob size are never compressed</span>
                 </cd-help-text>
                 <ng-container i18n>Maximum blob size</ng-container>
               </label>
               <div class="cd-col-form-input">
-                <input id="maxBlobSize"
-                       type="text"
-                       min="0"
-                       formControlName="maxBlobSize"
-                       class="form-control"
-                       i18n-placeholder
-                       placeholder="e.g., 512KiB"
-                       defaultUnit="KiB"
-                       cdDimlessBinary>
+                <div class="input-group mb-1">
+                  <input id="maxBlobSize"
+                         type="text"
+                         min="0"
+                         formControlName="maxBlobSize"
+                         class="form-control">
+                  <select id="minUnit"
+                          class="form-input form-select"
+                          formControlName="maxBlobSizeUnit">
+                    <option *ngFor="let u of blobUnits"
+                            [value]="u">
+                        {{ u }}
+                    </option>
+                  </select>
+                </div>
                 <cd-help-text>
                   <span i18n>Chunks larger than `Maximum Blob Size` are broken into smaller blobs of size mentioned before being compressed.</span>
                 </cd-help-text>
               </label>
               <div class="cd-col-form-input">
                 <input id="ratio"
-                       name="ratio"
                        formControlName="ratio"
                        type="number"
                        min="0"
               <ng-container i18n>Max bytes</ng-container>
             </label>
             <div class="cd-col-form-input">
-              <input class="form-control"
-                     id="max_bytes"
-                     name="max_bytes"
-                     type="text"
-                     formControlName="max_bytes"
-                     i18n-placeholder
-                     placeholder="e.g., 10GiB"
-                     defaultUnit="GiB"
-                     cdDimlessBinary>
+              <div class="input-group mb-1">
+                <input class="form-control"
+                       id="max_bytes"
+                       type="text"
+                       formControlName="max_bytes">
+                <select id="unit"
+                        class="form-input form-select"
+                        formControlName="maxBytesUnit">
+                  <option *ngFor="let u of maxBytesUnits"
+                          [value]="u">
+                    {{ u }}
+                  </option>
+                </select>
+              </div>
               <cd-help-text>
                 <span i18n>Leave it blank or specify 0 to disable this quota.</span>
                 <br>
               <input class="form-control"
                      id="max_objects"
                      min="0"
-                     name="max_objects"
                      type="number"
                      formControlName="max_objects">
               <cd-help-text>
index 9c2bb5ed5d9cccd26419be37454418791efc28d0..7ab4584a09fbd6350959262bfd5ce08a99301fe8 100644 (file)
@@ -336,30 +336,35 @@ describe('PoolFormComponent', () => {
       it('validates minBlobSize to be only valid between 0 and maxBlobSize', () => {
         formHelper.expectErrorChange('minBlobSize', -1, 'min');
         formHelper.expectValidChange('minBlobSize', 0);
-        formHelper.setValue('maxBlobSize', '2 KiB');
-        formHelper.expectErrorChange('minBlobSize', '3 KiB', 'maximum');
-        formHelper.expectValidChange('minBlobSize', '1.9 KiB');
+        formHelper.setValue('minBlobSizeUnit', 'KiB');
+        formHelper.setValue('maxBlobSize', '2');
+        formHelper.setValue('maxBlobSizeUnit', 'KiB');
+        formHelper.expectErrorChange('minBlobSize', '3', 'maximum');
+        formHelper.expectValidChange('minBlobSize', '1.9');
       });
 
       it('validates minBlobSize converts numbers', () => {
         const control = formHelper.setValue('minBlobSize', '1');
+        const controlUnit = formHelper.setValue('minBlobSizeUnit', 'KiB');
         fixture.detectChanges();
         formHelper.expectValid(control);
-        expect(control.value).toBe('1 KiB');
+        expect(control.value).toBe('1');
+        expect(controlUnit.value).toBe('KiB');
       });
 
       it('validates maxBlobSize to be only valid bigger than minBlobSize', () => {
         formHelper.expectErrorChange('maxBlobSize', -1, 'min');
-        formHelper.setValue('minBlobSize', '1 KiB');
-        formHelper.expectErrorChange('maxBlobSize', '0.5 KiB', 'minimum');
-        formHelper.expectValidChange('maxBlobSize', '1.5 KiB');
+        formHelper.setValue('minBlobSize', '1');
+        formHelper.setValue('minBlobSizeUnit', 'MiB');
+        formHelper.expectErrorChange('maxBlobSize', '0.5', 'minimum');
+        formHelper.expectValidChange('maxBlobSize', '1.5');
       });
 
       it('s valid to only use one blob size', () => {
-        formHelper.expectValid(formHelper.setValue('minBlobSize', '1 KiB'));
+        formHelper.expectValid(formHelper.setValue('minBlobSize', '1'));
         formHelper.expectValid(formHelper.setValue('maxBlobSize', ''));
         formHelper.expectValid(formHelper.setValue('minBlobSize', ''));
-        formHelper.expectValid(formHelper.setValue('maxBlobSize', '1 KiB'));
+        formHelper.expectValid(formHelper.setValue('maxBlobSize', '1'));
       });
 
       it('dismisses any size error if one of the blob sizes is changed into a valid state', () => {
@@ -378,19 +383,22 @@ describe('PoolFormComponent', () => {
 
       it('validates maxBlobSize converts numbers', () => {
         const control = formHelper.setValue('maxBlobSize', '2');
+        const controlUnit = formHelper.setValue('maxBlobSizeUnit', 'KiB');
         fixture.detectChanges();
-        expect(control.value).toBe('2 KiB');
+        expect(control.value).toBe('2');
+        expect(controlUnit.value).toBe('KiB');
       });
 
       it('validates that odd size validator works as expected', () => {
-        const odd = (min: string, max: string) => component['oddBlobSize'](min, max);
-        expect(odd('10', '8')).toBe(true);
-        expect(odd('8', '-')).toBe(false);
-        expect(odd('8', '10')).toBe(false);
-        expect(odd(null, '8')).toBe(false);
-        expect(odd('10', '')).toBe(false);
-        expect(odd('10', null)).toBe(false);
-        expect(odd(null, null)).toBe(false);
+        const odd = (min: string, minUnit: string, max: string, maxUnit: string) =>
+          component['oddBlobSize'](min, minUnit, max, maxUnit);
+        expect(odd('10', 'KiB', '8', 'KiB')).toBe(true);
+        expect(odd('8', 'KiB', '-', 'KiB')).toBe(false);
+        expect(odd('8', 'KiB', '10', 'KiB')).toBe(false);
+        expect(odd(null, 'KiB', '8', 'KiB')).toBe(false);
+        expect(odd('10', 'KiB', '', 'KiB')).toBe(false);
+        expect(odd('10', 'KiB', null, 'KiB')).toBe(false);
+        expect(odd(null, 'KiB', null, 'KiB')).toBe(false);
       });
 
       it('validates ratio to be only valid between 0 and 1', () => {
@@ -1149,10 +1157,13 @@ describe('PoolFormComponent', () => {
         setMultipleValues({
           mode: 'passive',
           algorithm: 'lz4',
-          minBlobSize: '4 K',
-          maxBlobSize: '4 M',
+          minBlobSize: '4',
+          minBlobSizeUnit: 'KiB',
+          maxBlobSize: '4',
+          maxBlobSizeUnit: 'MiB',
           ratio: 0.7
         });
+        fixture.detectChanges();
         expectEcSubmit({
           compression_mode: 'passive',
           compression_algorithm: 'lz4',
@@ -1237,7 +1248,8 @@ describe('PoolFormComponent', () => {
 
       it('creates a pool with quotas', () => {
         setMultipleValues({
-          max_bytes: 1024 * 1024,
+          max_bytes: 1,
+          maxBytesUnit: 'MiB',
           max_objects: 3000
         });
         component.data.applications.selected = ['cephfs', 'rgw'];
@@ -1343,10 +1355,13 @@ describe('PoolFormComponent', () => {
         expect(form.getValue('pgNum')).toBe(pool.pg_num);
         expect(form.getValue('mode')).toBe(pool.options.compression_mode);
         expect(form.getValue('algorithm')).toBe(pool.options.compression_algorithm);
-        expect(form.getValue('minBlobSize')).toBe('512 KiB');
-        expect(form.getValue('maxBlobSize')).toBe('1 MiB');
+        expect(form.getValue('minBlobSize')).toBe('512');
+        expect(form.getValue('minBlobSizeUnit')).toBe('KiB');
+        expect(form.getValue('maxBlobSize')).toBe('1');
+        expect(form.getValue('maxBlobSizeUnit')).toBe('MiB');
         expect(form.getValue('ratio')).toBe(pool.options.compression_required_ratio);
-        expect(form.getValue('max_bytes')).toBe('1 GiB');
+        expect(form.getValue('max_bytes')).toBe('1');
+        expect(form.getValue('maxBytesUnit')).toBe('GiB');
         expect(form.getValue('max_objects')).toBe(pool.quota_max_objects);
       });
 
index b7cda346e984bdddfbe3ea78bdcc588f19d407fc..697b425319f71c3ec97ec2b0d45f699d88974c3b 100644 (file)
@@ -68,6 +68,8 @@ export class PoolFormComponent extends CdForm implements OnInit {
   editing = false;
   isReplicated = false;
   isErasure = false;
+  blobUnits = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
+  maxBytesUnits = ['KiB', 'MiB', 'GiB', 'TiB'];
   data = new PoolFormData();
   externalPgChange = false;
   current: Record<string, any> = {
@@ -131,9 +133,15 @@ export class PoolFormComponent extends CdForm implements OnInit {
       minBlobSize: new UntypedFormControl('', {
         updateOn: 'blur'
       }),
+      minBlobSizeUnit: new UntypedFormControl(this.blobUnits[0], {
+        updateOn: 'blur'
+      }),
       maxBlobSize: new UntypedFormControl('', {
         updateOn: 'blur'
       }),
+      maxBlobSizeUnit: new UntypedFormControl(this.blobUnits[2], {
+        updateOn: 'blur'
+      }),
       ratio: new UntypedFormControl(this.DEFAULT_RATIO, {
         updateOn: 'blur'
       })
@@ -182,6 +190,7 @@ export class PoolFormComponent extends CdForm implements OnInit {
         ecOverwrites: new UntypedFormControl(false),
         compression: compressionForm,
         max_bytes: new UntypedFormControl(''),
+        maxBytesUnit: new UntypedFormControl(this.maxBytesUnits[2]),
         max_objects: new UntypedFormControl(0),
         rbdMirroring: new UntypedFormControl(false)
       },
@@ -264,6 +273,13 @@ export class PoolFormComponent extends CdForm implements OnInit {
       initialData: pool.configuration,
       sourceType: RbdConfigurationSourceField.pool
     });
+    const maxBytesConverted = this.dimlessBinaryPipe.transform(pool.quota_max_bytes).split(' ');
+    const minBlobSizeConverted = this.dimlessBinaryPipe
+      .transform(pool.options.compression_min_blob_size)
+      .split(' ');
+    const maxBlobSizeConverted = this.dimlessBinaryPipe
+      .transform(pool.options.compression_max_blob_size)
+      .split(' ');
     this.poolTypeChange(pool.type);
     const rules = this.info.crush_rules_replicated.concat(this.info.crush_rules_erasure);
     const dataMap = {
@@ -277,10 +293,13 @@ export class PoolFormComponent extends CdForm implements OnInit {
       ecOverwrites: pool.flags_names.includes('ec_overwrites'),
       mode: pool.options.compression_mode,
       algorithm: pool.options.compression_algorithm,
-      minBlobSize: this.dimlessBinaryPipe.transform(pool.options.compression_min_blob_size),
-      maxBlobSize: this.dimlessBinaryPipe.transform(pool.options.compression_max_blob_size),
+      minBlobSize: minBlobSizeConverted[0],
+      minBlobSizeUnit: minBlobSizeConverted[1],
+      maxBlobSize: maxBlobSizeConverted[0],
+      maxBlobSizeUnit: maxBlobSizeConverted[1],
       ratio: pool.options.compression_required_ratio,
-      max_bytes: this.dimlessBinaryPipe.transform(pool.quota_max_bytes),
+      max_bytes: maxBytesConverted[0],
+      maxBytesUnit: maxBytesConverted[1],
       max_objects: pool.quota_max_objects
     };
     Object.keys(dataMap).forEach((controlName: string) => {
@@ -378,9 +397,15 @@ export class PoolFormComponent extends CdForm implements OnInit {
     this.form.get('minBlobSize').valueChanges.subscribe(() => {
       this.form.get('maxBlobSize').updateValueAndValidity({ emitEvent: false });
     });
+    this.form.get('minBlobSizeUnit').valueChanges.subscribe(() => {
+      this.form.get('maxBlobSize').updateValueAndValidity({ emitEvent: false });
+    });
     this.form.get('maxBlobSize').valueChanges.subscribe(() => {
       this.form.get('minBlobSize').updateValueAndValidity({ emitEvent: false });
     });
+    this.form.get('maxBlobSizeUnit').valueChanges.subscribe(() => {
+      this.form.get('minBlobSize').updateValueAndValidity({ emitEvent: false });
+    });
   }
 
   private poolTypeChange(poolType: string) {
@@ -541,13 +566,23 @@ export class PoolFormComponent extends CdForm implements OnInit {
     CdValidators.validateIf(this.form.get('minBlobSize'), () => this.hasCompressionEnabled(), [
       Validators.min(0),
       CdValidators.custom('maximum', (size: string) =>
-        this.oddBlobSize(size, this.form.getValue('maxBlobSize'))
+        this.oddBlobSize(
+          size,
+          this.form.getValue('minBlobSizeUnit'),
+          this.form.getValue('maxBlobSize'),
+          this.form.getValue('maxBlobSizeUnit')
+        )
       )
     ]);
     CdValidators.validateIf(this.form.get('maxBlobSize'), () => this.hasCompressionEnabled(), [
       Validators.min(0),
       CdValidators.custom('minimum', (size: string) =>
-        this.oddBlobSize(this.form.getValue('minBlobSize'), size)
+        this.oddBlobSize(
+          this.form.getValue('minBlobSize'),
+          this.form.getValue('minBlobSizeUnit'),
+          size,
+          this.form.getValue('maxBlobSizeUnit')
+        )
       )
     ]);
     CdValidators.validateIf(this.form.get('ratio'), () => this.hasCompressionEnabled(), [
@@ -556,9 +591,9 @@ export class PoolFormComponent extends CdForm implements OnInit {
     ]);
   }
 
-  private oddBlobSize(minimum: string, maximum: string) {
-    const min = this.formatter.toBytes(minimum);
-    const max = this.formatter.toBytes(maximum);
+  private oddBlobSize(minimum: string, minUnit: string, maximum: string, maxUnit: string) {
+    const min = this.formatter.toBytes(minimum + minUnit);
+    const max = this.formatter.toBytes(maximum + maxUnit);
     return Boolean(min && max && min >= max);
   }
 
@@ -779,7 +814,10 @@ export class PoolFormComponent extends CdForm implements OnInit {
       {
         externalFieldName: 'quota_max_bytes',
         formControlName: 'max_bytes',
-        replaceFn: this.formatter.toBytes,
+        replaceFn: (value: string) => {
+          const unit = this.form.getValue('maxBytesUnit');
+          return this.formatter.toBytes(value + unit);
+        },
         editable: true,
         resetValue: this.editing ? 0 : undefined
       },
@@ -821,14 +859,20 @@ export class PoolFormComponent extends CdForm implements OnInit {
           {
             externalFieldName: 'compression_min_blob_size',
             formControlName: 'minBlobSize',
-            replaceFn: this.formatter.toBytes,
+            replaceFn: (value: string) => {
+              const unit = this.form.getValue('minBlobSizeUnit');
+              return this.formatter.toBytes(value + unit);
+            },
             editable: true,
             resetValue: 0
           },
           {
             externalFieldName: 'compression_max_blob_size',
             formControlName: 'maxBlobSize',
-            replaceFn: this.formatter.toBytes,
+            replaceFn: (value: string) => {
+              const unit = this.form.getValue('maxBlobSizeUnit');
+              return this.formatter.toBytes(value + unit);
+            },
             editable: true,
             resetValue: 0
           },