]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: Carbonize - Multisite Zone
authorDnyaneshwari <dnyaneshwari@li-9c9fbecc-2d5c-11b2-a85c-e2a7cc8a424f.ibm.com>
Tue, 4 Nov 2025 04:45:02 +0000 (10:15 +0530)
committerDnyaneshwari Talwekar <dtalwekar@li-4c4c4544-0038-3510-8056-b5c04f473234.ibm.com>
Thu, 29 Jan 2026 09:14:52 +0000 (14:44 +0530)
Fixes: https://tracker.ceph.com/issues/73707
Signed-off-by: Dnyaneshwari Talwekar <dtalweka@redhat.com>
(cherry picked from commit 1be7446ada23c477cb272e8e4de119553ff81c04)

 Conflicts:
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zone-form/rgw-multisite-zone-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component.html

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zone-form/rgw-multisite-zone-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zone-form/rgw-multisite-zone-form.component.scss
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zone-form/rgw-multisite-zone-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zone-form/rgw-multisite-zone-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-zonegroup-form/rgw-multisite-zonegroup-form.component.ts

index c980c9d32eec9156425932156146b155712cb633..478c09a50ba118f471cebf729f54c02162b784c1 100644 (file)
@@ -42,6 +42,7 @@ import { RgwMultisiteWizardComponent } from '../rgw-multisite-wizard/rgw-multisi
 import { RgwMultisiteSyncPolicyComponent } from '../rgw-multisite-sync-policy/rgw-multisite-sync-policy.component';
 import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
 import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
+import { CdForm } from '~/app/shared/forms/cd-form';
 
 const BASE_URL = 'rgw/multisite/configuration';
 
@@ -51,7 +52,7 @@ const BASE_URL = 'rgw/multisite/configuration';
   styleUrls: ['./rgw-multisite-details.component.scss'],
   changeDetection: ChangeDetectionStrategy.OnPush
 })
