]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-form/pool-form.component.html
import ceph quincy 17.2.6
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / pool / pool-form / pool-form.component.html
index 3ccfd2a024be6fe3e34d4b63cd4e7d8d7b23bb85..b159f12530d04d28383d7fc82414c03ff0140aad 100644 (file)
@@ -1,9 +1,6 @@
-<cd-loading-panel *ngIf="!(info && ecProfiles)"
-                  i18n>Loading...</cd-loading-panel>
-
-<div class="cd-col-form">
+<div class="cd-col-form"
+     *cdFormLoading="loading">
   <form name="form"
-        *ngIf="info && ecProfiles"
         #formDir="ngForm"
         [formGroup]="form"
         novalidate>
@@ -48,7 +45,7 @@
                  for="poolType"
                  i18n>Pool type</label>
           <div class="cd-col-form-input">
-            <select class="form-control custom-select"
+            <select class="form-select"
                     id="poolType"
                     formControlName="poolType"
                     name="poolType">
@@ -72,7 +69,7 @@
                    class="cd-col-form-label"
                    for="pgAutoscaleMode">PG Autoscale</label>
             <div class="cd-col-form-input">
-              <select class="form-control custom-select"
+              <select class="form-select"
                       id="pgAutoscaleMode"
                       name="pgAutoscaleMode"
                       formControlName="pgAutoscaleMode">
                     *ngIf="form.showError('pgNum', formDir, '34')"
                     i18n>Your cluster can't handle this many PGs. Please recalculate the PG amount needed.</span>
               <span class="form-text text-muted">
-                <a i18n
-                   target="_blank"
-                   href="http://ceph.com/pgcalc">Calculation help</a>
+                <cd-doc section="pgs"
+                        docText="Calculation help"
+                        i18n-docText></cd-doc>
               </span>
               <span class="form-text text-muted"
                     *ngIf="externalPgChange"
               <span class="invalid-feedback"
                     *ngIf="form.showError('size', formDir)"
                     i18n>The size specified is out of range. A value from
-                {{ getMinSize() }} to {{ getMaxSize() }} is valid.</span>
+                {{ getMinSize() }} to {{ getMaxSize() }} is usable.</span>
+              <span class="text-warning-dark"
+                    *ngIf="form.getValue('size') === 1"
+                    i18n>A size of 1 will not create a replication of the
+                object. The 'Replicated size' includes the object itself.</span>
             </div>
           </div>
 
                               [selectionLimit]="4"
                               (selection)="appSelection()">
             </cd-select-badges>
+            <i *ngIf="data.applications.selected <= 0"
+               i18n-title
+               title="Pools should be associated with an application tag"
+               class="{{icons.warning}} icon-warning-color">
+            </i>
           </div>
         </div>
-
         <!-- CRUSH -->
         <div *ngIf="isErasure || isReplicated">
 
                    class="cd-col-form-label"
                    for="erasureProfile">Erasure code profile</label>
             <div class="cd-col-form-input">
-              <div class="input-group">
-                <select class="form-control custom-select"
+              <div class="input-group mb-1">
+                <select class="form-select"
                         id="erasureProfile"
                         name="erasureProfile"
                         formControlName="erasureProfile">
                     {{ ecp.name }}
                   </option>
                 </select>
-                <span class="input-group-append">
-                  <button class="btn btn-light"
-                          [ngClass]="{'active': data.erasureInfo}"
-                          id="ecp-info-button"
-                          type="button"
-                          (click)="data.erasureInfo = !data.erasureInfo">
-                    <i [ngClass]="[icons.questionCircle]"
-                       aria-hidden="true"></i>
-                  </button>
-                  <button class="btn btn-light"
-                          type="button"
-                          *ngIf="!editing"
-                          (click)="addErasureCodeProfile()">
-                    <i [ngClass]="[icons.add]"
-                       aria-hidden="true"></i>
-                  </button>
-                  <button class="btn btn-light"
-                          type="button"
-                          *ngIf="!editing"
-                          (click)="deleteErasureCodeProfile()">
-                    <i [ngClass]="[icons.trash]"
-                       aria-hidden="true"></i>
-                  </button>
-                </span>
+                <button class="btn btn-light"
+                        [ngClass]="{'active': data.erasureInfo}"
+                        id="ecp-info-button"
+                        type="button"
+                        (click)="data.erasureInfo = !data.erasureInfo">
+                  <i [ngClass]="[icons.questionCircle]"
+                     aria-hidden="true"></i>
+                </button>
+                <button class="btn btn-light"
+                        type="button"
+                        *ngIf="!editing"
+                        (click)="addErasureCodeProfile()">
+                  <i [ngClass]="[icons.add]"
+                     aria-hidden="true"></i>
+                </button>
+                <button class="btn btn-light"
+                        type="button"
+                        *ngIf="!editing"
+                        ngbTooltip="This profile can't be deleted as it is in use."
+                        i18n-ngbTooltip
+                        triggers="manual"
+                        #ecpDeletionBtn="ngbTooltip"
+                        (click)="deleteErasureCodeProfile()">
+                  <i [ngClass]="[icons.trash]"
+                     aria-hidden="true"></i>
+                </button>
               </div>
               <span class="form-text text-muted"
                     id="ecp-info-block"
                     *ngIf="data.erasureInfo && form.getValue('erasureProfile')">