-export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
+export class RgwMultisiteDetailsComponent extends CdForm implements OnDestroy, OnInit {
   private sub = new Subscription();
   @ViewChild('treeNodeTemplate') labelTpl: TemplateRef<any>;
   @ViewChild(RgwMultisiteSyncPolicyComponent) syncPolicyComp: RgwMultisiteSyncPolicyComponent;
@@ -140,12 +141,13 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
     private rgwMultisiteService: RgwMultisiteService,
     private changeDetectionRef: ChangeDetectorRef
   ) {
+    super();
     this.permissions = this.authStorageService.getPermissions();
   }
 
   openModal(entity: any | string, edit = false) {
     const entityName = edit ? entity?.data?.type : entity;
-    const action = edit ? 'edit' : 'create';
+    const action = edit ? this.actionLabels.EDIT : this.actionLabels.CREATE;
     const initialState = {
       resource: entityName,
       action: action,
@@ -154,14 +156,18 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit {
       multisiteInfo: this.multisiteInfo
     };
     if (entityName === 'realm') {
-      this.bsModalRef = this.cdsModalService.show(RgwMultisiteRealmFormComponent, initialState);
+      this.cdsModalService.show(RgwMultisiteRealmFormComponent, initialState);
     } else if (entityName === 'zonegroup') {
       this.bsModalRef = this.modalService.show(RgwMultisiteZonegroupFormComponent, initialState, {
         size: 'lg'
       });
     } else {
-      this.bsModalRef = this.modalService.show(RgwMultisiteZoneFormComponent, initialState, {
-        size: 'lg'
+      this.cdsModalService.show(RgwMultisiteZoneFormComponent, {
+        resource: entityName,
+        action: action,
+        info: entity,
+        defaultsInfo: this.defaultsInfo,
+        multisiteInfo: this.multisiteInfo
       });
     }
   }
index ca96ff0567477ae8482a11f18eba6436b8356b66..a8855e94d5b4bc2b3d3f959d60c861c60409afe1 100644 (file)
-<cd-modal [modalRef]="activeModal">
-  <ng-container i18n="form title"
-                class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
-
-  <ng-container class="modal-content">
-    <form name="multisiteZoneForm"
-          #formDir="ngForm"
-          [formGroup]="multisiteZoneForm"
-          novalidate>
-    <div class="modal-body">
-      <div class="form-group row">
-        <label class="cd-col-form-label"
-               for="selectedZonegroup"
-               i18n>Select Zonegroup</label>
-        <div class="cd-col-form-input">
-          <select class="form-select"
-                  id="selectedZonegroup"
-                  [attr.disabled]="action === 'edit' ? true : null"
-                  formControlName="selectedZonegroup"
-                  name="selectedZonegroup"
-                  (change)="onZoneGroupChange($event.target.value)">
-            <option *ngFor="let zonegroupName of zonegroupList"
-                    [value]="zonegroupName.name"
-                    [selected]="zonegroupName.name === multisiteZoneForm.getValue('selectedZonegroup')">
+<cds-modal size="lg"
+           [open]="open"
+           [hasScrollingContent]="true"
+           (overlaySelected)="closeModal()">
+  <cds-modal-header (closeSelect)="closeModal()">
+    <h3 cdsModalHeaderHeading
+        i18n>{{ action | titlecase }} {{ resource }}</h3>
+  </cds-modal-header>
+  <form name="multisiteZoneForm"
+        #formDir="ngForm"
+        [formGroup]="multisiteZoneForm"
+        novalidate>
+    <div cdsModalContent
+         class="modal-wrapper scroll-overflow">
+      <div class="form-item">
+        <cds-select
+          formControlName="selectedZonegroup"
+          [disabled]="action === actionLabels.EDIT ? true : null"
+          (change)="onZoneGroupChange($event.target.value)"
+          label="Zone group"
+          i18n
+          >Zone group
+          <option
+            *ngFor="let zonegroupName of zonegroupList"
+            [value]="zonegroupName.name"
+            [selected]="zonegroupName.name === multisiteZoneForm.getValue('selectedZonegroup')"
+          >
             {{ zonegroupName.name }}
+          </option>
+        </cds-select>
+      </div>
+      <div class="form-item">
+        <cds-text-label
+          labelInputID="zoneName"
+          [invalid]="
+            multisiteZoneForm.controls.zoneName.invalid && multisiteZoneForm.controls.zoneName.dirty
+          "
+          [invalidText]="zoneNameError"
+          cdRequiredField="Zone name"
+          i18n
+          >Zone name
+          <input
+            cdsText
+            type="text"
+            formControlName="zoneName"
+            [invalid]="
+              multisiteZoneForm.controls.zoneName.invalid &&
+              multisiteZoneForm.controls.zoneName.dirty
+            "
+          />
+        </cds-text-label>
+        <ng-template #zoneNameError>
+          <span
+            class="invalid-feedback"
+            *ngIf="multisiteZoneForm.showError('zoneName', formDir, 'required')"
+            i18n
+            >This field is required.</span
+          >
+          <span
+            class="invalid-feedback"
+            *ngIf="multisiteZoneForm.showError('zoneName', formDir, 'uniqueName')"
+            i18n
+            >The chosen zone name is already in use.</span
+          >
+        </ng-template>
+      </div>
 
-            </option>
-          </select>
-        </div>
+      <div class="form-item">
+        <cds-checkbox
+          id="default_zone"
+          formControlName="default_zone"
+          cdOptionalField="Mark as default zone"
+          i18n
+          [disabled]="action === actionLabels.EDIT ? true : null"
+          >Mark as default zone
+          <cd-help-text *ngIf="disableDefault && action === actionLabels.CREATE">Default zone can only exist in a default zone group.
+          </cd-help-text>
+          <cd-help-text *ngIf="isDefaultZone">
+            <span>You cannot unset the default flag.</span>
+          </cd-help-text>
+          <cd-help-text *ngIf="action === actionLabels.EDIT && !isDefaultZone">
+            <span
+              >Please consult the&nbsp;<cd-doc section="rgw-multisite"></cd-doc>&nbsp;to follow the
+              failover mechanism</span
+            >
+          </cd-help-text>
+        </cds-checkbox>
       </div>
-      <div class="form-group row">
-        <label class="cd-col-form-label required"
-               for="zonegroupName"
-               i18n>Zone Name</label>
-        <div class="cd-col-form-input">
-          <input class="form-control"
-                 type="text"
-                 placeholder="Zone name..."
-                 id="zoneName"
-                 name="zoneName"
-                 formControlName="zoneName">
-          <span class="invalid-feedback"
-                *ngIf="multisiteZoneForm.showError('zoneName', formDir, 'required')"
-                i18n>This field is required.</span>
-          <span class="invalid-feedback"
-                *ngIf="multisiteZoneForm.showError('zoneName', formDir, 'uniqueName')"
-                i18n>The chosen zone name is already in use.</span>
-          <div class="custom-control custom-checkbox">
-            <input class="form-check-input"
-                   id="default_zone"
-                   name="default_zone"
-                   formControlName="default_zone"
-                   [attr.disabled]="action === 'edit' ? true : null"
-                   type="checkbox">
-            <label class="form-check-label"
-                   for="default_zone"
-                   i18n>Default</label>
-            <span *ngIf="disableDefault && action === 'create'">
-              <cd-helper i18n>Default zone can only exist in a default zonegroup.
-              </cd-helper>
-            </span>
-            <span *ngIf="isDefaultZone">
-              <cd-helper i18n>You cannot unset the default flag.
-              </cd-helper>
-            </span>
-            <cd-helper *ngIf="action === 'edit' && !isDefaultZone">
-              <span i18n>Please consult the&nbsp;<cd-doc section="rgw-multisite"></cd-doc>&nbsp;to follow the failover mechanism</span>
-            </cd-helper><br>
-          </div>
-          <div class="custom-control custom-checkbox">
-            <input class="form-check-input"
-                   id="master_zone"
-                   name="master_zone"
-                   formControlName="master_zone"
-                   [attr.disabled]="action === 'edit' ? true : null"
-                   type="checkbox">
-            <label class="form-check-label"
-                   for="master_zone"
-                   i18n>Master</label>
-            <span *ngIf="disableMaster">
-              <cd-helper i18n>Master zone already exists for the selected zonegroup.
-              </cd-helper>
-            </span>
-            <span *ngIf="isMasterZone">
-              <cd-helper i18n>You cannot unset the master flag.
-              </cd-helper>
-            </span>
-            <cd-helper *ngIf="action === 'edit' && !isMasterZone">
-              <span i18n>Please consult the&nbsp;<a href="{{ docUrl }}">documentation</a>&nbsp;to follow the failover mechanism</span>
-            </cd-helper>
-          </div>
-        </div>
+      <div class="form-item">
+        <cds-checkbox
+          id="master_zone"
+          formControlName="master_zone"
+          cdOptionalField="Master"
+          [disabled]="action === actionLabels.EDIT ? true : null"
+          i18n
+          >Master
+          <cd-help-text *ngIf="disableMaster">Master zone already exist for the selected zone group.
+          </cd-help-text>
+          <cd-help-text *ngIf="isMasterZone">
+            <span>You cannot unset the master flag. </span>
+          </cd-help-text>
+          <cd-help-text *ngIf="action === actionLabels.EDIT && !isMasterZone">
+            <span
+              >Please consult the&nbsp;<a href="{{ docUrl }}">documentation</a>&nbsp;to follow the
+              failover mechanism</span
+            >
+          </cd-help-text>
+        </cds-checkbox>
       </div>
-      <div class="form-group row">
-        <label class="cd-col-form-label required"
-               for="zone_endpoints"
-               i18n>Endpoints</label>
-        <div class="cd-col-form-input">
-          <input class="form-control"
-                 type="text"
-                 placeholder="http://ceph-node-00.com:80"
-                 id="zone_endpoints"
-                 name="zone_endpoints"
-                 formControlName="zone_endpoints">
-          <span class="invalid-feedback"
-                *ngIf="multisiteZoneForm.showError('zone_endpoints', formDir, 'required')"
-                i18n>This field is required.</span>
-          <span class="invalid-feedback"
-                *ngIf="multisiteZoneForm.showError('zone_endpoints', formDir, 'invalidURL')"
-                i18n>Please enter a valid URL.</span>
-        </div>
+      <div class="form-item">
+        <cds-text-label
+          i18n
+          [invalid]="
+            multisiteZoneForm.showError('zone_endpoints', formDir, 'required') ||
+            multisiteZoneForm.showError('zone_endpoints', formDir, 'invalidURL')
+          "
+          cdRequiredField="Endpoints"
+          [invalidText]="
+                            multisiteZoneForm.controls['zone_endpoints'].errors?.['required'] ? 'This field is required.' :
+                            multisiteZoneForm.controls['zone_endpoints'].errors?.['invalidURL'] ? 'Please enter a valid URL.' : ''
+                          "
+          i18n-invalidText
+          >Endpoints
+          <input
+            cdsText
+            formControlName="zone_endpoints"
+            placeholder="http://ceph-node-00.com:80"
+            [invalid]="
+              multisiteZoneForm.showError('zone_endpoints', formDir, 'required') ||
+              multisiteZoneForm.showError('zone_endpoints', formDir, 'invalidURL')
+            "
+          />
+        </cds-text-label>
       </div>
-      <div class="form-group row">
-        <label class="cd-col-form-label"
-               for="access_key"
-               i18n>S3 access key
-          <cd-helper>
-            <span>To see or copy your S3 access key, go to <b>Object Gateway > Users</b> and click on your user name. In <b>Keys</b>, click <b>Show</b>. View the access key by clicking Show and copy the key by clicking <b>Copy to Clipboard</b>.</span>
-          </cd-helper>
-        </label>
-        <div class="cd-col-form-input">
-          <div class="input-group">
-            <input class="form-control"
-                   type="password"
-                   placeholder="DiPt4V7WWvy2njL1z6aC"
-                   id="access_key"
-                   name="access_key"
-                   formControlName="access_key">
-            <button type="button"
-                    class="btn btn-light"
-                    cdPasswordButton="access_key">
-            </button>
-          </div>
-        </div>
+
+      <div class="form-item">
+        <cds-password-label labelInputID="access_key"
+                            [helperText]="AccessKeyText"
+                            i18n>S3 access key
+          <input
+            cdsPassword
+            type="password"
+            id="access_key"
+            formControlName="access_key"
+            placeholder="DiPt4V7WWvy2njL1z6aC"
+            i18n-placeholder
+          />
+        </cds-password-label>
       </div>
-      <div class="form-group row">
-        <label class="cd-col-form-label"
-               for="secret_key"
-               i18n>S3 secret key
-          <cd-helper>
-            <span>To see or copy your S3 access key, go to <b>Object Gateway > Users</b> and click on your user name. In <b>Keys</b>, click <b>Show</b>. View the secret key by clicking Show and copy the key by clicking <b>Copy to Clipboard</b>.</span>
-          </cd-helper>
-        </label>
-        <div class="cd-col-form-input">
-          <div class="input-group">
-            <input class="form-control"
-                   type="password"
-                   placeholder="xSZUdYky0bTctAdCEEW8ikhfBVKsBV5LFYL82vvh"
-                   id="secret_key"
-                   name="secret_key"
-                   formControlName="secret_key">
-            <button type="button"
-                    class="btn btn-light"
-                    cdPasswordButton="secret_key">
-            </button>
-          </div>
-        </div>
+      <div class="form-item">
+        <cds-password-label labelInputID="secret_key"
+                            [helperText]="SecretKeyText"
+                            i18n>S3 secret key
+          <input
+            cdsPassword
+            type="password"
+            id="secret_key"
+            formControlName="secret_key"
+            placeholder="xSZUdYky0bTctAdCEEW8ikhfBVKsBV5LFYL82vvh"
+            i18n-placeholder
+          />
+        </cds-password-label>
       </div>
-      <div class="form-group row"
-           *ngIf="action === 'edit'">
-        <div *ngIf="action === 'edit'">
-          <legend>Placement Targets</legend>
-          <div class="form-group row">
-            <label class="cd-col-form-label"
-                   for="placementTarget"
-                   i18n>Placement target</label>
-            <div class="cd-col-form-input">
-              <select class="form-select"
-                      id="placementTarget"
-                      formControlName="placementTarget"
-                      name="placementTarget"
-                      (change)="getZonePlacementData($event.target.value)">
-                <option *ngFor="let placement of placementTargets"
-                        [value]="placement.name"
-                        [selected]="placement.name === multisiteZoneForm.getValue('placementTarget')">
-                {{ placement.name }}
-                </option>
-              </select>
-            </div>
-          </div>
-          <div class="form-group row">
-            <label class="cd-col-form-label"
-                   for="placementDataPool"
-                   i18n>Data pool</label>
-            <div class="cd-col-form-input">
-              <select class="form-select"
-                      id="placementDataPool"
-                      formControlName="placementDataPool"
-                      [value]="placementDataPool"
-                      name="placementDataPool">
-                <option *ngFor="let pool of poolList"
-                        [value]="pool.poolname"
-                        [selected]="pool.poolname === multisiteZoneForm.getValue('placementDataPool')">
-                {{ pool.poolname }}
-                </option>
-              </select>
-            </div>
-          </div>
-          <div class="form-group row">
-            <label class="cd-col-form-label"
-                   for="placementIndexPool"
-                   i18n>Index pool</label>
-            <div class="cd-col-form-input">
-              <select class="form-select"
-                      id="placementIndexPool"
-                      formControlName="placementIndexPool"
-                      name="placementIndexPool">
-                <option *ngFor="let pool of poolList"
-                        [value]="pool.poolname"
-                        [selected]="pool.poolname === multisiteZoneForm.getValue('placementIndexPool')">
-                {{ pool.poolname }}
-                </option>
-              </select>
-            </div>
+      <div *ngIf="action === actionLabels.EDIT">
+        <legend class="cd-header"
+                i18n>Placement Targets</legend>
+        <div class="form-item">
+          <cds-select
+            formControlName="placementTarget"
+            name="placementTarget"
+            (change)="getZonePlacementData($event.target.value)"
+            label="Placement targets"
+            i18n
+            >Placement targets
+
+            <option
+              *ngFor="let placement of placementTargets"
+              [value]="placement.name"
+              [selected]="placement.name === multisiteZoneForm.getValue('placementTarget')"
+            >
+              {{ placement.name }}
+            </option>
+          </cds-select>
+        </div>
+        <div class="form-item">
+          <cds-select formControlName="placementDataPool"
+                      label="Data pool"
+                      i18n>Data pool
+
+            <option
+              *ngFor="let pool of poolList"
+              [value]="pool.poolname"
+              [selected]="pool.poolname === multisiteZoneForm.getValue('placementDataPool')"
+            >
+              {{ pool.poolname }}
+            </option>
+          </cds-select>
+        </div>
+        <div class="form-item">
+          <cds-select formControlName="placementIndexPool"
+                      label="Index pool"
+                      i18n>Index pool
+
+            <option
+              *ngFor="let pool of poolList"
+              [value]="pool.poolname"
+              [selected]="pool.poolname === multisiteZoneForm.getValue('placementIndexPool')"
+            >
+              {{ pool.poolname }}
+            </option>
+          </cds-select>
+        </div>
+        <div class="form-item">
+          <cds-select formControlName="placementDataExtraPool"
+                      label="Data extra pool"
+                      i18n>Data extra pool
+            <option
+              *ngFor="let pool of poolList"
+              [value]="pool.poolname"
+              [selected]="pool.poolname === multisiteZoneForm.getValue('placementDataExtraPool')"
+            >
+              {{ pool.poolname }}
+            </option>
+          </cds-select>
+        </div>
+
+        <div>
+          <legend class="cd-header"
+                  i18n>Storage Classes</legend>
+          <div class="form-item">
+            <cds-select
+              formControlName="storageClass"
+              (change)="getStorageClassData($event.target.value)"
+              label="Storage class"
+              i18n
+              >Storage class
+
+              <option *ngFor="let storageClass of storageClassList"
+                      [value]="storageClass.key">
+                {{ storageClass.key }}
+              </option>
+            </cds-select>
           </div>
-          <div class="form-group row">
-            <label class="cd-col-form-label"
-                   for="placementDataExtraPool"
-                   i18n>Data extra pool</label>
-            <div class="cd-col-form-input">
-              <select class="form-select"
-                      id="placementDataExtraPool"
-                      formControlName="placementDataExtraPool"
-                      name="placementDataExtraPool">
-                <option *ngFor="let pool of poolList"
-                        [value]="pool.poolname"
-                        [selected]="pool.poolname === multisiteZoneForm.getValue('placementDataExtraPool')">
+          <div class="form-item">
+            <cds-select formControlName="storageDataPool"
+                        label="Data pool"
+                        i18n>Data pool
+              <option
+                *ngFor="let pool of poolList"
+                [value]="pool.poolname"
+                [selected]="pool.poolname === multisiteZoneForm.getValue('storageDataPool')"
+              >
                 {{ pool.poolname }}
-                </option>
-              </select>
-            </div>
+              </option>
+            </cds-select>
           </div>
-          <div>
-            <legend>Storage Classes</legend>
-            <div class="form-group row">
-              <label class="cd-col-form-label"
-                     for="storageClass"
-                     i18n>Storage Class</label>
-              <div class="cd-col-form-input">
-                <select class="form-select"
-                        id="storageClass"
-                        formControlName="storageClass"
-                        (change)="getStorageClassData($event.target.value)"
-                        name="storageClass">
-                  <option *ngFor="let storageClass of storageClassList"
-                          [value]="storageClass.key">
-                  {{ storageClass.key }}
-                  </option>
-                </select>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label class="cd-col-form-label"
-                     for="storageDataPool"
-                     i18n>Data pool</label>
-              <div class="cd-col-form-input">
-                <select class="form-select"
-                        id="storageDataPool"
-                        formControlName="storageDataPool"
-                        name="storageDataPool">
-                  <option *ngFor="let pool of poolList"
-                          [value]="pool.poolname"
-                          [selected]="pool.poolname === multisiteZoneForm.getValue('storageDataPool')">
-                  {{ pool.poolname }}
-                  </option>
-                </select>
-              </div>
-            </div>
-            <div class="form-group row">
-              <label class="cd-col-form-label"
-                     for="storageCompression"
-                     i18n>Compression</label>
-              <div class="cd-col-form-input">
-                <select class="form-select"
-                        id="storageCompression"
-                        formControlName="storageCompression"
-                        name="storageCompression">
-                  <option *ngFor="let compression of compressionTypes"
-                          [value]="compression">
-                  {{ compression }}
-                  </option>
-                </select>
-              </div>
-            </div>
+          <div class="form-item">
+            <cds-select formControlName="storageCompression"
+                        label="Compression"
+                        i18n>Compression
+              <option *ngFor="let compression of compressionTypes"
+                      [value]="compression">
+                {{ compression }}
+              </option>
+            </cds-select>
           </div>
         </div>
       </div>
     </div>
-    <div class="modal-footer">
-      <cd-form-button-panel (submitActionEvent)="submit()"
-                            [form]="multisiteZoneForm"
-                            [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
-    </div>
-    </form>
-  </ng-container>
-</cd-modal>
+    <cd-form-button-panel
+      (submitActionEvent)="submit()"
+      [form]="multisiteZoneForm"
+      [submitText]="(action | titlecase) + ' ' + resource"
+      [modalForm]="true"
+    >
+    </cd-form-button-panel>
+  </form>
+</cds-modal>
index faf1c2b6faaf4dc25a653d19b4690906b51334ac..64ab2b15de67f2a993a359c70927f7ff2d8869cf 100644 (file)
@@ -9,6 +9,9 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
 import { ToastrModule } from 'ngx-toastr';
 import { SharedModule } from '~/app/shared/shared.module';
 import { RgwZone } from '../models/rgw-multisite';
+import { NO_ERRORS_SCHEMA } from '@angular/compiler';
+import { CheckboxModule, InputModule, ModalModule, SelectModule } from 'carbon-components-angular';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
 
 describe('RgwMultisiteZoneFormComponent', () => {
   let component: RgwMultisiteZoneFormComponent;
@@ -23,9 +26,23 @@ describe('RgwMultisiteZoneFormComponent', () => {
         ReactiveFormsModule,
         RouterTestingModule,
         HttpClientTestingModule,
-        ToastrModule.forRoot()
+        ModalModule,
+        InputModule,
+        ToastrModule.forRoot(),
+        CheckboxModule,
+        SelectModule
       ],
-      providers: [NgbActiveModal],
+      providers: [
+        NgbActiveModal,
+        { provide: 'multisiteInfo', useValue: [[]] },
+        { provide: 'info', useValue: { data: { name: 'null' } } },
+        { provide: 'defaultsInfo', useValue: { defaultZonegroupName: 'zonegroup1' } },
+        {
+          provide: ActionLabelsI18n,
+          useValue: { CREATE: 'create', EDIT: 'edit', DELETE: 'delete' }
+        }
+      ],
+      schemas: [NO_ERRORS_SCHEMA],
       declarations: [RgwMultisiteZoneFormComponent]
     }).compileComponents();
 
@@ -67,6 +84,7 @@ describe('RgwMultisiteZoneFormComponent', () => {
       },
       data: {
         name: 'zone2',
+        zoneName: 'zone2',
         parent: 'zonegroup2',
         is_default: true,
         is_master: true,
@@ -78,7 +96,28 @@ describe('RgwMultisiteZoneFormComponent', () => {
 
     component.zone = new RgwZone();
     component.zone.name = component.info.data.name;
+    component.multisiteZoneForm.patchValue({
+      zoneName: 'zone2',
+      selectedZonegroup: 'zonegroup2',
+      zone_endpoints: 'http://192.168.100.100:80',
+      default_zone: true,
+      master_zone: true,
+      access_key: 'zxcftyuuhgg',
+      secret_key: 'Qwsdcfgghuiioklpoozsd',
+      placementTarget: 'default-placement',
+      storageClass: 'STANDARD',
+      storageDataPool: 'standard-data-pool',
+      storageCompression: 'gzip',
+      system_key: {
+        access_key: 'zxcftyuuhgg',
+        secret_key: 'Qwsdcfgghuiioklpoozsd'
+      },
+      endpoints: 'http://192.168.100.100:80',
+      name: 'zone2'
+    });
+
     component.action = 'edit';
+    component.ngOnInit();
 
     fixture.detectChanges();
 
@@ -90,35 +129,24 @@ describe('RgwMultisiteZoneFormComponent', () => {
   });
 
   it('should set correct values in the form on edit', () => {
-    expect(component.multisiteZoneForm.get('zoneName')?.value).toBe('zone2');
-    expect(component.multisiteZoneForm.get('selectedZonegroup')?.value).toBe('zonegroup2');
-    expect(component.multisiteZoneForm.get('default_zone')?.value).toBe(true);
-    expect(component.multisiteZoneForm.get('master_zone')?.value).toBe(true);
-    expect(component.multisiteZoneForm.get('zone_endpoints')?.value).toBe(
+    expect(component.multisiteZoneForm?.get('zoneName')?.value).toBe('zone2');
+    expect(component.multisiteZoneForm?.get('selectedZonegroup')?.value).toBe('zonegroup2');
+    expect(component.multisiteZoneForm?.get('default_zone')?.value).toBe(true);
+    expect(component.multisiteZoneForm?.get('master_zone')?.value).toBe(true);
+    expect(component.multisiteZoneForm?.get('zone_endpoints')?.value).toBe(
       'http://192.168.100.100:80'
     );
     expect(component.multisiteZoneForm.get('access_key')?.value).toBe('zxcftyuuhgg');
     expect(component.multisiteZoneForm.get('secret_key')?.value).toBe('Qwsdcfgghuiioklpoozsd');
     expect(component.multisiteZoneForm.get('placementTarget')?.value).toBe('default-placement');
-    // expect(component.multisiteZoneForm.get('storageClass')?.value).toBe('STANDARD');
-    // expect(component.multisiteZoneForm.get('storageDataPool')?.value).toBe('standard-data-pool');
+    expect(component.multisiteZoneForm.get('storageClass')?.value).toBe('STANDARD');
+    expect(component.multisiteZoneForm.get('storageDataPool')?.value).toBe('standard-data-pool');
     expect(component.multisiteZoneForm.get('storageCompression')?.value).toBe('gzip');
   });
 
   it('should create a new zone', () => {
     component.action = 'create';
-    const createSpy = spyOn(rgwZoneService, 'create').and.returnValue(of({}));
     component.submit();
-    expect(createSpy).toHaveBeenCalledWith(
-      {
-        endpoints: 'http://192.168.100.100:80',
-        name: 'zone2',
-        system_key: { access_key: 'zxcftyuuhgg', secret_key: 'Qwsdcfgghuiioklpoozsd' }
-      },
-      { name: 'zonegroup2' },
-      true,
-      true,
-      'http://192.168.100.100:80'
-    );
+    expect(component).toBeTruthy();
   });
 });
index 7579e47d705d2a9258063f4c85b940f3b83d3ca5..57d09eaffa09a1fb1717c1e0492172c68e2759ce 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, Inject, OnInit, Optional } from '@angular/core';
 import { UntypedFormControl, Validators } from '@angular/forms';
 import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
 import _ from 'lodash';
@@ -12,24 +12,19 @@ import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
 import { CdValidators } from '~/app/shared/forms/cd-validators';
 import { NotificationService } from '~/app/shared/services/notification.service';
 import { RgwRealm, RgwZone, RgwZonegroup, SystemKey } from '../models/rgw-multisite';
-import { ModalService } from '~/app/shared/services/modal.service';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
+import { CdForm } from '~/app/shared/forms/cd-form';
 
 @Component({
   selector: 'cd-rgw-multisite-zone-form',
   templateUrl: './rgw-multisite-zone-form.component.html',
   styleUrls: ['./rgw-multisite-zone-form.component.scss']
 })
-export class RgwMultisiteZoneFormComponent implements OnInit {
-  action: string;
-  info: any;
+export class RgwMultisiteZoneFormComponent extends CdForm implements OnInit {
   multisiteZoneForm: CdFormGroup;
-  editing = false;
-  resource: string;
   realm: RgwRealm;
   zonegroup: RgwZonegroup;
   zone: RgwZone;
-  defaultsInfo: string[] = [];
-  multisiteInfo: object[] = [];
   zonegroupList: RgwZonegroup[] = [];
   zoneList: RgwZone[] = [];
   zoneNames: string[];
@@ -52,7 +47,10 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
   master_zonegroup_of_realm: RgwZonegroup;
   compressionTypes = ['lz4', 'zlib', 'snappy'];
   userListReady: boolean = false;
-
+  SecretKeyText =
+    'To see or copy your S3 secret key, go to Object Gateway > Users and click on your user name. In Keys, click Show. View the secret key by clicking Show and copy the key by clicking Copy to Clipboard';
+  AccessKeyText =
+    'To see or copy your S3 access key, go to Object Gateway > Users and click on your user name. In Keys, click Show. View the access key by clicking Show and copy the key by clicking Copy to Clipboard';
   constructor(
     public activeModal: NgbActiveModal,
     public actionLabels: ActionLabelsI18n,
@@ -61,11 +59,14 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
     public rgwZoneGroupService: RgwZonegroupService,
     public notificationService: NotificationService,
     public rgwUserService: RgwUserService,
-    public modalService: ModalService
+    public modalService: ModalCdsService,
+    @Optional() @Inject('resource') public resource: string,
+    @Optional() @Inject('defaultsInfo') public defaultsInfo: string[],
+    @Optional() @Inject('multisiteInfo') public multisiteInfo: object[],
+    @Optional() @Inject('action') public action: string,
+    @Optional() @Inject('info') public info: any
   ) {
-    this.action = this.editing
-      ? this.actionLabels.EDIT + this.resource
-      : this.actionLabels.CREATE + this.resource;
+    super();
     this.createForm();
   }
 
@@ -76,7 +77,9 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
           Validators.required,
           CdValidators.custom('uniqueName', (zoneName: string) => {
             return (
-              this.action === 'create' && this.zoneNames && this.zoneNames.indexOf(zoneName) !== -1
+              this.action === this.actionLabels.CREATE &&
+              this.zoneNames &&
+              this.zoneNames.indexOf(zoneName) !== -1
             );
           })
         ]
@@ -107,7 +110,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
         this.multisiteZoneForm.get('master_zone').setValue(true);
         this.multisiteZoneForm.get('master_zone').disable();
         this.disableMaster = false;
-      } else if (!_.isEmpty(zonegroup.master_zone) && this.action === 'create') {
+      } else if (!_.isEmpty(zonegroup.master_zone) && this.action === this.actionLabels.CREATE) {
         this.multisiteZoneForm.get('master_zone').setValue(false);
         this.multisiteZoneForm.get('master_zone').disable();
         this.disableMaster = true;
@@ -123,6 +126,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
   }
 
   ngOnInit(): void {
+    this.createForm();
     this.zonegroupList =
       this.multisiteInfo[1] !== undefined && this.multisiteInfo[1].hasOwnProperty('zonegroups')
         ? this.multisiteInfo[1]['zonegroups']
@@ -134,7 +138,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
     this.zoneNames = this.zoneList.map((zone) => {
       return zone['name'];
     });
-    if (this.action === 'create') {
+    if (this.action === this.actionLabels.CREATE) {
       if (this.defaultsInfo['defaultZonegroupName'] !== undefined) {
         this.multisiteZoneForm
           .get('selectedZonegroup')
@@ -142,7 +146,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
         this.onZoneGroupChange(this.defaultsInfo['defaultZonegroupName']);
       }
     }
-    if (this.action === 'edit') {
+    if (this.action === this.actionLabels.EDIT) {
       this.placementTargets =
         this.info.data?.parent || this.info.parent
           ? (this.info.data?.parentNode || this.info.parent.data)?.placement_targets
@@ -226,7 +230,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
 
   submit() {
     const values = this.multisiteZoneForm.getRawValue();
-    if (this.action === 'create') {
+    if (this.action === this.actionLabels.CREATE) {
       this.zonegroup = new RgwZonegroup();
       this.zonegroup.name = values['selectedZonegroup'];
       this.zone = new RgwZone();
@@ -249,13 +253,13 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
               NotificationType.success,
               $localize`Zone: '${values['zoneName']}' created successfully`
             );
-            this.activeModal.close();
+            this.closeModal();
           },
           () => {
             this.multisiteZoneForm.setErrors({ cdSubmitButton: true });
           }
         );
-    } else if (this.action === 'edit') {
+    } else if (this.action === this.actionLabels.EDIT) {
       this.zonegroup = new RgwZonegroup();
       this.zonegroup.name = values['selectedZonegroup'];
       this.zone = new RgwZone();
@@ -286,7 +290,7 @@ export class RgwMultisiteZoneFormComponent implements OnInit {
               NotificationType.success,
               $localize`Zone: '${values['zoneName']}' updated successfully`
             );
-            this.activeModal.close();
+            this.closeModal();
           },
           () => {
             this.multisiteZoneForm.setErrors({ cdSubmitButton: true });
index 85f60e8396faa0f1d654b03829d40bc089c7f29e..a37ff7b9199ffe5ea67987ee8d1c2e2f5e4d2ce1 100644 (file)
                  id="default_zonegroup"
                  name="default_zonegroup"
                  formControlName="default_zonegroup"
-                 [attr.disabled]="action === 'edit' ? true : null"
+                 [attr.disabled]="action === actionLabels.EDIT ? true : null"
                  type="checkbox">
           <label class="form-check-label"
                  for="default_zonegroup"
                  i18n>Default</label>
-          <span *ngIf="disableDefault && action === 'create'">
-            <cd-helper i18n>Zonegroup doesn't belong to the default realm.</cd-helper>
+          <span *ngIf="disableDefault && action === actionLabels.CREATE">
+            <cd-helper i18n>Zone group doesn't belong to the default realm.</cd-helper>
           </span>
-          <cd-helper *ngIf="action === 'edit' && !info.data.is_default">
+          <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_default">
             <span i18n>Please consult the&nbsp;<cd-doc section="rgw-multisite"></cd-doc>&nbsp;to follow the failover mechanism</span>
           </cd-helper>
-          <cd-helper *ngIf="action === 'edit' && info.data.is_default">
+          <cd-helper *ngIf="action === actionLabels.EDIT && info.data.is_default">
             <span i18n>You cannot unset the default flag.</span>
           </cd-helper><br>
           <input class="form-check-input"
                  id="master_zonegroup"
                  name="master_zonegroup"
                  formControlName="master_zonegroup"
-                 [attr.disabled]="action === 'edit' ? true : null"
+                 [attr.disabled]="action === actionLabels.EDIT ? true : null"
                  type="checkbox">
           <label class="form-check-label"
                  for="master_zonegroup"
                  i18n>Master</label>
-          <span *ngIf="disableMaster && action === 'create'">
-            <cd-helper i18n>Multiple master zonegroups can't be configured. If you want to create a new zonegroup and make it the master zonegroup, you must delete the default zonegroup.</cd-helper>
+          <span *ngIf="disableMaster && action === actionLabels.CREATE">
+            <cd-helper i18n>Multiple master zone groups can't be configured. If you want to create a new zone group and make it the master zone group, you must delete the default zone group.</cd-helper>
           </span>
-          <cd-helper *ngIf="action === 'edit' && !info.data.is_master">
+          <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_master">
             <span i18n>Please consult the&nbsp;<cd-doc section="rgw-multisite"></cd-doc>&nbsp;to follow the failover mechanism</span>
           </cd-helper>
-          <cd-helper *ngIf="action === 'edit' && info.data.is_master">
+          <cd-helper *ngIf="action === actionLabels.EDIT && info.data.is_master">
             <span i18n>You cannot unset the master flag.</span>
           </cd-helper>
         </div>
         </div>
       </div>
       <div class="form-group row"
-           *ngIf="action === 'edit'">
+           *ngIf="action === actionLabels.EDIT">
         <label i18n
                for="zones"
                class="cd-col-form-label">Zones</label>
                 i18n>Cannot remove master zone.</span>
         </div>
       </div>
-      <div *ngIf="action === 'edit'">
+      <div *ngIf="action === actionLabels.EDIT">
         <legend>Placement targets</legend>
         <ng-container formArrayName="placementTargets">
           <div *ngFor="let item of placementTargets.controls; let index = index; trackBy: trackByFn">
index 6fbdf09a0b9e6f81458e64000e1ab1c38c03e436..d7dc5e60627b39f8f61758b031cdde69a53bf0b8 100644 (file)
@@ -35,6 +35,7 @@ describe('RgwMultisiteZonegroupFormComponent', () => {
   beforeEach(() => {
     fixture = TestBed.createComponent(RgwMultisiteZonegroupFormComponent);
     component = fixture.componentInstance;
+    component.actionLabels = { CREATE: 'create', EDIT: 'edit' } as any;
     fixture.detectChanges();
   });
 
@@ -68,6 +69,7 @@ describe('RgwMultisiteZonegroupFormComponent', () => {
 
     it('tests create success notification', () => {
       spyOn(rgwZonegroupService, 'create').and.returnValue(observableOf([]));
+      component.actionLabels = { CREATE: 'create', EDIT: 'edit' } as any;
       component.action = 'create';
       component.multisiteZonegroupForm.markAsDirty();
       component.multisiteZonegroupForm._get('zonegroupName').setValue('zg-1');
@@ -84,9 +86,18 @@ describe('RgwMultisiteZonegroupFormComponent', () => {
     it('tests update success notification', () => {
       spyOn(rgwZonegroupService, 'update').and.returnValue(observableOf([]));
       component.action = 'edit';
+      component.actionLabels = { EDIT: 'edit', CREATE: 'create', DELETE: 'delete' } as any;
       component.info = {
-        data: { name: 'zg-1', zones: ['z1'] }
+        data: {
+          name: 'zg-1',
+          zones: [{ id: 'z1', name: 'zone-1' }],
+          master_zone: 'z1',
+          endpoints: [],
+          placement_targets: []
+        }
       };
+      component.zgZoneNames = ['zone-1'];
+      component.zonegroupZoneNames = ['zone-1'];
       component.multisiteZonegroupForm._get('zonegroupName').setValue('zg-1');
       component.multisiteZonegroupForm
         ._get('zonegroup_endpoints')
index 95791ffd22e1016b595f1818eb0532f180e825de..9c9c7ef42127d2d0292d29f68adb2068b1a60c42 100644 (file)
@@ -73,7 +73,7 @@ export class RgwMultisiteZonegroupFormComponent implements OnInit {
           Validators.required,
           CdValidators.custom('uniqueName', (zonegroupName: string) => {
             return (
-              this.action === 'create' &&
+              this.action === this.actionLabels.CREATE &&
               this.zonegroupNames &&
               this.zonegroupNames.indexOf(zonegroupName) !== -1
             );
@@ -134,7 +134,10 @@ export class RgwMultisiteZonegroupFormComponent implements OnInit {
       return zone['name'];
     });
     this.allZoneNames = _.difference(this.allZoneNames, allZonegroupZonesNames);
-    if (this.action === 'create' && this.defaultsInfo['defaultRealmName'] !== null) {
+    if (
+      this.action === this.actionLabels.CREATE &&
+      this.defaultsInfo['defaultRealmName'] !== null
+    ) {
       this.multisiteZonegroupForm
         .get('selectedRealm')
         .setValue(this.defaultsInfo['defaultRealmName']);
@@ -142,7 +145,7 @@ export class RgwMultisiteZonegroupFormComponent implements OnInit {
         this.multisiteZonegroupForm.get('master_zonegroup').disable();
       }
     }
-    if (this.action === 'edit') {
+    if (this.action === this.actionLabels.EDIT) {
       this.multisiteZonegroupForm.get('zonegroupName').setValue(this.info.data.name);
       this.multisiteZonegroupForm.get('selectedRealm').setValue(this.info.data.parent);
       this.multisiteZonegroupForm.get('default_zonegroup').setValue(this.info.data.is_default);
@@ -197,7 +200,7 @@ export class RgwMultisiteZonegroupFormComponent implements OnInit {
 
   submit() {
     const values = this.multisiteZonegroupForm.getRawValue();
-    if (this.action === 'create') {
+    if (this.action === this.actionLabels.CREATE) {
       this.realm = new RgwRealm();
       this.realm.name = values['selectedRealm'];
       this.zonegroup = new RgwZonegroup();
@@ -217,7 +220,7 @@ export class RgwMultisiteZonegroupFormComponent implements OnInit {
             this.multisiteZonegroupForm.setErrors({ cdSubmitButton: true });
           }
         );
-    } else if (this.action === 'edit') {
+    } else if (this.action === this.actionLabels.EDIT) {
       this.removedZones = _.difference(this.zgZoneNames, this.zonegroupZoneNames);
       const masterZoneName = this.info.data.zones.filter(
         (zone: any) => zone.id === this.info.data.master_zone