-                <cd-table-key-value [renderObjects]="true"
-                                    [data]="form.getValue('erasureProfile')"
-                                    [autoReload]="false">
-                </cd-table-key-value>
+                <nav ngbNav
+                     #ecpInfoTabs="ngbNav"
+                     class="nav-tabs">
+                  <ng-container ngbNavItem="ecp-info">
+                    <a ngbNavLink
+                       i18n>Profile</a>
+                    <ng-template ngbNavContent>
+                      <cd-table-key-value [renderObjects]="true"
+                                          [hideKeys]="['name']"
+                                          [data]="form.getValue('erasureProfile')"
+                                          [autoReload]="false">
+                      </cd-table-key-value>
+                    </ng-template>
+                  </ng-container>
+                  <ng-container ngbNavItem="used-by-pools">
+                    <a ngbNavLink
+                       i18n>Used by pools</a>
+                    <ng-template ngbNavContent>
+                      <ng-template #ecpIsNotUsed>
+                        <span i18n>Profile is not in use.</span>
+                      </ng-template>
+                      <ul *ngIf="ecpUsage; else ecpIsNotUsed">
+                        <li *ngFor="let pool of ecpUsage">
+                          {{ pool }}
+                        </li>
+                      </ul>
+                    </ng-template>
+                  </ng-container>
+                </nav>
+
+                <div [ngbNavOutlet]="ecpInfoTabs"></div>
               </span>
             </div>
           </div>
               </ng-template>
               <div *ngIf="current.rules.length > 0; else noRules">
                 <div class="input-group">
-                  <select class="form-control custom-select"
+                  <select class="form-select"
                           id="crushRule"
                           formControlName="crushRule"
                           name="crushSet">
                       {{ rule.rule_name }}
                     </option>
                   </select>
-                  <span class="input-group-append">
-                    <button class="btn btn-light"
-                            [ngClass]="{'active': data.crushInfo}"
-                            id="crush-info-button"
-                            type="button"
-                            (click)="data.crushInfo = !data.crushInfo">
-                      <i [ngClass]="[icons.questionCircle]"
-                         aria-hidden="true"></i>
-                    </button>
-                    <button class="btn btn-light"
-                            type="button"
-                            *ngIf="isReplicated && !editing"
-                            (click)="addCrushRule()">
-                      <i [ngClass]="[icons.add]"
-                         aria-hidden="true"></i>
-                    </button>
-                    <button class="btn btn-light"
-                            *ngIf="isReplicated && !editing"
-                            type="button"
-                            tooltip="This rule can't be deleted as it is in use."
-                            i18n-tooltip
-                            triggers=""
-                            #crushDeletionBtn="bs-tooltip"
-                            (click)="deleteCrushRule()">
-                      <i [ngClass]="[icons.trash]"
-                         aria-hidden="true"></i>
-                    </button>
-                  </span>
+                  <button class="btn btn-light"
+                          [ngClass]="{'active': data.crushInfo}"
+                          id="crush-info-button"
+                          type="button"
+                          ngbTooltip="Placement and
+                          replication strategies or distribution policies that allow to
+                          specify how CRUSH places data replicas."
+                          i18n-ngbTooltip
+                          (click)="data.crushInfo = !data.crushInfo">
+                    <i [ngClass]="[icons.questionCircle]"
+                       aria-hidden="true"></i>
+                  </button>
+                  <button class="btn btn-light"
+                          type="button"
+                          *ngIf="isReplicated && !editing"
+                          (click)="addCrushRule()">
+                    <i [ngClass]="[icons.add]"
+                       aria-hidden="true"></i>
+                  </button>
+                  <button class="btn btn-light"
+                          *ngIf="isReplicated && !editing"
+                          type="button"
+                          ngbTooltip="This rule can't be deleted as it is in use."
+                          i18n-ngbTooltip
+                          triggers="manual"
+                          #crushDeletionBtn="ngbTooltip"
+                          (click)="deleteCrushRule()">
+                    <i [ngClass]="[icons.trash]"
+                       aria-hidden="true"></i>
+                  </button>
                 </div>
-                <span class="form-text text-muted"
-                      id="crush-info-block"
-                      *ngIf="data.crushInfo && form.getValue('crushRule')">
-                  <tabset #crushInfoTabs>
-                    <tab i18n-heading
-                         heading="Crush rule"
-                         class="crush-rule-info">
-                      <cd-table-key-value [renderObjects]="true"
-                                          [data]="form.getValue('crushRule')"
-                                          [autoReload]="false">
-                      </cd-table-key-value>
-                    </tab>
-                    <tab i18n-heading
-                         heading="Crush steps"
-                         class="crush-rule-steps">
-                      <ol>
-                        <li *ngFor="let step of form.get('crushRule').value.steps">
-                          {{ describeCrushStep(step) }}
-                        </li>
-                      </ol>
-                    </tab>
-                    <tab i18n-heading
-                         heading="Used by pools"
-                         class="used-by-pools">
-                      <ng-template #ruleIsNotUsed>
-                        <span i18n>Rule is not in use.</span>
+
+                <div class="form-text text-muted"
+                     id="crush-info-block"
+                     *ngIf="data.crushInfo && form.getValue('crushRule')">
+                  <nav ngbNav
+                       #crushInfoTabs="ngbNav"
+                       class="nav-tabs">
+                    <ng-container ngbNavItem="crush-rule-info">
+                      <a ngbNavLink
+                         i18n>Crush rule</a>
+                      <ng-template ngbNavContent>
+                        <cd-table-key-value [renderObjects]="false"
+                                            [hideKeys]="['steps', 'type', 'rule_name']"
+                                            [data]="form.getValue('crushRule')"
+                                            [autoReload]="false">
+                        </cd-table-key-value>
                       </ng-template>
-                      <ul *ngIf="crushUsage; else ruleIsNotUsed">
-                        <li *ngFor="let pool of crushUsage">
-                          {{ pool }}
-                        </li>
-                      </ul>
-                    </tab>
-                  </tabset>
-                </span>
+                    </ng-container>
+                    <ng-container ngbNavItem="crush-rule-steps">
+                      <a ngbNavLink
+                         i18n>Crush steps</a>
+                      <ng-template ngbNavContent>
+                        <ol>
+                          <li *ngFor="let step of form.get('crushRule').value.steps">
+                            {{ describeCrushStep(step) }}
+                          </li>
+                        </ol>
+                      </ng-template>
+                    </ng-container>
+                    <ng-container ngbNavItem="used-by-pools">
+                      <a ngbNavLink
+                         i18n>Used by pools</a>
+                      <ng-template ngbNavContent>
+
+                        <ng-template #ruleIsNotUsed>
+                          <span i18n>Rule is not in use.</span>
+                        </ng-template>
+                        <ul *ngIf="crushUsage; else ruleIsNotUsed">
+                          <li *ngFor="let pool of crushUsage">
+                            {{ pool }}
+                          </li>
+                        </ul>
+                      </ng-template>
+                    </ng-container>
+                  </nav>
+
+                  <div [ngbNavOutlet]="crushInfoTabs"></div>
+                </div>
                 <span class="invalid-feedback"
                       *ngIf="form.showError('crushRule', formDir, 'required')"
                       i18n>This field is required!</span>
                    class="cd-col-form-label"
                    for="mode">Mode</label>
             <div class="cd-col-form-input">
-              <select class="form-control custom-select"
+              <select class="form-select"
                       id="mode"
                       name="mode"
                       formControlName="mode">
                      class="cd-col-form-label"
                      for="algorithm">Algorithm</label>
               <div class="cd-col-form-input">
-                <select class="form-control custom-select"
+                <select class="form-select"
                         id="algorithm"
                         name="algorithm"
                         formControlName="algorithm">
         </div>
       </div>
       <div class="card-footer">
-        <div class="button-group text-right">
-          <cd-submit-button [form]="formDir"
-                            i18n="form action button|Example: Create Pool@@formActionButton"
-                            (submitAction)="submit()">{{ action | titlecase }} {{ resource | upperFirst }}
-          </cd-submit-button>
-          <cd-back-button></cd-back-button>
-        </div>
+        <cd-form-button-panel (submitActionEvent)="submit()"
+                              [form]="form"
+                              [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+                              wrappingClass="text-right"></cd-form-button-panel>
       </div>
 
     </div>