"tabWidth": 2,
"useTabs": false,
"endOfLine": "lf",
- "singleAttributePerLine": true,
+ "singleAttributePerLine": true,
"htmlWhitespaceSensitivity": "css"
}
-<div class="form-group"
- [formGroup]="settingsForm">
- <label class="col-form-label"
- for="{{ setting }}">{{ setting }}</label>
- <select id="{{ setting }}"
- name="{{ setting }}"
- *ngIf="limits['type'] === 'enum'"
- class="form-control"
- [formControlName]="setting">
+<div
+ class="form-group"
+ [formGroup]="settingsForm"
+>
+ <label
+ class="col-form-label"
+ for="{{ setting }}"
+ >{{ setting }}</label
+ >
+ <select
+ id="{{ setting }}"
+ name="{{ setting }}"
+ *ngIf="limits['type'] === 'enum'"
+ class="form-control"
+ [formControlName]="setting"
+ >
<option [ngValue]="null"></option>
- <option *ngFor="let opt of limits['values']"
- [ngValue]="opt">{{ opt }}</option>
+ <option
+ *ngFor="let opt of limits['values']"
+ [ngValue]="opt"
+ >
+ {{ opt }}
+ </option>
</select>
<span *ngIf="limits['type'] !== 'enum'">
- <input type="number"
- *ngIf="limits['type'] === 'int'"
- class="form-control"
- [formControlName]="setting">
+ <input
+ type="number"
+ *ngIf="limits['type'] === 'int'"
+ class="form-control"
+ [formControlName]="setting"
+ />
- <input type="text"
- *ngIf="limits['type'] === 'str'"
- class="form-control"
- [formControlName]="setting">
+ <input
+ type="text"
+ *ngIf="limits['type'] === 'str'"
+ class="form-control"
+ [formControlName]="setting"
+ />
<ng-container *ngIf="limits['type'] === 'bool'">
- <br>
+ <br />
<div class="custom-control custom-radio custom-control-inline">
- <input type="radio"
- [id]="setting + 'True'"
- [value]="true"
- [formControlName]="setting"
- class="custom-control-input">
- <label class="custom-control-label"
- [for]="setting + 'True'">Yes</label>
+ <input
+ type="radio"
+ [id]="setting + 'True'"
+ [value]="true"
+ [formControlName]="setting"
+ class="custom-control-input"
+ />
+ <label
+ class="custom-control-label"
+ [for]="setting + 'True'"
+ >Yes</label
+ >
</div>
<div class="custom-control custom-radio custom-control-inline">
- <input type="radio"
- [id]="setting + 'False'"
- [value]="false"
- class="custom-control-input"
- [formControlName]="setting">
- <label class="custom-control-label"
- [for]="setting + 'False'">No</label>
+ <input
+ type="radio"
+ [id]="setting + 'False'"
+ [value]="false"
+ class="custom-control-input"
+ [formControlName]="setting"
+ />
+ <label
+ class="custom-control-label"
+ [for]="setting + 'False'"
+ >No</label
+ >
</div>
</ng-container>
</span>
- <span class="invalid-feedback"
- *ngIf="settingsForm.showError(setting, formDir, 'min')">
+ <span
+ class="invalid-feedback"
+ *ngIf="settingsForm.showError(setting, formDir, 'min')"
+ >
<ng-container i18n>Must be greater than or equal to {{ limits['min'] }}.</ng-container>
</span>
- <span class="invalid-feedback"
- *ngIf="settingsForm.showError(setting, formDir, 'max')">
+ <span
+ class="invalid-feedback"
+ *ngIf="settingsForm.showError(setting, formDir, 'max')"
+ >
<ng-container i18n>Must be less than or equal to {{ limits['max'] }}.</ng-container>
</span>
</div>
<ul class="nav nav-tabs">
<li class="nav-item">
- <a class="nav-link"
- routerLink="/block/iscsi/overview"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- i18n>Overview</a>
+ <a
+ class="nav-link"
+ routerLink="/block/iscsi/overview"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n
+ >Overview</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="/block/iscsi/targets"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- i18n>Targets</a>
+ <a
+ class="nav-link"
+ routerLink="/block/iscsi/targets"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n
+ >Targets</a
+ >
</li>
</ul>
<div class="col-6 card-tree">
<legend i18n>iSCSI Topology</legend>
- <cds-tree-view #tree
- [tree]="nodes"
- (select)="onNodeSelected($event)">
+ <cds-tree-view
+ #tree
+ [tree]="nodes"
+ (select)="onNodeSelected($event)"
+ >
</cds-tree-view>
- <ng-template #treeNodeTemplate
- let-node>
- {{node?.data?.cdIcon}}
- <svg [cdsIcon]="node?.data?.cdIcon"
- [size]="icons.size16"
- ></svg>
+ <ng-template
+ #treeNodeTemplate
+ let-node
+ >
+ {{ node?.data?.cdIcon }}
+ <svg
+ [cdsIcon]="node?.data?.cdIcon"
+ [size]="icons.size16"
+ ></svg>
<span>{{ node?.name }}</span>
- <cds-tag [class]="{'tag-success': ['logged_in'].includes(node?.status), 'tag-danger': ['logged_out'].includes(node?.status)}">
+ <cds-tag
+ [class]="{
+ 'tag-success': ['logged_in'].includes(node?.status),
+ 'tag-danger': ['logged_out'].includes(node?.status)
+ }"
+ >
{{ node?.status }}
</cds-tag>
</ng-template>
</div>
- <div class="col-6 metadata"
- *ngIf="data">
+ <div
+ class="col-6 metadata"
+ *ngIf="data"
+ >
<legend>{{ title }}</legend>
- <cd-table #detailTable
- [data]="data"
- columnMode="flex"
- [columns]="columns"
- [limit]="0">
+ <cd-table
+ #detailTable
+ [data]="data"
+ columnMode="flex"
+ [columns]="columns"
+ [limit]="0"
+ >
</cd-table>
</div>
</div>
-<ng-template #highlightTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #highlightTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<span *ngIf="row.default === undefined || row.default === row.current">{{ value }}</span>
<strong *ngIf="row.default !== undefined && row.default !== row.current">{{ value }}</strong>
</ng-template>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>Discovery Authentication</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >Discovery Authentication</ng-container
+ >
<ng-container class="modal-content">
- <form name="discoveryForm"
- #formDir="ngForm"
- [formGroup]="discoveryForm"
- novalidate>
+ <form
+ name="discoveryForm"
+ #formDir="ngForm"
+ [formGroup]="discoveryForm"
+ novalidate
+ >
<div class="modal-body">
<!-- User -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="user"
- i18n>User</label>
+ <label
+ class="cd-col-form-label"
+ for="user"
+ i18n
+ >User</label
+ >
<div class="cd-col-form-input">
- <input id="user"
- class="form-control"
- formControlName="user"
- type="text"
- autocomplete="off">
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('user', formDir, 'required')"
- i18n>This field is required.</span>
+ <input
+ id="user"
+ class="form-control"
+ formControlName="user"
+ type="text"
+ autocomplete="off"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain alphanumeric
+ characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- Password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="password"
- i18n>Password</label>
+ <label
+ class="cd-col-form-label"
+ for="password"
+ i18n
+ >Password</label
+ >
<div class="cd-col-form-input">
<div class="input-group">
- <input id="password"
- class="form-control"
- formControlName="password"
- type="password"
- autocomplete="new-password">
+ <input
+ id="password"
+ class="form-control"
+ formControlName="password"
+ type="password"
+ autocomplete="new-password"
+ />
- <button type="button"
- class="btn btn-light"
- cdPasswordButton="password">
- </button>
- <cd-copy-2-clipboard-button source="password">
- </cd-copy-2-clipboard-button>
+ <button
+ type="button"
+ class="btn btn-light"
+ cdPasswordButton="password"
+ ></button>
+ <cd-copy-2-clipboard-button source="password"> </cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('password', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain alphanumeric
+ characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
<!-- mutual_user -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="mutual_user">
+ <label
+ class="cd-col-form-label"
+ for="mutual_user"
+ >
<ng-container i18n>Mutual User</ng-container>
</label>
<div class="cd-col-form-input">
- <input id="mutual_user"
- class="form-control"
- formControlName="mutual_user"
- type="text"
- autocomplete="off">
+ <input
+ id="mutual_user"
+ class="form-control"
+ formControlName="mutual_user"
+ type="text"
+ autocomplete="off"
+ />
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('mutual_user', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('mutual_user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('mutual_user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('mutual_user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain alphanumeric
+ characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- mutual_password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="mutual_password"
- i18n>Mutual Password</label>
+ <label
+ class="cd-col-form-label"
+ for="mutual_password"
+ i18n
+ >Mutual Password</label
+ >
<div class="cd-col-form-input">
<div class="input-group">
- <input id="mutual_password"
- class="form-control"
- formControlName="mutual_password"
- type="password"
- autocomplete="new-password">
+ <input
+ id="mutual_password"
+ class="form-control"
+ formControlName="mutual_password"
+ type="password"
+ autocomplete="new-password"
+ />
- <button type="button"
- class="btn btn-light"
- cdPasswordButton="mutual_password">
- </button>
- <cd-copy-2-clipboard-button source="mutual_password">
- </cd-copy-2-clipboard-button>
+ <button
+ type="button"
+ class="btn btn-light"
+ cdPasswordButton="mutual_password"
+ ></button>
+ <cd-copy-2-clipboard-button source="mutual_password"> </cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('mutual_password', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('mutual_password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
- <span class="invalid-feedback"
- *ngIf="discoveryForm.showError('mutual_password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="discoveryForm.showError('mutual_password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain alphanumeric
+ characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submitAction()"
- [form]="discoveryForm"
- [showSubmit]="hasPermission"
- [submitText]="actionLabels.SUBMIT"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="discoveryForm"
+ [showSubmit]="hasPermission"
+ [submitText]="actionLabels.SUBMIT"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
-<div class="cd-col-form"
- *cdFormLoading="loading">
- <form name="targetForm"
- #formDir="ngForm"
- [formGroup]="targetForm"
- novalidate>
+<div
+ class="cd-col-form"
+ *cdFormLoading="loading"
+>
+ <form
+ name="targetForm"
+ #formDir="ngForm"
+ [formGroup]="targetForm"
+ novalidate
+ >
<div class="card">
- <div i18n="form title"
- class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+ <div
+ i18n="form title"
+ class="card-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
<div class="card-body">
<!-- Target IQN -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="target_iqn"
- i18n>Target IQN</label>
+ <label
+ class="cd-col-form-label required"
+ for="target_iqn"
+ i18n
+ >Target IQN</label
+ >
<div class="cd-col-form-input">
<div class="input-group">
- <input class="form-control"
- type="text"
- id="target_iqn"
- name="target_iqn"
- formControlName="target_iqn"
- cdTrim />
- <button class="btn btn-light"
- id="ecp-info-button"
- type="button"
- (click)="targetSettingsModal()">
- <svg [cdsIcon]="icons.deepCheck"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="form-control"
+ type="text"
+ id="target_iqn"
+ name="target_iqn"
+ formControlName="target_iqn"
+ cdTrim
+ />
+ <button
+ class="btn btn-light"
+ id="ecp-info-button"
+ type="button"
+ (click)="targetSettingsModal()"
+ >
+ <svg
+ [cdsIcon]="icons.deepCheck"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('target_iqn', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('target_iqn', formDir, 'pattern')"
- i18n>IQN has wrong pattern.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('target_iqn', formDir, 'iqn')">
- <ng-container i18n>An IQN has the following notation
- 'iqn.$year-$month.$reversedAddress:$definedName'</ng-container>
- <br>
- <ng-container i18n>For example: iqn.2016-06.org.dashboard:storage:disk.sn-a8675309</ng-container>
- <br>
- <a target="_blank"
- href="https://en.wikipedia.org/wiki/ISCSI#Addressing"
- i18n>More information</a>
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('target_iqn', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('target_iqn', formDir, 'pattern')"
+ i18n
+ >IQN has wrong pattern.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('target_iqn', formDir, 'iqn')"
+ >
+ <ng-container i18n
+ >An IQN has the following notation
+ 'iqn.$year-$month.$reversedAddress:$definedName'</ng-container
+ >
+ <br />
+ <ng-container i18n
+ >For example: iqn.2016-06.org.dashboard:storage:disk.sn-a8675309</ng-container
+ >
+ <br />
+ <a
+ target="_blank"
+ href="https://en.wikipedia.org/wiki/ISCSI#Addressing"
+ i18n
+ >More information</a
+ >
</span>
- <span class="form-text text-muted"
- *ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))"
- i18n>This target has modified advanced settings.</span>
+ <span
+ class="form-text text-muted"
+ *ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))"
+ i18n
+ >This target has modified advanced settings.</span
+ >
<hr />
</div>
</div>
<!-- Portals -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="portals"
- i18n>Portals</label>
+ <label
+ class="cd-col-form-label required"
+ for="portals"
+ i18n
+ >Portals</label
+ >
<div class="cd-col-form-input">
-
<ng-container *ngFor="let portal of portals.value; let i = index">
<div class="input-group cd-mb">
- <input class="cd-form-control"
- type="text"
- [value]="portal"
- disabled />
- <button class="btn btn-light"
- type="button"
- (click)="removePortal(i, portal)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="cd-form-control"
+ type="text"
+ [value]="portal"
+ disabled
+ />
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="removePortal(i, portal)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
</ng-container>
<div class="row">
<div class="col-md-12">
- <cd-select [data]="portals.value"
- [options]="portalsSelections"
- [messages]="messages.portals"
- (selection)="onPortalSelection($event)"
- elemClass="btn btn-light float-end">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <cd-select
+ [data]="portals.value"
+ [options]="portalsSelections"
+ [messages]="messages.portals"
+ (selection)="onPortalSelection($event)"
+ elemClass="btn btn-light float-end"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add portal</ng-container>
</cd-select>
</div>
</div>
- <input class="form-control"
- type="hidden"
- id="portals"
- name="portals"
- formControlName="portals" />
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('portals', formDir, 'minGateways')"
- i18n>At least {{ minimum_gateways }} gateways are required.</span>
+ <input
+ class="form-control"
+ type="hidden"
+ id="portals"
+ name="portals"
+ formControlName="portals"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('portals', formDir, 'minGateways')"
+ i18n
+ >At least {{ minimum_gateways }} gateways are required.</span
+ >
<hr />
</div>
<!-- Images -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="disks"
- i18n>Images</label>
+ <label
+ class="cd-col-form-label"
+ for="disks"
+ i18n
+ >Images</label
+ >
<div class="cd-col-form-input">
<ng-container *ngFor="let image of targetForm.getValue('disks'); let i = index">
<div class="input-group cd-mb">
- <input class="cd-form-control"
- type="text"
- [value]="image"
- disabled />
- <div class="input-group-text"
- *ngIf="api_version >= 1">lun: {{ imagesSettings[image]['lun'] }}</div>
- <button class="btn btn-light"
- type="button"
- (click)="imageSettingsModal(image)">
- <svg [cdsIcon]="icons.deepCheck"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="cd-form-control"
+ type="text"
+ [value]="image"
+ disabled
+ />
+ <div
+ class="input-group-text"
+ *ngIf="api_version >= 1"
+ >
+ lun: {{ imagesSettings[image]['lun'] }}
+ </div>
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="imageSettingsModal(image)"
+ >
+ <svg
+ [cdsIcon]="icons.deepCheck"
+ [size]="icons.size16"
+ ></svg>
</button>
- <button class="btn btn-light"
- type="button"
- (click)="removeImage(i, image)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="removeImage(i, image)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
</button>
-
</div>
<span class="form-text text-muted">
- <ng-container *ngIf="backstores.length > 1"
- i18n>Backstore: {{ imagesSettings[image].backstore | iscsiBackstore }}. </ng-container>
-
- <ng-container *ngIf="hasAdvancedSettings(imagesSettings[image][imagesSettings[image].backstore])"
- i18n>This image has modified settings.</ng-container>
+ <ng-container
+ *ngIf="backstores.length > 1"
+ i18n
+ >Backstore:
+ {{ imagesSettings[image].backstore | iscsiBackstore }}. </ng-container
+ >
+
+ <ng-container
+ *ngIf="
+ hasAdvancedSettings(imagesSettings[image][imagesSettings[image].backstore])
+ "
+ i18n
+ >This image has modified settings.</ng-container
+ >
</span>
</ng-container>
- <input class="form-control"
- type="hidden"
- id="disks"
- name="disks"
- formControlName="disks" />
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('disks', formDir, 'dupLunId')"
- i18n>Duplicated LUN numbers.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('disks', formDir, 'dupWwn')"
- i18n>Duplicated WWN.</span>
+ <input
+ class="form-control"
+ type="hidden"
+ id="disks"
+ name="disks"
+ formControlName="disks"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('disks', formDir, 'dupLunId')"
+ i18n
+ >Duplicated LUN numbers.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('disks', formDir, 'dupWwn')"
+ i18n
+ >Duplicated WWN.</span
+ >
<div class="row">
<div class="col-md-12">
- <cd-select [data]="disks.value"
- [options]="imagesSelections"
- [messages]="messages.images"
- (selection)="onImageSelection($event)"
- elemClass="btn btn-light float-end">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <cd-select
+ [data]="disks.value"
+ [options]="imagesSelections"
+ [messages]="messages.images"
+ (selection)="onImageSelection($event)"
+ elemClass="btn btn-light float-end"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add image</ng-container>
</cd-select>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- formControlName="acl_enabled"
- name="acl_enabled"
- id="acl_enabled">
- <label for="acl_enabled"
- class="custom-control-label"
- i18n>ACL authentication</label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ formControlName="acl_enabled"
+ name="acl_enabled"
+ id="acl_enabled"
+ />
+ <label
+ for="acl_enabled"
+ class="custom-control-label"
+ i18n
+ >ACL authentication</label
+ >
</div>
<hr />
</div>
<!-- Target level authentication was introduced in ceph-iscsi config v11 -->
- <div formGroupName="auth"
- *ngIf="cephIscsiConfigVersion > 10 && !targetForm.getValue('acl_enabled')">
-
+ <div
+ formGroupName="auth"
+ *ngIf="cephIscsiConfigVersion > 10 && !targetForm.getValue('acl_enabled')"
+ >
<!-- Target user -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="target_user">
+ <label
+ class="cd-col-form-label"
+ for="target_user"
+ >
<ng-container i18n>User</ng-container>
</label>
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- autocomplete="off"
- id="target_user"
- name="target_user"
- formControlName="user" />
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('user', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <input
+ class="form-control"
+ type="text"
+ autocomplete="off"
+ id="target_user"
+ name="target_user"
+ formControlName="user"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain alphanumeric
+ characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- Target password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="target_password">
+ <label
+ class="cd-col-form-label"
+ for="target_password"
+ >
<ng-container i18n>Password</ng-container>
</label>
<div class="cd-col-form-input">
<div class="input-group">
- <input class="form-control"
- type="password"
- autocomplete="new-password"
- id="target_password"
- name="target_password"
- formControlName="password" />
- <button type="button"
- class="btn btn-light"
- cdPasswordButton="target_password">
- </button>
- <cd-copy-2-clipboard-button source="target_password">
- </cd-copy-2-clipboard-button>
+ <input
+ class="form-control"
+ type="password"
+ autocomplete="new-password"
+ id="target_password"
+ name="target_password"
+ formControlName="password"
+ />
+ <button
+ type="button"
+ class="btn btn-light"
+ cdPasswordButton="target_password"
+ ></button>
+ <cd-copy-2-clipboard-button source="target_password"> </cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('password', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain alphanumeric
+ characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
<!-- Target mutual_user -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="target_mutual_user">
+ <label
+ class="cd-col-form-label"
+ for="target_mutual_user"
+ >
<ng-container i18n>Mutual User</ng-container>
</label>
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- autocomplete="off"
- id="target_mutual_user"
- name="target_mutual_user"
- formControlName="mutual_user" />
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('mutual_user', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('mutual_user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <input
+ class="form-control"
+ type="text"
+ autocomplete="off"
+ id="target_mutual_user"
+ name="target_mutual_user"
+ formControlName="mutual_user"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('mutual_user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('mutual_user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain alphanumeric
+ characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- Target mutual_password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="target_mutual_password">
+ <label
+ class="cd-col-form-label"
+ for="target_mutual_password"
+ >
<ng-container i18n>Mutual Password</ng-container>
</label>
<div class="cd-col-form-input">
<div class="input-group">
- <input class="form-control"
- type="password"
- autocomplete="new-password"
- id="target_mutual_password"
- name="target_mutual_password"
- formControlName="mutual_password" />
-
- <button type="button"
- class="btn btn-light"
- cdPasswordButton="target_mutual_password">
- </button>
+ <input
+ class="form-control"
+ type="password"
+ autocomplete="new-password"
+ id="target_mutual_password"
+ name="target_mutual_password"
+ formControlName="mutual_password"
+ />
+
+ <button
+ type="button"
+ class="btn btn-light"
+ cdPasswordButton="target_mutual_password"
+ ></button>
<cd-copy-2-clipboard-button source="target_mutual_password">
</cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('mutual_password', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="targetForm.showError('mutual_password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('mutual_password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="targetForm.showError('mutual_password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain alphanumeric
+ characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
-
</div>
<!-- Initiators -->
- <div class="form-group row"
- *ngIf="targetForm.getValue('acl_enabled')">
- <label class="cd-col-form-label"
- for="initiators"
- i18n>Initiators</label>
- <div class="cd-col-form-input"
- formArrayName="initiators">
- <div class="card mb-2"
- *ngFor="let initiator of initiators.controls; let ii = index"
- [formGroup]="initiator">
+ <div
+ class="form-group row"
+ *ngIf="targetForm.getValue('acl_enabled')"
+ >
+ <label
+ class="cd-col-form-label"
+ for="initiators"
+ i18n
+ >Initiators</label
+ >
+ <div
+ class="cd-col-form-input"
+ formArrayName="initiators"
+ >
+ <div
+ class="card mb-2"
+ *ngFor="let initiator of initiators.controls; let ii = index"
+ [formGroup]="initiator"
+ >
<div class="card-header">
<ng-container i18n>Initiator</ng-container>: {{ initiator.getValue('client_iqn') }}
- <button type="button"
- class="btn-close float-end"
- (click)="removeInitiator(ii)">
- </button>
+ <button
+ type="button"
+ class="btn-close float-end"
+ (click)="removeInitiator(ii)"
+ ></button>
</div>
<div class="card-body">
<!-- Initiator: Name -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="client_iqn"
- i18n>Client IQN</label>
+ <label
+ class="cd-col-form-label required"
+ for="client_iqn"
+ i18n
+ >Client IQN</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- formControlName="client_iqn"
- cdTrim
- (blur)="updatedInitiatorSelector()">
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('client_iqn', formDir, 'notUnique')"
- i18n>Initiator IQN needs to be unique.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('client_iqn', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('client_iqn', formDir, 'pattern')"
- i18n>IQN has wrong pattern.</span>
+ <input
+ class="form-control"
+ type="text"
+ formControlName="client_iqn"
+ cdTrim
+ (blur)="updatedInitiatorSelector()"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('client_iqn', formDir, 'notUnique')"
+ i18n
+ >Initiator IQN needs to be unique.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('client_iqn', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('client_iqn', formDir, 'pattern')"
+ i18n
+ >IQN has wrong pattern.</span
+ >
</div>
</div>
<ng-container formGroupName="auth">
<!-- Initiator: User -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="user"
- i18n>User</label>
+ <label
+ class="cd-col-form-label"
+ for="user"
+ i18n
+ >User</label
+ >
<div class="cd-col-form-input">
- <input [id]="'user' + ii"
- class="form-control"
- formControlName="user"
- autocomplete="off"
- type="text">
- <span class="invalid-feedback"
- *ngIf="initiator.showError('user', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <input
+ [id]="'user' + ii"
+ class="form-control"
+ formControlName="user"
+ autocomplete="off"
+ type="text"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain
+ alphanumeric characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- Initiator: Password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="password"
- i18n>Password</label>
+ <label
+ class="cd-col-form-label"
+ for="password"
+ i18n
+ >Password</label
+ >
<div class="cd-col-form-input">
<div class="input-group">
- <input [id]="'password' + ii"
- class="form-control"
- formControlName="password"
- autocomplete="new-password"
- type="password">
-
- <button type="button"
- class="btn btn-light"
- [cdPasswordButton]="'password' + ii">
- </button>
+ <input
+ [id]="'password' + ii"
+ class="form-control"
+ formControlName="password"
+ autocomplete="new-password"
+ type="password"
+ />
+
+ <button
+ type="button"
+ class="btn btn-light"
+ [cdPasswordButton]="'password' + ii"
+ ></button>
<cd-copy-2-clipboard-button [source]="'password' + ii">
</cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="initiator.showError('password', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain
+ alphanumeric characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
-
<!-- Initiator: mutual_user -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="mutual_user">
+ <label
+ class="cd-col-form-label"
+ for="mutual_user"
+ >
<ng-container i18n>Mutual User</ng-container>
</label>
<div class="cd-col-form-input">
- <input [id]="'mutual_user' + ii"
- class="form-control"
- formControlName="mutual_user"
- autocomplete="off"
- type="text">
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('mutual_user', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('mutual_user', formDir, 'pattern')"
- i18n>User names must have a length of 8 to 64 characters and can contain
- alphanumeric characters, '.', '@', '-', '_' or ':'.</span>
+ <input
+ [id]="'mutual_user' + ii"
+ class="form-control"
+ formControlName="mutual_user"
+ autocomplete="off"
+ type="text"
+ />
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('mutual_user', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('mutual_user', formDir, 'pattern')"
+ i18n
+ >User names must have a length of 8 to 64 characters and can contain
+ alphanumeric characters, '.', '@', '-', '_' or ':'.</span
+ >
</div>
</div>
<!-- Initiator: mutual_password -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="mutual_password"
- i18n>Mutual Password</label>
+ <label
+ class="cd-col-form-label"
+ for="mutual_password"
+ i18n
+ >Mutual Password</label
+ >
<div class="cd-col-form-input">
<div class="input-group">
- <input [id]="'mutual_password' + ii"
- class="form-control"
- formControlName="mutual_password"
- autocomplete="new-password"
- type="password">
-
- <button type="button"
- class="btn btn-light"
- [cdPasswordButton]="'mutual_password' + ii">
- </button>
+ <input
+ [id]="'mutual_password' + ii"
+ class="form-control"
+ formControlName="mutual_password"
+ autocomplete="new-password"
+ type="password"
+ />
+
+ <button
+ type="button"
+ class="btn btn-light"
+ [cdPasswordButton]="'mutual_password' + ii"
+ ></button>
<cd-copy-2-clipboard-button [source]="'mutual_password' + ii">
</cd-copy-2-clipboard-button>
</div>
- <span class="invalid-feedback"
- *ngIf="initiator.showError('mutual_password', formDir, 'required')"
- i18n>This field is required.</span>
-
- <span class="invalid-feedback"
- *ngIf="initiator.showError('mutual_password', formDir, 'pattern')"
- i18n>Passwords must have a length of 12 to 16 characters and can contain
- alphanumeric characters, '@', '-', '_' or '/'.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('mutual_password', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+
+ <span
+ class="invalid-feedback"
+ *ngIf="initiator.showError('mutual_password', formDir, 'pattern')"
+ i18n
+ >Passwords must have a length of 12 to 16 characters and can contain
+ alphanumeric characters, '@', '-', '_' or '/'.</span
+ >
</div>
</div>
</ng-container>
<!-- Initiator: Images -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="luns"
- i18n>Images</label>
+ <label
+ class="cd-col-form-label"
+ for="luns"
+ i18n
+ >Images</label
+ >
<div class="cd-col-form-input">
<ng-container *ngFor="let image of initiator.getValue('luns'); let li = index">
<div class="input-group cd-mb">
- <input class="cd-form-control"
- type="text"
- [value]="image"
- disabled />
- <button class="btn btn-light"
- type="button"
- (click)="removeInitiatorImage(initiator, li, ii, image)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="cd-form-control"
+ type="text"
+ [value]="image"
+ disabled
+ />
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="removeInitiatorImage(initiator, li, ii, image)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
</ng-container>
- <span *ngIf="initiator.getValue('cdIsInGroup')"
- i18n>Initiator belongs to a group. Images will be configure in the group.</span>
+ <span
+ *ngIf="initiator.getValue('cdIsInGroup')"
+ i18n
+ >Initiator belongs to a group. Images will be configure in the group.</span
+ >
- <div class="row"
- *ngIf="!initiator.getValue('cdIsInGroup')">
+ <div
+ class="row"
+ *ngIf="!initiator.getValue('cdIsInGroup')"
+ >
<div class="col-md-12">
- <cd-select [data]="initiator.getValue('luns')"
- [options]="imagesInitiatorSelections[ii]"
- [messages]="messages.initiatorImage"
- elemClass="btn btn-light float-end">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <cd-select
+ [data]="initiator.getValue('luns')"
+ [options]="imagesInitiatorSelections[ii]"
+ [messages]="messages.initiatorImage"
+ elemClass="btn btn-light float-end"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add image</ng-container>
</cd-select>
</div>
<div class="row">
<div class="col-md-12">
- <span class="form-text text-muted"
- *ngIf="initiators.controls.length === 0"
- i18n>No items added.</span>
-
- <button (click)="addInitiator(); false"
- class="btn btn-light float-end"
- type="button">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <span
+ class="form-text text-muted"
+ *ngIf="initiators.controls.length === 0"
+ i18n
+ >No items added.</span
+ >
+
+ <button
+ (click)="addInitiator(); (false)"
+ class="btn btn-light float-end"
+ type="button"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add initiator</ng-container>
</button>
</div>
</div>
<!-- Groups -->
- <div class="form-group row"
- *ngIf="targetForm.getValue('acl_enabled')">
- <label class="cd-col-form-label"
- for="initiators"
- i18n>Groups</label>
- <div class="cd-col-form-input"
- formArrayName="groups">
- <div class="card mb-2"
- *ngFor="let group of groups.controls; let gi = index"
- [formGroup]="group">
+ <div
+ class="form-group row"
+ *ngIf="targetForm.getValue('acl_enabled')"
+ >
+ <label
+ class="cd-col-form-label"
+ for="initiators"
+ i18n
+ >Groups</label
+ >
+ <div
+ class="cd-col-form-input"
+ formArrayName="groups"
+ >
+ <div
+ class="card mb-2"
+ *ngFor="let group of groups.controls; let gi = index"
+ [formGroup]="group"
+ >
<div class="card-header">
<ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }}
- <button type="button"
- class="btn-close float-end"
- (click)="removeGroup(gi)">
- </button>
+ <button
+ type="button"
+ class="btn-close float-end"
+ (click)="removeGroup(gi)"
+ ></button>
</div>
<div class="card-body">
<!-- Group: group_id -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="group_id"
- i18n>Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="group_id"
+ i18n
+ >Name</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- formControlName="group_id">
+ <input
+ class="form-control"
+ type="text"
+ formControlName="group_id"
+ />
</div>
</div>
<!-- Group: members -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="members">
+ <label
+ class="cd-col-form-label"
+ for="members"
+ >
<ng-container i18n>Initiators</ng-container>
</label>
<div class="cd-col-form-input">
<ng-container *ngFor="let member of group.getValue('members'); let i = index">
<div class="input-group cd-mb">
- <input class="cd-form-control"
- type="text"
- [value]="member"
- disabled />
- <button class="btn btn-light"
- type="button"
- (click)="removeGroupInitiator(group, i, gi)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="cd-form-control"
+ type="text"
+ [value]="member"
+ disabled
+ />
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="removeGroupInitiator(group, i, gi)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
</ng-container>
<div class="row">
<div class="col-md-12">
- <cd-select [data]="group.getValue('members')"
- [options]="groupMembersSelections[gi]"
- [messages]="messages.groupInitiator"
- (selection)="onGroupMemberSelection($event, gi)"
- elemClass="btn btn-light float-end">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <cd-select
+ [data]="group.getValue('members')"
+ [options]="groupMembersSelections[gi]"
+ [messages]="messages.groupInitiator"
+ (selection)="onGroupMemberSelection($event, gi)"
+ elemClass="btn btn-light float-end"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add initiator</ng-container>
</cd-select>
</div>
<!-- Group: disks -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="disks">
+ <label
+ class="cd-col-form-label"
+ for="disks"
+ >
<ng-container i18n>Images</ng-container>
</label>
<div class="cd-col-form-input">
<ng-container *ngFor="let disk of group.getValue('disks'); let i = index">
<div class="input-group cd-mb">
- <input class="cd-form-control"
- type="text"
- [value]="disk"
- disabled />
- <button class="btn btn-light"
- type="button"
- (click)="removeGroupDisk(group, i, gi)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
+ <input
+ class="cd-form-control"
+ type="text"
+ [value]="disk"
+ disabled
+ />
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="removeGroupDisk(group, i, gi)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
</ng-container>
<div class="row">
<div class="col-md-12">
- <cd-select [data]="group.getValue('disks')"
- [options]="groupDiskSelections[gi]"
- [messages]="messages.initiatorImage"
- elemClass="btn btn-light float-end">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <cd-select
+ [data]="group.getValue('disks')"
+ [options]="groupDiskSelections[gi]"
+ [messages]="messages.initiatorImage"
+ elemClass="btn btn-light float-end"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add image</ng-container>
</cd-select>
</div>
<div class="row">
<div class="col-md-12">
- <span class="form-text text-muted"
- *ngIf="groups.controls.length === 0"
- i18n>No items added.</span>
-
- <button (click)="addGroup(); false"
- class="btn btn-light float-end"
- type="button">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <span
+ class="form-text text-muted"
+ *ngIf="groups.controls.length === 0"
+ i18n
+ >No items added.</span
+ >
+
+ <button
+ (click)="addGroup(); (false)"
+ class="btn btn-light float-end"
+ type="button"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add group</ng-container>
</button>
</div>
</div>
</div>
</div>
-
</div>
<div class="card-footer">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="targetForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="targetForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</div>
</div>
</form>
</ng-container>
<ng-container class="modal-content">
- <form name="settingsForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="settingsForm"
- novalidate>
+ <form
+ name="settingsForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="settingsForm"
+ novalidate
+ >
<div class="modal-body">
- <p class="alert-warning"
- i18n>Changing these parameters from their default values is usually not necessary.</p>
+ <p
+ class="alert-warning"
+ i18n
+ >
+ Changing these parameters from their default values is usually not necessary.
+ </p>
<span *ngIf="api_version >= 1">
- <legend class="cd-header"
- i18n>Identifier</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Identifier
+ </legend>
<!-- LUN -->
<div class="form-group row">
<div class="col-sm-12">
- <label class="col-form-label required"
- for="lun"
- i18n>lun</label>
- <input type="number"
- class="form-control"
- id="lun"
- name="lun"
- formControlName="lun">
- <span class="invalid-feedback"
- *ngIf="settingsForm.showError('lun', formDir, 'required')"
- i18n>This field is required.</span>
+ <label
+ class="col-form-label required"
+ for="lun"
+ i18n
+ >lun</label
+ >
+ <input
+ type="number"
+ class="form-control"
+ id="lun"
+ name="lun"
+ formControlName="lun"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="settingsForm.showError('lun', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
</div>
<!-- WWN -->
<div class="form-group row">
<div class="col-sm-12">
- <label class="col-form-label"
- for="wwn"
- i18n>wwn</label>
- <input type="text"
- class="form-control"
- id="wwn"
- name="wwn"
- formControlName="wwn">
+ <label
+ class="col-form-label"
+ for="wwn"
+ i18n
+ >wwn</label
+ >
+ <input
+ type="text"
+ class="form-control"
+ id="wwn"
+ name="wwn"
+ formControlName="wwn"
+ />
</div>
</div>
</span>
- <legend class="cd-header"
- i18n>Settings</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Settings
+ </legend>
<!-- BACKSTORE -->
<div class="form-group row">
<div class="col-sm-12">
- <label class="col-form-label"
- for="backstore"
- i18n>Backstore</label>
- <select id="backstore"
- name="backstore"
- class="form-select"
- formControlName="backstore">
- <option *ngFor="let bs of backstores"
- [value]="bs">{{ bs | iscsiBackstore }}</option>
+ <label
+ class="col-form-label"
+ for="backstore"
+ i18n
+ >Backstore</label
+ >
+ <select
+ id="backstore"
+ name="backstore"
+ class="form-select"
+ formControlName="backstore"
+ >
+ <option
+ *ngFor="let bs of backstores"
+ [value]="bs"
+ >
+ {{ bs | iscsiBackstore }}
+ </option>
</select>
</div>
</div>
<!-- CONTROLS -->
<ng-container *ngFor="let bs of backstores">
<ng-container *ngIf="settingsForm.value['backstore'] === bs">
- <div class="form-group row"
- *ngFor="let setting of disk_default_controls[bs] | keyvalue">
+ <div
+ class="form-group row"
+ *ngFor="let setting of disk_default_controls[bs] | keyvalue"
+ >
<div class="col-sm-12">
- <cd-iscsi-setting [settingsForm]="settingsForm"
- [formDir]="formDir"
- [setting]="setting.key"
- [limits]="getDiskControlLimits(bs, setting.key)"></cd-iscsi-setting>
+ <cd-iscsi-setting
+ [settingsForm]="settingsForm"
+ [formDir]="formDir"
+ [setting]="setting.key"
+ [limits]="getDiskControlLimits(bs, setting.key)"
+ ></cd-iscsi-setting>
</div>
</div>
</ng-container>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="save()"
- [form]="settingsForm"
- [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="save()"
+ [form]="settingsForm"
+ [submitText]="actionLabels.UPDATE"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>Advanced Settings</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >Advanced Settings</ng-container
+ >
<ng-container class="modal-content">
- <form name="settingsForm"
- #formDir="ngForm"
- [formGroup]="settingsForm"
- novalidate>
+ <form
+ name="settingsForm"
+ #formDir="ngForm"
+ [formGroup]="settingsForm"
+ novalidate
+ >
<div class="modal-body">
- <p class="alert-warning"
- i18n>Changing these parameters from their default values is usually not necessary.</p>
+ <p
+ class="alert-warning"
+ i18n
+ >
+ Changing these parameters from their default values is usually not necessary.
+ </p>
- <div class="form-group row"
- *ngFor="let setting of settingsForm.controls | keyvalue">
+ <div
+ class="form-group row"
+ *ngFor="let setting of settingsForm.controls | keyvalue"
+ >
<div class="col-sm-12">
- <cd-iscsi-setting [settingsForm]="settingsForm"
- [formDir]="formDir"
- [setting]="setting.key"
- [limits]="getTargetControlLimits(setting.key)"></cd-iscsi-setting>
+ <cd-iscsi-setting
+ [settingsForm]="settingsForm"
+ [formDir]="formDir"
+ [setting]="setting.key"
+ [limits]="getTargetControlLimits(setting.key)"
+ ></cd-iscsi-setting>
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="save()"
- [form]="settingsForm"
- [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="save()"
+ [form]="settingsForm"
+ [submitText]="actionLabels.UPDATE"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-iscsi-tabs></cd-iscsi-tabs>
-<cd-alert-panel type="info"
- *ngIf="available === false"
- title="iSCSI Targets not available"
- i18n-title>
- <ng-container i18n>Please consult the <cd-doc section="iscsi"></cd-doc> on
- how to configure and enable the iSCSI Targets management functionality.</ng-container>
+<cd-alert-panel
+ type="info"
+ *ngIf="available === false"
+ title="iSCSI Targets not available"
+ i18n-title
+>
+ <ng-container i18n
+ >Please consult the <cd-doc section="iscsi"></cd-doc> on how to configure and enable
+ the iSCSI Targets management functionality.</ng-container
+ >
<ng-container *ngIf="status">
- <br>
+ <br />
<span i18n>Available information:</span>
<pre>{{ status }}</pre>
</ng-container>
</cd-alert-panel>
-<cd-table #table
- *ngIf="available === true"
- [data]="targets"
- columnMode="flex"
- [columns]="columns"
- identifier="target_iqn"
- forceIdentifier="true"
- selectionType="single"
- [hasDetails]="true"
- [autoReload]="false"
- [status]="tableStatus"
- (fetchData)="getTargets()"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ #table
+ *ngIf="available === true"
+ [data]="targets"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="target_iqn"
+ forceIdentifier="true"
+ selectionType="single"
+ [hasDetails]="true"
+ [autoReload]="false"
+ [status]="tableStatus"
+ (fetchData)="getTargets()"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions class="btn-group"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <button class="btn btn-light"
- type="button"
- (click)="configureDiscoveryAuth()">
- <svg [cdsIcon]="icons.key"
- [size]="icons.size16"
- ></svg>
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="configureDiscoveryAuth()"
+ >
+ <svg
+ [cdsIcon]="icons.key"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Discovery authentication</ng-container>
</button>
</div>
<ng-container *ngIf="expandedRow">
- <cd-iscsi-target-details *cdTableDetail
- [cephIscsiConfigVersion]="cephIscsiConfigVersion"
- [selection]="expandedRow"
- [settings]="settings"></cd-iscsi-target-details>
+ <cd-iscsi-target-details
+ *cdTableDetail
+ [cephIscsiConfigVersion]="cephIscsiConfigVersion"
+ [selection]="expandedRow"
+ [settings]="settings"
+ ></cd-iscsi-target-details>
</ng-container>
</cd-table>
<legend i18n>Gateways</legend>
<div>
- <cd-table [data]="gateways"
- (fetchData)="refresh()"
- [columns]="gatewaysColumns">
+ <cd-table
+ [data]="gateways"
+ (fetchData)="refresh()"
+ [columns]="gatewaysColumns"
+ >
</cd-table>
</div>
<legend i18n>Images</legend>
<div>
- <cd-table [data]="images"
- [columns]="imagesColumns">
+ <cd-table
+ [data]="images"
+ [columns]="imagesColumns"
+ >
</cd-table>
</div>
-<ng-template #iscsiSparklineTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #iscsiSparklineTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<span *ngIf="row.backstore === 'user:rbd'">
- <cd-sparkline [data]="value"
- [isBinary]="row.cdIsBinary"></cd-sparkline>
+ <cd-sparkline
+ [data]="value"
+ [isBinary]="row.cdIsBinary"
+ ></cd-sparkline>
</span>
- <span *ngIf="row.backstore !== 'user:rbd'"
- class="text-muted">
+ <span
+ *ngIf="row.backstore !== 'user:rbd'"
+ class="text-muted"
+ >
n/a
</span>
</ng-template>
-<ng-template #iscsiPerSecondTpl
- let-row="data.row"
- let-value="data.value">
- <span *ngIf="row.backstore === 'user:rbd'">
- {{ value }} /s
- </span>
- <span *ngIf="row.backstore !== 'user:rbd'"
- class="text-muted">
+<ng-template
+ #iscsiPerSecondTpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <span *ngIf="row.backstore === 'user:rbd'"> {{ value }} /s </span>
+ <span
+ *ngIf="row.backstore !== 'user:rbd'"
+ class="text-muted"
+ >
n/a
</span>
</ng-template>
-<ng-template #iscsiRelativeDateTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #iscsiRelativeDateTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<span *ngIf="row.backstore === 'user:rbd'">
{{ value | relativeDate | notAvailable }}
</span>
- <span *ngIf="row.backstore !== 'user:rbd'"
- class="text-muted">
+ <span
+ *ngIf="row.backstore !== 'user:rbd'"
+ class="text-muted"
+ >
n/a
</span>
</ng-template>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Create Bootstrap Token</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Create Bootstrap Token
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="createBootstrapForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="createBootstrapForm"
- novalidate>
+ <form
+ name="createBootstrapForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="createBootstrapForm"
+ novalidate
+ >
<p>
- <ng-container i18n>To create a bootstrap token which can be imported
- by a peer site cluster, provide the local site's name, select
- which pools will have mirroring enabled, and click
- <kbd>Generate</kbd>.</ng-container>
+ <ng-container i18n
+ >To create a bootstrap token which can be imported by a peer site cluster, provide the
+ local site's name, select which pools will have mirroring enabled, and click
+ <kbd>Generate</kbd>.</ng-container
+ >
</p>
<div class="form-item">
- <cds-text-label for="siteName"
- cdRequiredField="Site Name"
- [invalid]="!createBootstrapForm.controls['siteName'].valid && (createBootstrapForm.controls['siteName'].dirty || createBootstrapForm.controls['siteName'].touched)"
- [invalidText]="siteNameError"
- i18n>Site Name
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="siteName"
- name="siteName"
- formControlName="siteName"
- [invalid]="!createBootstrapForm.controls['siteName'].valid && (createBootstrapForm.controls['siteName'].dirty || createBootstrapForm.controls['siteName'].touched)"
- autofocus>
+ <cds-text-label
+ for="siteName"
+ cdRequiredField="Site Name"
+ [invalid]="
+ !createBootstrapForm.controls['siteName'].valid &&
+ (createBootstrapForm.controls['siteName'].dirty ||
+ createBootstrapForm.controls['siteName'].touched)
+ "
+ [invalidText]="siteNameError"
+ i18n
+ >Site Name
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="siteName"
+ name="siteName"
+ formControlName="siteName"
+ [invalid]="
+ !createBootstrapForm.controls['siteName'].valid &&
+ (createBootstrapForm.controls['siteName'].dirty ||
+ createBootstrapForm.controls['siteName'].touched)
+ "
+ autofocus
+ />
</cds-text-label>
<ng-template #siteNameError>
- <span *ngIf="createBootstrapForm.showError('siteName', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ *ngIf="createBootstrapForm.showError('siteName', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
- <div class="form-item"
- formGroupName="pools">
+ <div
+ class="form-item"
+ formGroupName="pools"
+ >
<fieldset>
- <label class="cds--label"
- for="pools"
- i18n>Pools</label>
+ <label
+ class="cds--label"
+ for="pools"
+ i18n
+ >Pools</label
+ >
<ng-container *ngFor="let pool of pools">
- <cds-checkbox i18n-label
- [id]="pool.name"
- [name]="pool.name"
- [formControlName]="pool.name">
+ <cds-checkbox
+ i18n-label
+ [id]="pool.name"
+ [name]="pool.name"
+ [formControlName]="pool.name"
+ >
{{ pool.name }}
</cds-checkbox>
</ng-container>
</fieldset>
- <span *ngIf="createBootstrapForm.showError('pools', formDir, 'requirePool')"
- class="invalid-feedback"
- i18n>At least one pool is required.</span>
+ <span
+ *ngIf="createBootstrapForm.showError('pools', formDir, 'requirePool')"
+ class="invalid-feedback"
+ i18n
+ >At least one pool is required.</span
+ >
</div>
- <cd-submit-button i18n
- [form]="createBootstrapForm"
- (submitAction)="generate()">Generate</cd-submit-button>
+ <cd-submit-button
+ i18n
+ [form]="createBootstrapForm"
+ (submitAction)="generate()"
+ >Generate</cd-submit-button
+ >
<div class="form-item mt-2">
- <cds-textarea-label for="token"
- i18n>Token
- <textarea cdsTextArea
- placeholder="Generated token..."
- i18n-placeholder
- id="token"
- formControlName="token"
- cols="200"
- rows="5"
- readonly>
+ <cds-textarea-label
+ for="token"
+ i18n
+ >Token
+ <textarea
+ cdsTextArea
+ placeholder="Generated token..."
+ i18n-placeholder
+ id="token"
+ formControlName="token"
+ cols="200"
+ rows="5"
+ readonly
+ >
</textarea>
</cds-textarea-label>
- <cd-copy-2-clipboard-button source="token">
- </cd-copy-2-clipboard-button>
+ <cd-copy-2-clipboard-button source="token"> </cd-copy-2-clipboard-button>
</div>
</form>
</section>
- <cd-form-button-panel (backAction)="closeModal()"
- [showSubmit]="false"
- [modalForm]="true"
- cancelText="Close"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (backAction)="closeModal()"
+ [showSubmit]="false"
+ [modalForm]="true"
+ cancelText="Close"
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
-
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Import Bootstrap Token</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Import Bootstrap Token
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="importBootstrapForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="importBootstrapForm"
- novalidate>
+ <form
+ name="importBootstrapForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="importBootstrapForm"
+ novalidate
+ >
<p>
- <ng-container i18n>To import a bootstrap token which was created
- by a peer site cluster, provide the local site's name, select
- which pools will have mirroring enabled, provide the generated
- token, and click <kbd>Import</kbd>.</ng-container>
+ <ng-container i18n
+ >To import a bootstrap token which was created by a peer site cluster, provide the local
+ site's name, select which pools will have mirroring enabled, provide the generated token,
+ and click <kbd>Import</kbd>.</ng-container
+ >
</p>
<div class="form-item">
- <cds-text-label for="siteName"
- i18n
- cdRequiredField="Site Name"
- [invalid]="!importBootstrapForm.controls['siteName'].valid && importBootstrapForm.controls['siteName'].dirty"
- [invalidText]="siteNameError"
- i18n-invalidText>Site Name
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="siteName"
- name="siteName"
- formControlName="siteName"
- [invalid]="!importBootstrapForm.controls['siteName'].valid && importBootstrapForm.controls['siteName'].dirty"
- autofocus>
+ <cds-text-label
+ for="siteName"
+ i18n
+ cdRequiredField="Site Name"
+ [invalid]="
+ !importBootstrapForm.controls['siteName'].valid &&
+ importBootstrapForm.controls['siteName'].dirty
+ "
+ [invalidText]="siteNameError"
+ i18n-invalidText
+ >Site Name
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="siteName"
+ name="siteName"
+ formControlName="siteName"
+ [invalid]="
+ !importBootstrapForm.controls['siteName'].valid &&
+ importBootstrapForm.controls['siteName'].dirty
+ "
+ autofocus
+ />
</cds-text-label>
<ng-template #siteNameError>
- <span *ngIf="importBootstrapForm.showError('siteName', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ *ngIf="importBootstrapForm.showError('siteName', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<div class="form-item">
- <cds-select label="Direction"
- for="direction"
- name="direction"
- id="direction"
- formControlName="direction">
- <option *ngFor="let direction of directions"
- [value]="direction.key">{{ direction.desc }}</option>
+ <cds-select
+ label="Direction"
+ for="direction"
+ name="direction"
+ id="direction"
+ formControlName="direction"
+ >
+ <option
+ *ngFor="let direction of directions"
+ [value]="direction.key"
+ >
+ {{ direction.desc }}
+ </option>
</cds-select>
</div>
- <div class="form-item"
- formGroupName="pools">
+ <div
+ class="form-item"
+ formGroupName="pools"
+ >
<fieldset>
- <label class="cds--label"
- for="pools"
- i18n>Pools</label>
+ <label
+ class="cds--label"
+ for="pools"
+ i18n
+ >Pools</label
+ >
<ng-container *ngFor="let pool of pools">
- <cds-checkbox i18n-label
- [id]="pool.name"
- [name]="pool.name"
- [formControlName]="pool.name">
+ <cds-checkbox
+ i18n-label
+ [id]="pool.name"
+ [name]="pool.name"
+ [formControlName]="pool.name"
+ >
{{ pool.name }}
</cds-checkbox>
</ng-container>
</fieldset>
- <span *ngIf="importBootstrapForm.showError('pools', formDir, 'requirePool')"
- class="invalid-feedback"
- i18n>At least one pool is required.</span>
+ <span
+ *ngIf="importBootstrapForm.showError('pools', formDir, 'requirePool')"
+ class="invalid-feedback"
+ i18n
+ >At least one pool is required.</span
+ >
</div>
<div class="form-item">
- <cds-textarea-label for="token"
- [invalid]="importBootstrapForm.controls['token'].invalid && (importBootstrapForm.controls['token'].dirty)"
- [invalidText]="tokenError"
- cdRequiredField="Token"
- i18n>Token
- <textarea cdsTextArea
- placeholder="Generated token..."
- i18n-placeholder
- id="token"
- formControlName="token"
- cols="200"
- rows="5"
- [invalid]="importBootstrapForm.controls['token'].invalid && (importBootstrapForm.controls['token'].dirty)">
+ <cds-textarea-label
+ for="token"
+ [invalid]="
+ importBootstrapForm.controls['token'].invalid &&
+ importBootstrapForm.controls['token'].dirty
+ "
+ [invalidText]="tokenError"
+ cdRequiredField="Token"
+ i18n
+ >Token
+ <textarea
+ cdsTextArea
+ placeholder="Generated token..."
+ i18n-placeholder
+ id="token"
+ formControlName="token"
+ cols="200"
+ rows="5"
+ [invalid]="
+ importBootstrapForm.controls['token'].invalid &&
+ importBootstrapForm.controls['token'].dirty
+ "
+ >
</textarea>
</cds-textarea-label>
<ng-template #tokenError>
- <span *ngIf="importBootstrapForm.showError('token', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
- <span *ngIf="importBootstrapForm.showError('token', formDir, 'invalidToken')"
- class="invalid-feedback"
- i18n>The token is invalid.</span>
+ <span
+ *ngIf="importBootstrapForm.showError('token', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="importBootstrapForm.showError('token', formDir, 'invalidToken')"
+ class="invalid-feedback"
+ i18n
+ >The token is invalid.</span
+ >
</ng-template>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="import()"
- [form]="importBootstrapForm"
- [submitText]="actionLabels.SUBMIT"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="import()"
+ [form]="importBootstrapForm"
+ [submitText]="actionLabels.SUBMIT"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cd-table [data]="data"
- columnMode="flex"
- [columns]="columns"
- [autoReload]="-1"
- (fetchData)="refresh()"
- [status]="tableStatus">
+<cd-table
+ [data]="data"
+ columnMode="flex"
+ [columns]="columns"
+ [autoReload]="-1"
+ (fetchData)="refresh()"
+ [status]="tableStatus"
+>
</cd-table>
-<ng-template #healthTmpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #healthTmpl
+ let-row="data.row"
+ let-value="data.value"
+>
<cds-tag [class]="row.health_color | mirrorHealthColor">{{ value }}</cds-tag>
</ng-template>
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="image-list">
+<nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="image-list"
+>
<ng-container ngbNavItem="issues">
- <a ngbNavLink
- i18n>Issues ({{ image_error.data.length }})</a>
+ <a
+ ngbNavLink
+ i18n
+ >Issues ({{ image_error.data.length }})</a
+ >
<ng-template ngbNavContent>
- <cd-table [data]="image_error.data"
- columnMode="flex"
- [columns]="image_error.columns"
- [autoReload]="-1"
- (fetchData)="refresh()"
- [status]="tableStatus">
+ <cd-table
+ [data]="image_error.data"
+ columnMode="flex"
+ [columns]="image_error.columns"
+ [autoReload]="-1"
+ (fetchData)="refresh()"
+ [status]="tableStatus"
+ >
</cd-table>
</ng-template>
</ng-container>
<ng-container ngbNavItem="syncing">
- <a ngbNavLink
- i18n>Syncing ({{ image_syncing.data.length }})</a>
+ <a
+ ngbNavLink
+ i18n
+ >Syncing ({{ image_syncing.data.length }})</a
+ >
<ng-template ngbNavContent>
- <cd-table [data]="image_syncing.data"
- columnMode="flex"
- [columns]="image_syncing.columns"
- [autoReload]="-1"
- (fetchData)="refresh()"
- [status]="tableStatus">
+ <cd-table
+ [data]="image_syncing.data"
+ columnMode="flex"
+ [columns]="image_syncing.columns"
+ [autoReload]="-1"
+ (fetchData)="refresh()"
+ [status]="tableStatus"
+ >
</cd-table>
</ng-template>
</ng-container>
<ng-container ngbNavItem="ready">
- <a ngbNavLink
- i18n>Ready ({{ image_ready.data.length }})</a>
+ <a
+ ngbNavLink
+ i18n
+ >Ready ({{ image_ready.data.length }})</a
+ >
<ng-template ngbNavContent>
- <cd-table [data]="image_ready.data"
- columnMode="flex"
- [columns]="image_ready.columns"
- [autoReload]="-1"
- (fetchData)="refresh()"
- [status]="tableStatus">
+ <cd-table
+ [data]="image_ready.data"
+ columnMode="flex"
+ [columns]="image_ready.columns"
+ [autoReload]="-1"
+ (fetchData)="refresh()"
+ [status]="tableStatus"
+ >
</cd-table>
</ng-template>
</ng-container>
<div [ngbNavOutlet]="nav"></div>
-<ng-template #stateTmpl
- let-row="data.row"
- let-value="data.value">
-
-<cds-tag size="sm"
- [class]="row.state_color | mirrorHealthColor">{{ value }}</cds-tag>
-
+<ng-template
+ #stateTmpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <cds-tag
+ size="sm"
+ [class]="row.state_color | mirrorHealthColor"
+ >{{ value }}</cds-tag
+ >
</ng-template>
-<ng-template #progressTmpl
- let-row="data.row"
- let-value="data.value">
- <div *ngIf="row.state === 'Replaying'">
- </div>
+<ng-template
+ #progressTmpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <div *ngIf="row.state === 'Replaying'"></div>
<div class="w-100 h-100 d-flex justify-content-center align-items-center">
- <ngb-progressbar *ngIf="row.state === 'Replaying'"
- type="info"
- class="w-100"
- [value]="value"
- [showValue]="true"></ngb-progressbar>
+ <ngb-progressbar
+ *ngIf="row.state === 'Replaying'"
+ type="info"
+ class="w-100"
+ [value]="value"
+ [showValue]="true"
+ ></ngb-progressbar>
</div>
</ng-template>
-<ng-template #entriesBehindPrimaryTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #entriesBehindPrimaryTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<span *ngIf="row.mirror_mode === 'journal'">
{{ value }}
</span>
- <span *ngIf="row.mirror_mode === 'snapshot'"
- ngbTooltip="Not available with mirroring snapshot mode">-</span>
+ <span
+ *ngIf="row.mirror_mode === 'snapshot'"
+ ngbTooltip="Not available with mirroring snapshot mode"
+ >-</span
+ >
</ng-template>
-<form name="rbdmirroringForm"
- #formDir="ngForm"
- [formGroup]="rbdmirroringForm"
- novalidate>
+<form
+ name="rbdmirroringForm"
+ #formDir="ngForm"
+ [formGroup]="rbdmirroringForm"
+ novalidate
+>
<div class="form-item">
- <div cdsCol
- [columnNumbers]="{md: 4}"
- class="d-flex">
- <cds-text-label for="siteName"
- i18n>Site Name
+ <div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ class="d-flex"
+ >
+ <cds-text-label
+ for="siteName"
+ i18n
+ >Site Name
<div class="cds-input-group">
- <input type="text"
- id="siteName"
- name="siteName"
- formControlName="siteName"
- [attr.disabled]="!editing ? true : null"
- cdsText>
- <cds-icon-button kind="ghost"
- size="md"
- (click)="updateSiteName()"
- [title]="editing ? 'Save' : 'Edit'">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size32"
- class="cds--btn__icon"
- *ngIf="!editing"></svg>
- <svg [cdsIcon]="icons.check"
- [size]="icons.size32"
- class="cds--btn__icon"
- *ngIf="editing"></svg>
+ <input
+ type="text"
+ id="siteName"
+ name="siteName"
+ formControlName="siteName"
+ [attr.disabled]="!editing ? true : null"
+ cdsText
+ />
+ <cds-icon-button
+ kind="ghost"
+ size="md"
+ (click)="updateSiteName()"
+ [title]="editing ? 'Save' : 'Edit'"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ *ngIf="!editing"
+ ></svg>
+ <svg
+ [cdsIcon]="icons.check"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ *ngIf="editing"
+ ></svg>
</cds-icon-button>
- <cd-copy-2-clipboard-button [source]="siteName"
- [byId]="false">
+ <cd-copy-2-clipboard-button
+ [source]="siteName"
+ [byId]="false"
+ >
</cd-copy-2-clipboard-button>
</div>
</cds-text-label>
[disabled]="action.disable()"
[attr.aria-label]="action.name"
[attr.data-testid]="action.name"
- [preserveFragment]="action.preserveFragment ? '' : null">
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ >
<span i18n>{{ action.name }}</span>
<svg
class="cds--btn__icon"
[cdsIcon]="action.icon"
- size="16">
- </svg>
+ size="16"
+ ></svg>
</button>
}
</ng-container>
<div class="col-sm-6">
<legend i18n>Daemons</legend>
<div>
- <cd-mirroring-daemons>
- </cd-mirroring-daemons>
+ <cd-mirroring-daemons> </cd-mirroring-daemons>
</div>
</div>
<legend i18n>Pools</legend>
<div>
- <cd-mirroring-pools>
- </cd-mirroring-pools>
+ <cd-mirroring-pools> </cd-mirroring-pools>
</div>
</div>
</div>
<div class="col-md-12">
<legend i18n>Images</legend>
<div>
- <cd-mirroring-images>
- </cd-mirroring-images>
+ <cd-mirroring-images> </cd-mirroring-images>
</div>
</div>
</div>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Edit pool mirror mode</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Edit pool mirror mode
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="editModeForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="editModeForm"
- novalidate>
+ <form
+ name="editModeForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="editModeForm"
+ novalidate
+ >
<p>
- <ng-container i18n>To edit the mirror mode for pool
- <kbd>{{ poolName }}</kbd>, select a new mode from the list and click
- <kbd>Update</kbd>.</ng-container>
+ <ng-container i18n
+ >To edit the mirror mode for pool <kbd>{{ poolName }}</kbd
+ >, select a new mode from the list and click <kbd>Update</kbd>.</ng-container
+ >
</p>
<div class="form-item">
- <cds-select label="Mode"
- for="mirrorMode"
- formControlName="mirrorMode"
- name="mirrorMode"
- id="mirrorMode"
- [invalid]="editModeForm.controls['mirrorMode'].invalid && (editModeForm.controls['mirrorMode'].dirty)"
- [invalidText]="mirrorModeError"
- cdRequiredField="Mode"
- i18n>
- <option *ngFor="let mirrorMode of mirrorModes"
- [value]="mirrorMode.id">{{ mirrorMode.name }}</option>
+ <cds-select
+ label="Mode"
+ for="mirrorMode"
+ formControlName="mirrorMode"
+ name="mirrorMode"
+ id="mirrorMode"
+ [invalid]="
+ editModeForm.controls['mirrorMode'].invalid && editModeForm.controls['mirrorMode'].dirty
+ "
+ [invalidText]="mirrorModeError"
+ cdRequiredField="Mode"
+ i18n
+ >
+ <option
+ *ngFor="let mirrorMode of mirrorModes"
+ [value]="mirrorMode.id"
+ >
+ {{ mirrorMode.name }}
+ </option>
</cds-select>
<ng-template #mirrorModeError>
- <span class="invalid-feedback"
- *ngIf="editModeForm.showError('mirrorMode', formDir, 'cannotDisable')"
- i18n>Peer clusters must be removed prior to disabling mirror.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="editModeForm.showError('mirrorMode', formDir, 'cannotDisable')"
+ i18n
+ >Peer clusters must be removed prior to disabling mirror.</span
+ >
</ng-template>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="update()"
- [form]="editModeForm"
- [submitText]="actionLabels.UPDATE"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="update()"
+ [form]="editModeForm"
+ [submitText]="actionLabels.UPDATE"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
{mode, select, edit {Edit} other {Add}} pool mirror peer
</h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="editPeerForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="editPeerForm"
- novalidate>
+ <form
+ name="editPeerForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="editPeerForm"
+ novalidate
+ >
<p>
- <span i18n>{mode, select, edit {Edit} other {Add}} the pool
- mirror peer attributes for pool <kbd>{{ poolName }}</kbd> and click
- <kbd>Submit</kbd>.</span>
+ <span i18n
+ >{mode, select, edit {Edit} other {Add}} the pool mirror peer attributes for pool
+ <kbd>{{ poolName }}</kbd> and click <kbd>Submit</kbd>.</span
+ >
</p>
<div class="form-item">
- <cds-text-label for="clusterName"
- [invalid]="editPeerForm.controls['clusterName'].invalid && (editPeerForm.controls['clusterName'].dirty)"
- [invalidText]="clusterNameError"
- cdRequiredField="Cluster Name"
- i18n>Cluster Name
- <input cdsText
- type="text"
- placeholder="Name..."
- i18n-placeholder
- id="clusterName"
- name="clusterName"
- formControlName="clusterName"
- [invalid]="editPeerForm.controls['clusterName'].invalid && (editPeerForm.controls['clusterName'].dirty)"
- autofocus>
+ <cds-text-label
+ for="clusterName"
+ [invalid]="
+ editPeerForm.controls['clusterName'].invalid &&
+ editPeerForm.controls['clusterName'].dirty
+ "
+ [invalidText]="clusterNameError"
+ cdRequiredField="Cluster Name"
+ i18n
+ >Cluster Name
+ <input
+ cdsText
+ type="text"
+ placeholder="Name..."
+ i18n-placeholder
+ id="clusterName"
+ name="clusterName"
+ formControlName="clusterName"
+ [invalid]="
+ editPeerForm.controls['clusterName'].invalid &&
+ editPeerForm.controls['clusterName'].dirty
+ "
+ autofocus
+ />
</cds-text-label>
<ng-template #clusterNameError>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('clusterName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('clusterName', formDir, 'invalidClusterName')"
- i18n>The cluster name is not valid.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('clusterName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('clusterName', formDir, 'invalidClusterName')"
+ i18n
+ >The cluster name is not valid.</span
+ >
</ng-template>
</div>
<div class="form-item">
- <cds-text-label for="clientID"
- [invalid]="editPeerForm.controls['clientID'].invalid && (editPeerForm.controls['clientID'].dirty)"
- [invalidText]="clientIDError"
- cdRequiredField="CephX ID"
- i18n>CephX ID
- <input cdsText
- type="text"
- placeholder="CephX ID..."
- i18n-placeholder
- id="clientID"
- name="clientID"
- formControlName="clientID"
- [invalid]="editPeerForm.controls['clientID'].invalid && (editPeerForm.controls['clientID'].dirty)">
+ <cds-text-label
+ for="clientID"
+ [invalid]="
+ editPeerForm.controls['clientID'].invalid && editPeerForm.controls['clientID'].dirty
+ "
+ [invalidText]="clientIDError"
+ cdRequiredField="CephX ID"
+ i18n
+ >CephX ID
+ <input
+ cdsText
+ type="text"
+ placeholder="CephX ID..."
+ i18n-placeholder
+ id="clientID"
+ name="clientID"
+ formControlName="clientID"
+ [invalid]="
+ editPeerForm.controls['clientID'].invalid && editPeerForm.controls['clientID'].dirty
+ "
+ />
</cds-text-label>
<ng-template #clientIDError>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('clientID', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('clientID', formDir, 'invalidClientID')"
- i18n>The CephX ID is not valid.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('clientID', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('clientID', formDir, 'invalidClientID')"
+ i18n
+ >The CephX ID is not valid.</span
+ >
</ng-template>
</div>
<div class="form-item">
- <cds-text-label for="monAddr"
- [invalid]="editPeerForm.controls['monAddr'].invalid && (editPeerForm.controls['monAddr'].dirty)"
- [invalidText]="monAddrError"
- i18n>Monitor Addresses
- <input cdsText
- type="text"
- placeholder="Comma-delimited addresses..."
- i18n-placeholder
- id="monAddr"
- name="monAddr"
- formControlName="monAddr"
- [invalid]="editPeerForm.controls['monAddr'].invalid && (editPeerForm.controls['monAddr'].dirty)">
+ <cds-text-label
+ for="monAddr"
+ [invalid]="
+ editPeerForm.controls['monAddr'].invalid && editPeerForm.controls['monAddr'].dirty
+ "
+ [invalidText]="monAddrError"
+ i18n
+ >Monitor Addresses
+ <input
+ cdsText
+ type="text"
+ placeholder="Comma-delimited addresses..."
+ i18n-placeholder
+ id="monAddr"
+ name="monAddr"
+ formControlName="monAddr"
+ [invalid]="
+ editPeerForm.controls['monAddr'].invalid && editPeerForm.controls['monAddr'].dirty
+ "
+ />
</cds-text-label>
<ng-template #monAddrError>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('monAddr', formDir, 'invalidMonAddr')"
- i18n>The monitory address is not valid.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('monAddr', formDir, 'invalidMonAddr')"
+ i18n
+ >The monitory address is not valid.</span
+ >
</ng-template>
</div>
<div class="form-item">
- <cds-text-label for="key"
- [invalid]="editPeerForm.controls['key'].invalid && (editPeerForm.controls['key'].dirty)"
- [invalidText]="keyError"
- i18n>CephX Key
- <input cdsText
- type="text"
- placeholder="Base64-encoded key..."
- i18n-placeholder
- id="key"
- name="key"
- formControlName="key"
- [invalid]="editPeerForm.controls['key'].invalid && (editPeerForm.controls['key'].dirty)">
+ <cds-text-label
+ for="key"
+ [invalid]="editPeerForm.controls['key'].invalid && editPeerForm.controls['key'].dirty"
+ [invalidText]="keyError"
+ i18n
+ >CephX Key
+ <input
+ cdsText
+ type="text"
+ placeholder="Base64-encoded key..."
+ i18n-placeholder
+ id="key"
+ name="key"
+ formControlName="key"
+ [invalid]="editPeerForm.controls['key'].invalid && editPeerForm.controls['key'].dirty"
+ />
</cds-text-label>
<ng-template #keyError>
- <span class="invalid-feedback"
- *ngIf="editPeerForm.showError('key', formDir, 'invalidKey')"
- i18n>CephX key must be base64 encoded.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="editPeerForm.showError('key', formDir, 'invalidKey')"
+ i18n
+ >CephX key must be base64 encoded.</span
+ >
</ng-template>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="update()"
- [form]="editPeerForm"
- [submitText]="actionLabels.SUBMIT"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="update()"
+ [form]="editPeerForm"
+ [submitText]="actionLabels.SUBMIT"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cd-table [data]="data"
- columnMode="flex"
- [columns]="columns"
- identifier="name"
- forceIdentifier="true"
- [autoReload]="-1"
- (fetchData)="refresh()"
- selectionType="single"
- (updateSelection)="updateSelection($event)"
- [status]="tableStatus">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="data"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="name"
+ forceIdentifier="true"
+ [autoReload]="-1"
+ (fetchData)="refresh()"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ [status]="tableStatus"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
-<ng-template #healthTmpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #healthTmpl
+ let-row="data.row"
+ let-value="data.value"
+>
<cds-tag [class]="row.health_color | mirrorHealthColor">
- {{ value }}
+ {{ value }}
</cds-tag>
</ng-template>
<ng-template #localTmpl>
- <span i18n
- i18n-ngbTooltip
- ngbTooltip="Local image count"># Local</span>
+ <span
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="Local image count"
+ ># Local</span
+ >
</ng-template>
<ng-template #remoteTmpl>
- <span i18n
- i18n-ngbTooltip
- ngbTooltip="Remote image count"># Remote</span>
+ <span
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="Remote image count"
+ ># Remote</span
+ >
</ng-template>
<router-outlet name="modal"></router-outlet>
-<cd-tearsheet [steps]="steps"
- [title]="title"
- [description]="description"
- size="md"
- [isSubmitLoading]="isSubmitLoading"
- [submitButtonLabel]="'Save changes'"
- [submitButtonLoadingLabel]="'Saving'"
- (submitRequested)="onSubmit()"
- (closeRequested)="closeModal()">
+<cd-tearsheet
+ [steps]="steps"
+ [title]="title"
+ [description]="description"
+ size="md"
+ [isSubmitLoading]="isSubmitLoading"
+ [submitButtonLabel]="'Save changes'"
+ [submitButtonLoadingLabel]="'Saving'"
+ (submitRequested)="onSubmit()"
+ (closeRequested)="closeModal()"
+>
<cd-tearsheet-step>
@if (showAuthAlert) {
- <cd-alert-panel type="warning"
- title="Subsystem DHCHAP Key will be deleted permanently"
- i18n-title
- class="cd-nvmeof-edit-auth-downgrade-alert">
- <span i18n>
- Switching from bidirectional authentication to unidirectional method will remove the subsystem authentication key,
- exposing the subsystem to unauthorised access.
- </span>
- </cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ title="Subsystem DHCHAP Key will be deleted permanently"
+ i18n-title
+ class="cd-nvmeof-edit-auth-downgrade-alert"
+ >
+ <span i18n>
+ Switching from bidirectional authentication to unidirectional method will remove the
+ subsystem authentication key, exposing the subsystem to unauthorised access.
+ </span>
+ </cd-alert-panel>
}
<cd-nvmeof-subsystem-step-three
#tearsheetStep
[group]="groupName"
[initialAuthType]="initialAuthType"
- [stepTwoValue]="stepTwoValue">
+ [stepTwoValue]="stepTwoValue"
+ >
</cd-nvmeof-subsystem-step-three>
</cd-tearsheet-step>
</cd-tearsheet>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
<h2
- cdsModalHeaderLabel
- i18n>
- {{'Subsystem'}}
+ cdsModalHeaderLabel
+ i18n
+ >
+ {{ 'Subsystem' }}
</h2>
- <!-- Step 1: Enter DHCHAP key -->
- <ng-container *ngIf="!showConfirmation">
- <h2
+ <!-- Step 1: Enter DHCHAP key -->
+ <ng-container *ngIf="!showConfirmation">
+ <h2
class="cds--type-heading-03"
cdsModalHeaderHeading
- i18n>Edit Host Key</h2>
- </ng-container>
+ i18n
+ >
+ Edit Host Key
+ </h2>
+ </ng-container>
- <!-- Step 2: Confirm changes -->
- <ng-container *ngIf="showConfirmation">
- <h2
+ <!-- Step 2: Confirm changes -->
+ <ng-container *ngIf="showConfirmation">
+ <h2
class="cds--type-heading-03"
cdsModalHeaderHeading
- i18n>Confirm changes</h2>
- </ng-container>
+ i18n
+ >
+ Confirm changes
+ </h2>
+ </ng-container>
</cds-modal-header>
<section cdsModalContent>
<!-- Step 1: Enter DHCHAP key -->
<ng-container *ngIf="!showConfirmation">
- <p class="cds--type-body-01 cds-mb-5"
- i18n>Update DHCHAP authentication key for the selected host.</p>
- <form name="editForm"
- #formDir="ngForm"
- [formGroup]="editForm"
- class="form-item "
- novalidate>
+ <p
+ class="cds--type-body-01 cds-mb-5"
+ i18n
+ >
+ Update DHCHAP authentication key for the selected host.
+ </p>
+ <form
+ name="editForm"
+ #formDir="ngForm"
+ [formGroup]="editForm"
+ class="form-item"
+ novalidate
+ >
<cds-text-label
i18n
helperText="Enter or update the authentication key for this host."
i18n-helperText
labelInputID="dhchapKey"
[invalid]="dhchapKey.isInvalid"
- [invalidText]="dhchapKeyError">
+ [invalidText]="dhchapKeyError"
+ >
DHCHAP Key | {{ hostNQN }}
- <input cdsPassword
- cdValidate
- #dhchapKey="cdValidate"
- [invalid]="dhchapKey.isInvalid"
- formControlName="dhchapKey"
- type="password"
- id="dhchap_key"
- placeholder="Enter Host DH-HMAC-CHAP key"
- i18n-placeholder
- modal-primary-focus
- autofocus
- autocomplete="off">
+ <input
+ cdsPassword
+ cdValidate
+ #dhchapKey="cdValidate"
+ [invalid]="dhchapKey.isInvalid"
+ formControlName="dhchapKey"
+ type="password"
+ id="dhchap_key"
+ placeholder="Enter Host DH-HMAC-CHAP key"
+ i18n-placeholder
+ modal-primary-focus
+ autofocus
+ autocomplete="off"
+ />
</cds-text-label>
<ng-template #dhchapKeyError>
- <span *ngIf="editForm.controls.dhchapKey.hasError('required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
- <span *ngIf="editForm.controls.dhchapKey.hasError('invalidBase64')"
- class="invalid-feedback"
- i18n>Invalid DH-HMAC-CHAP key. Please enter a valid Base64 encoded key.</span>
+ <span
+ *ngIf="editForm.controls.dhchapKey.hasError('required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="editForm.controls.dhchapKey.hasError('invalidBase64')"
+ class="invalid-feedback"
+ i18n
+ >Invalid DH-HMAC-CHAP key. Please enter a valid Base64 encoded key.</span
+ >
</ng-template>
</form>
</ng-container>
<!-- Step 2: Confirm changes -->
<ng-container *ngIf="showConfirmation">
- <p class="cds--type-body-01"
- i18n>Modifying or removing the Host key can invalidate existing NVMe sessions and interrupt secure communication with hosts. Ensure new keys are configured on all connected systems before continuing.</p>
+ <p
+ class="cds--type-body-01"
+ i18n
+ >
+ Modifying or removing the Host key can invalidate existing NVMe sessions and interrupt
+ secure communication with hosts. Ensure new keys are configured on all connected systems
+ before continuing.
+ </p>
</ng-container>
</section>
<!-- Step 1: Save button -->
- <cd-form-button-panel *ngIf="!showConfirmation"
- (submitActionEvent)="onSave()"
- (backActionEvent)="closeModal()"
- [form]="editForm"
- [submitText]="'Save'"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ *ngIf="!showConfirmation"
+ (submitActionEvent)="onSave()"
+ (backActionEvent)="closeModal()"
+ [form]="editForm"
+ [submitText]="'Save'"
+ [modalForm]="true"
+ ></cd-form-button-panel>
<!-- Step 2: Confirm button -->
- <cd-form-button-panel *ngIf="showConfirmation"
- (submitActionEvent)="onSubmit()"
- (backActionEvent)="goBack()"
- [form]="editForm"
- [submitText]="'Save changes'"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ *ngIf="showConfirmation"
+ (submitActionEvent)="onSubmit()"
+ (backActionEvent)="goBack()"
+ [form]="editForm"
+ [submitText]="'Save changes'"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
<div class="nvmeof-gateway-group-filter cds-mt-3">
- <span class="nvmeof-gateway-group-filter__label cds--type-body-compact-01"
- i18n>Gateway group:</span>
- <cds-combo-box type="single"
- size="sm"
- class="nvmeof-gateway-group-filter__combo"
- [placeholder]="placeholder"
- [items]="items"
- [disabled]="disabled"
- (selected)="onSelected($event)"
- (clear)="onClear()">
+ <span
+ class="nvmeof-gateway-group-filter__label cds--type-body-compact-01"
+ i18n
+ >Gateway group:</span
+ >
+ <cds-combo-box
+ type="single"
+ size="sm"
+ class="nvmeof-gateway-group-filter__combo"
+ [placeholder]="placeholder"
+ [items]="items"
+ [disabled]="disabled"
+ (selected)="onSelected($event)"
+ (clear)="onClear()"
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</div>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h2 cdsModalHeaderLabel
- modal-primary-focus
- i18n>Manage {{ gatewayName }}</h2>
- <span class="cds--type-heading-03"
- cdsModalHeaderHeading
- i18n>Can't delete {{ gatewayName }}</span>
+ <h2
+ cdsModalHeaderLabel
+ modal-primary-focus
+ i18n
+ >
+ Manage {{ gatewayName }}
+ </h2>
+ <span
+ class="cds--type-heading-03"
+ cdsModalHeaderHeading
+ i18n
+ >Can't delete {{ gatewayName }}</span
+ >
</cds-modal-header>
<section cdsModalContent>
- <p class="cds--type-body-01 cds--mb-05"
- i18n>
- This resource has connected items that must be deleted first. Delete the connected items, and try again.
+ <p
+ class="cds--type-body-01 cds--mb-05"
+ i18n
+ >
+ This resource has connected items that must be deleted first. Delete the connected items, and
+ try again.
+ </p>
+ <p
+ class="cds--type-label-01 cds--mb-04"
+ i18n
+ >
+ View connected items:
</p>
- <p class="cds--type-label-01 cds--mb-04"
- i18n>View connected items:</p>
<div>
@for (sub of connectedSubsystems; track sub.nqn) {
- <div class="cds--mb-04">
- <a class="cds--link cds--type-body-01"
- tabindex="0"
- (click)="navigateToSubsystem(sub.nqn)"
- (keydown.enter)="navigateToSubsystem(sub.nqn)">
- <span class="cds--mr-03">{{ sub.nqn }}</span>
- <cd-icon type="launch"></cd-icon>
- </a>
- </div>
+ <div class="cds--mb-04">
+ <a
+ class="cds--link cds--type-body-01"
+ tabindex="0"
+ (click)="navigateToSubsystem(sub.nqn)"
+ (keydown.enter)="navigateToSubsystem(sub.nqn)"
+ >
+ <span class="cds--mr-03">{{ sub.nqn }}</span>
+ <cd-icon type="launch"></cd-icon>
+ </a>
+ </div>
}
</div>
</section>
emptyStateTitle="No gateway group created"
i18n-emptyStateTitle
emptyStateMessage="Set up your first gateway group to start using NVMe over Fabrics. This will allow you to create high-performance block storage with NVMe/TCP protocol."
- i18n-emptyStateMessage>
-
+ i18n-emptyStateMessage
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</ng-container>
-<ng-template #dateTpl
- let-created="data.value">
- <span *ngIf="created">{{ created | date:'EEE d MMM, yyyy' }}</span>
+<ng-template
+ #dateTpl
+ let-created="data.value"
+>
+ <span *ngIf="created">{{ created | date: 'EEE d MMM, yyyy' }}</span>
</ng-template>
-<ng-template #customTableItemTemplate
- let-value="data.value">
- <a cdsLink
- [routerLink]="[viewUrl, value | encodeUri]"
- (click)="$event.stopPropagation()">
+<ng-template
+ #customTableItemTemplate
+ let-value="data.value"
+>
+ <a
+ cdsLink
+ [routerLink]="[viewUrl, value | encodeUri]"
+ (click)="$event.stopPropagation()"
+ >
{{ value }}
</a>
</ng-template>
-<ng-template #gatewayStatusTpl
- let-gateway="data.value">
- <div [cdsStack]="'horizontal'"
- [gap]="4">
-
+<ng-template
+ #gatewayStatusTpl
+ let-gateway="data.value"
+>
+ <div
+ [cdsStack]="'horizontal'"
+ [gap]="4"
+ >
@if (gateway.running > 0) {
- <span [ngClass]="gateway.error > 0 ? 'cds-mr-3' : ''">
- <cd-icon type="success"></cd-icon>
- <span class="cds-ml-3">{{ gateway.running }}</span>
- </span>
+ <span [ngClass]="gateway.error > 0 ? 'cds-mr-3' : ''">
+ <cd-icon type="success"></cd-icon>
+ <span class="cds-ml-3">{{ gateway.running }}</span>
+ </span>
}
@if (gateway.error > 0) {
- <span>
- <cd-icon type="error"></cd-icon>
- <span class="cds-ml-3">{{ gateway.error }}</span>
- </span>
+ <span>
+ <cd-icon type="error"></cd-icon>
+ <span class="cds-ml-3">{{ gateway.error }}</span>
+ </span>
}
</div>
</ng-template>
-<ng-template #deleteTpl
- let-groupName="groupName"
- let-subsystemCount="subsystemCount">
+<ng-template
+ #deleteTpl
+ let-groupName="groupName"
+ let-subsystemCount="subsystemCount"
+>
@if (subsystemCount > 0) {
- <cd-alert-panel type="warning"
- spacingClass="cds-mb-3">
- <h1 class="cds--type-heading-compact-01"
- i18n>Cannot delete gateway group</h1>
- <p class="cds--type-body-compact-01"
- i18n>This gateway group includes dependent NVMe-oF resources. Remove the associated initiators and gateway targets before proceeding with deletion.</p>
- </cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="cds-mb-3"
+ >
+ <h1
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Cannot delete gateway group
+ </h1>
+ <p
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ This gateway group includes dependent NVMe-oF resources. Remove the associated initiators
+ and gateway targets before proceeding with deletion.
+ </p>
+ </cd-alert-panel>
}
</ng-template>
-<cds-modal [open]="open"
- (overlaySelected)="closeModal()"
- [size]="'md'">
+<cds-modal
+ [open]="open"
+ (overlaySelected)="closeModal()"
+ [size]="'md'"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h4 class="cds--type-heading-04"
- i18n>
+ <h4
+ class="cds--type-heading-04"
+ i18n
+ >
Add gateway nodes
</h4>
- <p class="cds--type-body-01"
- i18n>
+ <p
+ class="cds--type-body-01"
+ i18n
+ >
Select NVMe-oF gateway nodes to associate with this gateway group.
</p>
</cds-modal-header>
<section cdsModalContent>
-
<div class="cds-ml-5 cds-mt-5">
- <p class="cds--type-heading-01" i18n>Select gateway nodes</p>
- <p class="cds--type-label-01" i18n>Nodes to run NVMe-oF target pods/services</p>
+ <p
+ class="cds--type-heading-01"
+ i18n
+ >
+ Select gateway nodes
+ </p>
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Nodes to run NVMe-oF target pods/services
+ </p>
</div>
<!-- Table on white background -->
- <cd-table (fetchData)="getHosts($event)"
- selectionType="multiClick"
- [searchableObjects]="true"
- [data]="hosts"
- [columns]="columns"
- (updateSelection)="updateSelection($event)"
- [autoReload]="false">
+ <cd-table
+ (fetchData)="getHosts($event)"
+ selectionType="multiClick"
+ [searchableObjects]="true"
+ [data]="hosts"
+ [columns]="columns"
+ (updateSelection)="updateSelection($event)"
+ [autoReload]="false"
+ >
</cd-table>
- <ng-template #addrTemplate
- let-value="data.value">
+ <ng-template
+ #addrTemplate
+ let-value="data.value"
+ >
<span>{{ value || '-' }}</span>
</ng-template>
- <ng-template #statusTemplate
- let-value="data.value"
- let-row="data.row">
- <div class="status-cell"
- cdsStack="horizontal"
- gap="3">
+ <ng-template
+ #statusTemplate
+ let-value="data.value"
+ let-row="data.row"
+ >
+ <div
+ class="status-cell"
+ cdsStack="horizontal"
+ gap="3"
+ >
@if (value === HostStatus.AVAILABLE) {
- <cd-icon type="success"></cd-icon>
+ <cd-icon type="success"></cd-icon>
}
<span>{{ value | titlecase }}</span>
</div>
</ng-template>
- <ng-template #labelsTemplate
- let-value="data.value">
+ <ng-template
+ #labelsTemplate
+ let-value="data.value"
+ >
@if (value && value.length > 0) {
- <cds-tag *ngFor="let label of value"
- class="tag tag-dark">{{ label }}</cds-tag>
+ <cds-tag
+ *ngFor="let label of value"
+ class="tag tag-dark"
+ >{{ label }}</cds-tag
+ >
} @else {
- <span>-</span>
+ <span>-</span>
}
</ng-template>
-
</section>
- <cd-form-button-panel [modalForm]="true"
- [showSubmit]="true"
- submitText="Add"
- i18n-submitText
- [disabled]="selection.selected.length === 0"
- (submitActionEvent)="onSubmit()"
- (backActionEvent)="closeModal()">
+ <cd-form-button-panel
+ [modalForm]="true"
+ [showSubmit]="true"
+ submitText="Add"
+ i18n-submitText
+ [disabled]="selection.selected.length === 0"
+ (submitActionEvent)="onSubmit()"
+ (backActionEvent)="closeModal()"
+ >
</cd-form-button-panel>
-</cds-modal>
\ No newline at end of file
+</cds-modal>
<div class="content-theme">
@if (mode === 'details' && groupName) {
- <cd-details-card cardTitle="Details" i18n-cardTitle [details]="gatewayDetails" [showEditButton]="false"
- class="cds-mb-5">
- </cd-details-card>
+ <cd-details-card
+ cardTitle="Details"
+ i18n-cardTitle
+ [details]="gatewayDetails"
+ [showEditButton]="false"
+ class="cds-mb-5"
+ >
+ </cd-details-card>
}
@if (mode === 'details') {
- <div class="cds-mb-5">
- <h2 class="cds--type-heading-03 cds-mt-5" i18n>Gateway nodes</h2>
- <p class="cds--type-body-compact-01" i18n>Nodes running NVMe-oF target pods/services</p>
- </div>
+ <div class="cds-mb-5">
+ <h2
+ class="cds--type-heading-03 cds-mt-5"
+ i18n
+ >
+ Gateway nodes
+ </h2>
+ <p
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ Nodes running NVMe-oF target pods/services
+ </p>
+ </div>
}
- <cd-table #table
- [data]="hosts"
- [columns]="columns"
- columnMode="flex"
- (fetchData)="getHosts($event)"
- [selectionType]="selectionType"
- [searchableObjects]="true"
- [serverSide]="false"
- [maxLimit]="25"
- identifier="hostname"
- [forceIdentifier]="true"
- (updateSelection)="updateSelection($event)"
- emptyStateTitle="No nodes available" i18n-emptyStateTitle
- emptyStateMessage="Add your first gateway node to start using NVMe over Fabrics. Nodes provide the resources required to expose NVMe/TCP block storage."
- i18n-emptyStateMessage>
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table
+ #table
+ [data]="hosts"
+ [columns]="columns"
+ columnMode="flex"
+ (fetchData)="getHosts($event)"
+ [selectionType]="selectionType"
+ [searchableObjects]="true"
+ [serverSide]="false"
+ [maxLimit]="25"
+ identifier="hostname"
+ [forceIdentifier]="true"
+ (updateSelection)="updateSelection($event)"
+ emptyStateTitle="No nodes available"
+ i18n-emptyStateTitle
+ emptyStateMessage="Add your first gateway node to start using NVMe over Fabrics. Nodes provide the resources required to expose NVMe/TCP block storage."
+ i18n-emptyStateMessage
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
</div>
-<ng-template #hostNameTpl
- let-value="data.value">
+<ng-template
+ #hostNameTpl
+ let-value="data.value"
+>
<span class="cds-ml-2">{{ value }}</span>
</ng-template>
-<ng-template #addrTpl let-value="data.value">
+<ng-template
+ #addrTpl
+ let-value="data.value"
+>
<span>{{ value || '-' }}</span>
</ng-template>
-<ng-template #statusTpl
- let-value="data.value"
- let-row="data.row">
+<ng-template
+ #statusTpl
+ let-value="data.value"
+ let-row="data.row"
+>
@if (value) {
- <div [cdsStack]="'horizontal'" [gap]="4">
- @if (value === HostStatus.AVAILABLE || value === HostStatus.RUNNING) {
- <cd-icon type="success"></cd-icon>
- } @else {
- <cd-icon type="error"></cd-icon>
- }
- <span class="cds-ml-3">{{ value | titlecase }}</span>
- </div>
+ <div
+ [cdsStack]="'horizontal'"
+ [gap]="4"
+ >
+ @if (value === HostStatus.AVAILABLE || value === HostStatus.RUNNING) {
+ <cd-icon type="success"></cd-icon>
+ } @else {
+ <cd-icon type="error"></cd-icon>
+ }
+ <span class="cds-ml-3">{{ value | titlecase }}</span>
+ </div>
} @else {
- <span>-</span>
+ <span>-</span>
}
</ng-template>
-<ng-template #labelsTpl let-value="data.value">
+<ng-template
+ #labelsTpl
+ let-value="data.value"
+>
@if (value && value.length > 0) {
- <cds-tag *ngFor="let label of value" class="tag tag-dark">{{ label }}</cds-tag>
+ <cds-tag
+ *ngFor="let label of value"
+ class="tag tag-dark"
+ >{{ label }}</cds-tag
+ >
} @else {
- <span>-</span>
+ <span>-</span>
}
-</ng-template>
\ No newline at end of file
+</ng-template>
</cd-table>
</div>
-<ng-template #authTpl
- let-row="data.row">
- <div cdsStack="horizontal"
- gap="4">
- @if (row.auth === authType.NO_AUTH) {
- <cd-icon type="warning"></cd-icon>
- } @else {
- <cd-icon type="success"></cd-icon>
- }
- <span class="cds-ml-3">{{ row.auth }}</span>
+<ng-template
+ #authTpl
+ let-row="data.row"
+>
+ <div
+ cdsStack="horizontal"
+ gap="4"
+ >
+ @if (row.auth === authType.NO_AUTH) {
+ <cd-icon type="warning"></cd-icon>
+ } @else {
+ <cd-icon type="success"></cd-icon>
+ }
+ <span class="cds-ml-3">{{ row.auth }}</span>
</div>
</ng-template>
<fieldset>
<legend>
<h1 class="cds--type-heading-03">NVMe over Fabrics (TCP)</h1>
- <cd-help-text>Monitor and manage NVMe-over-TCP resources for high-performance block storage.</cd-help-text>
+ <cd-help-text
+ >Monitor and manage NVMe-over-TCP resources for high-performance block storage.</cd-help-text
+ >
</legend>
</fieldset>
<section>
- <cds-tabs type="contained"
- followFocus="true"
- isNavigation="true"
- [cacheActive]="false">
- <cds-tab
- heading="Gateway groups"
- [tabContent]="gateways_content"
+ <cds-tabs
+ type="contained"
+ followFocus="true"
+ isNavigation="true"
+ [cacheActive]="false"
+ >
+ <cds-tab
+ heading="Gateway groups"
+ [tabContent]="gateways_content"
+ i18n-heading
+ [active]="activeTab === Tabs.gateways"
+ (selected)="onSelected(Tabs.gateways)"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Subsystem"
+ [tabContent]="subsystem_content"
+ i18n-heading
+ [active]="activeTab === Tabs.subsystem"
+ (selected)="onSelected(Tabs.subsystem)"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Namespace"
+ [tabContent]="namespace_content"
+ i18n-heading
+ [active]="activeTab === Tabs.namespace"
+ (selected)="onSelected(Tabs.namespace)"
+ >
+ </cds-tab>
+ </cds-tabs>
- i18n-heading
- [active]="activeTab === Tabs.gateways"
- (selected)="onSelected(Tabs.gateways)">
- </cds-tab>
- <cds-tab
- heading="Subsystem"
- [tabContent]="subsystem_content"
+ <ng-template #gateways_content>
+ <cd-nvmeof-gateway-group></cd-nvmeof-gateway-group>
+ </ng-template>
- i18n-heading
- [active]="activeTab === Tabs.subsystem"
- (selected)="onSelected(Tabs.subsystem)">
- </cds-tab>
- <cds-tab
- heading="Namespace"
- [tabContent]="namespace_content"
+ <ng-template #subsystem_content>
+ <cd-nvmeof-subsystems></cd-nvmeof-subsystems>
+ </ng-template>
- i18n-heading
- [active]="activeTab === Tabs.namespace"
- (selected)="onSelected(Tabs.namespace)">
- </cds-tab>
-</cds-tabs>
-
-<ng-template #gateways_content>
- <cd-nvmeof-gateway-group></cd-nvmeof-gateway-group>
-</ng-template>
-
-<ng-template #subsystem_content>
- <cd-nvmeof-subsystems></cd-nvmeof-subsystems>
-</ng-template>
-
-<ng-template #namespace_content>
- <cd-nvmeof-namespaces-list></cd-nvmeof-namespaces-list>
-</ng-template>
+ <ng-template #namespace_content>
+ <cd-nvmeof-namespaces-list></cd-nvmeof-namespaces-list>
+ </ng-template>
</section>
<router-outlet name="modal"></router-outlet>
-
[formGroup]="groupForm"
novalidate
>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{ sm: 4, md: 8 }">
- <div cdsRow
- class="form-heading form-item cds-mt-5">
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8 }"
+ >
+ <div
+ cdsRow
+ class="form-heading form-item cds-mt-5"
+ >
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<cds-text-label
labelInputID="name"
i18n
i18n-helperText
helperText="A unique name to identify this gateway group."
- [invalid]="groupName.isInvalid">
+ [invalid]="groupName.isInvalid"
+ >
Gateway group name
<input
cdsText
autofocus
formControlName="groupName"
cdRequiredField="Gateway group name"
- [invalid]="groupName.isInvalid" />
+ [invalid]="groupName.isInvalid"
+ />
</cds-text-label>
<span
class="invalid-feedback"
*ngIf="groupForm.showError('groupName', formDir, 'required')"
- i18n>This field is required.</span>
+ i18n
+ >This field is required.</span
+ >
<span
class="invalid-feedback"
- *ngIf="groupForm.get('groupName')?.hasError('notUnique') && (groupForm.get('groupName')?.dirty || groupForm.get('groupName')?.touched)"
- i18n>Group name must be unique.</span>
+ *ngIf="
+ groupForm.get('groupName')?.hasError('notUnique') &&
+ (groupForm.get('groupName')?.dirty || groupForm.get('groupName')?.touched)
+ "
+ i18n
+ >Group name must be unique.</span
+ >
<span
class="invalid-feedback"
- *ngIf="groupForm.get('groupName')?.hasError('invalidChars') && (groupForm.get('groupName')?.dirty || groupForm.get('groupName')?.touched)"
- i18n>Special characters are not allowed.</span>
+ *ngIf="
+ groupForm.get('groupName')?.hasError('invalidChars') &&
+ (groupForm.get('groupName')?.dirty || groupForm.get('groupName')?.touched)
+ "
+ i18n
+ >Special characters are not allowed.</span
+ >
</div>
</div>
cdsRow
class="form-item"
>
- <div cdsCol>
- <h1 class="cds--type-heading-02">Select target nodes</h1>
- <cd-help-text>
- <span i18n>
- Gateway nodes to run NVMe-oF target pods/services
- </span>
- </cd-help-text>
+ <div cdsCol>
+ <h1 class="cds--type-heading-02">Select target nodes</h1>
+ <cd-help-text>
+ <span i18n> Gateway nodes to run NVMe-oF target pods/services </span>
+ </cd-help-text>
+ </div>
+ <div
+ cdsCol
+ class="cds-pt-3 cds-pb-3"
+ >
+ <cd-nvmeof-gateway-node (hostsLoaded)="onHostsLoaded($event)"></cd-nvmeof-gateway-node>
+ </div>
</div>
<div
- cdsCol
- class="cds-pt-3 cds-pb-3"
+ cdsRow
+ class="form-item cds-mb-0"
>
- <cd-nvmeof-gateway-node
- (hostsLoaded)="onHostsLoaded($event)"
- ></cd-nvmeof-gateway-node>
- </div>
- </div>
- <div cdsRow class="form-item cds-mb-0">
<div cdsCol>
<cds-tile [cdsLayer]="1">
<!-- Encryption -->
- <div cdsRow class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<div class="cds--stack cds--stack-horizontal">
- <label class="cds--type-label-01"
- for="enableEncryption"
- i18n>Enable encryption</label>
- <cds-tag type="green"
- size="sm"
- i18n>Recommended</cds-tag>
+ <label
+ class="cds--type-label-01"
+ for="enableEncryption"
+ i18n
+ >Enable encryption</label
+ >
+ <cds-tag
+ type="green"
+ size="sm"
+ i18n
+ >Recommended</cds-tag
+ >
</div>
- <cds-checkbox id="enableEncryption"
- formControlName="enableEncryption">
+ <cds-checkbox
+ id="enableEncryption"
+ formControlName="enableEncryption"
+ >
<span
- class="cds--type-body-01"
- i18n>Secures group metadata and unlocks advanced authentication features.</span>
+ class="cds--type-body-01"
+ i18n
+ >Secures group metadata and unlocks advanced authentication features.</span
+ >
</cds-checkbox>
</div>
</div>
- @if (!groupForm.controls.enableEncryption.value) {
- <div cdsRow
- class="cds-mt-2">
- <div cdsCol>
- <cd-alert-panel type="warning"
- spacingClass="mb-0"
- i18n>
- <span class="cds--type-heading-01">Encryption is required if you plan to use DH-CHAP or mTLS authentication.</span>
- </cd-alert-panel>
- </div>
- </div>
- }
+ @if (!groupForm.controls.enableEncryption.value) {
+ <div
+ cdsRow
+ class="cds-mt-2"
+ >
+ <div cdsCol>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-0"
+ i18n
+ >
+ <span class="cds--type-heading-01"
+ >Encryption is required if you plan to use DH-CHAP or mTLS
+ authentication.</span
+ >
+ </cd-alert-panel>
+ </div>
+ </div>
+ }
@if (groupForm.controls.enableEncryption.value) {
- <div cdsRow class="form-item">
- <div cdsCol>
- <cds-textarea-label
- labelInputID="encryptionKey"
- helperText="Provide the encryption key used for securing the gateway group."
- i18n
- i18n-helperText>
- Encryption key
- <textarea
- cdsTextArea
- id="encryptionKey"
- formControlName="encryptionKey"
- rows="4"
- cols="100"
- cdsTheme="g10">
- </textarea>
- </cds-textarea-label>
- <span
- class="invalid-feedback"
- *ngIf="groupForm.showError('encryptionKey', formDir, 'required')"
- i18n>This field is required.</span>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-textarea-label
+ labelInputID="encryptionKey"
+ helperText="Provide the encryption key used for securing the gateway group."
+ i18n
+ i18n-helperText
+ >
+ Encryption key
+ <textarea
+ cdsTextArea
+ id="encryptionKey"
+ formControlName="encryptionKey"
+ rows="4"
+ cols="100"
+ cdsTheme="g10"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('encryptionKey', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
- </div>
}
</cds-tile>
- <cds-tile [cdsLayer]="1"
- class="cds-mt-3">
- <div cdsRow class="form-item">
+ <cds-tile
+ [cdsLayer]="1"
+ class="cds-mt-3"
+ >
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<div class="cds--stack cds--stack-horizontal cds-mb-3">
- <label class="cds--type-label-01" for="enableMtls" i18n>Enable Mutual TLS (mTLS)</label>
+ <label
+ class="cds--type-label-01"
+ for="enableMtls"
+ i18n
+ >Enable Mutual TLS (mTLS)</label
+ >
</div>
- <cds-checkbox id="enableMtls" formControlName="enableMtls">
+ <cds-checkbox
+ id="enableMtls"
+ formControlName="enableMtls"
+ >
<span
- class="cds--type-body-01"
- i18n>Use mutual TLS (mTLS) to encrypt control and monitoring commands exchanged with NVMe-oF gateways.</span>
+ class="cds--type-body-01"
+ i18n
+ >Use mutual TLS (mTLS) to encrypt control and monitoring commands exchanged with
+ NVMe-oF gateways.</span
+ >
</cds-checkbox>
</div>
</div>
@if (!groupForm.controls.enableMtls.value) {
- <div cdsRow class="cds-mt-3">
- <div cdsCol>
- <cd-alert-panel type="warning"
- spacingClass="mb-0"
- class="cds--type-heading-01"
- i18n>
- Disabling mTLS leaves gateway control and monitoring communication unencrypted.
- </cd-alert-panel>
+ <div
+ cdsRow
+ class="cds-mt-3"
+ >
+ <div cdsCol>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-0"
+ class="cds--type-heading-01"
+ i18n
+ >
+ Disabling mTLS leaves gateway control and monitoring communication unencrypted.
+ </cd-alert-panel>
+ </div>
</div>
- </div>
}
@if (groupForm.controls.enableMtls.value) {
- <div cdsRow class="form-item">
- <div cdsCol>
- <label class="cds--label fw-bold" for="certificateType"
- i18n>Choose Certificate Authority</label>
- <cds-radio-group
- formControlName="certificateType"
- orientation="horizontal"
- helperText="Select how certificates will be signed for this service. Choose internal to use the cluster's CA, or external to upload certificates signed by your organization."
- i18n-helperText>
- <cds-radio
- value="internal"
- [checked]="groupForm.controls.certificateType.value === CertificateType.internal"
- (change)="onCertificateTypeChange(CertificateType.internal)"
- i18n>
- Internal
- </cds-radio>
- <cds-radio
- value="external"
- [checked]="groupForm.controls.certificateType.value === CertificateType.external"
- (change)="onCertificateTypeChange(CertificateType.external)"
- i18n>
- External
- </cds-radio>
- </cds-radio-group>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <label
+ class="cds--label fw-bold"
+ for="certificateType"
+ i18n
+ >Choose Certificate Authority</label
+ >
+ <cds-radio-group
+ formControlName="certificateType"
+ orientation="horizontal"
+ helperText="Select how certificates will be signed for this service. Choose internal to use the cluster's CA, or external to upload certificates signed by your organization."
+ i18n-helperText
+ >
+ <cds-radio
+ value="internal"
+ [checked]="
+ groupForm.controls.certificateType.value === CertificateType.internal
+ "
+ (change)="onCertificateTypeChange(CertificateType.internal)"
+ i18n
+ >
+ Internal
+ </cds-radio>
+ <cds-radio
+ value="external"
+ [checked]="
+ groupForm.controls.certificateType.value === CertificateType.external
+ "
+ (change)="onCertificateTypeChange(CertificateType.external)"
+ i18n
+ >
+ External
+ </cds-radio>
+ </cds-radio-group>
+ </div>
</div>
- </div>
}
</cds-tile>
</div>
</div>
- @if (groupForm.controls.enableMtls.value && groupForm.controls.certificateType.value === CertificateType.internal) {
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- i18n>
- Certificate will be generated automatically by Cephadm CA for internal certificate type.
- </cd-alert-panel>
- <cd-text-label-list formControlName="custom_sans"
- label="Custom SAN Entries"
- i18n-label
- helperText="Optional list of Subject Alternative Names (hostnames, IPs, or DNS names) to include in the auto-generated certificate."
- i18n-helperText>
- </cd-text-label-list>
+ @if (
+ groupForm.controls.enableMtls.value &&
+ groupForm.controls.certificateType.value === CertificateType.internal
+ ) {
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ >
+ Certificate will be generated automatically by Cephadm CA for internal certificate
+ type.
+ </cd-alert-panel>
+ <cd-text-label-list
+ formControlName="custom_sans"
+ label="Custom SAN Entries"
+ i18n-label
+ helperText="Optional list of Subject Alternative Names (hostnames, IPs, or DNS names) to include in the auto-generated certificate."
+ i18n-helperText
+ >
+ </cd-text-label-list>
+ </div>
</div>
- </div>
}
- @if (groupForm.controls.enableMtls.value && groupForm.controls.certificateType.value === CertificateType.external) {
- <!-- Root CA Certificate Input -->
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-text-label
- labelInputID="rootCACert"
- i18n
- i18n-helperText
- helperText="Upload a Root CA certificate file, or paste the Root CA certificate PEM content directly.">
- Root CA Certificate Input
- </cds-text-label>
- <div class="cds-mb-2">
- <button
- cdsButton="tertiary"
- type="button"
- (click)="rootCAFileInput.click()"
- i18n>
- Upload File
- </button>
- <input
- #rootCAFileInput
- type="file"
- accept=".pem,.crt,.cer"
- style="display: none"
- (change)="onFileUpload($event, 'rootCACert')"
- />
+ @if (
+ groupForm.controls.enableMtls.value &&
+ groupForm.controls.certificateType.value === CertificateType.external
+ ) {
+ <!-- Root CA Certificate Input -->
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="rootCACert"
+ i18n
+ i18n-helperText
+ helperText="Upload a Root CA certificate file, or paste the Root CA certificate PEM content directly."
+ >
+ Root CA Certificate Input
+ </cds-text-label>
+ <div class="cds-mb-2">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="rootCAFileInput.click()"
+ i18n
+ >
+ Upload File
+ </button>
+ <input
+ #rootCAFileInput
+ type="file"
+ accept=".pem,.crt,.cer"
+ style="display: none"
+ (change)="onFileUpload($event, 'rootCACert')"
+ />
+ </div>
+ <cds-textarea-label
+ labelInputID="rootCACertText"
+ helperText="Uploaded files will populate the Root CA certificate details automatically. Or paste the PEM content directly in the text area."
+ i18n-helperText
+ >
+ <textarea
+ cdsTextArea
+ id="rootCACertText"
+ formControlName="rootCACert"
+ placeholder="Paste certificate or private key PEM content"
+ i18n-placeholder
+ cols="100"
+ rows="4"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('rootCACert', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
- <cds-textarea-label
- labelInputID="rootCACertText"
- helperText="Uploaded files will populate the Root CA certificate details automatically. Or paste the PEM content directly in the text area."
- i18n-helperText>
- <textarea cdsTextArea
- id="rootCACertText"
- formControlName="rootCACert"
- placeholder="Paste certificate or private key PEM content"
- i18n-placeholder
- cols="100"
- rows="4">
- </textarea>
- </cds-textarea-label>
- <span class="invalid-feedback"
- *ngIf="groupForm.showError('rootCACert', formDir, 'required')"
- i18n>This field is required.</span>
</div>
- </div>
- <!-- Client Certificate Input -->
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-text-label
- labelInputID="clientCert"
- i18n
- i18n-helperText
- helperText="Upload a client certificate file, or paste the client certificate PEM content directly.">
- Client Certificate Input
- </cds-text-label>
- <div class="cds-mb-2">
- <button
- cdsButton="tertiary"
- type="button"
- (click)="clientCertFileInput.click()"
- i18n>
- Upload File
- </button>
- <input
- #clientCertFileInput
- type="file"
- accept=".pem,.crt,.cer"
- style="display: none"
- (change)="onFileUpload($event, 'clientCert')"
- />
+ <!-- Client Certificate Input -->
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="clientCert"
+ i18n
+ i18n-helperText
+ helperText="Upload a client certificate file, or paste the client certificate PEM content directly."
+ >
+ Client Certificate Input
+ </cds-text-label>
+ <div class="cds-mb-2">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="clientCertFileInput.click()"
+ i18n
+ >
+ Upload File
+ </button>
+ <input
+ #clientCertFileInput
+ type="file"
+ accept=".pem,.crt,.cer"
+ style="display: none"
+ (change)="onFileUpload($event, 'clientCert')"
+ />
+ </div>
+ <cds-textarea-label
+ labelInputID="clientCertText"
+ helperText="Uploaded files will populate the client certificate details automatically. Or paste the PEM content directly in the text area."
+ i18n-helperText
+ >
+ <textarea
+ cdsTextArea
+ id="clientCertText"
+ formControlName="clientCert"
+ placeholder="Paste certificate or private key PEM content"
+ i18n-placeholder
+ cols="100"
+ rows="4"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('clientCert', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
- <cds-textarea-label
- labelInputID="clientCertText"
- helperText="Uploaded files will populate the client certificate details automatically. Or paste the PEM content directly in the text area."
- i18n-helperText>
- <textarea cdsTextArea
- id="clientCertText"
- formControlName="clientCert"
- placeholder="Paste certificate or private key PEM content"
- i18n-placeholder
- cols="100"
- rows="4">
- </textarea>
- </cds-textarea-label>
- <span class="invalid-feedback"
- *ngIf="groupForm.showError('clientCert', formDir, 'required')"
- i18n>This field is required.</span>
</div>
- </div>
- <!-- Client Key Input -->
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-text-label
- labelInputID="clientKey"
- i18n
- i18n-helperText
- helperText="Upload a client key file, or paste the client key PEM content directly.">
- Client Key Input
- </cds-text-label>
- <div class="cds-mb-2">
- <button
- cdsButton="tertiary"
- type="button"
- (click)="clientKeyFileInput.click()"
- i18n>
- Upload File
- </button>
- <input
- #clientKeyFileInput
- type="file"
- accept=".pem,.key"
- style="display: none"
- (change)="onFileUpload($event, 'clientKey')"
- />
+ <!-- Client Key Input -->
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="clientKey"
+ i18n
+ i18n-helperText
+ helperText="Upload a client key file, or paste the client key PEM content directly."
+ >
+ Client Key Input
+ </cds-text-label>
+ <div class="cds-mb-2">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="clientKeyFileInput.click()"
+ i18n
+ >
+ Upload File
+ </button>
+ <input
+ #clientKeyFileInput
+ type="file"
+ accept=".pem,.key"
+ style="display: none"
+ (change)="onFileUpload($event, 'clientKey')"
+ />
+ </div>
+ <cds-textarea-label
+ labelInputID="clientKeyText"
+ helperText="Uploaded files will populate the client key details automatically. Or paste the PEM content directly in the text area."
+ i18n-helperText
+ >
+ <textarea
+ cdsTextArea
+ id="clientKeyText"
+ formControlName="clientKey"
+ placeholder="Paste certificate or private key PEM content"
+ i18n-placeholder
+ cols="100"
+ rows="4"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('clientKey', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
- <cds-textarea-label
- labelInputID="clientKeyText"
- helperText="Uploaded files will populate the client key details automatically. Or paste the PEM content directly in the text area."
- i18n-helperText>
- <textarea cdsTextArea
- id="clientKeyText"
- formControlName="clientKey"
- placeholder="Paste certificate or private key PEM content"
- i18n-placeholder
- cols="100"
- rows="4">
- </textarea>
- </cds-textarea-label>
- <span class="invalid-feedback"
- *ngIf="groupForm.showError('clientKey', formDir, 'required')"
- i18n>This field is required.</span>
</div>
- </div>
- <!-- Server Certificate Input -->
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-text-label
- labelInputID="serverCert"
- i18n
- i18n-helperText
- helperText="Upload a server certificate file, or paste the server certificate PEM content directly.">
- Server Certificate Input
- </cds-text-label>
- <div class="cds-mb-2">
- <button
- cdsButton="tertiary"
- type="button"
- (click)="serverCertFileInput.click()"
- i18n>
- Upload File
- </button>
- <input
- #serverCertFileInput
- type="file"
- accept=".pem,.crt,.cer"
- style="display: none"
- (change)="onFileUpload($event, 'serverCert')"
- />
+ <!-- Server Certificate Input -->
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="serverCert"
+ i18n
+ i18n-helperText
+ helperText="Upload a server certificate file, or paste the server certificate PEM content directly."
+ >
+ Server Certificate Input
+ </cds-text-label>
+ <div class="cds-mb-2">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="serverCertFileInput.click()"
+ i18n
+ >
+ Upload File
+ </button>
+ <input
+ #serverCertFileInput
+ type="file"
+ accept=".pem,.crt,.cer"
+ style="display: none"
+ (change)="onFileUpload($event, 'serverCert')"
+ />
+ </div>
+ <cds-textarea-label
+ labelInputID="serverCertText"
+ helperText="Uploaded files will populate the server certificate details automatically. Or paste the PEM content directly in the text area."
+ i18n-helperText
+ >
+ <textarea
+ cdsTextArea
+ id="serverCertText"
+ formControlName="serverCert"
+ placeholder="Paste certificate or private key PEM content"
+ i18n-placeholder
+ cols="100"
+ rows="4"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('serverCert', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
- <cds-textarea-label
- labelInputID="serverCertText"
- helperText="Uploaded files will populate the server certificate details automatically. Or paste the PEM content directly in the text area."
- i18n-helperText>
- <textarea cdsTextArea
- id="serverCertText"
- formControlName="serverCert"
- placeholder="Paste certificate or private key PEM content"
- i18n-placeholder
- cols="100"
- rows="4">
- </textarea>
- </cds-textarea-label>
- <span class="invalid-feedback"
- *ngIf="groupForm.showError('serverCert', formDir, 'required')"
- i18n>This field is required.</span>
</div>
- </div>
- <!-- Server Key Input -->
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-text-label
- labelInputID="serverKey"
- i18n
- i18n-helperText
- helperText="Upload a server key file, or paste the server key PEM content directly.">
- Server Key Input
- </cds-text-label>
- <div class="cds-mb-2">
- <button
- cdsButton="tertiary"
- type="button"
- (click)="serverKeyFileInput.click()"
- i18n>
- Upload File
- </button>
- <input
- #serverKeyFileInput
- type="file"
- accept=".pem,.key"
- style="display: none"
- (change)="onFileUpload($event, 'serverKey')"
- />
+ <!-- Server Key Input -->
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="serverKey"
+ i18n
+ i18n-helperText
+ helperText="Upload a server key file, or paste the server key PEM content directly."
+ >
+ Server Key Input
+ </cds-text-label>
+ <div class="cds-mb-2">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="serverKeyFileInput.click()"
+ i18n
+ >
+ Upload File
+ </button>
+ <input
+ #serverKeyFileInput
+ type="file"
+ accept=".pem,.key"
+ style="display: none"
+ (change)="onFileUpload($event, 'serverKey')"
+ />
+ </div>
+ <cds-textarea-label
+ labelInputID="serverKeyText"
+ helperText="Uploaded files will populate the server key details automatically. Or paste the PEM content directly in the text area."
+ i18n-helperText
+ >
+ <textarea
+ cdsTextArea
+ id="serverKeyText"
+ formControlName="serverKey"
+ placeholder="Paste certificate or private key PEM content"
+ i18n-placeholder
+ cols="100"
+ rows="4"
+ >
+ </textarea>
+ </cds-textarea-label>
+ <span
+ class="invalid-feedback"
+ *ngIf="groupForm.showError('serverKey', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
- <cds-textarea-label
- labelInputID="serverKeyText"
- helperText="Uploaded files will populate the server key details automatically. Or paste the PEM content directly in the text area."
- i18n-helperText>
- <textarea cdsTextArea
- id="serverKeyText"
- formControlName="serverKey"
- placeholder="Paste certificate or private key PEM content"
- i18n-placeholder
- cols="100"
- rows="4">
- </textarea>
- </cds-textarea-label>
- <span class="invalid-feedback"
- *ngIf="groupForm.showError('serverKey', formDir, 'required')"
- i18n>This field is required.</span>
</div>
- </div>
}
- <div cdsRow class="cds-mt-5">
+ <div
+ cdsRow
+ class="cds-mt-5"
+ >
<cd-form-button-panel
(submitActionEvent)="onSubmit()"
[form]="groupForm"
- [submitText]="(action | titlecase) + ' ' + (resource)"
+ [submitText]="(action | titlecase) + ' ' + resource"
[disabled]="isCreateDisabled"
- wrappingClass="text-right">
+ wrappingClass="text-right"
+ >
</cd-form-button-panel>
</div>
</div>
(stepChanged)="onStepChanged()"
[isSubmitLoading]="isSubmitLoading"
submitButtonLabel="Add"
- i18n-submitButtonLabel>
-
+ i18n-submitButtonLabel
+>
<cd-tearsheet-step>
<cd-nvmeof-subsystem-step-two
#tearsheetStep
- modal-primary-focus
+ modal-primary-focus
[group]="group"
[allowAllHosts]="allowAllHosts"
- [existingHosts]="existingHosts"></cd-nvmeof-subsystem-step-two>
- </cd-tearsheet-step>
- @if(showAuthStep) {
- <cd-tearsheet-step>
- <cd-nvmeof-subsystem-step-three
- #tearsheetStep
- [stepTwoValue]="stepTwoValue"
- [group]="group"></cd-nvmeof-subsystem-step-three>
+ [existingHosts]="existingHosts"
+ ></cd-nvmeof-subsystem-step-two>
</cd-tearsheet-step>
+ @if (showAuthStep) {
+ <cd-tearsheet-step>
+ <cd-nvmeof-subsystem-step-three
+ #tearsheetStep
+ [stepTwoValue]="stepTwoValue"
+ [group]="group"
+ ></cd-nvmeof-subsystem-step-three>
+ </cd-tearsheet-step>
}
</cd-tearsheet>
@if (allowAllHosts) {
<cd-alert-panel
- class="cds-mb-4"
- type="warning"
- [showTitle]="false">
- <div cdsStack="vertical"
- gap="1">
- <strong class="cds-mb-1"
- i18n>All hosts allowed</strong>
- <p class="cds-mb-0"
- i18n>
- Allowing all hosts grants access to every initiator on the network. Authentication is not supported in this mode, which may expose the subsystem to unauthorized access.
- </p>
- </div>
-</cd-alert-panel>
+ class="cds-mb-4"
+ type="warning"
+ [showTitle]="false"
+ >
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <strong
+ class="cds-mb-1"
+ i18n
+ >All hosts allowed</strong
+ >
+ <p
+ class="cds-mb-0"
+ i18n
+ >
+ Allowing all hosts grants access to every initiator on the network. Authentication is not
+ supported in this mode, which may expose the subsystem to unauthorized access.
+ </p>
+ </div>
+ </cd-alert-panel>
}
-<cd-table [data]="initiators"
- columnMode="flex"
- (fetchData)="listInitiators()"
- [columns]="initiatorColumns"
- selectionType="multiClick"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ [data]="initiators"
+ columnMode="flex"
+ (fetchData)="listInitiators()"
+ [columns]="initiatorColumns"
+ selectionType="multiClick"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
-<ng-template #hostNqnTpl
- let-row="data.row">
+<ng-template
+ #hostNqnTpl
+ let-row="data.row"
+>
{{ getDisplayedHostNqn(row.nqn) }}
</ng-template>
-<ng-template #dhchapTpl
- let-row="data.row">
- <div cdsStack="horizontal"
- gap="4">
+<ng-template
+ #dhchapTpl
+ let-row="data.row"
+>
+ <div
+ cdsStack="horizontal"
+ gap="4"
+ >
@if (row.nqn === allowAllHost) {
{{ '-' }}
} @else {
(submitRequested)="onSubmit($event)"
[isSubmitLoading]="isSubmitLoading"
submitButtonLabel="Add"
- i18n-submitButtonLabel>
-
+ i18n-submitButtonLabel
+>
<cd-tearsheet-step>
<cd-nvmeof-subsystem-step-one
#tearsheetStep
- modal-primary-focus
+ modal-primary-focus
[group]="group"
[subsystemNQN]="subsystemNQN"
- [listenersOnly]="true"></cd-nvmeof-subsystem-step-one>
+ [listenersOnly]="true"
+ ></cd-nvmeof-subsystem-step-one>
</cd-tearsheet-step>
</cd-tearsheet>
-<cd-alert-panel *ngIf="listeners && listeners.length === 0"
- type="error"
- title="No listeners exists"
- spacingClass="cds-mb-3"
- i18n-title>
- <ng-container i18n>Currently, there are no listeners available in the NVMe subsystem. Please check your configuration or try again later.</ng-container>
+<cd-alert-panel
+ *ngIf="listeners && listeners.length === 0"
+ type="error"
+ title="No listeners exists"
+ spacingClass="cds-mb-3"
+ i18n-title
+>
+ <ng-container i18n
+ >Currently, there are no listeners available in the NVMe subsystem. Please check your
+ configuration or try again later.</ng-container
+ >
</cd-alert-panel>
-<cd-table [data]="listeners"
- columnMode="flex"
- (fetchData)="listListeners()"
- [columns]="listenerColumns"
- identifier="id"
- forceIdentifier="true"
- selectionType="single"
- emptyStateTitle="No listener found."
- i18n-emptyStateTitle
- emptyStateMessage="No listeners found. Add listeners to define network endpoints for hosts"
- i18n-emptyStateMessage
- [emptyStateImage]="emptyStateImage.search"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ [data]="listeners"
+ columnMode="flex"
+ (fetchData)="listListeners()"
+ [columns]="listenerColumns"
+ identifier="id"
+ forceIdentifier="true"
+ selectionType="single"
+ emptyStateTitle="No listener found."
+ i18n-emptyStateTitle
+ emptyStateMessage="No listeners found. Add listeners to define network endpoints for hosts"
+ i18n-emptyStateMessage
+ [emptyStateImage]="emptyStateImage.search"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
-<cds-modal size="sm"
- [open]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h4 cdsModalHeaderLabel
- class="cds--type-label-01"
- i18n>Namespace</h4>
- <h3 cdsModalHeaderHeading
- class="cds--type-heading-03"
- i18n>Expand namespace</h3>
+ <h4
+ cdsModalHeaderLabel
+ class="cds--type-label-01"
+ i18n
+ >
+ Namespace
+ </h4>
+ <h3
+ cdsModalHeaderHeading
+ class="cds--type-heading-03"
+ i18n
+ >
+ Expand namespace
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <div class="cds--type-body-01 cds-mb-3"
- i18n>
+ <div
+ class="cds--type-body-01 cds-mb-3"
+ i18n
+ >
Increase the NVMe namespace storage capacity by resizing the backing image.
</div>
<div class="cds--type-body-01 cds-mb-5">
<div class="cds-mb-3">
- <svg [cdsIcon]="icons.datastore"
- size="16"
- class="cds-mr-3"></svg>
+ <svg
+ [cdsIcon]="icons.datastore"
+ size="16"
+ class="cds-mr-3"
+ ></svg>
<strong><span i18n>namespace</span>-{{ nsid }}</strong>
</div>
- <div class="cds--type-helper-text-01 cds-mb-1">
- <span i18n>Image:</span> {{ imageName }}
- </div>
+ <div class="cds--type-helper-text-01 cds-mb-1"><span i18n>Image:</span> {{ imageName }}</div>
<div class="cds--type-helper-text-01">
<span i18n>Current size:</span> {{ currentBytes | dimlessBinary }}
</div>
</div>
- <form name="nsForm"
- #formDir="ngForm"
- [formGroup]="nsForm"
- novalidate>
+ <form
+ name="nsForm"
+ #formDir="ngForm"
+ [formGroup]="nsForm"
+ novalidate
+ >
<div class="form-item">
- <cds-number label="Enter the new size of the namespace image (GiB)"
- i18n-label
- [formControlName]="'image_size'"
- [invalid]="nsForm.controls['image_size'].invalid && (nsForm.controls['image_size'].dirty || nsForm.controls['image_size'].touched)"
- [invalidText]="sizeErrorRef"
- [min]="minSize"
- required
- modal-primary-focus></cds-number>
+ <cds-number
+ label="Enter the new size of the namespace image (GiB)"
+ i18n-label
+ [formControlName]="'image_size'"
+ [invalid]="
+ nsForm.controls['image_size'].invalid &&
+ (nsForm.controls['image_size'].dirty || nsForm.controls['image_size'].touched)
+ "
+ [invalidText]="sizeErrorRef"
+ [min]="minSize"
+ required
+ modal-primary-focus
+ ></cds-number>
<ng-template #sizeErrorRef>
- <ng-container *ngTemplateOutlet="validationErrors; context: { control: nsForm.get('image_size') }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="validationErrors; context: { control: nsForm.get('image_size') }"
+ ></ng-container>
</ng-template>
</div>
</form>
- <ng-template #validationErrors
- let-control="control">
- @for (err of control.errors | keyvalue; track err.key) {
- <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
- }
+ <ng-template
+ #validationErrors
+ let-control="control"
+ >
+ @for (err of control.errors | keyvalue; track err.key) {
+ <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ }
</ng-template>
</section>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [submitText]="expandText"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [submitText]="expandText"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
name="nsForm"
#formDir="ngForm"
[formGroup]="nsForm"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
-
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8}">
- <div cdsRow
- class="form-heading form-item">
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8 }"
+ >
+ <div
+ cdsRow
+ class="form-heading form-item"
+ >
<h3>{{ title }}</h3>
<cd-help-text>
<span>
</div>
<!-- Subsystem -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<cds-select
formControlName="subsystem"
[invalid]="subsystemRef.isInvalid"
invalidText="This field is required"
i18n-label
- i18n-invalidText>
+ i18n-invalidText
+ >
@if (!subsystems) {
- <option
- [ngValue]="null"
- disabled>Loading...</option>
+ <option
+ [ngValue]="null"
+ disabled
+ >
+ Loading...
+ </option>
}
@if (subsystems && subsystems.length === 0) {
- <option
- [ngValue]="null"
- disabled>-- No subsystems available --</option>
+ <option
+ [ngValue]="null"
+ disabled
+ >
+ -- No subsystems available --
+ </option>
}
@if (subsystems && subsystems.length > 0) {
- <option
- selectionFeedback="top-after-reopen"
- value=""
- selected>Select a subsystem</option>
+ <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>
+ <option [value]="subsystem.nqn">{{ subsystem.nqn }}</option>
}
</cds-select>
</div>
</div>
<!-- Namespace Count (Create only) -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<cds-number
cdValidate
[min]="MIN_NAMESPACE_CREATE"
[max]="MAX_NAMESPACE_CREATE"
[invalid]="nsCountRef.isInvalid"
- [invalidText]="nsForm.getError('required', 'nsCount') ? requiredInvalidText : nsCountInvalidText"
+ [invalidText]="
+ nsForm.getError('required', 'nsCount') ? requiredInvalidText : nsCountInvalidText
+ "
i18n-label
- i18n-helperText>
+ i18n-helperText
+ >
</cds-number>
</div>
</div>
<!-- Image Size -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div
cdsCol
- [columnNumbers]="{md: 4}">
+ [columnNumbers]="{ md: 4 }"
+ >
<cds-text-label
label="Image size (GiB)"
helperText="The size of the namespace image."
[invalidText]="sizeError"
cdRequiredField="Image Size"
i18n-label
- i18n-helperText>
- <input cdsText
- cdValidate
- #imageSize="cdValidate"
- type="text"
- placeholder="e.g. 100 GiB"
- id="image_size"
- formControlName="image_size"
- defaultUnit="GiB"
- [min]="0"
- [invalid]="imageSize.isInvalid"
- cdDimlessBinary>
+ i18n-helperText
+ >
+ <input
+ cdsText
+ cdValidate
+ #imageSize="cdValidate"
+ type="text"
+ placeholder="e.g. 100 GiB"
+ id="image_size"
+ formControlName="image_size"
+ defaultUnit="GiB"
+ [min]="0"
+ [invalid]="imageSize.isInvalid"
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #sizeError>
- <span
- i18n>Enter a valid size (e.g., 10GiB).</span>
+ <span i18n>Enter a valid size (e.g., 10GiB).</span>
</ng-template>
</div>
</div>
<!-- Host Access (UI only) -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<legend
class="cds--type-label-01"
- i18n>Host access (Initiators)</legend>
+ i18n
+ >
+ Host access (Initiators)
+ </legend>
<div class="form-item">
<cds-radio-group
formControlName="host_access"
- orientation="horizontal">
+ orientation="horizontal"
+ >
<cds-radio
value="all"
- [checked]="true">
+ [checked]="true"
+ >
<div>
<span
class="cds--type-body-compact-01"
- i18n>All hosts on the subsystem</span>
+ i18n
+ >All hosts on the subsystem</span
+ >
<span
class="cds--type-helper-text-01 cds-ml-1 d-block"
- i18n>Allow all hosts associated with the selected subsystem to access the namespace.</span>
+ i18n
+ >Allow all hosts associated with the selected subsystem to access the
+ namespace.</span
+ >
</div>
</cds-radio>
<cds-radio value="specific">
<div>
<span
class="cds--type-body-compact-01"
- i18n>Select specific hosts</span>
+ i18n
+ >Select specific hosts</span
+ >
<span
class="cds--type-helper-text-01 cds-ml-1 d-block"
- i18n>Only the selected hosts will be able to access this namespace.</span>
+ i18n
+ >Only the selected hosts will be able to access this namespace.</span
+ >
</div>
</cds-radio>
</cds-radio-group>
<!-- Host Selection (Visible only when 'specific' is selected) -->
@if (nsForm.getValue('host_access') === 'specific') {
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <div class="form-item">
- <cds-combo-box
- type="multi"
- selectionFeedback="top-after-reopen"
- label="Select hosts"
- i18n-label
- placeholder="Select one or more hosts"
- [appendInline]="true"
- [items]="initiatorCandidates"
- (selected)="onInitiatorSelection($event)"
- [invalid]="nsForm.controls['initiators'].invalid && (nsForm.controls['initiators'].dirty || nsForm.controls['initiators'].touched)"
- invalidText="This field is required"
- i18n-invalidText
- i18n-placeholder>
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <div class="form-item">
+ <cds-combo-box
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ label="Select hosts"
+ i18n-label
+ placeholder="Select one or more hosts"
+ [appendInline]="true"
+ [items]="initiatorCandidates"
+ (selected)="onInitiatorSelection($event)"
+ [invalid]="
+ nsForm.controls['initiators'].invalid &&
+ (nsForm.controls['initiators'].dirty || nsForm.controls['initiators'].touched)
+ "
+ invalidText="This field is required"
+ i18n-invalidText
+ i18n-placeholder
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ </div>
</div>
</div>
- </div>
}
<!-- Pool -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<cds-select
formControlName="pool"
helperText="Pool where the backing Ceph block device resides."
i18n-label
i18n-invalidText
- i18n-helperText>
+ i18n-helperText
+ >
@if (rbdPools === null) {
- <option
- [ngValue]="null"
- disabled>Loading...</option>
+ <option
+ [ngValue]="null"
+ disabled
+ >
+ Loading...
+ </option>
}
@if (rbdPools && rbdPools.length === 0) {
- <option
- [ngValue]="null"
- disabled>-- No block pools available --</option>
+ <option
+ [ngValue]="null"
+ disabled
+ >
+ -- No block pools available --
+ </option>
}
@if (rbdPools && rbdPools.length > 0) {
- <option
- value=""
- selected>Select a RBD image pool</option>
+ <option
+ value=""
+ selected
+ >
+ Select a RBD image pool
+ </option>
}
@for (pool of rbdPools; track pool.pool_name) {
- <option
- [value]="pool.pool_name">{{ pool.pool_name }}</option>
+ <option [value]="pool.pool_name">{{ pool.pool_name }}</option>
}
</cds-select>
</div>
</div>
<!-- RBD image creation (UI only) -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<legend
class="cds--type-label-01"
- i18n>RBD image creation</legend>
+ i18n
+ >
+ RBD image creation
+ </legend>
<cds-radio-group
formControlName="rbd_image_creation"
- orientation="vertical">
+ orientation="vertical"
+ >
<cds-radio
value="gateway_provisioned"
- i18n>Gateway-provisioned image</cds-radio>
+ i18n
+ >Gateway-provisioned image</cds-radio
+ >
<cds-radio
value="externally_managed"
[disabled]="nsForm.getValue('nsCount') > 1"
- [title]="nsForm.getValue('nsCount') > 1 ? 'Unavailable during bulk creation. RBD images are created automatically.' : ''"
- i18n>Externally managed image</cds-radio>
+ [title]="
+ nsForm.getValue('nsCount') > 1
+ ? 'Unavailable during bulk creation. RBD images are created automatically.'
+ : ''
+ "
+ i18n
+ >Externally managed image</cds-radio
+ >
</cds-radio-group>
</div>
</div>
<!-- Image Name (Visible only when 'gateway_provisioned' is selected) -->
- @if (nsForm.getValue('rbd_image_creation') === 'gateway_provisioned' && nsForm.getValue('nsCount') > 1) {
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cd-alert-panel
- type="info"
- [dismissible]="false"
- [showTitle]="false">
- <strong i18n>For bulk namespace creation, RBD images are provisioned automatically.</strong>
- </cd-alert-panel>
+ @if (
+ nsForm.getValue('rbd_image_creation') === 'gateway_provisioned' &&
+ nsForm.getValue('nsCount') > 1
+ ) {
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cd-alert-panel
+ type="info"
+ [dismissible]="false"
+ [showTitle]="false"
+ >
+ <strong i18n
+ >For bulk namespace creation, RBD images are provisioned automatically.</strong
+ >
+ </cd-alert-panel>
- <div class="form-item">
- <label
- for="rbd_image_name"
- class="cds--type-label-01"
- 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]="rbdImageName.isInvalid"
- [invalidText]="nsForm.getError('rbdImageName', 'rbd_image_name') ? 'Image name contains invalid characters' : ''"
- i18n-helperText
- i18n-invalidText>
- <input cdsText
- cdValidate
- #rbdImageName="cdValidate"
- placeholder="Enter a name"
- formControlName="rbd_image_name"
- [invalid]="rbdImageName.isInvalid" />
- </cds-text-label>
+ <div class="form-item">
+ <label
+ for="rbd_image_name"
+ class="cds--type-label-01"
+ 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]="rbdImageName.isInvalid"
+ [invalidText]="
+ nsForm.getError('rbdImageName', 'rbd_image_name')
+ ? 'Image name contains invalid characters'
+ : ''
+ "
+ i18n-helperText
+ i18n-invalidText
+ >
+ <input
+ cdsText
+ cdValidate
+ #rbdImageName="cdValidate"
+ placeholder="Enter a name"
+ formControlName="rbd_image_name"
+ [invalid]="rbdImageName.isInvalid"
+ />
+ </cds-text-label>
+ </div>
</div>
</div>
- </div>
}
<!-- Image Selection (Visible only when 'externally_managed' is selected) -->
@if (nsForm.getValue('rbd_image_creation') === 'externally_managed') {
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <cds-select
- formControlName="rbd_image_name"
- cdValidate
- #rbdImageSelectRef="cdValidate"
- label="RBD Image"
- [invalid]="rbdImageSelectRef.isInvalid"
- invalidText="This field is required"
- helperText="Select an existing RBD image from the pool to expose as a namespace."
- i18n-label
- i18n-invalidText
- i18n-helperText>
- <option
- [ngValue]="null"
- disabled
- selected>Select an image</option>
- @for (img of rbdImages; track img.name) {
- <option
- [value]="img.name">{{ img.name }} ({{ img.size | dimlessBinary }})</option>
- }
- </cds-select>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <cds-select
+ formControlName="rbd_image_name"
+ cdValidate
+ #rbdImageSelectRef="cdValidate"
+ label="RBD Image"
+ [invalid]="rbdImageSelectRef.isInvalid"
+ invalidText="This field is required"
+ helperText="Select an existing RBD image from the pool to expose as a namespace."
+ i18n-label
+ i18n-invalidText
+ i18n-helperText
+ >
+ <option
+ [ngValue]="null"
+ disabled
+ selected
+ >
+ Select an image
+ </option>
+ @for (img of rbdImages; track img.name) {
+ <option [value]="img.name">{{ img.name }} ({{ img.size | dimlessBinary }})</option>
+ }
+ </cds-select>
+ </div>
</div>
- </div>
}
<!-- Namespace Block Size (bytes) -->
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<div cdsCol>
<cds-number
cdValidate
[min]="0"
[invalid]="namespaceSize.isInvalid"
i18n-label
- i18n-helperText>
+ i18n-helperText
+ >
</cds-number>
</div>
</div>
(submitActionEvent)="onSubmit()"
[form]="nsForm"
[submitText]="(action | titlecase) + ' ' + (resource | titlecase)"
- wrappingClass="text-right form-button">
+ wrappingClass="text-right form-button"
+ >
</cd-form-button-panel>
</div>
-
</div>
</div>
</form>
<div class="nvmeof-content-layout">
<div class="nvmeof-content-main">
-<ng-container *ngIf="namespaces$ | async as namespaces">
- <cd-table [data]="namespaces"
- [compactSearchField]="true"
- columnMode="flex"
- (fetchData)="fetchData()"
- [columns]="namespacesColumns"
- identifier="unique_id"
- [forceIdentifier]="true"
- selectionType="single"
- (updateSelection)="updateSelection($event)"
- emptyStateTitle="No namespaces created."
- i18n-emptyStateTitle
- emptyStateMessage="Namespaces are storage volumes mapped to subsystems for host access. Create a namespace to start provisioning storage within a subsystem."
- i18n-emptyStateMessage>
+ <ng-container *ngIf="namespaces$ | async as namespaces">
+ <cd-table
+ [data]="namespaces"
+ [compactSearchField]="true"
+ columnMode="flex"
+ (fetchData)="fetchData()"
+ [columns]="namespacesColumns"
+ identifier="unique_id"
+ [forceIdentifier]="true"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ emptyStateTitle="No namespaces created."
+ i18n-emptyStateTitle
+ emptyStateMessage="Namespaces are storage volumes mapped to subsystems for host access. Create a namespace to start provisioning storage within a subsystem."
+ i18n-emptyStateMessage
+ >
+ <div class="table-filter">
+ <cd-nvmeof-gateway-group-filter (groupChange)="groupHandler.onGroupChange($event)">
+ </cd-nvmeof-gateway-group-filter>
+ </div>
- <div class="table-filter">
- <cd-nvmeof-gateway-group-filter
- (groupChange)="groupHandler.onGroupChange($event)">
- </cd-nvmeof-gateway-group-filter>
- </div>
-
- <div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
-</cd-table>
-</ng-container>
+ <div class="table-actions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ </div>
+ </cd-table>
+ </ng-container>
</div>
</div>
<cd-productive-card>
<ng-template #header>
- <div cdsStack="vertical"
- [gap]="3">
- <h2 class="cds--type-heading-03"
- i18n>Recommended first-time setup</h2>
- <p class="cds--type-body-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="3"
+ >
+ <h2
+ class="cds--type-heading-03"
+ i18n
+ >
+ Recommended first-time setup
+ </h2>
+ <p
+ class="cds--type-body-01"
+ i18n
+ >
Start your NVMe over Fabrics configuration by creating the essential resources in sequence.
</p>
</div>
</ng-template>
- <div cdsStack="horizontal" [gap]="4">
+ <div
+ cdsStack="horizontal"
+ [gap]="4"
+ >
<div>
<cd-setup-step-card
[stepNumber]="1"
[description]="cards.gateway.description"
[isConfigured]="hasGatewayGroups"
[successMessage]="cards.gateway.successMessage"
- [infoMessage]="cards.gateway.infoMessage">
+ [infoMessage]="cards.gateway.infoMessage"
+ >
</cd-setup-step-card>
</div>
- <div >
+ <div>
<cd-setup-step-card
[stepNumber]="2"
[title]="cards.subsystem.title"
[description]="cards.subsystem.description"
[isConfigured]="hasSubsystems"
[successMessage]="cards.subsystem.successMessage"
- [infoMessage]="cards.subsystem.infoMessage">
+ [infoMessage]="cards.subsystem.infoMessage"
+ >
</cd-setup-step-card>
</div>
- <div >
+ <div>
<cd-setup-step-card
[stepNumber]="3"
[title]="cards.namespace.title"
[description]="cards.namespace.description"
[isConfigured]="hasNamespaces"
[successMessage]="cards.namespace.successMessage"
- [infoMessage]="cards.namespace.infoMessage">
+ [infoMessage]="cards.namespace.infoMessage"
+ >
</cd-setup-step-card>
</div>
</div>
@if (isAllConfigured) {
- <div class="nvmeof-setup-cards__completion">
- <a cdsLink
- class="cds--link--disabled"
- aria-disabled="true"
- i18n>Configuration complete. View status →</a>
- </div>
+ <div class="nvmeof-setup-cards__completion">
+ <a
+ cdsLink
+ class="cds--link--disabled"
+ aria-disabled="true"
+ i18n
+ >Configuration complete. View status →</a
+ >
+ </div>
}
-</cd-productive-card>
\ No newline at end of file
+</cd-productive-card>
- <cd-table [data]="namespaces"
- columnMode="flex"
- (fetchData)="listNamespaces()"
- [columns]="namespacesColumns"
- selectionType="single"
- (updateSelection)="updateSelection($event)"
- emptyStateTitle="No namespaces created."
- i18n-emptyStateTitle
- emptyStateMessage="Namespaces are storage volumes mapped to subsystems for host access. Create a namespace to start provisioning storage within a subsystem."
- i18n-emptyStateMessage>
-
- <div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
- </cd-table>
+<cd-table
+ [data]="namespaces"
+ columnMode="flex"
+ (fetchData)="listNamespaces()"
+ [columns]="namespacesColumns"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ emptyStateTitle="No namespaces created."
+ i18n-emptyStateTitle
+ emptyStateMessage="Namespaces are storage volumes mapped to subsystems for host access. Create a namespace to start provisioning storage within a subsystem."
+ i18n-emptyStateMessage
+>
+ <div class="table-actions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ </div>
+</cd-table>
<cds-tile *ngIf="subsystem">
- <div [cdsStack]="'vertical'"
- [gap]="6">
- <div cdsGrid
- [useCssGrid]="true"
- [condensed]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{ sm: 4, md: 8, lg: 12 }">
- <h3 class="cds--type-heading-03"
- i18n>Subsystem details</h3>
+ <div
+ [cdsStack]="'vertical'"
+ [gap]="6"
+ >
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [condensed]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ >
+ <h3
+ class="cds--type-heading-03"
+ i18n
+ >
+ Subsystem details
+ </h3>
</div>
</div>
@for (row of getRows(); track row) {
- <div cdsGrid
- [useCssGrid]="true"
- [condensed]="true"
- [fullWidth]="true">
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [condensed]="true"
+ [fullWidth]="true"
+ >
+ @for (detail of getDetailsForRow(row); track detail.label) {
+ @if (detail.type === 'auth') {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Authentication</span
+ >
+ <div>
+ <cd-icon
+ [type]="getAuthStatusIcon(detail.value.toString())"
+ class="cds-mr-3"
+ ></cd-icon>
+ <span class="cds--type-label-02">{{ detail.value }}</span>
+ <a
+ cdsLink
+ class="cds-ml-2"
+ (click)="openEditAuthModal()"
+ (keydown.enter)="openEditAuthModal()"
+ [cdsStack]="'horizontal'"
+ tabindex="0"
+ [gap]="1"
+ >
+ <span i18n>Edit</span>
+ <cd-icon type="edit"></cd-icon>
+ </a>
+ </div>
+ </div>
- @for (detail of getDetailsForRow(row); track detail.label) {
- @if (detail.type === 'auth') {
- <div cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- [cdsStack]="'vertical'"
- [gap]="2">
- <span class="cds--type-label-01"
- i18n>Authentication</span>
- <div>
- <cd-icon [type]="getAuthStatusIcon(detail.value.toString())"
- class="cds-mr-3"></cd-icon>
+ } @else if (detail.type === 'listeners') {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
+ <div>
+ <span class="cds--type-label-01">{{ detail.label }}</span>
+ @if (detail.tooltip) {
+ <cd-icon
+ type="infoCircle"
+ class="cds-ml-2"
+ [ngbTooltip]="detail.tooltip"
+ ></cd-icon>
+ }
+ </div>
<span class="cds--type-label-02">{{ detail.value }}</span>
- <a cdsLink
- class="cds-ml-2"
- (click)="openEditAuthModal()"
- (keydown.enter)="openEditAuthModal()"
- [cdsStack]="'horizontal'"
- tabindex="0"
- [gap]="1">
- <span i18n>Edit</span>
- <cd-icon type="edit"></cd-icon>
- </a>
</div>
- </div>
- }
- @else if (detail.type === 'listeners') {
- <div cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- [cdsStack]="'vertical'"
- [gap]="2">
- <div>
+ } @else if (detail.type === 'host-access') {
+ <div
+ cdsCol
+ [columnNumbers]="getColNumbers(detail)"
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
<span class="cds--type-label-01">{{ detail.label }}</span>
- @if (detail.tooltip) {
- <cd-icon type="infoCircle"
- class="cds-ml-2"
- [ngbTooltip]="detail.tooltip"></cd-icon>
- }
+ <div class="cds--type-label-02">
+ <span>{{ detail.value ? 'Allow all hosts' : 'Restrict to specific hosts' }}</span>
+ <a
+ cdsLink
+ (click)="openEditHostAccessModal()"
+ (keydown.enter)="openEditHostAccessModal()"
+ [cdsStack]="'horizontal'"
+ class="cds-ml-2"
+ tabindex="0"
+ [gap]="1"
+ >
+ <span i18n>Edit</span>
+ <cd-icon type="edit"></cd-icon>
+ </a>
+ </div>
</div>
- <span class="cds--type-label-02">{{ detail.value }}</span>
- </div>
- }
+ }
- @else if (detail.type === 'host-access') {
- <div cdsCol
- [columnNumbers]="getColNumbers(detail)"
- [cdsStack]="'vertical'"
- [gap]="2">
- <span class="cds--type-label-01">{{ detail.label }}</span>
- <div class="cds--type-label-02">
- <span>{{ detail.value ? 'Allow all hosts' : 'Restrict to specific hosts' }}</span>
- <a cdsLink
- (click)="openEditHostAccessModal()"
- (keydown.enter)="openEditHostAccessModal()"
- [cdsStack]="'horizontal'"
- class="cds-ml-2"
- tabindex="0"
- [gap]="1">
- <span i18n>Edit</span>
- <cd-icon type="edit"></cd-icon>
- </a>
+ <!-- Default: plain text row -->
+ @else {
+ <div
+ cdsCol
+ [columnNumbers]="getColNumbers(detail)"
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
+ <span class="cds--type-label-01">{{ detail.label }}</span>
+ <span class="cds--type-label-02">{{ getDisplayValue(detail.value) }}</span>
</div>
- </div>
+ }
}
- <!-- Default: plain text row -->
- @else {
- <div cdsCol
- [columnNumbers]="getColNumbers(detail)"
- [cdsStack]="'vertical'"
- [gap]="2">
- <span class="cds--type-label-01">{{ detail.label }}</span>
- <span class="cds--type-label-02">{{ getDisplayValue(detail.value) }}</span>
- </div>
+ @if (getDetailsForRow(row).length < 3 && !isFullWidthRow(row)) {
+ @for (filler of getFillerCount(row); track filler) {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ ></div>
+ }
}
-
- }
-
- @if (getDetailsForRow(row).length < 3 && !isFullWidthRow(row)) {
- @for (filler of getFillerCount(row); track filler) {
- <div cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"></div>
- }
- }
- </div>
+ </div>
}
</div>
</cds-tile>
-<cd-grafana *ngIf="permissions.grafana.read && subsystemNQN && groupName"
- i18n-title
- title="Subsystem details"
- grafanaPath="ceph-nvme-of-gateways-performance?var-group={{groupName}}&var-subsystem={{subsystemNQN}}"
- [type]="'metrics'"
- uid="feeuv1dno43r4deed"
- grafanaStyle="three">
+<cd-grafana
+ *ngIf="permissions.grafana.read && subsystemNQN && groupName"
+ i18n-title
+ title="Subsystem details"
+ grafanaPath="ceph-nvme-of-gateways-performance?var-group={{ groupName }}&var-subsystem={{
+ subsystemNQN
+ }}"
+ [type]="'metrics'"
+ uid="feeuv1dno43r4deed"
+ grafanaStyle="three"
+>
</cd-grafana>
-<cd-helper *ngIf="!permissions.grafana.read"
- i18n>
+<cd-helper
+ *ngIf="!permissions.grafana.read"
+ i18n
+>
Grafana permissions are required to view performance details.
</cd-helper>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="subsystem-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="subsystem-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [data]="data">
- </cd-table-key-value>
+ <cd-table-key-value [data]="data"> </cd-table-key-value>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="performance-details"
- *ngIf="permissions.grafana.read">
- <a ngbNavLink
- i18n>Performance Details</a>
+ <ng-container
+ ngbNavItem="performance-details"
+ *ngIf="permissions.grafana.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Performance Details</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Subsystem details"
- grafanaPath="ceph-nvme-of-gateways-performance?var-group={{group}}&var-subsystem={{subsystemNQN}}"
- [type]="'metrics'"
- uid="feeuv1dno43r4deed"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="Subsystem details"
+ grafanaPath="ceph-nvme-of-gateways-performance?var-group={{ group }}&var-subsystem={{
+ subsystemNQN
+ }}"
+ [type]="'metrics'"
+ uid="feeuv1dno43r4deed"
+ grafanaStyle="three"
+ >
</cd-grafana>
</ng-template>
</ng-container>
-
-<form [formGroup]="formGroup"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8}">
+<form
+ [formGroup]="formGroup"
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8 }"
+ >
@if (!listenersOnly) {
- <div cdsRow
- class="form-heading">
- <h3 class="cds--type-heading-03"
- i18n>Subsystem details</h3>
- <p class="cds--type-label-02"
- i18n>Enter identifying and network details for this subsystem.</p>
- </div>
+ <div
+ cdsRow
+ class="form-heading"
+ >
+ <h3
+ class="cds--type-heading-03"
+ i18n
+ >
+ Subsystem details
+ </h3>
+ <p
+ class="cds--type-label-02"
+ i18n
+ >
+ Enter identifying and network details for this subsystem.
+ </p>
+ </div>
}
@if (!listenersOnly) {
- <div cdsRow
- class="form-item">
- <cds-text-label
- i18n
- [invalid]="nqnRef.isInvalid"
- helperText="A unique identifier for the subsystem."
- i18n-helperText>
- Subsystem NQN (NVMe Qualified Name)
- <input cdsText
- cdValidate
- #nqnRef="cdValidate"
- type="text"
- placeholder="nqn.2001-07.com.ceph:1722347201377"
- id="nqn"
- name="nqn"
- formControlName="nqn"
- [invalid]="nqnRef.isInvalid">
- </cds-text-label>
- @if (nqnRef.isInvalid) {
- @for (err of formGroup.get('nqn')?.errors | keyvalue; track err.key) {
- <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <cds-text-label
+ i18n
+ [invalid]="nqnRef.isInvalid"
+ helperText="A unique identifier for the subsystem."
+ i18n-helperText
+ >
+ Subsystem NQN (NVMe Qualified Name)
+ <input
+ cdsText
+ cdValidate
+ #nqnRef="cdValidate"
+ type="text"
+ placeholder="nqn.2001-07.com.ceph:1722347201377"
+ id="nqn"
+ name="nqn"
+ formControlName="nqn"
+ [invalid]="nqnRef.isInvalid"
+ />
+ </cds-text-label>
+ @if (nqnRef.isInvalid) {
+ @for (err of formGroup.get('nqn')?.errors | keyvalue; track err.key) {
+ <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ }
}
- }
- </div>
- <div cdsRow
- class="form-item">
- <cds-text-label
- i18n
- helperText="Gateway group routes traffic for this subsystem."
- i18n-helperText
- [disabled]="true">
- Gateway group
- <input cdsText
- type="text"
- disabled
- [value]="group"
- [skeleton]="!group">
- </cds-text-label>
- </div>
+ </div>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <cds-text-label
+ i18n
+ helperText="Gateway group routes traffic for this subsystem."
+ i18n-helperText
+ [disabled]="true"
+ >
+ Gateway group
+ <input
+ cdsText
+ type="text"
+ disabled
+ [value]="group"
+ [skeleton]="!group"
+ />
+ </cds-text-label>
+ </div>
}
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<fieldset class="cds--fieldset">
- <legend class="cds--label"
- i18n>Listeners</legend>
- <p class="cds--form__helper-text" i18n>Determine where and how hosts can connect to the subsystem over the network.</p>
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Listeners
+ </legend>
+ <p
+ class="cds--form__helper-text"
+ i18n
+ >
+ Determine where and how hosts can connect to the subsystem over the network.
+ </p>
<cds-radio-group
formControlName="listenerMode"
- orientation="horizontal">
- <cds-radio
- [value]="LISTENER_MODE.AUTO_FETCH">
+ orientation="horizontal"
+ >
+ <cds-radio [value]="LISTENER_MODE.AUTO_FETCH">
<span i18n>Auto-fetch</span>
</cds-radio>
- <cds-radio
- [value]="LISTENER_MODE.MANUAL">
+ <cds-radio [value]="LISTENER_MODE.MANUAL">
<span i18n>Add manually</span>
</cds-radio>
</cds-radio-group>
</fieldset>
</div>
@if (listenerMode === LISTENER_MODE.AUTO_FETCH) {
- <div cdsRow
- class="form-item">
- <cds-text-label
- i18n
- [invalid]="subnetMaskRef.isInvalid"
- [invalidText]="subnetMaskInvalidText"
- helperText="Listeners from this subnet-masks will be use."
- i18n-helperText>
- Subnet-mask
- <input cdsText
- cdValidate
- #subnetMaskRef="cdValidate"
- type="text"
- placeholder="e.g. 255.0.0.0"
- i18n-placeholder
- id="subnetMask"
- name="subnetMask"
- formControlName="subnetMask"
- [invalid]="subnetMaskRef.isInvalid">
- </cds-text-label>
- <ng-template #subnetMaskInvalidText>
- <span i18n>This field is required.</span>
- </ng-template>
- </div>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <cds-text-label
+ i18n
+ [invalid]="subnetMaskRef.isInvalid"
+ [invalidText]="subnetMaskInvalidText"
+ helperText="Listeners from this subnet-masks will be use."
+ i18n-helperText
+ >
+ Subnet-mask
+ <input
+ cdsText
+ cdValidate
+ #subnetMaskRef="cdValidate"
+ type="text"
+ placeholder="e.g. 255.0.0.0"
+ i18n-placeholder
+ id="subnetMask"
+ name="subnetMask"
+ formControlName="subnetMask"
+ [invalid]="subnetMaskRef.isInvalid"
+ />
+ </cds-text-label>
+ <ng-template #subnetMaskInvalidText>
+ <span i18n>This field is required.</span>
+ </ng-template>
+ </div>
}
@if (listenerMode === LISTENER_MODE.MANUAL) {
- <div cdsRow
- class="form-item">
- <cds-combo-box i18n
- [invalid]="formGroup.get('listeners')?.invalid && (formGroup.get('listeners')?.dirty || formGroup.get('listeners')?.touched)"
- [invalidText]="listenersInvalidText"
- [label]="listenersLabel"
- [helperText]="listenersHelperText"
- [title]="listenersLabel"
- [items]="hosts"
- [type]="'multi'"
- formControlName="listeners"
- name="listeners">
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- @if (formGroup.get('listeners').value?.length) {
- <div>
- @for (listener of formGroup.get('listeners').value; track listener.content; let i = $index) {
- <cds-tag-filter type="blue"
- [title]="listener.content"
- (close)="removeListener(i)">
- {{ listener.content }}
- </cds-tag-filter>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <cds-combo-box
+ i18n
+ [invalid]="
+ formGroup.get('listeners')?.invalid &&
+ (formGroup.get('listeners')?.dirty || formGroup.get('listeners')?.touched)
+ "
+ [invalidText]="listenersInvalidText"
+ [label]="listenersLabel"
+ [helperText]="listenersHelperText"
+ [title]="listenersLabel"
+ [items]="hosts"
+ [type]="'multi'"
+ formControlName="listeners"
+ name="listeners"
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ @if (formGroup.get('listeners').value?.length) {
+ <div>
+ @for (
+ listener of formGroup.get('listeners').value;
+ track listener.content;
+ let i = $index
+ ) {
+ <cds-tag-filter
+ type="blue"
+ [title]="listener.content"
+ (close)="removeListener(i)"
+ >
+ {{ listener.content }}
+ </cds-tag-filter>
+ }
+ </div>
}
- </div>
- }
- <ng-template #listenersLabel>
- <span i18n>Select listeners</span>
- </ng-template>
- <ng-template #listenersHelperText>
- <span i18n>Select listeners for this subsystem.</span>
- </ng-template>
- <ng-template #listenersInvalidText>
- <span i18n>This field is required.</span>
- </ng-template>
- </div>
+ <ng-template #listenersLabel>
+ <span i18n>Select listeners</span>
+ </ng-template>
+ <ng-template #listenersHelperText>
+ <span i18n>Select listeners for this subsystem.</span>
+ </ng-template>
+ <ng-template #listenersInvalidText>
+ <span i18n>This field is required.</span>
+ </ng-template>
+ </div>
}
</div>
</div>
</form>
@if (!listenersOnly) {
-<ng-template #nqnInvalidTemplate>
-@for (err of formGroup.get('nqn').errors | keyvalue; track err.key) {
-<span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
-}
-</ng-template>
+ <ng-template #nqnInvalidTemplate>
+ @for (err of formGroup.get('nqn').errors | keyvalue; track err.key) {
+ <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ }
+ </ng-template>
}
-
-<form [formGroup]="formGroup"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 16}"
- class="cd-nvmeof-subsystem-step-two">
- <div cdsRow
- class="form-item cds-mb-0">
- <h3 class="cds--type-heading-03"
- i18n>Host access (Initiators)</h3>
+<form
+ [formGroup]="formGroup"
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 16 }"
+ class="cd-nvmeof-subsystem-step-two"
+ >
+ <div
+ cdsRow
+ class="form-item cds-mb-0"
+ >
+ <h3
+ class="cds--type-heading-03"
+ i18n
+ >
+ Host access (Initiators)
+ </h3>
<p
class="cds--type-label-02"
- i18n>Select hosts that can initiate connections to this subsystem.</p>
+ i18n
+ >
+ Select hosts that can initiate connections to this subsystem.
+ </p>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-radio-group
formControlName="hostType"
- orientation="vertical">
+ orientation="vertical"
+ >
<cds-radio
[value]="HOST_TYPE.ALL"
[disabled]="!allowAllHosts"
class="cds-mb-2"
- i18n>Allow all hosts</cds-radio>
- <span class="cds--form__helper-text cds-mb-3"
- i18n>Any host can connect to this subsystem without verification.</span>
- @if(formGroup.get('hostType').value === HOST_TYPE.ALL) {
- <cd-alert-panel
- title="Caution"
- type="warning"
- class="cds-mb-3"
i18n
- i18n-title>
- Allowing all hosts grants access to every initiator on the network. Authentication is not supported in this mode, which may expose the subsystem to unauthorized access.
- </cd-alert-panel>
+ >Allow all hosts</cds-radio
+ >
+ <span
+ class="cds--form__helper-text cds-mb-3"
+ i18n
+ >Any host can connect to this subsystem without verification.</span
+ >
+ @if (formGroup.get('hostType').value === HOST_TYPE.ALL) {
+ <cd-alert-panel
+ title="Caution"
+ type="warning"
+ class="cds-mb-3"
+ i18n
+ i18n-title
+ >
+ Allowing all hosts grants access to every initiator on the network. Authentication is
+ not supported in this mode, which may expose the subsystem to unauthorized access.
+ </cd-alert-panel>
}
<cds-radio
[value]="HOST_TYPE.SPECIFIC"
- class="cds-mb-2">
+ class="cds-mb-2"
+ >
<span
class="cds-mr-3"
- i18n>Restrict to specific hosts</span>
+ i18n
+ >Restrict to specific hosts</span
+ >
<cds-tag
type="blue"
size="sm"
class="cd-nvmeof-subsystem-step-two-specific-hosts-tag"
- i18n>
+ i18n
+ >
Recommended for secure environments
</cds-tag>
</cds-radio>
- <span class="cds--form__helper-text cds-mb-3"
- i18n>Add the specific hosts permitted to connect.</span>
+ <span
+ class="cds--form__helper-text cds-mb-3"
+ i18n
+ >Add the specific hosts permitted to connect.</span
+ >
</cds-radio-group>
</div>
- @if(formGroup.get('hostType').value === HOST_TYPE.SPECIFIC) {
- <div cdsRow
- class="form-item">
- <h1
- class="cds--type-heading-compact-01"
- i18n>Add host manually</h1>
- <label class="cds--label"
- for="hostname">
- <span i18n>Host name</span>
- </label>
- <div class="cd-nvmeof-subsystem-step-two-manual-hosts">
- <cds-text-label
- [invalid]="host.isInvalid"
- [invalidText]="hostNameInvalidTemplate"
- class="cd-nvmeof-subsystem-step-two-manual-hosts-input">
- <input
- cdsText
- cdValidate
- id="hostname"
- #host="cdValidate"
- formControlName="hostname"
- [invalid]="host.isInvalid"
- placeholder="Enter host NQN"
- i18n-placeholder/>
- </cds-text-label>
- <button
- cdsButton="tertiary"
- [disabled]="host.isInvalid"
- size="md"
- class="cds-mt-3"
- type="button"
- (click)="addHost()">
- <span i18n>Add</span>
- <cd-icon type="add"></cd-icon>
- </button>
+ @if (formGroup.get('hostType').value === HOST_TYPE.SPECIFIC) {
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <h1
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Add host manually
+ </h1>
+ <label
+ class="cds--label"
+ for="hostname"
+ >
+ <span i18n>Host name</span>
+ </label>
+ <div class="cd-nvmeof-subsystem-step-two-manual-hosts">
+ <cds-text-label
+ [invalid]="host.isInvalid"
+ [invalidText]="hostNameInvalidTemplate"
+ class="cd-nvmeof-subsystem-step-two-manual-hosts-input"
+ >
+ <input
+ cdsText
+ cdValidate
+ id="hostname"
+ #host="cdValidate"
+ formControlName="hostname"
+ [invalid]="host.isInvalid"
+ placeholder="Enter host NQN"
+ i18n-placeholder
+ />
+ </cds-text-label>
+ <button
+ cdsButton="tertiary"
+ [disabled]="host.isInvalid"
+ size="md"
+ class="cds-mt-3"
+ type="button"
+ (click)="addHost()"
+ >
+ <span i18n>Add</span>
+ <cd-icon type="add"></cd-icon>
+ </button>
+ </div>
</div>
- </div>
- <div cdsRow
- class="form-item">
- <h1
- class="cds--type-heading-compact-01"
- i18n>Upload CSV file</h1>
- <p
- class="cds--type-body-01 cds-mb-3 cd-nvmeof-subsystem-step-two-added-hosts-text"
- i18n>Upload a CSV file containing a list of host names.</p>
- <div class="cd-nvmeof-subsystem-step-two-csv-container">
- <cds-file-uploader
- [drop]="true"
- [dropText]="csvDropText"
- [accept]="['csv']"
- [multiple]="false"
- size="md"
- class="cd-nvmeof-subsystem-step-two-csv-input"
- (filesChange)="onCsvUpload($event)"
- (removeFile)="onCsvUploadRemove()"></cds-file-uploader>
- @if(csvUploadError) {
- <cd-alert-panel
- type="danger"
- [showTitle]="false"
- size="slim"
- class="cds-mt-3 cd-nvmeof-subsystem-step-two-csv-error-panel">{{ csvUploadError }}</cd-alert-panel>
- }
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <h1
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Upload CSV file
+ </h1>
+ <p
+ class="cds--type-body-01 cds-mb-3 cd-nvmeof-subsystem-step-two-added-hosts-text"
+ i18n
+ >
+ Upload a CSV file containing a list of host names.
+ </p>
+ <div class="cd-nvmeof-subsystem-step-two-csv-container">
+ <cds-file-uploader
+ [drop]="true"
+ [dropText]="csvDropText"
+ [accept]="['csv']"
+ [multiple]="false"
+ size="md"
+ class="cd-nvmeof-subsystem-step-two-csv-input"
+ (filesChange)="onCsvUpload($event)"
+ (removeFile)="onCsvUploadRemove()"
+ ></cds-file-uploader>
+ @if (csvUploadError) {
+ <cd-alert-panel
+ type="danger"
+ [showTitle]="false"
+ size="slim"
+ class="cds-mt-3 cd-nvmeof-subsystem-step-two-csv-error-panel"
+ >{{ csvUploadError }}</cd-alert-panel
+ >
+ }
+ </div>
</div>
- </div>
}
</div>
</div>
i18n
cdsButton="ghost"
type="button"
- (click)="removeAll($event)">
+ (click)="removeAll($event)"
+ >
Remove all
</button>
</ng-template>
<ng-template
#removeHostTemplate
- let-host>
+ let-host
+>
<cds-icon-button
type="button"
kind="ghost"
description="Remove host"
i18n-description
- (click)="removeHost(host)">
- <cd-icon type="destroy"></cd-icon>
-</cds-icon-button>
+ (click)="removeHost(host)"
+ >
+ <cd-icon type="destroy"></cd-icon>
+ </cds-icon-button>
</ng-template>
<ng-template #rightInfluencer>
- @if(addedHostsLength === 0) {
- <h1
- class="cds--type-heading-compact-01"
- i18n>Added hosts ({{addedHostsLength}})</h1>
- <p
- i18n
- class="cds--type-body-01 cd-nvmeof-subsystem-step-two-added-hosts-text">No hosts added yet. Add hosts manually or upload a CSV file.</p>
+ @if (addedHostsLength === 0) {
+ <h1
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Added hosts ({{ addedHostsLength }})
+ </h1>
+ <p
+ i18n
+ class="cds--type-body-01 cd-nvmeof-subsystem-step-two-added-hosts-text"
+ >
+ No hosts added yet. Add hosts manually or upload a CSV file.
+ </p>
} @else {
- <cds-contained-list
- label="Added hosts ({{addedHostsLength}})"
- [action]="removeAllTemplate"
- class="cd-nvmeof-subsystem-step-two-influencer">
- @for (host of formGroup.get('addedHosts')?.value ; track host) {
- <cds-contained-list-item
- [action]="removeHostTemplate"
- [actionData]="host"
- class="cd-nvmeof-subsystem-step-two-host-list-item-container">
- <span
- class="cds--text-truncate--end"
- [title]="host">{{host}}</span>
- </cds-contained-list-item>
- }
- </cds-contained-list>
+ <cds-contained-list
+ label="Added hosts ({{ addedHostsLength }})"
+ [action]="removeAllTemplate"
+ class="cd-nvmeof-subsystem-step-two-influencer"
+ >
+ @for (host of formGroup.get('addedHosts')?.value; track host) {
+ <cds-contained-list-item
+ [action]="removeHostTemplate"
+ [actionData]="host"
+ class="cd-nvmeof-subsystem-step-two-host-list-item-container"
+ >
+ <span
+ class="cds--text-truncate--end"
+ [title]="host"
+ >{{ host }}</span
+ >
+ </cds-contained-list-item>
+ }
+ </cds-contained-list>
}
</ng-template>
<ng-template #hostNameInvalidTemplate>
-@for (err of formGroup.get('hostname').errors | keyvalue; track err.key) {
-<span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
-}
+ @for (err of formGroup.get('hostname').errors | keyvalue; track err.key) {
+ <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ }
</ng-template>
-
-<form [formGroup]="formGroup"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 10, md: 10, lg: 12}">
- <div cdsRow
- class="form-heading">
- <h3 class="cds--type-heading-03"
- i18n>Authentication</h3>
+<form
+ [formGroup]="formGroup"
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 10, md: 10, lg: 12 }"
+ >
+ <div
+ cdsRow
+ class="form-heading"
+ >
+ <h3
+ class="cds--type-heading-03"
+ i18n
+ >
+ Authentication
+ </h3>
<p
class="cds--type-label-02"
- i18n>Configure authentication to verify the identity of connecting hosts and protect the subsystem from unauthorized access.</p>
+ i18n
+ >
+ Configure authentication to verify the identity of connecting hosts and protect the
+ subsystem from unauthorized access.
+ </p>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-radio-group
formControlName="authType"
legend="Authentication type"
- i18n-legend>
- <cds-radio
- [value]="AUTHENTICATION.Unidirectional">
+ i18n-legend
+ >
+ <cds-radio [value]="AUTHENTICATION.Unidirectional">
<div class="auth-radio">
<span>Unidirectional</span>
- <span class="cds--form__helper-text"
- i18n>Each host can provide an optional DH-HMAC-CHAP key. The subsystem does not require its own key.</span>
+ <span
+ class="cds--form__helper-text"
+ i18n
+ >Each host can provide an optional DH-HMAC-CHAP key. The subsystem does not require
+ its own key.</span
+ >
</div>
</cds-radio>
- <cds-radio
- [value]="AUTHENTICATION.Bidirectional">
+ <cds-radio [value]="AUTHENTICATION.Bidirectional">
<div class="auth-radio">
<div cdsStack="horizontal">
<span i18n>Bidirectional</span>
<cds-tag
type="blue"
size="sm"
- i18n>
+ i18n
+ >
Requires keys on both sides
</cds-tag>
</div>
- <span class="cds--form__helper-text"
- i18n>Both subsystem and hosts must provide DH-HMAC-CHAP keys. All connections will be verified in both directions.</span>
+ <span
+ class="cds--form__helper-text"
+ i18n
+ >Both subsystem and hosts must provide DH-HMAC-CHAP keys. All connections will be
+ verified in both directions.</span
+ >
</div>
</cds-radio>
</cds-radio-group>
</div>
- @if(formGroup.get('authType').value === AUTHENTICATION.Bidirectional) {
- <div cdsRow
- class="form-item step-3-form-item">
- <div class="step-3-heading">
- <h1
- class="cds--type-heading-compact-01"
- i18n>Subsystem authentication detail</h1>
- <p class="cds--type-label-01 text-helper"
- i18n>Mandatory field.</p>
+ @if (formGroup.get('authType').value === AUTHENTICATION.Bidirectional) {
+ <div
+ cdsRow
+ class="form-item step-3-form-item"
+ >
+ <div class="step-3-heading">
+ <h1
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Subsystem authentication detail
+ </h1>
+ <p
+ class="cds--type-label-01 text-helper"
+ i18n
+ >
+ Mandatory field.
+ </p>
+ </div>
+ <cds-text-label
+ i18n
+ helperText="A secret key for the subsystem to authenticate itself to hosts."
+ i18n-helperText
+ [invalid]="subDK.isInvalid"
+ [invalidText]="
+ formGroup.get('subsystemDchapKey')?.errors?.invalidBase64
+ ? INVALID_TEXTS['invalidBase64']
+ : INVALID_TEXTS['required']
+ "
+ >
+ Subsystem DH-HMAC-CHAP key
+ <input
+ cdsPassword
+ cdValidate
+ #subDK="cdValidate"
+ [invalid]="subDK.isInvalid"
+ formControlName="subsystemDchapKey"
+ type="password"
+ class="step-3-form-item"
+ placeholder="Enter subsystem DH-HMAC-CHAP key"
+ i18n-placeholder
+ autocomplete
+ />
+ </cds-text-label>
</div>
- <cds-text-label
- i18n
- helperText="A secret key for the subsystem to authenticate itself to hosts."
- i18n-helperText
- [invalid]="subDK.isInvalid"
- [invalidText]="
- formGroup.get('subsystemDchapKey')?.errors?.invalidBase64
- ? INVALID_TEXTS['invalidBase64']
- : INVALID_TEXTS['required']
- ">
- Subsystem DH-HMAC-CHAP key
- <input cdsPassword
- cdValidate
- #subDK="cdValidate"
- [invalid]="subDK.isInvalid"
- formControlName="subsystemDchapKey"
- type="password"
- class="step-3-form-item"
- placeholder="Enter subsystem DH-HMAC-CHAP key"
- i18n-placeholder
- autocomplete>
- </cds-text-label>
- </div>
}
- <div cdsRow
- class="form-item step-3-form-item"
- formArrayName="hostDchapKeyList">
+ <div
+ cdsRow
+ class="form-item step-3-form-item"
+ formArrayName="hostDchapKeyList"
+ >
<div class="step-3-heading">
<h1
class="cds--type-heading-compact-01"
- i18n>Host authentication details</h1>
- <p class="cds--type-label-01 text-helper"
- i18n>{{formGroup.get('authType').value === AUTHENTICATION.Bidirectional ? 'All fields are required.' : 'Optional fields.'}}</p>
+ i18n
+ >
+ Host authentication details
+ </h1>
+ <p
+ class="cds--type-label-01 text-helper"
+ i18n
+ >
+ {{
+ formGroup.get('authType').value === AUTHENTICATION.Bidirectional
+ ? 'All fields are required.'
+ : 'Optional fields.'
+ }}
+ </p>
</div>
@if (hostDchapKeyList.controls.length) {
- @for (hostDchapKeyItem of hostDchapKeyList.controls; track $index; let i = $index) {
- <div [formGroupName]="i">
- <cds-text-label
- class="cds-mb-3"
- [invalid]="hostKey.isInvalid"
- [invalidText]="
- hostDhchapKeyCtrl(i)?.errors?.invalidBase64
- ? INVALID_TEXTS['invalidBase64']
- : INVALID_TEXTS['required']
- ">
- <span
- class="cds-mb-3"
- i18n>DHCHAP Key | {{hostDchapKeyItem.get('host_nqn')?.value }}</span>
- <input cdsPassword
- cdValidate
- #hostKey="cdValidate"
- formControlName="dhchap_key"
- type="password"
- placeholder="Enter DHCHAP key"
- class="step-3-form-item"
- i18n-placeholder
- autocomplete
- [invalid]="hostKey.isInvalid">
- </cds-text-label>
- </div>
- }
+ @for (hostDchapKeyItem of hostDchapKeyList.controls; track $index; let i = $index) {
+ <div [formGroupName]="i">
+ <cds-text-label
+ class="cds-mb-3"
+ [invalid]="hostKey.isInvalid"
+ [invalidText]="
+ hostDhchapKeyCtrl(i)?.errors?.invalidBase64
+ ? INVALID_TEXTS['invalidBase64']
+ : INVALID_TEXTS['required']
+ "
+ >
+ <span
+ class="cds-mb-3"
+ i18n
+ >DHCHAP Key | {{ hostDchapKeyItem.get('host_nqn')?.value }}</span
+ >
+ <input
+ cdsPassword
+ cdValidate
+ #hostKey="cdValidate"
+ formControlName="dhchap_key"
+ type="password"
+ placeholder="Enter DHCHAP key"
+ class="step-3-form-item"
+ i18n-placeholder
+ autocomplete
+ [invalid]="hostKey.isInvalid"
+ />
+ </cds-text-label>
+ </div>
+ }
} @else {
- <p
- class="cds--type-label-01 text-helper"
- i18ns>No hosts selected.</p>
+ <p
+ class="cds--type-label-01 text-helper"
+ i18ns
+ >
+ No hosts selected.
+ </p>
}
</div>
</div>
-<div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}">
- <h3 class="cds--type-heading-03 cds-mb-5"
- i18n>Review summary</h3>
+<div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ >
+ <h3
+ class="cds--type-heading-03 cds-mb-5"
+ i18n
+ >
+ Review summary
+ </h3>
</div>
<!-- Subsystem details -->
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}"
- class="cds-mt-5">
- <h4 class="cds--type-heading-compact-01"
- i18n>Subsystem details</h4>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-5"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Subsystem details
+ </h4>
</div>
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Subsystem NQN</p>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Subsystem NQN
+ </p>
<p class="cds--type-label-02 cds-mt-2">{{ nqn }}</p>
</div>
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Gateway group</p>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Gateway group
+ </p>
<p class="cds--type-label-02 cds-mt-2">{{ group }}</p>
</div>
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Listeners</p>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Listeners
+ </p>
@if (listenerCount > 0) {
- <p class="cds--type-label-02 cds-mt-2"
- i18n>{{ listenerCount }} listener(s) added</p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ listenerCount }} listener(s) added
+ </p>
} @else {
- <p class="cds--type-label-02 cds-mt-2"
- i18n>None selected</p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ None selected
+ </p>
}
</div>
<!-- Host access control (Initiators) -->
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}"
- class="cds-mt-7">
- <h4 class="cds--type-heading-compact-01"
- i18n>Host access control (Initiators)</h4>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-7"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Host access control (Initiators)
+ </h4>
</div>
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Host access</p>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Host access
+ </p>
<p class="cds--type-label-02 cds-mt-2">{{ hostAccessLabel }}</p>
</div>
@if (hostType === HOST_TYPE.SPECIFIC) {
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Specific hosts</p>
- <p class="cds--type-label-02 cds-mt-2"
- i18n>{{ hostCount }} hosts added.</p>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Specific hosts
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ hostCount }} hosts added.
+ </p>
+ </div>
}
<!-- Authentication details -->
@if (hostType === HOST_TYPE.SPECIFIC) {
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}"
- class="cds-mt-7">
- <h4 class="cds--type-heading-compact-01"
- i18n>Authentication details</h4>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-7"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Authentication details
+ </h4>
+ </div>
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Authentication type</p>
- <p class="cds--type-label-02 cds-mt-2">{{ authTypeLabel }}</p>
- </div>
- @if (authType === AUTHENTICATION.Bidirectional) {
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 4, lg: 6}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Subsystem DH-HMAC-CHAP key</p>
- @if (hasSubsystemKey) {
- <p class="cds--type-label-02 cds-mt-2">••••••••••••</p>
- } @else {
- <p class="cds--type-label-02 cds-mt-2"
- i18n>Not set</p>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Authentication type
+ </p>
+ <p class="cds--type-label-02 cds-mt-2">{{ authTypeLabel }}</p>
+ </div>
+ @if (authType === AUTHENTICATION.Bidirectional) {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Subsystem DH-HMAC-CHAP key
+ </p>
+ @if (hasSubsystemKey) {
+ <p class="cds--type-label-02 cds-mt-2">••••••••••••</p>
+ } @else {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ Not set
+ </p>
+ }
+ </div>
}
- </div>
- }
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 12}"
- class="cds-mt-5">
- <p class="cds--type-label-01"
- i18n>Host key</p>
- @if (hostDchapKeyCount > 0) {
- <p class="cds--type-label-02 cds-mt-2"
- i18n>{{ hostDchapKeyCount }} keys added</p>
- } @else {
- <p class="cds--type-label-02 cds-mt-2"
- i18n>No keys added</p>
- }
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Host key
+ </p>
+ @if (hostDchapKeyCount > 0) {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ hostDchapKeyCount }} keys added
+ </p>
+ } @else {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ No keys added
+ </p>
+ }
+ </div>
}
</div>
<cd-tearsheet
- [steps]="steps"
- [title]="title"
- [description]="description"
- [isSubmitLoading]="isSubmitLoading"
- (submitRequested)="onSubmit($event)"
- (stepChanged)="populateReviewData()">
+ [steps]="steps"
+ [title]="title"
+ [description]="description"
+ [isSubmitLoading]="isSubmitLoading"
+ (submitRequested)="onSubmit($event)"
+ (stepChanged)="populateReviewData()"
+>
<cd-tearsheet-step>
<cd-nvmeof-subsystem-step-one
- #tearsheetStep
- [group]="group"></cd-nvmeof-subsystem-step-one>
+ #tearsheetStep
+ [group]="group"
+ ></cd-nvmeof-subsystem-step-one>
</cd-tearsheet-step>
<cd-tearsheet-step>
<cd-nvmeof-subsystem-step-two
#tearsheetStep
- [group]="group"></cd-nvmeof-subsystem-step-two>
- </cd-tearsheet-step>
- @if(showAuthStep) {
- <cd-tearsheet-step>
- <cd-nvmeof-subsystem-step-three
- #tearsheetStep
- [stepTwoValue]="stepTwoValue"
- [group]="group"></cd-nvmeof-subsystem-step-three>
+ [group]="group"
+ ></cd-nvmeof-subsystem-step-two>
</cd-tearsheet-step>
+ @if (showAuthStep) {
+ <cd-tearsheet-step>
+ <cd-nvmeof-subsystem-step-three
+ #tearsheetStep
+ [stepTwoValue]="stepTwoValue"
+ [group]="group"
+ ></cd-nvmeof-subsystem-step-three>
+ </cd-tearsheet-step>
}
<cd-tearsheet-step>
<cd-nvmeof-subsystem-step-four
- #tearsheetStep
- [group]="group"
- [nqn]="reviewNqn"
- [listeners]="reviewListeners"
- [hostType]="reviewHostType"
- [addedHosts]="reviewAddedHosts"
- [authType]="reviewAuthType"
- [subsystemDchapKey]="reviewSubsystemDchapKey"
- [hostDchapKeyCount]="reviewHostDchapKeyCount"></cd-nvmeof-subsystem-step-four>
+ #tearsheetStep
+ [group]="group"
+ [nqn]="reviewNqn"
+ [listeners]="reviewListeners"
+ [hostType]="reviewHostType"
+ [addedHosts]="reviewAddedHosts"
+ [authType]="reviewAuthType"
+ [subsystemDchapKey]="reviewSubsystemDchapKey"
+ [hostDchapKeyCount]="reviewHostDchapKeyCount"
+ ></cd-nvmeof-subsystem-step-four>
</cd-tearsheet-step>
</cd-tearsheet>
-
<div class="nvmeof-content-layout">
<div class="nvmeof-content-main">
-<ng-container *ngIf="subsystems$ | async as subsystems">
- <cd-table #table
- [data]="subsystems"
- [columns]="subsystemsColumns"
- [compactSearchField]="true"
- columnMode="flex"
- selectionType="single"
- (updateSelection)="updateSelection($event)"
- (fetchData)="fetchData()"
- emptyStateTitle="No subsystems created"
- i18n-emptyStateTitle
- emptyStateMessage="Subsystems group NVMe namespaces and manage host access. Create a subsystem to start mapping NVMe volumes to hosts."
- i18n-emptyStateMessage>
+ <ng-container *ngIf="subsystems$ | async as subsystems">
+ <cd-table
+ #table
+ [data]="subsystems"
+ [columns]="subsystemsColumns"
+ [compactSearchField]="true"
+ columnMode="flex"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ (fetchData)="fetchData()"
+ emptyStateTitle="No subsystems created"
+ i18n-emptyStateTitle
+ emptyStateMessage="Subsystems group NVMe namespaces and manage host access. Create a subsystem to start mapping NVMe volumes to hosts."
+ i18n-emptyStateMessage
+ >
+ <div class="table-filter">
+ <cd-nvmeof-gateway-group-filter (groupChange)="groupHandler.onGroupChange($event)">
+ </cd-nvmeof-gateway-group-filter>
+ </div>
- <div class="table-filter">
- <cd-nvmeof-gateway-group-filter
- (groupChange)="groupHandler.onGroupChange($event)">
- </cd-nvmeof-gateway-group-filter>
- </div>
+ <div class="table-actions">
+ <cd-table-actions
+ [permission]="permissions.nvmeof"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ </div>
- <div class="table-actions">
- <cd-table-actions [permission]="permissions.nvmeof"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
-
- <cd-nvmeof-subsystems-details *cdTableDetail
- [selection]="expandedRow"
- [permissions]="permissions"
- [group]="expandedRow?.gw_group">
- </cd-nvmeof-subsystems-details>
- </cd-table>
-</ng-container>
+ <cd-nvmeof-subsystems-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ [permissions]="permissions"
+ [group]="expandedRow?.gw_group"
+ >
+ </cd-nvmeof-subsystems-details>
+ </cd-table>
+ </ng-container>
</div>
</div>
-<ng-template #customTableItemTemplate
- let-value="data.value"
- let-row="data.row">
- <a cdsLink
- [routerLink]="['/block/nvmeof/subsystems', value]"
- [queryParams]="{ group: row.gw_group }"
- (click)="$event.stopPropagation()">
+<ng-template
+ #customTableItemTemplate
+ let-value="data.value"
+ let-row="data.row"
+>
+ <a
+ cdsLink
+ [routerLink]="['/block/nvmeof/subsystems', value]"
+ [queryParams]="{ group: row.gw_group }"
+ (click)="$event.stopPropagation()"
+ >
{{ value }}
</a>
</ng-template>
-<ng-template #authenticationTpl
- let-row="data.row">
- <div [cdsStack]="'horizontal'"
- gap="4">
- @if (row.auth === authType.NO_AUTH) {
- <cd-icon type="warning"></cd-icon>
- } @else {
- <cd-icon type="success"></cd-icon>
- }
- <span class="cds-ml-3">{{ row.auth }}</span>
+<ng-template
+ #authenticationTpl
+ let-row="data.row"
+>
+ <div
+ [cdsStack]="'horizontal'"
+ gap="4"
+ >
+ @if (row.auth === authType.NO_AUTH) {
+ <cd-icon type="warning"></cd-icon>
+ } @else {
+ <cd-icon type="success"></cd-icon>
+ }
+ <span class="cds-ml-3">{{ row.auth }}</span>
</div>
</ng-template>
-<ng-template #encryptionTpl
- let-row="data.row">
- <div [cdsStack]="'horizontal'"
- gap="4">
- @if (row.enable_ha) {
- <cd-icon type="success"></cd-icon>
- <span class="cds-ml-3"
- i18n>Enabled</span>
- } @else {
- <cd-icon type="error"></cd-icon>
- <span class="cds-ml-3"
- i18n>Disabled</span>
- }
+<ng-template
+ #encryptionTpl
+ let-row="data.row"
+>
+ <div
+ [cdsStack]="'horizontal'"
+ gap="4"
+ >
+ @if (row.enable_ha) {
+ <cd-icon type="success"></cd-icon>
+ <span
+ class="cds-ml-3"
+ i18n
+ >Enabled</span
+ >
+ } @else {
+ <cd-icon type="error"></cd-icon>
+ <span
+ class="cds-ml-3"
+ i18n
+ >Disabled</span
+ >
+ }
</div>
</ng-template>
<fieldset>
<legend class="cds-mb-5">
<h1 class="cds--type-heading-04">NVMe over Fabrics (TCP)</h1>
- <p class="cds--type-body-01" i18n>Monitor and manage NVMe-over-TCP resources for high-performance block storage.</p>
+ <p
+ class="cds--type-body-01"
+ i18n
+ >
+ Monitor and manage NVMe-over-TCP resources for high-performance block storage.
+ </p>
</legend>
</fieldset>
@if (showSetupCards) {
- <cd-nvmeof-setup-cards
- [hasGatewayGroups]="hasGatewayGroups"
- [hasSubsystems]="hasSubsystems"
- [hasNamespaces]="hasNamespaces"
- [isAllConfigured]="isAllConfigured">
- </cd-nvmeof-setup-cards>
+ <cd-nvmeof-setup-cards
+ [hasGatewayGroups]="hasGatewayGroups"
+ [hasSubsystems]="hasSubsystems"
+ [hasNamespaces]="hasNamespaces"
+ [isAllConfigured]="isAllConfigured"
+ >
+ </cd-nvmeof-setup-cards>
}
<section class="cds-mt-5">
- <cds-tabs type="contained"
- followFocus="true"
- isNavigation="true"
- [cacheActive]="false">
- <cds-tab
- heading="Gateways"
- i18n-heading
- [active]="activeTab === Tabs.gateways"
- (selected)="onSelected(Tabs.gateways)">
- </cds-tab>
- <cds-tab
- heading="Subsystems"
- i18n-heading
- [active]="activeTab === Tabs.subsystems"
- (selected)="onSelected(Tabs.subsystems)">
- </cds-tab>
- <cds-tab
- heading="Namespaces"
- i18n-heading
- [active]="activeTab === Tabs.namespaces"
- (selected)="onSelected(Tabs.namespaces)">
- </cds-tab>
- </cds-tabs>
+ <cds-tabs
+ type="contained"
+ followFocus="true"
+ isNavigation="true"
+ [cacheActive]="false"
+ >
+ <cds-tab
+ heading="Gateways"
+ i18n-heading
+ [active]="activeTab === Tabs.gateways"
+ (selected)="onSelected(Tabs.gateways)"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Subsystems"
+ i18n-heading
+ [active]="activeTab === Tabs.subsystems"
+ (selected)="onSelected(Tabs.subsystems)"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Namespaces"
+ i18n-heading
+ [active]="activeTab === Tabs.namespaces"
+ (selected)="onSelected(Tabs.namespaces)"
+ >
+ </cds-tab>
+ </cds-tabs>
</section>
}
-<fieldset #cfgFormGroup
- [formGroup]="form.get('configuration')">
+<fieldset
+ #cfgFormGroup
+ [formGroup]="form.get('configuration')"
+>
<legend i18n>RBD Configuration</legend>
<div *ngFor="let section of rbdConfigurationService.sections">
<h5 class="cd-header">
- <legend (click)="toggleSectionVisibility(section.class)"
- class="collapsible"
- tabindex="0"
- (keydown.enter)="toggleSectionVisibility(section.class)">
+ <legend
+ (click)="toggleSectionVisibility(section.class)"
+ class="collapsible"
+ tabindex="0"
+ (keydown.enter)="toggleSectionVisibility(section.class)"
+ >
{{ section.heading }}
- <svg [cdsIcon]="!sectionVisibility[section.class] ? icons.addCircle : icons.minusCircle"
- [size]="icons.size20"
- ></svg>
+ <svg
+ [cdsIcon]="!sectionVisibility[section.class] ? icons.addCircle : icons.minusCircle"
+ [size]="icons.size20"
+ ></svg>
</legend>
</h5>
- <div class="{{ section.class }}"
- [hidden]="!sectionVisibility[section.class]">
- <div class="form-item"
- *ngFor="let option of section.options">
- <cds-text-label [helperText]="option.description"
- [invalid]="form.get('configuration').controls[option.name].invalid && (form.get('configuration').controls[option.name].dirty)"
- [invalidText]="formError">
+ <div
+ class="{{ section.class }}"
+ [hidden]="!sectionVisibility[section.class]"
+ >
+ <div
+ class="form-item"
+ *ngFor="let option of section.options"
+ >
+ <cds-text-label
+ [helperText]="option.description"
+ [invalid]="
+ form.get('configuration').controls[option.name].invalid &&
+ form.get('configuration').controls[option.name].dirty
+ "
+ [invalidText]="formError"
+ >
{{ option.displayName }}
<div class="cds-input-group">
<ng-container [ngSwitch]="option.type">
<ng-container *ngSwitchCase="configurationType.milliseconds">
- <input [id]="option.name"
- [name]="option.name"
- [formControlName]="option.name"
- type="text"
- cdsText
- [ngDataReady]="ngDataReady"
- [invalid]="form.get('configuration').controls[option.name].invalid && (form.get('configuration').controls[option.name].dirty)"
- cdMilliseconds>
+ <input
+ [id]="option.name"
+ [name]="option.name"
+ [formControlName]="option.name"
+ type="text"
+ cdsText
+ [ngDataReady]="ngDataReady"
+ [invalid]="
+ form.get('configuration').controls[option.name].invalid &&
+ form.get('configuration').controls[option.name].dirty
+ "
+ cdMilliseconds
+ />
</ng-container>
<ng-container *ngSwitchCase="configurationType.bps">
- <input [id]="option.name"
- [name]="option.name"
- [formControlName]="option.name"
- type="text"
- cdsText
- defaultUnit="b"
- [ngDataReady]="ngDataReady"
- [invalid]="form.get('configuration').controls[option.name].invalid && (form.get('configuration').controls[option.name].dirty)"
- cdDimlessBinaryPerSecond>
+ <input
+ [id]="option.name"
+ [name]="option.name"
+ [formControlName]="option.name"
+ type="text"
+ cdsText
+ defaultUnit="b"
+ [ngDataReady]="ngDataReady"
+ [invalid]="
+ form.get('configuration').controls[option.name].invalid &&
+ form.get('configuration').controls[option.name].dirty
+ "
+ cdDimlessBinaryPerSecond
+ />
</ng-container>
<ng-container *ngSwitchCase="configurationType.iops">
- <input [id]="option.name"
- [name]="option.name"
- [formControlName]="option.name"
- type="text"
- cdsText
- [ngDataReady]="ngDataReady"
- [invalid]="form.get('configuration').controls[option.name].invalid && (form.get('configuration').controls[option.name].dirty)"
- cdIops>
+ <input
+ [id]="option.name"
+ [name]="option.name"
+ [formControlName]="option.name"
+ type="text"
+ cdsText
+ [ngDataReady]="ngDataReady"
+ [invalid]="
+ form.get('configuration').controls[option.name].invalid &&
+ form.get('configuration').controls[option.name].dirty
+ "
+ cdIops
+ />
</ng-container>
</ng-container>
- <cds-icon-button kind="ghost"
- size="md"
- (click)="reset(option.name)"
- data-toggle="button">
- <svg cdsIcon="close"
- size="32"
- class="cds--btn__icon"
- *ngIf="!form.get('configuration').get(option.name).disabled; else resetIcon"></svg>
+ <cds-icon-button
+ kind="ghost"
+ size="md"
+ (click)="reset(option.name)"
+ data-toggle="button"
+ >
+ <svg
+ cdsIcon="close"
+ size="32"
+ class="cds--btn__icon"
+ *ngIf="!form.get('configuration').get(option.name).disabled; else resetIcon"
+ ></svg>
<ng-template #resetIcon>
- <svg cdsIcon="reset"
- size="32"
- *ngIf="form.get('configuration').get(option.name).disabled"></svg>
+ <svg
+ cdsIcon="reset"
+ size="32"
+ *ngIf="form.get('configuration').get(option.name).disabled"
+ ></svg>
</ng-template>
</cds-icon-button>
<ng-template #formError>
- <span class="invalid-feedback"
- *ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')"
- i18n>The minimum value is 0.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')"
+ i18n
+ >The minimum value is 0.</span
+ >
</ng-template>
</div>
</cds-text-label>
-<cd-table #poolConfTable
- [data]="data"
- [columns]="poolConfigurationColumns"
- identifier="name">
+<cd-table
+ #poolConfTable
+ [data]="data"
+ [columns]="poolConfigurationColumns"
+ identifier="name"
+>
</cd-table>
-<ng-template #configurationSourceTpl
- let-value="data.value">
-
+<ng-template
+ #configurationSourceTpl
+ let-value="data.value"
+>
<div [ngSwitch]="value">
- <span *ngSwitchCase="'global'"
- i18n>Global</span>
- <strong *ngSwitchCase="'image'"
- i18n>Image</strong>
- <strong *ngSwitchCase="'pool'"
- i18n>Pool</strong>
+ <span
+ *ngSwitchCase="'global'"
+ i18n
+ >Global</span
+ >
+ <strong
+ *ngSwitchCase="'image'"
+ i18n
+ >Image</strong
+ >
+ <strong
+ *ngSwitchCase="'pool'"
+ i18n
+ >Pool</strong
+ >
</div>
</ng-template>
-<ng-template #configurationValueTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #configurationValueTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<div [ngSwitch]="row.type">
<span *ngSwitchCase="typeField.bps">{{ value | dimlessBinaryPerSecond }}</span>
<span *ngSwitchCase="typeField.milliseconds">{{ value | milliseconds }}</span>
<ng-template #usageNotAvailableTooltipTpl>
- <ng-container i18n>Only available for RBD images with <strong>fast-diff</strong> enabled</ng-container>
+ <ng-container i18n
+ >Only available for RBD images with <strong>fast-diff</strong> enabled</ng-container
+ >
</ng-template>
<ng-container *ngIf="selection && selection.source !== 'REMOVING'">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="rbd-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="rbd-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="rbd-details-table">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rbd-details-table"
+ >
<tbody>
<tr cdstablerow>
- <td i18n
- class="bold w-25"
- cdstabledata>Name</td>
+ <td
+ i18n
+ class="bold w-25"
+ cdstabledata
+ >
+ Name
+ </td>
<td class="w-75">{{ selection.name }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold"
- cdstabledata>Pool</td>
+ <td
+ i18n
+ class="bold"
+ cdstabledata
+ >
+ Pool
+ </td>
<td>{{ selection.pool_name }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Data Pool</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Data Pool
+ </td>
<td>{{ selection.data_pool | empty }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Created</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Created
+ </td>
<td>{{ selection.timestamp | cdDate }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Size</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Size
+ </td>
<td>{{ selection.size | dimlessBinary }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Objects</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Objects
+ </td>
<td>{{ selection.num_objs | dimless }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Object size</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Object size
+ </td>
<td>{{ selection.obj_size | dimlessBinary }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Features</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Features
+ </td>
<td>
<span *ngFor="let feature of selection.features_name">
<cds-tag class="tag-dark me-2">{{ feature }}</cds-tag>
</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Provisioned</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Provisioned
+ </td>
<td>
<span *ngIf="selection.features_name?.indexOf('fast-diff') === -1">
- <span class="form-text text-muted"
- [ngbTooltip]="usageNotAvailableTooltipTpl"
- placement="top"
- i18n>N/A</span>
+ <span
+ class="form-text text-muted"
+ [ngbTooltip]="usageNotAvailableTooltipTpl"
+ placement="top"
+ i18n
+ >N/A</span
+ >
</span>
<span *ngIf="selection.features_name?.indexOf('fast-diff') !== -1">
{{ selection.disk_usage | dimlessBinary }}
</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Total provisioned</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Total provisioned
+ </td>
<td>
<span *ngIf="selection.features_name?.indexOf('fast-diff') === -1">
- <span class="form-text text-muted"
- [ngbTooltip]="usageNotAvailableTooltipTpl"
- placement="top"
- i18n>N/A</span>
+ <span
+ class="form-text text-muted"
+ [ngbTooltip]="usageNotAvailableTooltipTpl"
+ placement="top"
+ i18n
+ >N/A</span
+ >
</span>
<span *ngIf="selection.features_name?.indexOf('fast-diff') !== -1">
{{ selection.total_disk_usage | dimlessBinary }}
</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Striping unit</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Striping unit
+ </td>
<td>{{ selection.stripe_unit | dimlessBinary }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Striping count</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Striping count
+ </td>
<td>{{ selection.stripe_count }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Parent</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Parent
+ </td>
<td>
- <span *ngIf="selection.parent">{{ selection.parent.pool_name }}<span
- *ngIf="selection.parent.pool_namespace">/{{ selection.parent.pool_namespace }}</span>/{{ selection.parent.image_name }}@{{ selection.parent.snap_name }}</span>
+ <span *ngIf="selection.parent"
+ >{{ selection.parent.pool_name
+ }}<span *ngIf="selection.parent.pool_namespace"
+ >/{{ selection.parent.pool_namespace }}</span
+ >/{{ selection.parent.image_name }}@{{ selection.parent.snap_name }}</span
+ >
<span *ngIf="!selection.parent">-</span>
</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Block name prefix</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Block name prefix
+ </td>
<td>{{ selection.block_name_prefix }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Order</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Order
+ </td>
<td>{{ selection.order }}</td>
</tr>
<tr cdstablerow>
- <td i18n
- class="bold">Format Version</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Format Version
+ </td>
<td>{{ selection.image_format }}</td>
</tr>
</tbody>
</ng-template>
</ng-container>
<ng-container ngbNavItem="snapshots">
- <a ngbNavLink
- i18n>Snapshots</a>
+ <a
+ ngbNavLink
+ i18n
+ >Snapshots</a
+ >
<ng-template ngbNavContent>
- <cd-rbd-snapshot-list [snapshots]="selection.snapshots"
- [featuresName]="selection.features_name"
- [poolName]="selection.pool_name"
- [primary]="selection.primary"
- [namespace]="selection.namespace"
- [mirroring]="selection.mirror_mode"
- [rbdName]="selection.name"></cd-rbd-snapshot-list>
+ <cd-rbd-snapshot-list
+ [snapshots]="selection.snapshots"
+ [featuresName]="selection.features_name"
+ [poolName]="selection.pool_name"
+ [primary]="selection.primary"
+ [namespace]="selection.namespace"
+ [mirroring]="selection.mirror_mode"
+ [rbdName]="selection.name"
+ ></cd-rbd-snapshot-list>
</ng-template>
</ng-container>
<ng-container ngbNavItem="configuration">
- <a ngbNavLink
- i18n>Configuration</a>
+ <a
+ ngbNavLink
+ i18n
+ >Configuration</a
+ >
<ng-template ngbNavContent>
- <cd-rbd-configuration-table [data]="selection['configuration']"></cd-rbd-configuration-table>
+ <cd-rbd-configuration-table
+ [data]="selection['configuration']"
+ ></cd-rbd-configuration-table>
</ng-template>
</ng-container>
<ng-container ngbNavItem="performance">
- <a ngbNavLink
- i18n>Performance</a>
+ <a
+ ngbNavLink
+ i18n
+ >Performance</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="RBD details"
- [grafanaPath]="rbdDashboardUrl"
- [type]="'metrics'"
- uid="YhCYGcuZz"
- grafanaStyle="one">
+ <cd-grafana
+ i18n-title
+ title="RBD details"
+ [grafanaPath]="rbdDashboardUrl"
+ [type]="'metrics'"
+ uid="YhCYGcuZz"
+ grafanaStyle="one"
+ >
</cd-grafana>
</ng-template>
</ng-container>
<div [ngbNavOutlet]="nav"></div>
</ng-container>
<ng-container *ngIf="selection && selection.source === 'REMOVING'">
- <cd-alert-panel type="warning"
- i18n>Information can not be displayed for RBD in status 'Removing'.</cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ i18n
+ >Information can not be displayed for RBD in status 'Removing'.</cd-alert-panel
+ >
</ng-container>
-<ng-template #poolConfigurationSourceTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #poolConfigurationSourceTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<ng-container *ngIf="+value; else global">
- <strong i18n
- i18n-ngbTooltip
- ngbTooltip="This setting overrides the global value">Image</strong>
+ <strong
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="This setting overrides the global value"
+ >Image</strong
+ >
</ng-container>
<ng-template #global>
- <span i18n
- i18n-ngbTooltip
- ngbTooltip="This is the global value. No value for this option has been set for this image.">Global</span>
+ <span
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="This is the global value. No value for this option has been set for this image."
+ >Global</span
+ >
</ng-template>
</ng-template>
-<div cdsCol
- [columnNumbers]="{md: 4}">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="rbdForm"
- #formDir="ngForm"
- [formGroup]="rbdForm"
- novalidate>
-
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}
+ <form
+ name="rbdForm"
+ #formDir="ngForm"
+ [formGroup]="rbdForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
<cd-help-text>
- <div *ngIf="action === 'Copy'">{{copyMessage}}
- </div>
+ <div *ngIf="action === 'Copy'">{{ copyMessage }}</div>
</cd-help-text>
</div>
<!-- Parent -->
- <div class="form-item"
- *ngIf="rbdForm.getValue('parent')">
- <cds-text-label for="parent"
- i18n>{{ action | titlecase }} from
- <input cdsText
- type="text"
- id="parent"
- name="parent"
- formControlName="parent"
- autofocus>
+ <div
+ class="form-item"
+ *ngIf="rbdForm.getValue('parent')"
+ >
+ <cds-text-label
+ for="parent"
+ i18n
+ >{{ action | titlecase }} from
+ <input
+ cdsText
+ type="text"
+ id="parent"
+ name="parent"
+ formControlName="parent"
+ autofocus
+ />
</cds-text-label>
</div>
<!-- Name -->
<div class="form-item">
- <cds-text-label [invalid]="!rbdForm.controls['name'].valid && (rbdForm.controls['name'].dirty)"
- [invalidText]="nameError"
- for="name"
- i18n
- cdRequiredField="Name">Name
- <input cdsText
- type="text"
- placeholder="Name..."
- id="name"
- name="name"
- formControlName="name"
- [invalid]="!rbdForm.controls['name'].valid && (rbdForm.controls['name'].dirty)"
- autofocus>
+ <cds-text-label
+ [invalid]="!rbdForm.controls['name'].valid && rbdForm.controls['name'].dirty"
+ [invalidText]="nameError"
+ for="name"
+ i18n
+ cdRequiredField="Name"
+ >Name
+ <input
+ cdsText
+ type="text"
+ placeholder="Name..."
+ id="name"
+ name="name"
+ formControlName="name"
+ [invalid]="!rbdForm.controls['name'].valid && rbdForm.controls['name'].dirty"
+ autofocus
+ />
</cds-text-label>
<ng-template #nameError>
<span *ngIf="rbdForm.showError('name', formDir, 'required')">
</div>
<!-- Pool -->
- <div class="form-item"
- (change)="onPoolChange($event.target.value)">
- <cds-text-label for="pool"
- i18n
- *ngIf="mode === 'editing' || !poolPermission.read">Pool
- <input cdsText
- type="text"
- placeholder="Pool name..."
- id="pool"
- name="pool"
- formControlName="pool">
+ <div
+ class="form-item"
+ (change)="onPoolChange($event.target.value)"
+ >
+ <cds-text-label
+ for="pool"
+ i18n
+ *ngIf="mode === 'editing' || !poolPermission.read"
+ >Pool
+ <input
+ cdsText
+ type="text"
+ placeholder="Pool name..."
+ id="pool"
+ name="pool"
+ formControlName="pool"
+ />
</cds-text-label>
- <cds-select label="Pool"
- for="pool"
- name="pool"
- id="pool"
- formControlName="pool"
- cdRequiredField="Pool"
- [invalid]="!rbdForm.controls['pool'].valid && (rbdForm.controls['pool'].dirty)"
- [invalidText]="poolError"
- (valueChange)="setPoolMirrorMode()"
- *ngIf="mode !== 'editing' && poolPermission.read">
- <option *ngIf="pools === null"
- [ngValue]="null"
- i18n>Loading...</option>
- <option *ngIf="pools !== null && pools.length === 0"
- [ngValue]="null"
- i18n>-- No block pools available --</option>
- <option *ngIf="pools !== null && pools.length > 0"
- [ngValue]="null"
- i18n>-- Select a pool --</option>
- <option *ngFor="let pool of pools"
- [value]="pool.pool_name">{{ pool.pool_name }}</option>
+ <cds-select
+ label="Pool"
+ for="pool"
+ name="pool"
+ id="pool"
+ formControlName="pool"
+ cdRequiredField="Pool"
+ [invalid]="!rbdForm.controls['pool'].valid && rbdForm.controls['pool'].dirty"
+ [invalidText]="poolError"
+ (valueChange)="setPoolMirrorMode()"
+ *ngIf="mode !== 'editing' && poolPermission.read"
+ >
+ <option
+ *ngIf="pools === null"
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="pools !== null && pools.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No block pools available --
+ </option>
+ <option
+ *ngIf="pools !== null && pools.length > 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a pool --
+ </option>
+ <option
+ *ngFor="let pool of pools"
+ [value]="pool.pool_name"
+ >
+ {{ pool.pool_name }}
+ </option>
</cds-select>
<ng-template #poolError>
- <span *ngIf="rbdForm.showError('pool', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ *ngIf="rbdForm.showError('pool', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Size -->
<div class="form-item">
- <cds-text-label labelInputID="size"
- i18n
- [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
- [invalidText]="sizeError"
- cdRequiredField="Size">Size
- <input cdsText
- type="text"
- placeholder="e.g., 10GiB"
- id="size"
- formControlName="size"
- defaultUnit="GiB"
- [invalid]="!rbdForm.controls['size'].valid && (rbdForm.controls['size'].dirty)"
- cdDimlessBinary>
+ <cds-text-label
+ labelInputID="size"
+ i18n
+ [invalid]="!rbdForm.controls['size'].valid && rbdForm.controls['size'].dirty"
+ [invalidText]="sizeError"
+ cdRequiredField="Size"
+ >Size
+ <input
+ cdsText
+ type="text"
+ placeholder="e.g., 10GiB"
+ id="size"
+ formControlName="size"
+ defaultUnit="GiB"
+ [invalid]="!rbdForm.controls['size'].valid && rbdForm.controls['size'].dirty"
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #sizeError>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('size', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
- i18n>Size must be increased.</span>
- <span *ngIf="rbdForm.showError('size', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('size', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
+ i18n
+ >Size must be increased.</span
+ >
+ <span
+ *ngIf="rbdForm.showError('size', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
<!-- Namespace -->
<!-- Skeleton-->
- <div class="form-item"
- *ngIf="mode !== 'editing' && rbdForm.getValue('pool') && namespaces === null">
- <cds-select label="Namespace"
- labelInputID="namespace"
- id="namespace"
- [skeleton]="true"
- formControlName="namespace">
- <option [ngValue]="null"
- i18n>Loading...</option>
+ <div
+ class="form-item"
+ *ngIf="mode !== 'editing' && rbdForm.getValue('pool') && namespaces === null"
+ >
+ <cds-select
+ label="Namespace"
+ labelInputID="namespace"
+ id="namespace"
+ [skeleton]="true"
+ formControlName="namespace"
+ >
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
</cds-select>
</div>
- <div class="form-item"
- *ngIf="(mode === 'editing' && rbdForm.getValue('namespace')) || mode !== 'editing' && (namespaces && namespaces.length > 0 || !poolPermission.read)">
- <cds-text-label label="Namespace"
- labelInputID="namespace"
- [helperText]="namespaceHelperTpl"
- *ngIf="mode === 'editing' || !poolPermission.read"
- i18n>Namespace
- <input cdsText
- id="namespace"
- formControlName="namespace">
+ <div
+ class="form-item"
+ *ngIf="
+ (mode === 'editing' && rbdForm.getValue('namespace')) ||
+ (mode !== 'editing' && ((namespaces && namespaces.length > 0) || !poolPermission.read))
+ "
+ >
+ <cds-text-label
+ label="Namespace"
+ labelInputID="namespace"
+ [helperText]="namespaceHelperTpl"
+ *ngIf="mode === 'editing' || !poolPermission.read"
+ i18n
+ >Namespace
+ <input
+ cdsText
+ id="namespace"
+ formControlName="namespace"
+ />
</cds-text-label>
- <cds-select label="Namespace"
- [helperText]="namespaceHelperTpl"
- id="namespace"
- formControlName="namespace"
- (valueChange)="disableMirroring($event)"
- *ngIf="mode !== 'editing' && poolPermission.read">
- <option *ngIf="namespaces === null"
- [ngValue]="null"
- i18n>Loading...</option>
- <option *ngIf="namespaces !== null && namespaces.length === 0"
- [ngValue]="null"
- i18n>-- No namespaces available --</option>
- <option *ngIf="namespaces !== null && namespaces.length > 0"
- value=""
- i18n>-- Select a namespace --</option>
- <option *ngFor="let namespace of namespaces"
- [value]="namespace">{{ namespace }}</option>
+ <cds-select
+ label="Namespace"
+ [helperText]="namespaceHelperTpl"
+ id="namespace"
+ formControlName="namespace"
+ (valueChange)="disableMirroring($event)"
+ *ngIf="mode !== 'editing' && poolPermission.read"
+ >
+ <option
+ *ngIf="namespaces === null"
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="namespaces !== null && namespaces.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No namespaces available --
+ </option>
+ <option
+ *ngIf="namespaces !== null && namespaces.length > 0"
+ value=""
+ i18n
+ >
+ -- Select a namespace --
+ </option>
+ <option
+ *ngFor="let namespace of namespaces"
+ [value]="namespace"
+ >
+ {{ namespace }}
+ </option>
</cds-select>
<ng-template #namespaceHelperTpl>
- Namespace allows you to logically group RBD images within your Ceph Cluster.Choosing a namespace makes it easier to locate and manage related RBD images efficiently.
+ Namespace allows you to logically group RBD images within your Ceph Cluster.Choosing a
+ namespace makes it easier to locate and manage related RBD images efficiently.
</ng-template>
</div>
<!-- Mirroring -->
<div class="form-item">
- <cds-checkbox id="mirroring"
- name="mirroring"
- formControlName="mirroring"
- (checkedChange)="setMirrorMode()"
- i18n>Mirroring
- <cd-help-text>Allow data to be asynchronously mirrored between two Ceph clusters</cd-help-text>
-
+ <cds-checkbox
+ id="mirroring"
+ name="mirroring"
+ formControlName="mirroring"
+ (checkedChange)="setMirrorMode()"
+ i18n
+ >Mirroring
+ <cd-help-text
+ >Allow data to be asynchronously mirrored between two Ceph clusters</cd-help-text
+ >
</cds-checkbox>
- <cd-alert-panel *ngIf="showMirrorDisableMessage"
- spacingClass="mt-2"
- [showTitle]="false"
- type="info">Mirroring can not be disabled on <b> Pool </b> mirror mode.
- You need to change the mirror mode to enable this option.
+ <cd-alert-panel
+ *ngIf="showMirrorDisableMessage"
+ spacingClass="mt-2"
+ [showTitle]="false"
+ type="info"
+ >Mirroring can not be disabled on <b> Pool </b> mirror mode. You need to change
+ the mirror mode to enable this option.
</cd-alert-panel>
- <cd-alert-panel *ngIf="currentPoolMirrorMode === 'disabled'"
- type="info"
- [showTitle]="false"
- spacingClass="mt-2"
- actionName="Set mode"
- (action)="onAlertAction($event)">
- You need to set <b>mirror mode</b> in the selected pool to enable mirroring.
+ <cd-alert-panel
+ *ngIf="currentPoolMirrorMode === 'disabled'"
+ type="info"
+ [showTitle]="false"
+ spacingClass="mt-2"
+ actionName="Set mode"
+ (action)="onAlertAction($event)"
+ >
+ You need to set <b>mirror mode</b> in the selected pool to enable mirroring.
</cd-alert-panel>
</div>
<!-- Mirroring Modes -->
- <div *ngIf="mirroring && currentPoolMirrorMode !== 'disabled'"
- class="form-item">
- <cds-radio-group formControlName="mirroringMode"
- name="mirroringMode">
- <cds-radio *ngFor="let option of mirroringOptions"
- [value]="option.value"
- [id]="option.value"
- (change)="setExclusiveLock()"
- [disabled]="shouldDisable(option.value)">
+ <div
+ *ngIf="mirroring && currentPoolMirrorMode !== 'disabled'"
+ class="form-item"
+ >
+ <cds-radio-group
+ formControlName="mirroringMode"
+ name="mirroringMode"
+ >
+ <cds-radio
+ *ngFor="let option of mirroringOptions"
+ [value]="option.value"
+ [id]="option.value"
+ (change)="setExclusiveLock()"
+ [disabled]="shouldDisable(option.value)"
+ >
{{ option.value | titlecase }}
- <cd-helper> {{ option.text}} </cd-helper>
+ <cd-helper> {{ option.text }} </cd-helper>
</cds-radio>
</cds-radio-group>
- <cd-alert-panel *ngIf="currentPoolMirrorMode === 'pool' && mode !== 'editing'"
- type="info"
- [showTitle]="false"
- spacingClass="mt-2"
- actionName="Set mode"
- (action)="onAlertAction($event)"
- i18n>
- You need to set mode as <b>Image</b> in the selected pool to enable snapshot mirroring.
+ <cd-alert-panel
+ *ngIf="currentPoolMirrorMode === 'pool' && mode !== 'editing'"
+ type="info"
+ [showTitle]="false"
+ spacingClass="mt-2"
+ actionName="Set mode"
+ (action)="onAlertAction($event)"
+ i18n
+ >
+ You need to set mode as <b>Image</b> in the selected pool to enable snapshot
+ mirroring.
</cd-alert-panel>
</div>
<!-- Snapshot Schedule Interval -->
- <div class="form-item"
- *ngIf="rbdForm.getValue('mirroringMode') === rbdMirrorModes.snapshot && mirroring">
- <cds-text-label for="schedule"
- helperText="Create Mirror-Snapshots automatically on a periodic basis. The interval can be specified in days, hours, or minutes using d, h, m suffix respectively. To create mirror snapshots, you must import or create and have available peers to mirror"
- cdRequiredField="Schedule Interval"
- [invalid]="!rbdForm.controls['schedule'].valid && (rbdForm.controls['schedule'].dirty)"
- [invalidText]="scheduleError"
- i18n>Schedule Interval
- <input cdsText
- type="text"
- placeholder="e.g., 12h or 1d or 10m"
- id="schedule"
- name="schedule"
- formControlName="schedule"
- [disabled]="(peerConfigured === false) ? true : null"
- [invalid]="!rbdForm.controls['schedule'].valid && (rbdForm.controls['schedule'].dirty)">
+ <div
+ class="form-item"
+ *ngIf="rbdForm.getValue('mirroringMode') === rbdMirrorModes.snapshot && mirroring"
+ >
+ <cds-text-label
+ for="schedule"
+ helperText="Create Mirror-Snapshots automatically on a periodic basis. The interval can be specified in days, hours, or minutes using d, h, m suffix respectively. To create mirror snapshots, you must import or create and have available peers to mirror"
+ cdRequiredField="Schedule Interval"
+ [invalid]="!rbdForm.controls['schedule'].valid && rbdForm.controls['schedule'].dirty"
+ [invalidText]="scheduleError"
+ i18n
+ >Schedule Interval
+ <input
+ cdsText
+ type="text"
+ placeholder="e.g., 12h or 1d or 10m"
+ id="schedule"
+ name="schedule"
+ formControlName="schedule"
+ [disabled]="peerConfigured === false ? true : null"
+ [invalid]="!rbdForm.controls['schedule'].valid && rbdForm.controls['schedule'].dirty"
+ />
</cds-text-label>
<ng-template #scheduleError>
- <span *ngIf="rbdForm.showError('schedule', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ *ngIf="rbdForm.showError('schedule', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Use a dedicated pool -->
- <div class="form-item"
- *ngIf="allDataPools.length > 1 || mode === 'editing'">
- <cds-checkbox id="useDataPool"
- name="useDataPool"
- formControlName="useDataPool"
- (change)="onUseDataPoolChange()"
- i18n>
- Use a dedicated data pool
+ <div
+ class="form-item"
+ *ngIf="allDataPools.length > 1 || mode === 'editing'"
+ >
+ <cds-checkbox
+ id="useDataPool"
+ name="useDataPool"
+ formControlName="useDataPool"
+ (change)="onUseDataPoolChange()"
+ i18n
+ >
+ Use a dedicated data pool
- <cd-help-text>Use a dedicated pool to store the image data. If not selected,
- the image data will be stored in the same pool as the image metadata.
+ <cd-help-text
+ >Use a dedicated pool to store the image data. If not selected, the image data will be
+ stored in the same pool as the image metadata.
</cd-help-text>
<cd-helper *ngIf="allDataPools.length <= 1 && mode !== 'editing'">
- <span>You need more than one pool with the rbd application label use to use a dedicated data pool.</span>
+ <span
+ >You need more than one pool with the rbd application label use to use a dedicated
+ data pool.</span
+ >
</cd-helper>
</cds-checkbox>
</div>
<!-- Data pools -->
- <div class="form-item"
- *ngIf="rbdForm.getValue('useDataPool')">
- <cds-select label="Data pool"
- helperText="Dedicated pool that stores the object-data of the RBD"
- for="dataPool"
- name="dataPool"
- id="dataPool"
- [invalid]="!rbdForm.controls['dataPool'].valid && (rbdForm.controls['dataPool'].dirty)"
- [invalidText]="dataPoolError"
- formControlName="dataPool"
- cdRequiredField="Data pool"
- *ngIf="mode !== 'editing' && poolPermission.read">
- <option *ngIf="dataPools === null"
- [ngValue]="null"
- i18n>Loading...</option>
- <option *ngIf="dataPools !== null && dataPools.length === 0"
- [ngValue]="null"
- i18n>-- No data pools available --</option>
- <option *ngIf="dataPools !== null && dataPools.length > 0"
- [ngValue]="null"
- i18n>-- Select a data pool --</option>
- <option *ngFor="let dataPool of dataPools"
- [value]="dataPool.pool_name">{{ dataPool.pool_name }}</option>
+ <div
+ class="form-item"
+ *ngIf="rbdForm.getValue('useDataPool')"
+ >
+ <cds-select
+ label="Data pool"
+ helperText="Dedicated pool that stores the object-data of the RBD"
+ for="dataPool"
+ name="dataPool"
+ id="dataPool"
+ [invalid]="!rbdForm.controls['dataPool'].valid && rbdForm.controls['dataPool'].dirty"
+ [invalidText]="dataPoolError"
+ formControlName="dataPool"
+ cdRequiredField="Data pool"
+ *ngIf="mode !== 'editing' && poolPermission.read"
+ >
+ <option
+ *ngIf="dataPools === null"
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="dataPools !== null && dataPools.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No data pools available --
+ </option>
+ <option
+ *ngIf="dataPools !== null && dataPools.length > 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a data pool --
+ </option>
+ <option
+ *ngFor="let dataPool of dataPools"
+ [value]="dataPool.pool_name"
+ >
+ {{ dataPool.pool_name }}
+ </option>
</cds-select>
<ng-template #dataPoolError>
- <span *ngIf="rbdForm.showError('dataPool', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ *ngIf="rbdForm.showError('dataPool', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Advanced Section -->
<cd-form-advanced-fieldset>
<!-- Features -->
- <div class="form-item"
- formGroupName="features">
+ <div
+ class="form-item"
+ formGroupName="features"
+ >
<fieldset>
- <label class="cds--label"
- for="features"
- i18n>Features</label>
+ <label
+ class="cds--label"
+ for="features"
+ i18n
+ >Features</label
+ >
<ng-container *ngFor="let feature of featuresList">
- <cds-checkbox [id]="feature.key"
- [name]="feature.key"
- [formControlName]="feature.key"
- class="spacing-03">
- {{ feature.key | titlecase}}
+ <cds-checkbox
+ [id]="feature.key"
+ [name]="feature.key"
+ [formControlName]="feature.key"
+ class="spacing-03"
+ >
+ {{ feature.key | titlecase }}
<cd-help-text *ngIf="feature.helperText">
- {{ feature.helperText}}
+ {{ feature.helperText }}
</cd-help-text>
- <cd-alert-panel type="warning"
- spacingClass="mt-2"
- [showTitle]="false"
- *ngIf="feature.helperHtml && rbdForm.getValue(feature.key) === false">
- {{ feature.helperHtml }}
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mt-2"
+ [showTitle]="false"
+ *ngIf="feature.helperHtml && rbdForm.getValue(feature.key) === false"
+ >
+ {{ feature.helperHtml }}
</cd-alert-panel>
</cds-checkbox>
</ng-container>
</fieldset>
</div>
- <legend class="cd-header"
- i18n>Striping</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Striping
+ </legend>
<!-- Object Size -->
<div class="form-item">
- <cds-select i18n
- for="obj_size"
- label="Object size"
- helperText="Objects in the Ceph Storage Cluster have a maximum configurable size (e.g., 2MB, 4MB, etc.). The object size should be large enough to accommodate many stripe units, and should be a multiple of the stripe unit."
- id="obj_size"
- name="obj_size"
- formControlName="obj_size">
- <option *ngFor="let objectSize of objectSizes"
- [value]="objectSize">{{ objectSize }}</option>
+ <cds-select
+ i18n
+ for="obj_size"
+ label="Object size"
+ helperText="Objects in the Ceph Storage Cluster have a maximum configurable size (e.g., 2MB, 4MB, etc.). The object size should be large enough to accommodate many stripe units, and should be a multiple of the stripe unit."
+ id="obj_size"
+ name="obj_size"
+ formControlName="obj_size"
+ >
+ <option
+ *ngFor="let objectSize of objectSizes"
+ [value]="objectSize"
+ >
+ {{ objectSize }}
+ </option>
</cds-select>
</div>
<!-- stripingUnit -->
<div class="form-item">
- <cds-select i18n
- for="stripingUnit"
- label="Stripe unit"
- helperText="Stripes have a configurable unit size (e.g., 64kb). The Ceph Client divides the data it will write to objects into equally sized stripe units, except for the last stripe unit. A stripe width, should be a fraction of the Object Size so that an object may contain many stripe units"
- id="stripingUnit"
- name="stripingUnit"
- formControlName="stripingUnit"
- cdRequiredField="Striping Unit"
- [invalid]="!rbdForm.controls['stripingUnit'].valid && (rbdForm.controls['stripingUnit'].dirty)"
- [invalidText]="stripingUnitError">
+ <cds-select
+ i18n
+ for="stripingUnit"
+ label="Stripe unit"
+ helperText="Stripes have a configurable unit size (e.g., 64kb). The Ceph Client divides the data it will write to objects into equally sized stripe units, except for the last stripe unit. A stripe width, should be a fraction of the Object Size so that an object may contain many stripe units"
+ id="stripingUnit"
+ name="stripingUnit"
+ formControlName="stripingUnit"
+ cdRequiredField="Striping Unit"
+ [invalid]="
+ !rbdForm.controls['stripingUnit'].valid && rbdForm.controls['stripingUnit'].dirty
+ "
+ [invalidText]="stripingUnitError"
+ >
<option [ngValue]="null">-- Select stripe unit --</option>
- <option *ngFor="let objectSize of objectSizes"
- [value]="objectSize">{{ objectSize }}</option>
+ <option
+ *ngFor="let objectSize of objectSizes"
+ [value]="objectSize"
+ >
+ {{ objectSize }}
+ </option>
</cds-select>
<ng-template #stripingUnitError>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('stripingUnit', formDir, 'required')"
- i18n>This field is required because stripe count is defined!</span>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('stripingUnit', formDir, 'invalidStripingUnit')"
- i18n>Stripe unit is greater than object size.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('stripingUnit', formDir, 'required')"
+ i18n
+ >This field is required because stripe count is defined!</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('stripingUnit', formDir, 'invalidStripingUnit')"
+ i18n
+ >Stripe unit is greater than object size.</span
+ >
</ng-template>
</div>
<!-- Stripe Count -->
<div class="form-item">
- <cds-number i18n
- for="stripingCount"
- label="Stripe count"
- helperText="The Ceph Client writes a sequence of stripe units over a series of objects determined by the stripe count. The series of objects is called an object set. After the Ceph Client writes to the last object in the object set, it returns to the first object in the object set."
- id="stripingCount"
- name="stripingCount"
- formControlName="stripingCount"
- cdRequiredField="Striping Count"
- [min]="1"
- [invalid]="!rbdForm.controls['stripingCount'].valid && (rbdForm.controls['stripingCount'].dirty)"
- [invalidText]="stripingCountError"
- [required]="true"></cds-number>
+ <cds-number
+ i18n
+ for="stripingCount"
+ label="Stripe count"
+ helperText="The Ceph Client writes a sequence of stripe units over a series of objects determined by the stripe count. The series of objects is called an object set. After the Ceph Client writes to the last object in the object set, it returns to the first object in the object set."
+ id="stripingCount"
+ name="stripingCount"
+ formControlName="stripingCount"
+ cdRequiredField="Striping Count"
+ [min]="1"
+ [invalid]="
+ !rbdForm.controls['stripingCount'].valid && rbdForm.controls['stripingCount'].dirty
+ "
+ [invalidText]="stripingCountError"
+ [required]="true"
+ ></cds-number>
<ng-template #stripingCountError>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('stripingCount', formDir, 'required')"
- i18n>This field is required because stripe unit is defined!</span>
- <span class="invalid-feedback"
- *ngIf="rbdForm.showError('stripingCount', formDir, 'min')"
- i18n>Stripe count must be greater than 0.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('stripingCount', formDir, 'required')"
+ i18n
+ >This field is required because stripe unit is defined!</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="rbdForm.showError('stripingCount', formDir, 'min')"
+ i18n
+ >Stripe count must be greater than 0.</span
+ >
</ng-template>
</div>
- <cd-rbd-configuration-form [form]="rbdForm"
- [initializeData]="initializeConfigData"
- (changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
+ <cd-rbd-configuration-form
+ [form]="rbdForm"
+ [initializeData]="initializeConfigData"
+ (changes)="getDirtyConfigurationValues = $event"
+ ></cd-rbd-configuration-form>
</cd-form-advanced-fieldset>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="formDir"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="formDir"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</ng-container>
</div>
<cd-rbd-tabs></cd-rbd-tabs>
-<cd-table #table
- [data]="images"
- columnMode="flex"
- [columns]="columns"
- identifier="unique_id"
- [searchableObjects]="true"
- [serverSide]="true"
- [count]="count"
- forceIdentifier="true"
- selectionType="single"
- [hasDetails]="true"
- [status]="tableStatus"
- [maxLimit]="25"
- [autoReload]="-1"
- (fetchData)="taskListService.fetch($event)"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [data]="images"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="unique_id"
+ [searchableObjects]="true"
+ [serverSide]="true"
+ [count]="count"
+ forceIdentifier="true"
+ selectionType="single"
+ [hasDetails]="true"
+ [status]="tableStatus"
+ [maxLimit]="25"
+ [autoReload]="-1"
+ (fetchData)="taskListService.fetch($event)"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-rbd-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-rbd-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rbd-details>
</cd-table>
-<ng-template #parentTpl
- let-value="data.value">
- <span *ngIf="value">{{ value.pool_name }}<span
- *ngIf="value.pool_namespace">/{{ value.pool_namespace }}</span>/{{ value.image_name }}@{{ value.snap_name }}</span>
+<ng-template
+ #parentTpl
+ let-value="data.value"
+>
+ <span *ngIf="value"
+ >{{ value.pool_name }}<span *ngIf="value.pool_namespace">/{{ value.pool_namespace }}</span
+ >/{{ value.image_name }}@{{ value.snap_name }}</span
+ >
<span *ngIf="!value">-</span>
</ng-template>
-<ng-template #mirroringTpl
- let-value="data.value"
- let-row="data.row">
- <cds-tag *ngIf="value?.length === 3; else probb"
- class="tag-info">
- {{ value[0] }}
- </cds-tag>
- <cds-tag *ngIf="value?.length === 3"
- class="tag-info">
- {{ value[1] }}
- </cds-tag>
- <cds-tag *ngIf="row?.primary === true"
- class="tag-info"
- i18n>
+<ng-template
+ #mirroringTpl
+ let-value="data.value"
+ let-row="data.row"
+>
+ <cds-tag
+ *ngIf="value?.length === 3; else probb"
+ class="tag-info"
+ >
+ {{ value[0] }} </cds-tag
+ >
+ <cds-tag
+ *ngIf="value?.length === 3"
+ class="tag-info"
+ >
+ {{ value[1] }} </cds-tag
+ >
+ <cds-tag
+ *ngIf="row?.primary === true"
+ class="tag-info"
+ i18n
+ >
primary
</cds-tag>
- <cds-tag *ngIf="row?.primary === false"
- class="tag-info"
- i18n>
+ <cds-tag
+ *ngIf="row?.primary === false"
+ class="tag-info"
+ i18n
+ >
secondary
</cds-tag>
<ng-template #probb>
<cds-tag class="tag-info">
{{ value }}
- </cds-tag >
+ </cds-tag>
</ng-template>
</ng-template>
-<ng-template #ScheduleTpl
- let-value="data.value"
- let-row="data.row">
- <cds-tag *ngIf="value?.length === 3"
- class="tag-info">
- {{ value[2] | cdDate }}
+<ng-template
+ #ScheduleTpl
+ let-value="data.value"
+ let-row="data.row"
+>
+ <cds-tag
+ *ngIf="value?.length === 3"
+ class="tag-info"
+ >
+ {{ value[2] | cdDate }}
</cds-tag>
</ng-template>
-<ng-template #flattenTpl
- let-value>
+<ng-template
+ #flattenTpl
+ let-value
+>
You are about to flatten
- <strong>{{ value.child }}</strong>.
- <br>
- <br> All blocks will be copied from parent
- <strong>{{ value.parent }}</strong> to child
- <strong>{{ value.child }}</strong>.
+ <strong>{{ value.child }}</strong
+ >.
+ <br />
+ <br />
+ All blocks will be copied from parent <strong>{{ value.parent }}</strong> to child
+ <strong>{{ value.child }}</strong
+ >.
</ng-template>
-<ng-template #deleteTpl
- let-hasSnapshots="hasSnapshots"
- let-snapshots="snapshots">
- <div class="alert alert-warning"
- *ngIf="hasSnapshots"
- role="alert">
+<ng-template
+ #deleteTpl
+ let-hasSnapshots="hasSnapshots"
+ let-snapshots="snapshots"
+>
+ <div
+ class="alert alert-warning"
+ *ngIf="hasSnapshots"
+ role="alert"
+ >
<span i18n>Deleting this image will also delete all its snapshots.</span>
- <br>
+ <br />
<ng-container *ngIf="snapshots.length > 0">
<span i18n>The following snapshots are currently protected and will be removed:</span>
<ul>
</div>
</ng-template>
-<ng-template #removingStatTpl
- let-column="data.column"
- let-value="data.value"
- let-row="data.row">
+<ng-template
+ #removingStatTpl
+ let-column="data.column"
+ let-value="data.value"
+ let-row="data.row"
+>
<cds-inline-loading *ngIf="row.cdExecuting"></cds-inline-loading>
- <span [ngClass]="column?.customTemplateConfig?.valueClass">
+ <span [ngClass]="column?.customTemplateConfig?.valueClass">
{{ value }}
</span>
- <span *ngIf="row.cdExecuting"
- [ngClass]="column?.customTemplateConfig?.executingClass ?
- column.customTemplateConfig.executingClass :
- 'text-muted italic'">
+ <span
+ *ngIf="row.cdExecuting"
+ [ngClass]="
+ column?.customTemplateConfig?.executingClass
+ ? column.customTemplateConfig.executingClass
+ : 'text-muted italic'
+ "
+ >
({{ row.cdExecuting }})
</span>
- <svg *ngIf="row.source && row.source === 'REMOVING'"
- i18n-title
- title="RBD in status 'Removing'"
- [cdsIcon]="icons.warning"
- [size]="icons.size16"
- class="cds-warning-color"></svg>
+ <svg
+ *ngIf="row.source && row.source === 'REMOVING'"
+ i18n-title
+ title="RBD in status 'Removing'"
+ [cdsIcon]="icons.warning"
+ [size]="icons.size16"
+ class="cds-warning-color"
+ ></svg>
</ng-template>
<ng-template #forcePromoteConfirmation>
<cd-alert-panel type="warning">{{ errorMessage }}</cd-alert-panel>
- <div class="m-4"
- i18n>
- <strong>
- Do you want to force the operation?
- </strong>
+ <div
+ class="m-4"
+ i18n
+ >
+ <strong> Do you want to force the operation? </strong>
</div>
</ng-template>
-<ng-template #imageUsageTpl
- let-row="data.row">
- <span *ngIf="row.features_name && !row.features_name.includes('fast-diff') ; else usageBar"
- [ngbTooltip]="usageTooltip">
+<ng-template
+ #imageUsageTpl
+ let-row="data.row"
+>
+ <span
+ *ngIf="row.features_name && !row.features_name.includes('fast-diff'); else usageBar"
+ [ngbTooltip]="usageTooltip"
+ >
<span>-</span>
</span>
<ng-template #usageBar>
- <cd-usage-bar *ngIf="row"
- [total]="row.size"
- [used]="row.disk_usage"
- [title]="row.name"
- decimals="2">
- </cd-usage-bar>
+ <cd-usage-bar
+ *ngIf="row"
+ [total]="row.size"
+ [used]="row.disk_usage"
+ [title]="row.name"
+ decimals="2"
+ >
+ </cd-usage-bar>
</ng-template>
</ng-template>
<ng-template #usageTooltip>
- <div i18n
- [innerHtml]="'Only available for RBD images with <strong>fast-diff</strong> enabled and without snapshot mirroring'"></div>
+ <div
+ i18n
+ [innerHtml]="'Only available for RBD images with <strong>fast-diff</strong> enabled and without snapshot mirroring'"
+ ></div>
</ng-template>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
Create Namespace
- </h3>
+ </h3>
</cds-modal-header>
<section cdsModalContent>
+ <form
+ name="namespaceForm"
+ #formDir="ngForm"
+ [formGroup]="namespaceForm"
+ novalidate
+ >
+ <!-- Pool -->
+ <div class="form-item">
+ <cds-select
+ label="Pool"
+ for="pool"
+ formControlName="pool"
+ name="pool"
+ id="pool"
+ [invalid]="namespaceForm.controls['pool'].invalid && namespaceForm.controls['pool'].dirty"
+ [invalidText]="poolError"
+ *ngIf="poolPermission.read"
+ cdRequiredField="Pool"
+ modal-primary-focus
+ i18n
+ >
+ <option
+ *ngIf="pools === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="pools !== null && pools.length === 0"
+ [ngValue]="null"
+ >
+ -- No rbd pools available --
+ </option>
+ <option
+ *ngIf="pools !== null && pools.length > 0"
+ [ngValue]="null"
+ >
+ -- Select a pool --
+ </option>
+ <option
+ *ngFor="let pool of pools"
+ [value]="pool.pool_name"
+ >
+ {{ pool.pool_name }}
+ </option>
+ </cds-select>
+ <ng-template #poolError>
+ <span
+ *ngIf="namespaceForm.showError('pool', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
- <form name="namespaceForm"
- #formDir="ngForm"
- [formGroup]="namespaceForm"
- novalidate>
-
- <!-- Pool -->
- <div class="form-item">
- <cds-select label="Pool"
- for="pool"
- formControlName="pool"
- name="pool"
- id="pool"
- [invalid]="namespaceForm.controls['pool'].invalid && (namespaceForm.controls['pool'].dirty)"
- [invalidText]="poolError"
- *ngIf="poolPermission.read"
- cdRequiredField="Pool"
- modal-primary-focus
- i18n>
-
- <option *ngIf="pools === null"
- [ngValue]="null">Loading...</option>
- <option *ngIf="pools !== null && pools.length === 0"
- [ngValue]="null">-- No rbd pools available --</option>
- <option *ngIf="pools !== null && pools.length > 0"
- [ngValue]="null">-- Select a pool --</option>
- <option *ngFor="let pool of pools"
- [value]="pool.pool_name">{{ pool.pool_name }}</option>
- </cds-select>
- <ng-template #poolError>
- <span *ngIf="namespaceForm.showError('pool', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
- </ng-template>
- </div>
-
- <!-- Name -->
- <div class="form-item">
- <cds-text-label label="Name"
- for="namespace"
- [invalid]="namespaceForm.controls['namespace'].invalid && (namespaceForm.controls['namespace'].dirty)"
- [invalidText]="namespaceError"
- cdRequiredField="Namespace"
- i18n>Namespace
- <input cdsText
- type="text"
- placeholder="Namespace name..."
- id="namespace"
- name="namespace"
- formControlName="namespace"
- [invalid]="namespaceForm.controls['namespace'].invalid && (namespaceForm.controls['namespace'].dirty)"
- autofocus>
- </cds-text-label>
- <ng-template #namespaceError>
- <span *ngIf="namespaceForm.showError('namespace', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
- <span *ngIf="namespaceForm.showError('namespace', formDir, 'namespaceExists')"
- class="invalid-feedback"
- i18n>The namespace already exists.</span>
- </ng-template>
- </div>
-
-
+ <!-- Name -->
+ <div class="form-item">
+ <cds-text-label
+ label="Name"
+ for="namespace"
+ [invalid]="
+ namespaceForm.controls['namespace'].invalid && namespaceForm.controls['namespace'].dirty
+ "
+ [invalidText]="namespaceError"
+ cdRequiredField="Namespace"
+ i18n
+ >Namespace
+ <input
+ cdsText
+ type="text"
+ placeholder="Namespace name..."
+ id="namespace"
+ name="namespace"
+ formControlName="namespace"
+ [invalid]="
+ namespaceForm.controls['namespace'].invalid &&
+ namespaceForm.controls['namespace'].dirty
+ "
+ autofocus
+ />
+ </cds-text-label>
+ <ng-template #namespaceError>
+ <span
+ *ngIf="namespaceForm.showError('namespace', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="namespaceForm.showError('namespace', formDir, 'namespaceExists')"
+ class="invalid-feedback"
+ i18n
+ >The namespace already exists.</span
+ >
+ </ng-template>
+ </div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="namespaceForm"
- [submitText]="actionLabels.CREATE"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="namespaceForm"
+ [submitText]="actionLabels.CREATE"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
<cd-rbd-tabs></cd-rbd-tabs>
-<cd-table [data]="namespaces"
- (fetchData)="refresh()"
- columnMode="flex"
- [columns]="columns"
- identifier="id"
- forceIdentifier="true"
- selectionType="single"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ [data]="namespaces"
+ (fetchData)="refresh()"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="id"
+ forceIdentifier="true"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions class="btn-group"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
<cd-rbd-tabs></cd-rbd-tabs>
-<cd-grafana i18n-title
- title="RBD overview"
- [grafanaPath]="'ceph-block-overview?'"
- [type]="'metrics'"
- uid="41FrpeUiz"
- grafanaStyle="two">
+<cd-grafana
+ i18n-title
+ title="RBD overview"
+ [grafanaPath]="'ceph-block-overview?'"
+ [type]="'metrics'"
+ uid="41FrpeUiz"
+ grafanaStyle="two"
+>
</cd-grafana>
-<cds-modal size="md"
- [open]="open"
- (overalSelected)="closeModal()">
-
+<cds-modal
+ size="md"
+ [open]="open"
+ (overalSelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="snapshotForm"
- #formDir="ngForm"
- [formGroup]="snapshotForm"
- novalidate>
+ <form
+ name="snapshotForm"
+ #formDir="ngForm"
+ [formGroup]="snapshotForm"
+ novalidate
+ >
<!-- Name -->
<div class="form-item">
- <cds-text-label label="Name"
- i18n-label
- for="snapshotName"
- i18n
- cdRequiredField="Name"
- [invalid]="snapshotForm.controls['snapshotName'].invalid && (snapshotForm.controls['snapshotName'].dirty)"
- [invalidText]="snapshotError">
- <input cdsText
- type="text"
- placeholder="Snapshot name..."
- id="snapshotName"
- name="snapshotName"
- formControlName="snapshotName"
- [attr.disabled]="((mirroring === 'snapshot') ? true : null) && (snapshotForm.getValue('mirrorImageSnapshot') === true) ? true: null"
- [invalid]="snapshotForm.controls['snapshotName'].invalid && (snapshotForm.controls['snapshotName'].dirty)"
- autofocus>
- <span *ngIf="((mirroring === 'snapshot') ? true : null) && (snapshotForm.getValue('mirrorImageSnapshot') === true) ? true: null">
- Snapshot mode is enabled on image <b>{{ imageName }}</b>: snapshot names are auto generated</span>
+ <cds-text-label
+ label="Name"
+ i18n-label
+ for="snapshotName"
+ i18n
+ cdRequiredField="Name"
+ [invalid]="
+ snapshotForm.controls['snapshotName'].invalid &&
+ snapshotForm.controls['snapshotName'].dirty
+ "
+ [invalidText]="snapshotError"
+ >
+ <input
+ cdsText
+ type="text"
+ placeholder="Snapshot name..."
+ id="snapshotName"
+ name="snapshotName"
+ formControlName="snapshotName"
+ [attr.disabled]="
+ (mirroring === 'snapshot' ? true : null) &&
+ snapshotForm.getValue('mirrorImageSnapshot') === true
+ ? true
+ : null
+ "
+ [invalid]="
+ snapshotForm.controls['snapshotName'].invalid &&
+ snapshotForm.controls['snapshotName'].dirty
+ "
+ autofocus
+ />
+ <span
+ *ngIf="
+ (mirroring === 'snapshot' ? true : null) &&
+ snapshotForm.getValue('mirrorImageSnapshot') === true
+ ? true
+ : null
+ "
+ >
+ Snapshot mode is enabled on image <b>{{ imageName }}</b
+ >: snapshot names are auto generated</span
+ >
</cds-text-label>
<ng-template #snapshotError>
- <span *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required.</span>
- <span *ngIf="snapshotForm.showError('snapshotName', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>The snapshot name cannot start with "." and cannot contain "/" and "@".</span>
+ <span
+ *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="snapshotForm.showError('snapshotName', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >The snapshot name cannot start with "." and cannot contain "/" and "@".</span
+ >
</ng-template>
</div>
<ng-container *ngIf="mirroring === 'snapshot'">
- <div class="form-item"
- *ngIf="peerConfigured$ | async as peerConfigured">
- <cds-checkbox id="mirrorImageSnapshot"
- formControlName="mirrorImageSnapshot"
- name="mirrorImageSnapshot"
- (checkedChange)="onMirrorCheckBoxChange()"
- [attr.disabled]="!peerConfigured.length > 0 ? true : null"
- i18n>Mirror Image Snapshot
+ <div
+ class="form-item"
+ *ngIf="peerConfigured$ | async as peerConfigured"
+ >
+ <cds-checkbox
+ id="mirrorImageSnapshot"
+ formControlName="mirrorImageSnapshot"
+ name="mirrorImageSnapshot"
+ (checkedChange)="onMirrorCheckBoxChange()"
+ [attr.disabled]="!peerConfigured.length > 0 ? true : null"
+ i18n
+ >Mirror Image Snapshot
</cds-checkbox>
</div>
</ng-container>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="snapshotForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="snapshotForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cd-table [data]="data"
- columnMode="flex"
- selectionType="single"
- (updateSelection)="updateSelection($event)"
- [columns]="columns">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="data"
+ columnMode="flex"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ [columns]="columns"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
-<ng-template #rollbackTpl
- let-value>
+<ng-template
+ #rollbackTpl
+ let-value
+>
<ng-container i18n>You are about to rollback</ng-container>
- <strong> {{ value.snapName }}</strong>.
+ <strong> {{ value.snapName }}</strong
+ >.
</ng-template>
<ul class="nav nav-tabs">
<li class="nav-item">
- <a class="nav-link"
- routerLink="/block/rbd"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Images</a>
+ <a
+ class="nav-link"
+ routerLink="/block/rbd"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Images</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="/block/rbd/namespaces"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Namespaces</a>
+ <a
+ class="nav-link"
+ routerLink="/block/rbd/namespaces"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Namespaces</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="/block/rbd/trash"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Trash</a>
+ <a
+ class="nav-link"
+ routerLink="/block/rbd/trash"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Trash</a
+ >
</li>
- <li class="nav-item"
- *ngIf="grafanaPermission.read">
- <a class="nav-link"
- routerLink="/block/rbd/performance"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Overall Performance</a>
+ <li
+ class="nav-item"
+ *ngIf="grafanaPermission.read"
+ >
+ <a
+ class="nav-link"
+ routerLink="/block/rbd/performance"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Overall Performance</a
+ >
</li>
</ul>
<cd-rbd-tabs></cd-rbd-tabs>
-<cd-table [data]="images"
- columnMode="flex"
- [columns]="columns"
- identifier="id"
- forceIdentifier="true"
- selectionType="single"
- [status]="tableStatus"
- [autoReload]="-1"
- (fetchData)="taskListService.fetch()"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ [data]="images"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="id"
+ forceIdentifier="true"
+ selectionType="single"
+ [status]="tableStatus"
+ [autoReload]="-1"
+ (fetchData)="taskListService.fetch()"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions class="btn-group"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <button cdsButton="tertiary"
- type="button"
- (click)="purgeModal()"
- [disabled]="disablePurgeBtn"
- *ngIf="permission.delete">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="purgeModal()"
+ [disabled]="disablePurgeBtn"
+ *ngIf="permission.delete"
+ >
<ng-container i18n>Purge Trash</ng-container>
- <svg class="cds--btn__icon"
- cdsIcon="close"
- size="16"></svg>
+ <svg
+ class="cds--btn__icon"
+ cdsIcon="close"
+ size="16"
+ ></svg>
</button>
</div>
</cd-table>
-<ng-template #expiresTpl
- let-row="data.row"
- let-value="data.value">
- <ng-container *ngIf="row.cdIsExpired"
- i18n>Expired at</ng-container>
+<ng-template
+ #expiresTpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <ng-container
+ *ngIf="row.cdIsExpired"
+ i18n
+ >Expired at</ng-container
+ >
- <ng-container *ngIf="!row.cdIsExpired"
- i18n>Protected until</ng-container>
+ <ng-container
+ *ngIf="!row.cdIsExpired"
+ i18n
+ >Protected until</ng-container
+ >
{{ value | cdDate }}
</ng-template>
-<ng-template #deleteTpl
- let-expiresAt="expiresAt"
- let-isExpired="isExpired">
- <p class="text-danger"
- *ngIf="!isExpired">
+<ng-template
+ #deleteTpl
+ let-expiresAt="expiresAt"
+ let-isExpired="isExpired"
+>
+ <p
+ class="text-danger"
+ *ngIf="!isExpired"
+ >
<strong>
<ng-container i18n>This image is protected until {{ expiresAt | cdDate }}.</ng-container>
</strong>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Move an image to trash</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Move an image to trash
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="moveForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="moveForm"
- novalidate>
- <cd-alert-panel type="warning"
- *ngIf="hasSnapshots"
- spacingClass="mb-2">
- <span i18n>This image contains snapshot(s), which will prevent it
- from being removed after moved to trash.</span>
+ <form
+ name="moveForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="moveForm"
+ novalidate
+ >
+ <cd-alert-panel
+ type="warning"
+ *ngIf="hasSnapshots"
+ spacingClass="mb-2"
+ >
+ <span i18n
+ >This image contains snapshot(s), which will prevent it from being removed after moved to
+ trash.</span
+ >
</cd-alert-panel>
- <p i18n>To move <kbd>{{ imageSpecStr }}</kbd> to trash,
- click <kbd>Move</kbd>. Optionally, you can pick an expiration date.</p>
+ <p i18n>
+ To move <kbd>{{ imageSpecStr }}</kbd> to trash, click <kbd>Move</kbd>. Optionally, you can
+ pick an expiration date.
+ </p>
<div class="form-item">
- <cds-checkbox formControlName="setExpiry"
- id="setExpiry"
- name="setExpiry"
- (checkedChange)="toggleExpiration()"
- modal-primary-focus
- i18n>Set expiration date</cds-checkbox>
+ <cds-checkbox
+ formControlName="setExpiry"
+ id="setExpiry"
+ name="setExpiry"
+ (checkedChange)="toggleExpiration()"
+ modal-primary-focus
+ i18n
+ >Set expiration date</cds-checkbox
+ >
</div>
- <div class="form-item"
- *ngIf="setExpirationDate">
- <cd-date-time-picker [control]="moveForm.get('expiresAt')"
- name="Protection expires at"
- i18n-name></cd-date-time-picker>
+ <div
+ class="form-item"
+ *ngIf="setExpirationDate"
+ >
+ <cd-date-time-picker
+ [control]="moveForm.get('expiresAt')"
+ name="Protection expires at"
+ i18n-name
+ ></cd-date-time-picker>
- <span class="invalid-feedback"
- *ngIf="moveForm.showError('expiresAt', formDir, 'format')"
- i18n>Wrong date format. Please use "YYYY-MM-DD HH:mm:ss".</span>
- <span class="invalid-feedback"
- *ngIf="moveForm.showError('expiresAt', formDir, 'expired')"
- i18n>Protection has already expired. Please pick a future date or leave it empty.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="moveForm.showError('expiresAt', formDir, 'format')"
+ i18n
+ >Wrong date format. Please use "YYYY-MM-DD HH:mm:ss".</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="moveForm.showError('expiresAt', formDir, 'expired')"
+ i18n
+ >Protection has already expired. Please pick a future date or leave it empty.</span
+ >
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="moveImage()"
- [form]="moveForm"
- [submitText]="actionLabels.MOVE"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="moveImage()"
+ [form]="moveForm"
+ [submitText]="actionLabels.MOVE"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="md"
- [open]="true"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="true"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Purge Trash</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Purge Trash
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="purgeForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="purgeForm"
- novalidate>
- <p i18n>To purge, select
- <kbd>All</kbd>
- or one pool and click
- <kbd>Purge</kbd>. </p>
+ <form
+ name="purgeForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="purgeForm"
+ novalidate
+ >
+ <p i18n>
+ To purge, select <kbd>All</kbd> or one pool and click
+ <kbd>Purge</kbd>.
+ </p>
<div class="form-item">
- <cds-select label="Pool"
- for="poolName"
- id="poolName"
- formControlName="poolName"
- *ngIf="poolPermission.read">
- <option value=""
- i18n>All</option>
- <option *ngFor="let pool of pools"
- [value]="pool">{{ pool }}</option>
+ <cds-select
+ label="Pool"
+ for="poolName"
+ id="poolName"
+ formControlName="poolName"
+ *ngIf="poolPermission.read"
+ >
+ <option
+ value=""
+ i18n
+ >
+ All
+ </option>
+ <option
+ *ngFor="let pool of pools"
+ [value]="pool"
+ >
+ {{ pool }}
+ </option>
</cds-select>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="purge()"
- [form]="purgeForm"
- [submitText]="actionLabels.PURGE"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="purge()"
+ [form]="purgeForm"
+ [submitText]="actionLabels.PURGE"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
-
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Restore Image</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Restore Image
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="restoreForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="restoreForm"
- novalidate>
- <p i18n>To restore
- <kbd>{{ imageSpec }}@{{ imageId }}</kbd>,
- type the image's new name and click
- <kbd>Restore</kbd>.</p>
+ <form
+ name="restoreForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="restoreForm"
+ novalidate
+ >
+ <p i18n>
+ To restore <kbd>{{ imageSpec }}@{{ imageId }}</kbd
+ >, type the image's new name and click <kbd>Restore</kbd>.
+ </p>
<div class="form-item">
- <cds-text-label for="name"
- i18n
- [invalid]="restoreForm.showError('name', formDir, 'required')"
- invalidText="The field is required"
- cdRequiredField="Name">Name
- <input cdsText
- name="name"
- id="name"
- formControlName="name"
- autocomplete="off"
- autofocus>
+ <cds-text-label
+ for="name"
+ i18n
+ [invalid]="restoreForm.showError('name', formDir, 'required')"
+ invalidText="The field is required"
+ cdRequiredField="Name"
+ >Name
+ <input
+ cdsText
+ name="name"
+ id="name"
+ formControlName="name"
+ autocomplete="off"
+ autofocus
+ />
</cds-text-label>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="restore()"
- [form]="restoreForm"
- [submitText]="actionLabels.RESTORE"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="restore()"
+ [form]="restoreForm"
+ [submitText]="actionLabels.RESTORE"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
<section class="cds--modal-content">
- <form name="form"
- #formDir="ngForm"
- [formGroup]="form">
-
- <!-- FsName -->
- <div class="form-item">
- <cds-text-label for="fsName"
- i18n
- cdRequiredField="FS name"
- [invalid]="!form.controls['fsName'].valid && (form.controls['fsName'].dirty)"
- [invalidText]="fsNameError"
- i18n-invalidText>FS name
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="fsName"
- name="fsName"
- formControlName="fsName"
- size="sm"
- [invalid]="!form.controls['fsName'].valid && (form.controls['fsName'].dirty)"
- autofocus>
- </cds-text-label>
- <ng-template #fsNameError>
- <span class="invalid-feedback"
- *ngIf="form.showError('fsName', formDir, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <form
+ name="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ >
+ <!-- FsName -->
+ <div class="form-item">
+ <cds-text-label
+ for="fsName"
+ i18n
+ cdRequiredField="FS name"
+ [invalid]="!form.controls['fsName'].valid && form.controls['fsName'].dirty"
+ [invalidText]="fsNameError"
+ i18n-invalidText
+ >FS name
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="fsName"
+ name="fsName"
+ formControlName="fsName"
+ size="sm"
+ [invalid]="!form.controls['fsName'].valid && form.controls['fsName'].dirty"
+ autofocus
+ />
+ </cds-text-label>
+ <ng-template #fsNameError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('fsName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
- <!-- UserId -->
- <div class="form-item">
- <cds-text-label for="userId"
- i18n
- cdRequiredField="User ID"
- [helperText]="userIdHelperText"
- [invalid]="!form.controls['userId'].valid && (form.controls['userId'].dirty)"
- [invalidText]="userIdError"
- i18n-invalidText>User ID
- <input cdsText
- value="client."
- readonly>
+ <!-- UserId -->
+ <div class="form-item">
+ <cds-text-label
+ for="userId"
+ i18n
+ cdRequiredField="User ID"
+ [helperText]="userIdHelperText"
+ [invalid]="!form.controls['userId'].valid && form.controls['userId'].dirty"
+ [invalidText]="userIdError"
+ i18n-invalidText
+ >User ID
+ <input
+ cdsText
+ value="client."
+ readonly
+ />
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="userId"
- name="userId"
- formControlName="userId"
- [invalid]="!form.controls['userId'].valid && (form.controls['userId'].dirty)">
- </cds-text-label>
- <ng-template #userIdHelperText>
- You can manage users from
- <a routerLink="/ceph-users"
- (click)="closeModal()">Ceph Users</a>
- page
- </ng-template>
- <ng-template #userIdError>
- <span class="invalid-feedback"
- *ngIf="form.showError('userId', formDir, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="userId"
+ name="userId"
+ formControlName="userId"
+ [invalid]="!form.controls['userId'].valid && form.controls['userId'].dirty"
+ />
+ </cds-text-label>
+ <ng-template #userIdHelperText>
+ You can manage users from
+ <a
+ routerLink="/ceph-users"
+ (click)="closeModal()"
+ >Ceph Users</a
+ >
+ page
+ </ng-template>
+ <ng-template #userIdError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('userId', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
- <!-- Directory -->
- <div class="form-item">
- <cds-text-label for="directory"
- i18n
- cdRequiredField="Directory"
- [invalid]="!form.controls['directory'].valid && (form.controls['directory'].dirty)"
- [invalidText]="directoryError"
- helperText="Path to restrict access to"
- [skeleton]="directoryStore.isLoading"
- i18n-invalidText
- i18n-helperText>Directory
- <input cdsText
- type="text"
- [placeholder]="directoryStore.isLoading ? '' : 'Directory path'"
- i18n-placeholder
- id="directory"
- name="directory"
- formControlName="directory"
- [skeleton]="directoryStore.isLoading"
- [invalid]="!form.controls['directory'].valid && (form.controls['directory'].dirty)"
- [ngbTypeahead]="search">
- </cds-text-label>
- <ng-template #directoryError>
- <span class="invalid-feedback"
- *ngIf="form.showError('directory', formDir, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <!-- Directory -->
+ <div class="form-item">
+ <cds-text-label
+ for="directory"
+ i18n
+ cdRequiredField="Directory"
+ [invalid]="!form.controls['directory'].valid && form.controls['directory'].dirty"
+ [invalidText]="directoryError"
+ helperText="Path to restrict access to"
+ [skeleton]="directoryStore.isLoading"
+ i18n-invalidText
+ i18n-helperText
+ >Directory
+ <input
+ cdsText
+ type="text"
+ [placeholder]="directoryStore.isLoading ? '' : 'Directory path'"
+ i18n-placeholder
+ id="directory"
+ name="directory"
+ formControlName="directory"
+ [skeleton]="directoryStore.isLoading"
+ [invalid]="!form.controls['directory'].valid && form.controls['directory'].dirty"
+ [ngbTypeahead]="search"
+ />
+ </cds-text-label>
+ <ng-template #directoryError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('directory', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
- <!-- Permissions -->
- <div class="form-item">
- <fieldset>
- <legend class="cds--label"
- i18n>Permissions</legend>
+ <!-- Permissions -->
+ <div class="form-item">
+ <fieldset>
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Permissions
+ </legend>
<ng-container *ngFor="let permission of clientPermissions">
- <cds-checkbox i18n-label
- [id]="permission.name"
- [name]="permission.name"
- [formControlName]="permission.name"
- (checkedChange)="toggleFormControl($event, permission.name)">
- {{ permission.name | titlecase }}
- <cd-help-text *ngIf="permission.description">
- {{ permission.description }}
- </cd-help-text>
- </cds-checkbox>
- </ng-container>
- </fieldset>
+ <cds-checkbox
+ i18n-label
+ [id]="permission.name"
+ [name]="permission.name"
+ [formControlName]="permission.name"
+ (checkedChange)="toggleFormControl($event, permission.name)"
+ >
+ {{ permission.name | titlecase }}
+ <cd-help-text *ngIf="permission.description">
+ {{ permission.description }}
+ </cd-help-text>
+ </cds-checkbox>
+ </ng-container>
+ </fieldset>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="form"
- [submitText]="(action | titlecase)"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="action | titlecase"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</ng-container>
</cds-modal>
<div class="chart-container">
- <canvas baseChart
- #chartCanvas
- [datasets]="chart.datasets"
- [options]="chart.options"
- [type]="chart.chartType">
+ <canvas
+ baseChart
+ #chartCanvas
+ [datasets]="chart.datasets"
+ [options]="chart.options"
+ [type]="chart.chartType"
+ >
</canvas>
- <div class="chartjs-tooltip"
- #chartTooltip>
+ <div
+ class="chartjs-tooltip"
+ #chartTooltip
+ >
<table></table>
</div>
</div>
-<cd-table [data]="clients.data"
- [columns]="columns"
- [status]="clients.status"
- [autoReload]="-1"
- (fetchData)="triggerApiUpdate.emit()"
- selectionType="single"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="clients.data"
+ [columns]="columns"
+ [status]="clients.status"
+ [autoReload]="-1"
+ (fetchData)="triggerApiUpdate.emit()"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
<div class="row">
<div class="col-sm-8">
<legend i18n>Ranks</legend>
- <cd-table [data]="data.ranks"
- [columns]="columns.ranks"
- [toolHeader]="false">
+ <cd-table
+ [data]="data.ranks"
+ [columns]="columns.ranks"
+ [toolHeader]="false"
+ >
</cd-table>
<legend i18n>Pools</legend>
- <cd-table [data]="data.pools"
- [columns]="columns.pools"
- [toolHeader]="false">
+ <cd-table
+ [data]="data.pools"
+ [columns]="columns.pools"
+ [toolHeader]="false"
+ >
</cd-table>
</div>
<div class="col-sm-4">
<legend i18n>Standbys</legend>
- <cd-table-key-value [data]="standbys">
- </cd-table-key-value>
+ <cd-table-key-value [data]="standbys"> </cd-table-key-value>
</div>
</div>
<legend i18n>MDS performance counters</legend>
-<div class="row"
- *ngFor="let mdsCounter of objectValues(data.mdsCounters); trackBy: trackByFn">
+<div
+ class="row"
+ *ngFor="let mdsCounter of objectValues(data.mdsCounters); trackBy: trackByFn"
+>
<div class="col-md-12">
<cd-cephfs-chart [mdsCounter]="mdsCounter"></cd-cephfs-chart>
</div>
</div>
<!-- templates -->
-<ng-template #poolUsageTpl
- let-row="data.row">
- <cd-usage-bar [total]="row.size"
- [used]="row.used"
- [title]="row.pool_name"></cd-usage-bar>
+<ng-template
+ #poolUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ [total]="row.size"
+ [used]="row.used"
+ [title]="row.pool_name"
+ ></cd-usage-bar>
</ng-template>
-<ng-template #activityTmpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #activityTmpl
+ let-row="data.row"
+ let-value="data.value"
+>
{{ row.state === 'standby-replay' ? 'Evts' : 'Reqs' }}: {{ value | dimless }} /s
</ng-template>
<div class="col-sm-4 pe-0">
<div class="card">
<div class="card-header">
- <button type="button"
- [class.disabled]="loadingIndicator"
- class="btn btn-light pull-right"
- (click)="refreshAllDirectories()">
- <svg [cdsIcon]="icons.refresh"
- [size]="icons.size16"></svg>
+ <button
+ type="button"
+ [class.disabled]="loadingIndicator"
+ class="btn btn-light pull-right"
+ (click)="refreshAllDirectories()"
+ >
+ <svg
+ [cdsIcon]="icons.refresh"
+ [size]="icons.size16"
+ ></svg>
</button>
</div>
<div class="card-body card-tree">
- <cds-tree-view [tree]="nodes"
- (select)="selectNode($event)">
+ <cds-tree-view
+ [tree]="nodes"
+ (select)="selectNode($event)"
+ >
</cds-tree-view>
<div *ngIf="loadingIndicator">
- <cds-loading [isActive]="true"
- [overlay]="false"
- size="sm"></cds-loading>
+ <cds-loading
+ [isActive]="true"
+ [overlay]="false"
+ size="sm"
+ ></cds-loading>
</div>
</div>
</div>
</div>
<!-- Selection details -->
- <div class="col-sm-8 metadata"
- *ngIf="selectedDir">
+ <div
+ class="col-sm-8 metadata"
+ *ngIf="selectedDir"
+ >
<div class="card">
<div class="card-header">
{{ selectedDir.path }}
<div class="card-body">
<ng-container *ngIf="selectedDir.path !== '/'">
<legend i18n>Quotas</legend>
- <cd-table [data]="settings"
- [columns]="quota.columns"
- [limit]="0"
- [footer]="false"
- selectionType="single"
- (updateSelection)="quota.updateSelection($event)"
- [onlyActionHeader]="true"
- identifier="quotaKey"
- [forceIdentifier]="true"
- [toolHeader]="false">
- <cd-table-actions class="only-table-actions"
- [permission]="permission"
- [selection]="quota.selection"
- [tableActions]="quota.tableActions">
+ <cd-table
+ [data]="settings"
+ [columns]="quota.columns"
+ [limit]="0"
+ [footer]="false"
+ selectionType="single"
+ (updateSelection)="quota.updateSelection($event)"
+ [onlyActionHeader]="true"
+ identifier="quotaKey"
+ [forceIdentifier]="true"
+ [toolHeader]="false"
+ >
+ <cd-table-actions
+ class="only-table-actions"
+ [permission]="permission"
+ [selection]="quota.selection"
+ [tableActions]="quota.tableActions"
+ >
</cd-table-actions>
</cd-table>
</ng-container>
<legend i18n>Snapshots</legend>
- <cd-table [data]="selectedDir.snapshots"
- [columns]="snapshot.columns"
- identifier="name"
- forceIdentifier="true"
- selectionType="single"
- (updateSelection)="snapshot.updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="snapshot.selection"
- [tableActions]="snapshot.tableActions">
+ <cd-table
+ [data]="selectedDir.snapshots"
+ [columns]="snapshot.columns"
+ identifier="name"
+ forceIdentifier="true"
+ selectionType="single"
+ (updateSelection)="snapshot.updateSelection($event)"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="snapshot.selection"
+ [tableActions]="snapshot.tableActions"
+ >
</cd-table-actions>
</cd-table>
</div>
</div>
</div>
-<ng-template #origin
- let-row="data.row"
- let-value="data.value">
- <span class="quota-origin"
- tabindex="0"
- (keydown.enter)="selectOrigin(value)"
- (click)="selectOrigin(value)">{{value}}</span>
+<ng-template
+ #origin
+ let-row="data.row"
+ let-value="data.value"
+>
+ <span
+ class="quota-origin"
+ tabindex="0"
+ (keydown.enter)="selectOrigin(value)"
+ (click)="selectOrigin(value)"
+ >{{ value }}</span
+ >
</ng-template>
<div cds-mb="lg">
- <div class="cds--type-heading-03"
- i18n>Select filesystem</div>
+ <div
+ class="cds--type-heading-03"
+ i18n
+ >
+ Select filesystem
+ </div>
</div>
<div class="cds-mt-5">
<cd-alert-panel type="info">
- <div [cdsStack]="'vertical'"
- [gap]="2">
- <div class="cds--type-heading-compact-01"
- i18n>Selection requirements</div>
+ <div
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
+ <div
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Selection requirements
+ </div>
<ul class="cds--type-body-compact-01 requirements-list">
<li i18n>Only one filesystem can be selected as the mirroring target</li>
<li i18n>The selected filesystem must have an active MDS (Metadata Server)</li>
</div>
<div class="cds-mt-5">
- <cd-table [data]="(filesystems$ | async) ?? []"
- [columns]="columns"
- columnMode="flex"
- selectionType="singleRadio"
- headerTitle="Select target filesystem"
- headerDescription="Choose the filesystem that will receive mirrored data from the local cluster."
- (updateSelection)="updateSelection($event)">
- <ng-template #mdsStatus
- let-value="data.value"
- let-row="data.row">
- <div [cdsStack]="'horizontal'"
- gap="2">
+ <cd-table
+ [data]="(filesystems$ | async) ?? []"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="singleRadio"
+ headerTitle="Select target filesystem"
+ headerDescription="Choose the filesystem that will receive mirrored data from the local cluster."
+ (updateSelection)="updateSelection($event)"
+ >
+ <ng-template
+ #mdsStatus
+ let-value="data.value"
+ let-row="data.row"
+ >
+ <div
+ [cdsStack]="'horizontal'"
+ gap="2"
+ >
@if (value === 'Active') {
- <cd-icon type="success"></cd-icon>
+ <cd-icon type="success"></cd-icon>
}
@if (value === 'Warning') {
- <cd-icon type="warning"></cd-icon>
+ <cd-icon type="warning"></cd-icon>
}
@if (value === 'Inactive') {
- <cd-icon type="error"></cd-icon>
+ <cd-icon type="error"></cd-icon>
}
<span class="cds--type-body-compact-01 cds-pt-2px">{{ mdsStatusLabels[value] }}</span>
</div>
</ng-template>
- <ng-template #mirroringStatus
- let-value="data.value"
- let-row="data.row">
- <div [cdsStack]="'horizontal'"
- gap="2">
+ <ng-template
+ #mirroringStatus
+ let-value="data.value"
+ let-row="data.row"
+ >
+ <div
+ [cdsStack]="'horizontal'"
+ gap="2"
+ >
@if (value === 'Enabled') {
- <cd-icon type="success"></cd-icon>
+ <cd-icon type="success"></cd-icon>
}
@if (value === 'Disabled') {
- <cd-icon type="warning"></cd-icon>
+ <cd-icon type="warning"></cd-icon>
}
<span class="cds--type-body-compact-01 cds-pt-2px">{{ mirroringStatusLabels[value] }}</span>
</div>
</ng-template>
- <ng-template let-row="row"
- let-col="col">
+ <ng-template
+ let-row="row"
+ let-col="col"
+ >
<ng-container [ngSwitch]="col.prop">
<ng-container *ngSwitchCase="'pools'">
@for (pool of row.pools; track $index; let last = $last) {
- <cd-badge>{{ pool }}</cd-badge>
- @if (!last) {
- <span>, </span>
- }
+ <cd-badge>{{ pool }}</cd-badge>
+ @if (!last) {
+ <span>, </span>
+ }
}
</ng-container>
<ng-container *ngSwitchDefault>
-<div cdsCol
- [columnNumbers]="{md: 4}"
- *ngIf="orchStatus$ | async as orchStatus">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ *ngIf="orchStatus$ | async as orchStatus"
+>
<ng-container *cdFormLoading="loading">
- <form #frm="ngForm"
- #formDir="ngForm"
- [formGroup]="form"
- novalidate>
- <div i18n="form title|Example: Create Volume@@formTitle"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+ <form
+ #frm="ngForm"
+ #formDir="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
+ <div
+ i18n="form title|Example: Create Volume@@formTitle"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
<div class="form-item">
<ng-container *ngIf="!orchStatus.available">
- <cd-alert-panel type="info"
- spacingClass="mb-2"
- i18n
- *ngIf="!editing">Orchestrator is not configured. Deploy MDS daemons manually after creating the volume.</cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-2"
+ i18n
+ *ngIf="!editing"
+ >Orchestrator is not configured. Deploy MDS daemons manually after creating the
+ volume.</cd-alert-panel
+ >
</ng-container>
- <cd-alert-panel type="info"
- spacingClass="mb-2"
- i18n
- *ngIf="editing && disableRename">
- <p>The File System can only be renamed if it is shutdown and `refuse_client_session` is set to true.
- Follow the steps below in the command line and refresh the page:</p>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-2"
+ i18n
+ *ngIf="editing && disableRename"
+ >
+ <p>
+ The File System can only be renamed if it is shutdown and `refuse_client_session` is set
+ to true. Follow the steps below in the command line and refresh the page:
+ </p>
<cd-code-block [codes]="[fsFailCmd]"></cd-code-block>
<cd-code-block [codes]="[fsSetCmd]"></cd-code-block>
</cd-alert-panel>
</div>
- <!-- Name -->
- <div class="form-item">
- <cds-text-label for="name"
- cdRequiredField="Name"
- [invalid]="!form.controls.name.valid && form.controls.name.dirty"
- [invalidText]="nameError"
- i18n>Name
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="name"
- name="name"
- formControlName="name"
- [invalid]="!form.controls.name.valid && form.controls.name.dirty"
- autofocus>
- </cds-text-label>
- <ng-template #nameError>
- <span class="invalid-feedback"
- *ngIf="form.showError('name', formDir, 'required')"
- i18n>This field is required!</span>
- <span *ngIf="form.showError('name', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>File System name should start with a letter or dot (.) and can only contain letters, numbers, '.', '-' or '_'</span>
- </ng-template>
- </div>
+ <!-- Name -->
+ <div class="form-item">
+ <cds-text-label
+ for="name"
+ cdRequiredField="Name"
+ [invalid]="!form.controls.name.valid && form.controls.name.dirty"
+ [invalidText]="nameError"
+ i18n
+ >Name
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="name"
+ name="name"
+ formControlName="name"
+ [invalid]="!form.controls.name.valid && form.controls.name.dirty"
+ autofocus
+ />
+ </cds-text-label>
+ <ng-template #nameError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('name', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
+ <span
+ *ngIf="form.showError('name', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >File System name should start with a letter or dot (.) and can only contain letters,
+ numbers, '.', '-' or '_'</span
+ >
+ </ng-template>
+ </div>
- <div class="form-item"
- *ngIf="!editing">
- <cds-checkbox id="customPools"
- name="customPools"
- formControlName="customPools"
- i18n>Use existing pools
- <cd-help-text>Allows you to use replicated pools with 'cephfs' application tag that are already created.</cd-help-text>
- </cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="!editing"
+ >
+ <cds-checkbox
+ id="customPools"
+ name="customPools"
+ formControlName="customPools"
+ i18n
+ >Use existing pools
+ <cd-help-text
+ >Allows you to use replicated pools with 'cephfs' application tag that are already
+ created.</cd-help-text
+ >
+ </cds-checkbox>
- <cd-alert-panel *ngIf="pools.length < 2"
- type="info"
- spacingClass="mt-1"
- i18n>
- You need to have atleast 2 pools that are empty, applied with cephfs label and not erasure-coded.
- </cd-alert-panel>
- </div>
+ <cd-alert-panel
+ *ngIf="pools.length < 2"
+ type="info"
+ spacingClass="mt-1"
+ i18n
+ >
+ You need to have atleast 2 pools that are empty, applied with cephfs label and not
+ erasure-coded.
+ </cd-alert-panel>
+ </div>
- <!-- Data pool -->
- <div class="form-item"
- *ngIf="form.get('customPools')?.value || editing">
- <cds-text-label for="dataPool"
- i18n
- *ngIf="editing">Data pool
- <input cdsText
- type="text"
- placeholder="Pool name..."
- id="dataPool"
- name="dataPool"
- formControlName="dataPool">
- </cds-text-label>
- <cds-select label="Data pool"
- for="dataPool"
- name="dataPool"
- id="dataPool"
- formControlName="dataPool"
- (valueChange)="onPoolChange($event)"
- cdRequiredField="Data pool"
- [invalid]="!form.controls.dataPool.valid && form.controls.dataPool.dirty"
- [invalidText]="dataPoolError"
- *ngIf="!editing">
- <option *ngIf="dataPools === null"
- [ngValue]="null"
- i18n>Loading...</option>
- <option *ngIf="dataPools !== null && dataPools?.length === 0"
- [ngValue]="null"
- i18n>-- No cephfs pools available --</option>
- <option *ngIf="dataPools !== null && dataPools?.length > 0"
- [ngValue]="null"
- i18n>-- Select a pool --</option>
- <option *ngFor="let pool of dataPools"
- [value]="pool?.pool_name">{{ pool?.pool_name }}</option>
- </cds-select>
- <ng-template #dataPoolError>
- <span class="invalid-feedback"
- *ngIf="form.showError('dataPool', formDir, 'required')"
- i18n>This field is required!</span>
- </ng-template>
- </div>
+ <!-- Data pool -->
+ <div
+ class="form-item"
+ *ngIf="form.get('customPools')?.value || editing"
+ >
+ <cds-text-label
+ for="dataPool"
+ i18n
+ *ngIf="editing"
+ >Data pool
+ <input
+ cdsText
+ type="text"
+ placeholder="Pool name..."
+ id="dataPool"
+ name="dataPool"
+ formControlName="dataPool"
+ />
+ </cds-text-label>
+ <cds-select
+ label="Data pool"
+ for="dataPool"
+ name="dataPool"
+ id="dataPool"
+ formControlName="dataPool"
+ (valueChange)="onPoolChange($event)"
+ cdRequiredField="Data pool"
+ [invalid]="!form.controls.dataPool.valid && form.controls.dataPool.dirty"
+ [invalidText]="dataPoolError"
+ *ngIf="!editing"
+ >
+ <option
+ *ngIf="dataPools === null"
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="dataPools !== null && dataPools?.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No cephfs pools available --
+ </option>
+ <option
+ *ngIf="dataPools !== null && dataPools?.length > 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a pool --
+ </option>
+ <option
+ *ngFor="let pool of dataPools"
+ [value]="pool?.pool_name"
+ >
+ {{ pool?.pool_name }}
+ </option>
+ </cds-select>
+ <ng-template #dataPoolError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('dataPool', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
+ </ng-template>
+ </div>
- <!-- Metadata pool -->
- <div class="form-item"
- *ngIf="form.get('customPools')?.value || editing">
- <cds-text-label for="metadataPool"
- i18n
- *ngIf="editing">Metadata pool
- <input cdsText
- type="text"
- placeholder="Pool name..."
- id="metadataPool"
- name="metadataPool"
- formControlName="metadataPool">
- </cds-text-label>
- <cds-select label="Metadata pool"
- for="metadataPool"
- name="metadataPool"
- id="metadataPool"
- formControlName="metadataPool"
- cdRequiredField="Metadata pool"
- [invalid]="!form.controls.metadataPool.valid && form.controls.metadataPool.dirty"
- [invalidText]="metadataPoolError"
- (valueChange)="onPoolChange($event, true)"
- *ngIf="!editing">
- <option *ngIf="metadatPools === null"
- [ngValue]="null"
- i18n>Loading...</option>
- <option *ngIf="metadatPools !== null && metadatPools?.length === 0"
- [ngValue]="null"
- i18n>-- No cephfs pools available --</option>
- <option *ngIf="metadatPools !== null && metadatPools?.length > 0"
- [ngValue]="null"
- i18n>-- Select a pool --</option>
- <option *ngFor="let pool of metadatPools"
- [value]="pool?.pool_name">{{ pool?.pool_name }}</option>
+ <!-- Metadata pool -->
+ <div
+ class="form-item"
+ *ngIf="form.get('customPools')?.value || editing"
+ >
+ <cds-text-label
+ for="metadataPool"
+ i18n
+ *ngIf="editing"
+ >Metadata pool
+ <input
+ cdsText
+ type="text"
+ placeholder="Pool name..."
+ id="metadataPool"
+ name="metadataPool"
+ formControlName="metadataPool"
+ />
+ </cds-text-label>
+ <cds-select
+ label="Metadata pool"
+ for="metadataPool"
+ name="metadataPool"
+ id="metadataPool"
+ formControlName="metadataPool"
+ cdRequiredField="Metadata pool"
+ [invalid]="!form.controls.metadataPool.valid && form.controls.metadataPool.dirty"
+ [invalidText]="metadataPoolError"
+ (valueChange)="onPoolChange($event, true)"
+ *ngIf="!editing"
+ >
+ <option
+ *ngIf="metadatPools === null"
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="metadatPools !== null && metadatPools?.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No cephfs pools available --
+ </option>
+ <option
+ *ngIf="metadatPools !== null && metadatPools?.length > 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a pool --
+ </option>
+ <option
+ *ngFor="let pool of metadatPools"
+ [value]="pool?.pool_name"
+ >
+ {{ pool?.pool_name }}
+ </option>
+ </cds-select>
+ <ng-template #metadataPoolError>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('metadataPool', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
+ </ng-template>
+ </div>
+
+ <ng-container *ngIf="orchStatus.available">
+ <!-- Placement -->
+ <div
+ class="form-item"
+ *ngIf="!editing"
+ >
+ <cds-select
+ label="Placement"
+ for="placement"
+ formControlName="placement"
+ name="placement"
+ id="placement"
+ i18n
+ >
+ <option value="hosts">Hosts</option>
+ <option value="label">Labels</option>
</cds-select>
- <ng-template #metadataPoolError>
- <span class="invalid-feedback"
- *ngIf="form.showError('metadataPool', formDir, 'required')"
- i18n>This field is required!</span>
- </ng-template>
</div>
- <ng-container *ngIf="orchStatus.available">
- <!-- Placement -->
- <div class="form-item"
- *ngIf="!editing">
- <cds-select label="Placement"
- for="placement"
- formControlName="placement"
- name="placement"
- id="placement"
- i18n>
- <option value="hosts">Hosts</option>
- <option value="label">Labels</option>
- </cds-select>
- </div>
-
- <ng-container *ngIf="hostsAndLabels$ | async as data">
+ <ng-container *ngIf="hostsAndLabels$ | async as data">
<!-- Label -->
- <div *ngIf="form.controls.placement.value === 'label' && !editing"
- class="form-item">
- <cds-combo-box type="multi"
- selectionFeedback="top-after-reopen"
- label="Label"
- for="label"
- name="label"
- formControlName="label"
- id="label"
- placeholder="Select labels..."
- [appendInline]="true"
- [items]="data.labels"
- i18n-placeholder
- (selected)="multiSelector($event, 'label')"
- [invalid]="form.controls.label.invalid && (form.controls.label.dirty)"
- [invalidText]="labelError"
- cdRequiredField="Label"
- cdDynamicInputCombobox
- (updatedItems)="data.labels = $event"
- i18n>
+ <div
+ *ngIf="form.controls.placement.value === 'label' && !editing"
+ class="form-item"
+ >
+ <cds-combo-box
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ label="Label"
+ for="label"
+ name="label"
+ formControlName="label"
+ id="label"
+ placeholder="Select labels..."
+ [appendInline]="true"
+ [items]="data.labels"
+ i18n-placeholder
+ (selected)="multiSelector($event, 'label')"
+ [invalid]="form.controls.label.invalid && form.controls.label.dirty"
+ [invalidText]="labelError"
+ cdRequiredField="Label"
+ cdDynamicInputCombobox
+ (updatedItems)="data.labels = $event"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
<ng-template #labelError>
- <span class="invalid-feedback"
- *ngIf="form.showError('label', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('label', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Hosts -->
- <div *ngIf="form.controls.placement.value === 'hosts' && !editing"
- class="form-item">
- <cds-combo-box type="multi"
- selectionFeedback="top-after-reopen"
- label="Hosts"
- for="hosts"
- name="hosts"
- formControlName="hosts"
- id="hosts"
- placeholder="Select hosts..."
- i18n-placeholder
- [appendInline]="true"
- [items]="data.hosts"
- (selected)="multiSelector($event, 'hosts')"
- i18n>
+ <div
+ *ngIf="form.controls.placement.value === 'hosts' && !editing"
+ class="form-item"
+ >
+ <cds-combo-box
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ label="Hosts"
+ for="hosts"
+ name="hosts"
+ formControlName="hosts"
+ id="hosts"
+ placeholder="Select hosts..."
+ i18n-placeholder
+ [appendInline]="true"
+ [items]="data.hosts"
+ (selected)="multiSelector($event, 'hosts')"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</div>
</ng-container>
</ng-container>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="formDir"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [disabled]="editing ? disableRename: false"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="formDir"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [disabled]="editing ? disableRename : false"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</ng-container>
</div>
[followFocus]="true"
[isNavigation]="false"
[cacheActive]="true"
- >
+>
<cds-tab
heading="File systems"
i18n-heading
- [tabContent]="fileSystemListContent">
+ [tabContent]="fileSystemListContent"
+ >
</cds-tab>
<cds-tab
heading="Overview"
i18n-heading
- [tabContent]="grafanaContent">
+ [tabContent]="grafanaContent"
+ >
</cds-tab>
</cds-tabs>
>
<cd-cephfs-tabs
*cdTableDetail
- [selection]="expandedRow">
+ [selection]="expandedRow"
+ >
</cd-cephfs-tabs>
<div class="table-actions">
<cd-table-actions
</ng-template>
<ng-template #deleteTpl>
- <cd-alert-panel type="danger"
- i18n>
- This will remove its data and metadata pools. It'll also remove the MDS daemon associated with the volume.
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
+ This will remove its data and metadata pools. It'll also remove the MDS daemon associated with
+ the volume.
</cd-alert-panel>
</ng-template>
<div class="scroll-overflow">
<div
[cdsStack]="'vertical'"
- gap="3">
+ gap="3"
+ >
<div
class="cds--type-heading-03"
- i18n>Create or select entity</div>
+ i18n
+ >
+ Create or select entity
+ </div>
<p
class="cds--type-body-01"
- i18n>
+ i18n
+ >
Choose an existing CephFS mirroring entity or create a new one to be used for mirroring.
</p>
</div>
<cds-radio
[value]="true"
(click)="onCreateEntitySelected()"
- i18n> Create new entity </cds-radio>
+ i18n
+ >
+ Create new entity
+ </cds-radio>
<cds-radio
[value]="false"
(click)="onExistingEntitySelected()"
- i18n> Use existing entity </cds-radio>
+ i18n
+ >
+ Use existing entity
+ </cds-radio>
</cds-radio-group>
</div>
@if (isCreatingNewEntity) {
- @if (showCreateRequirementsWarning) {
- <cd-alert-panel
- type="warning"
- class="cds-ml-3 cds-mr-3"
- dismissible="true"
- (dismissed)="onDismissCreateRequirementsWarning()">
- <div
- [cdsStack]="'vertical'"
- gap="2">
- <div
- class="cds--type-heading-compact-01"
- i18n>Mirroring entity requirements</div>
- <div
- class="cds--type-body-compact-01"
- i18n>
- This entity will be used by the mirroring service to manage snapshots and replication.
- It will require the proper permissions to replicate data.
- </div>
- </div>
- </cd-alert-panel>
- }
-
- @if (showCreateCapabilitiesInfo) {
- <cd-alert-panel
- type="info"
- dismissible="true"
- (dismissed)="onDismissCreateCapabilitiesInfo()">
- <div
- [cdsStack]="'vertical'"
- gap="1">
- <div
- class="cds--type-heading-compact-01"
- i18n>Capabilities added automatically.</div>
- <div
- class="cds--type-body-compact-01 requirements-list"
- i18n>
- If you create a new entity, the following capabilities will be assigned automatically:
- </div>
- <ul class="list-disc">
- @for (cap of capabilities; track cap.name) {
- <li>
- {{ cap.name }}: {{ cap.permission }}
- </li>
- }
- </ul>
- </div>
- </cd-alert-panel>
- }
+ @if (showCreateRequirementsWarning) {
+ <cd-alert-panel
+ type="warning"
+ class="cds-ml-3 cds-mr-3"
+ dismissible="true"
+ (dismissed)="onDismissCreateRequirementsWarning()"
+ >
+ <div
+ [cdsStack]="'vertical'"
+ gap="2"
+ >
+ <div
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Mirroring entity requirements
+ </div>
+ <div
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ This entity will be used by the mirroring service to manage snapshots and replication.
+ It will require the proper permissions to replicate data.
+ </div>
+ </div>
+ </cd-alert-panel>
+ }
- <form
- name="entityForm"
- #formDir="ngForm"
- [formGroup]="entityForm"
- novalidate>
- <div
- [cdsStack]="'vertical'"
- gap="5"
- class="form-item form-item-append cds-mt-5">
- <cds-text-label
- labelInputID="user_entity"
- i18n
- cdRequiredField="Ceph entity"
- [helperText]="userEntityHelperText"
- [invalid]="!entityForm.controls['user_entity'].valid && (entityForm.controls['user_entity'].dirty)"
- [invalidText]="userEntityError"
- i18n-invalidText>
- Ceph entity
+ @if (showCreateCapabilitiesInfo) {
+ <cd-alert-panel
+ type="info"
+ dismissible="true"
+ (dismissed)="onDismissCreateCapabilitiesInfo()"
+ >
<div
- [cdsStack]="'horizontal'"
- gap="0">
- <input
- cdsText
- value="client."
- readonly
- name="client_prefix" />
- <input
- cdsText
- name="user_entity"
- formControlName="user_entity"
- [invalid]="!entityForm.controls['user_entity'].valid && (entityForm.controls['user_entity'].dirty)" />
+ [cdsStack]="'vertical'"
+ gap="1"
+ >
+ <div
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Capabilities added automatically.
+ </div>
+ <div
+ class="cds--type-body-compact-01 requirements-list"
+ i18n
+ >
+ If you create a new entity, the following capabilities will be assigned automatically:
+ </div>
+ <ul class="list-disc">
+ @for (cap of capabilities; track cap.name) {
+ <li>{{ cap.name }}: {{ cap.permission }}</li>
+ }
+ </ul>
</div>
- </cds-text-label>
+ </cd-alert-panel>
+ }
- <ng-template #userEntityError>
- @if (entityForm.showError('user_entity', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (entityForm.showError('user_entity', formDir, 'forbiddenClientPrefix')) {
- <span
- class="invalid-feedback"
- i18n>Do not include 'client.' prefix. Enter only the entity suffix.</span>
- }
- </ng-template>
- </div>
- <div>
- <cd-form-button-panel
- (submitActionEvent)="submitAction()"
- [form]="entityForm"
- submitText="Create entity"
- i18n-submitText
- [showCancel]="false">
- </cd-form-button-panel>
- </div>
- </form>
+ <form
+ name="entityForm"
+ #formDir="ngForm"
+ [formGroup]="entityForm"
+ novalidate
+ >
+ <div
+ [cdsStack]="'vertical'"
+ gap="5"
+ class="form-item form-item-append cds-mt-5"
+ >
+ <cds-text-label
+ labelInputID="user_entity"
+ i18n
+ cdRequiredField="Ceph entity"
+ [helperText]="userEntityHelperText"
+ [invalid]="
+ !entityForm.controls['user_entity'].valid && entityForm.controls['user_entity'].dirty
+ "
+ [invalidText]="userEntityError"
+ i18n-invalidText
+ >
+ Ceph entity
+ <div
+ [cdsStack]="'horizontal'"
+ gap="0"
+ >
+ <input
+ cdsText
+ value="client."
+ readonly
+ name="client_prefix"
+ />
+ <input
+ cdsText
+ name="user_entity"
+ formControlName="user_entity"
+ [invalid]="
+ !entityForm.controls['user_entity'].valid &&
+ entityForm.controls['user_entity'].dirty
+ "
+ />
+ </div>
+ </cds-text-label>
+
+ <ng-template #userEntityError>
+ @if (entityForm.showError('user_entity', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (entityForm.showError('user_entity', formDir, 'forbiddenClientPrefix')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Do not include 'client.' prefix. Enter only the entity suffix.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <div>
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="entityForm"
+ submitText="Create entity"
+ i18n-submitText
+ [showCancel]="false"
+ >
+ </cd-form-button-panel>
+ </div>
+ </form>
}
@if (!isCreatingNewEntity && showSelectRequirementsWarning) {
- <cd-alert-panel
- type="warning"
- class="cds-ml-3 cds-mr-3"
- dismissible="true"
- (dismissed)="onDismissSelectRequirementsWarning()">
- <div
- [cdsStack]="'vertical'"
- gap="2">
- <div
- class="cds--type-heading-compact-01"
- i18n>Mirroring entity requirements</div>
+ <cd-alert-panel
+ type="warning"
+ class="cds-ml-3 cds-mr-3"
+ dismissible="true"
+ (dismissed)="onDismissSelectRequirementsWarning()"
+ >
<div
- class="cds--type-body-compact-01"
- i18n>
- This selected entity will be used by the mirroring service to manage snapshots and
- replication. It must have rwps capabilities on MDS, MON, and OSD.
- </div>
- </div>
- </cd-alert-panel>
- @if (showSelectEntityInfo) {
- <cd-alert-panel
- type="info"
- class="cds-mb-3"
- dismissible="true"
- (dismissed)="onDismissSelectEntityInfo()">
- <div
- [cdsStack]="'vertical'"
- gap="2">
- <div
- class="cds--type-heading-01"
- i18n>Entity selection note</div>
- <div
- class="cds--type-body-compact-01"
- i18n>
- Only entities with valid rwps capabilities can be used for mirroring.
+ [cdsStack]="'vertical'"
+ gap="2"
+ >
+ <div
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Mirroring entity requirements
+ </div>
+ <div
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ This selected entity will be used by the mirroring service to manage snapshots and
+ replication. It must have rwps capabilities on MDS, MON, and OSD.
+ </div>
</div>
- </div>
- </cd-alert-panel>
- }
+ </cd-alert-panel>
+ @if (showSelectEntityInfo) {
+ <cd-alert-panel
+ type="info"
+ class="cds-mb-3"
+ dismissible="true"
+ (dismissed)="onDismissSelectEntityInfo()"
+ >
+ <div
+ [cdsStack]="'vertical'"
+ gap="2"
+ >
+ <div
+ class="cds--type-heading-01"
+ i18n
+ >
+ Entity selection note
+ </div>
+ <div
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ Only entities with valid rwps capabilities can be used for mirroring.
+ </div>
+ </div>
+ </cd-alert-panel>
+ }
}
- @let entities = (entities$ | async);
+ @let entities = entities$ | async;
@if (!isCreatingNewEntity && entities) {
- <cd-table
- #table
- [data]="entities"
- [columns]="columns"
- columnMode="flex"
- selectionType="singleRadio"
- (updateSelection)="updateSelection($event)"
- (fetchData)="loadEntities($event)">
- </cd-table>
+ <cd-table
+ #table
+ [data]="entities"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="singleRadio"
+ (updateSelection)="updateSelection($event)"
+ (fetchData)="loadEntities($event)"
+ >
+ </cd-table>
}
</cds-tile>
</div>
-
<cds-inline-notification
[notificationObj]="{
- type: 'warning',
- title: 'CephFS Mirroring module is not enabled',
- message: 'To create mirror links and configure replication, the CephFS Mirroring module must be enabled on this cluster.',
- lowContrast: true,
- showClose: false
- }"
+ type: 'warning',
+ title: 'CephFS Mirroring module is not enabled',
+ message:
+ 'To create mirror links and configure replication, the CephFS Mirroring module must be enabled on this cluster.',
+ lowContrast: true,
+ showClose: false
+ }"
class="mt-2 mb-2 full-width padding-inline-0"
- i18n></cds-inline-notification>
+ i18n
+></cds-inline-notification>
<cds-tile>
- <p class="cds--type-heading-compact-01"
- i18n>Enable CephFS Mirroring</p>
- <p class="cds--type-body-compact-01"
- i18n>Turn on CephFS Mirroring to start creating mirror links and synchronizing data across clusters. After enabling, you can add mirror links.</p>
- <button cdsButton="primary"
- (click)="enableModule()"
- type="button"
- i18n>Enable CephFS Mirroring</button>
+ <p
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Enable CephFS Mirroring
+ </p>
+ <p
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ Turn on CephFS Mirroring to start creating mirror links and synchronizing data across clusters.
+ After enabling, you can add mirror links.
+ </p>
+ <button
+ cdsButton="primary"
+ (click)="enableModule()"
+ type="button"
+ i18n
+ >
+ Enable CephFS Mirroring
+ </button>
</cds-tile>
-<div cdsGrid
- class="mt-5">
+<div
+ cdsGrid
+ class="mt-5"
+>
<div cdsRow>
<div cdsCol>
- <img src="assets/empty-state.png"
- alt="no-mirror-links" />
+ <img
+ src="assets/empty-state.png"
+ alt="no-mirror-links"
+ />
</div>
</div>
<div cdsRow>
columnMode="flex"
selectionType="single"
(updateSelection)="updateSelection($event)"
- (fetchData)="loadDaemonStatus()">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ (fetchData)="loadDaemonStatus()"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
}
[title]="title"
[description]="description"
(submitRequested)="onSubmit()"
- (closeRequested)="onCancel()">
+ (closeRequested)="onCancel()"
+>
<cd-tearsheet-step>
<form [formGroup]="form">
<div>
- <div class="cds--type-heading-03"
- i18n>Choose mirror peer role</div>
+ <div
+ class="cds--type-heading-03"
+ i18n
+ >
+ Choose mirror peer role
+ </div>
<p i18n>Select how the cluster will participate in the CephFS mirroring relationship.</p>
</div>
<cds-radio
[value]="LOCAL_ROLE"
[checked]="form.get('localRole')?.value === LOCAL_ROLE"
- (click)="onLocalRoleChange()">
+ (click)="onLocalRoleChange()"
+ >
<div>
- <div class="cds--type-heading-compact-02"
- i18n>Configure local peer</div>
- <div class="cds--type-label-01 cds-mt-3"
- i18n>
+ <div
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Configure local peer
+ </div>
+ <div
+ class="cds--type-label-01 cds-mt-3"
+ i18n
+ >
This cluster will act as the initiating peer and send snapshots to a remote
peer.
</div>
<ul class="cds--type-body-compact-01 cds-mt-6">
@for (item of sourceList; track $index) {
- <li class="cds-mb-6 cds-mt-3">→ {{ item }}</li>
+ <li class="cds-mb-6 cds-mt-3">→ {{ item }}</li>
}
</ul>
</div>
<cds-radio
[value]="REMOTE_ROLE"
[checked]="form.get('remoteRole')?.value === REMOTE_ROLE"
- (click)="onRemoteRoleChange()">
+ (click)="onRemoteRoleChange()"
+ >
<div>
- <div class="cds--type-heading-compact-02"
- i18n>Configure remote peer</div>
- <div class="cds--type-label-01 cds-mt-3"
- i18n>
+ <div
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Configure remote peer
+ </div>
+ <div
+ class="cds--type-label-01 cds-mt-3"
+ i18n
+ >
A remote cluster will act as the receiving peer and store replicated snapshots.
</div>
<ul class="cds--type-body-compact-01 cds-mt-6">
@for (item of targetList; track $index) {
- <li class="cds-mb-6 cds-mt-3">→ {{ item }}</li>
+ <li class="cds-mb-6 cds-mt-3">→ {{ item }}</li>
}
</ul>
</div>
</div>
@if (form.get('localRole')?.value !== LOCAL_ROLE && showMessage) {
- <cd-alert-panel
- type="info"
- spacingClass="mb-3 mt-3"
- dismissible="true"
- (dismissed)="showMessage = false">
- <div>
- <div
- class="cds--type-heading-compact-01 cds-mb-2"
- i18n>About remote peer setup</div>
- <div
- class="cds--type-body-compact-01 cds-mb-3"
- i18n>
- As a remote peer, this cluster prepares to receive mirrored data from an initiating
- cluster. The setup includes environment validation, enabling filesystem mirroring,
- creating required Ceph users, and generating a bootstrap token.
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3 mt-3"
+ dismissible="true"
+ (dismissed)="showMessage = false"
+ >
+ <div>
+ <div
+ class="cds--type-heading-compact-01 cds-mb-2"
+ i18n
+ >
+ About remote peer setup
+ </div>
+ <div
+ class="cds--type-body-compact-01 cds-mb-3"
+ i18n
+ >
+ As a remote peer, this cluster prepares to receive mirrored data from an initiating
+ cluster. The setup includes environment validation, enabling filesystem mirroring,
+ creating required Ceph users, and generating a bootstrap token.
+ </div>
+ <div
+ class="cds--type-heading-compact-01 cds-mb-1 cds-mt-6"
+ i18n
+ >
+ What happens next:
+ </div>
+ <ul class="list-disc cds-ml-5 cds--type-body-compact-01">
+ <li i18n>Environment validation</li>
+ <li i18n>Ceph user creation</li>
+ <li i18n>Filesystem mirroring activation</li>
+ <li i18n>Bootstrap token generation</li>
+ </ul>
</div>
- <div
- class="cds--type-heading-compact-01 cds-mb-1 cds-mt-6"
- i18n>What happens next:</div>
- <ul class="list-disc cds-ml-5 cds--type-body-compact-01">
- <li i18n>Environment validation</li>
- <li i18n>Ceph user creation</li>
- <li i18n>Filesystem mirroring activation</li>
- <li i18n>Bootstrap token generation</li>
- </ul>
- </div>
- </cd-alert-panel>
+ </cd-alert-panel>
}
</form>
</cd-tearsheet-step>
<!-- Step 2 -->
<cd-tearsheet-step>
- <cd-cephfs-mirroring-entity [selectedFilesystem]="selectedFilesystem"
- (entitySelected)="onEntitySelected($event)">
+ <cd-cephfs-mirroring-entity
+ [selectedFilesystem]="selectedFilesystem"
+ (entitySelected)="onEntitySelected($event)"
+ >
</cd-cephfs-mirroring-entity>
</cd-tearsheet-step>
<!-- Step 3 -->
<cd-tearsheet-step>
- <div>
- Test 3
- </div>
+ <div>Test 3</div>
</cd-tearsheet-step>
</cd-tearsheet>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
Attach commands
</h3>
</cds-modal-header>
<div class="cds--modal-content">
- <h5 class="fw-bold"
- i18n>
+ <h5
+ class="fw-bold"
+ i18n
+ >
Using Mount command
</h5>
- <cd-code-block textWrap="true"
- [codes]="[mount]"></cd-code-block>
+ <cd-code-block
+ textWrap="true"
+ [codes]="[mount]"
+ ></cd-code-block>
- <h5 class="fw-bold"
- i18n>
+ <h5
+ class="fw-bold"
+ i18n
+ >
Using FUSE command
</h5>
- <cd-code-block textWrap="true"
- [codes]="[fuse]"></cd-code-block>
+ <cd-code-block
+ textWrap="true"
+ [codes]="[fuse]"
+ ></cd-code-block>
- <h5 class="fw-bold"
- i18n>
- Using NFS Command
+ <h5
+ class="fw-bold"
+ i18n
+ >
+ Using NFS Command
</h5>
- <cd-code-block textWrap="true"
- [codes]="[nfs]"></cd-code-block>
+ <cd-code-block
+ textWrap="true"
+ [codes]="[nfs]"
+ ></cd-code-block>
</div>
- <cd-form-button-panel [modalForm]="true"
- [showSubmit]="false"
- (backAction)="cancel()"
- i18n></cd-form-button-panel>
+ <cd-form-button-panel
+ [modalForm]="true"
+ [showSubmit]="false"
+ (backAction)="cancel()"
+ i18n
+ ></cd-form-button-panel>
</cds-modal>
-<cds-modal size="lg"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>
- {{ action | titlecase }} {{ resource | upperFirst }}
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
</h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
<div cdsModalContent>
- <form name="snapScheduleForm"
- #formDir="ngForm"
- [formGroup]="snapScheduleForm"
- novalidate>
+ <form
+ name="snapScheduleForm"
+ #formDir="ngForm"
+ [formGroup]="snapScheduleForm"
+ novalidate
+ >
<!-- Directory -->
<div class="form-item">
- <cds-text-label for="directory"
- i18n
- cdRequiredField="Directory"
- [invalid]="snapScheduleForm.controls.directory.invalid && (snapScheduleForm.controls.directory.dirty)"
- [invalidText]="directoryError"
- [skeleton]="directoryStore.isLoading"
- modal-primary-focus>
+ <cds-text-label
+ for="directory"
+ i18n
+ cdRequiredField="Directory"
+ [invalid]="
+ snapScheduleForm.controls.directory.invalid &&
+ snapScheduleForm.controls.directory.dirty
+ "
+ [invalidText]="directoryError"
+ [skeleton]="directoryStore.isLoading"
+ modal-primary-focus
+ >
<ng-container *ngIf="!directoryStore.isLoading">Directory (required)</ng-container>
- <input cdsText
- type="text"
- formControlName="directory"
- name="directory"
- [ngbTypeahead]="search"
- [invalid]="snapScheduleForm.controls.directory.invalid && (snapScheduleForm.controls.directory.dirty)"
- [placeholder]="directoryStore.isLoading ? '' : 'Directory path'"
- [skeleton]="directoryStore.isLoading"/>
+ <input
+ cdsText
+ type="text"
+ formControlName="directory"
+ name="directory"
+ [ngbTypeahead]="search"
+ [invalid]="
+ snapScheduleForm.controls.directory.invalid &&
+ snapScheduleForm.controls.directory.dirty
+ "
+ [placeholder]="directoryStore.isLoading ? '' : 'Directory path'"
+ [skeleton]="directoryStore.isLoading"
+ />
</cds-text-label>
<ng-template #directoryError>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('directory', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('directory', formDir, 'notUnique')"
- i18n>A snapshot schedule for this path already exists.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('directory', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('directory', formDir, 'notUnique')"
+ i18n
+ >A snapshot schedule for this path already exists.</span
+ >
</ng-template>
</div>
name="Start Date"
helperText="The time zone is assumed to be UTC"
[control]="snapScheduleForm.get('startDate')"
- [disabled]="isEdit"></cd-date-time-picker>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('startDate', formDir, 'required')"
- i18n>This field is required.</span>
+ [disabled]="isEdit"
+ ></cd-date-time-picker>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('startDate', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
<!-- Repeat interval -->
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
- <cds-number [id]="'repeatInterval'"
- [name]="'repeatInterval'"
- [formControlName]="'repeatInterval'"
- [label]="'Schedule'"
- [min]="1"
- [invalid]="!snapScheduleForm.controls.repeatInterval.valid && (snapScheduleForm.controls.repeatInterval.dirty)"
- [invalidText]="repeatIntervalError"
- cdRequiredField="Schedule"></cds-number>
+ <cds-number
+ [id]="'repeatInterval'"
+ [name]="'repeatInterval'"
+ [formControlName]="'repeatInterval'"
+ [label]="'Schedule'"
+ [min]="1"
+ [invalid]="
+ !snapScheduleForm.controls.repeatInterval.valid &&
+ snapScheduleForm.controls.repeatInterval.dirty
+ "
+ [invalidText]="repeatIntervalError"
+ cdRequiredField="Schedule"
+ ></cds-number>
</div>
<div cdsCol>
- <cds-select id="repeatFrequency"
- name="repeatFrequency"
- formControlName="repeatFrequency"
- label="Frequency"
- [invalid]="!snapScheduleForm.controls.repeatFrequency.valid && (snapScheduleForm.controls.repeatFrequency.dirty)"
- [invalidText]="repeatFrequencyError"
- *ngIf="repeatFrequencies">
- <option *ngFor="let freq of repeatFrequencies"
- [value]="freq[1]">{{ freq[0] }}
+ <cds-select
+ id="repeatFrequency"
+ name="repeatFrequency"
+ formControlName="repeatFrequency"
+ label="Frequency"
+ [invalid]="
+ !snapScheduleForm.controls.repeatFrequency.valid &&
+ snapScheduleForm.controls.repeatFrequency.dirty
+ "
+ [invalidText]="repeatFrequencyError"
+ *ngIf="repeatFrequencies"
+ >
+ <option
+ *ngFor="let freq of repeatFrequencies"
+ [value]="freq[1]"
+ >
+ {{ freq[0] }}
</option>
</cds-select>
<ng-template #repeatFrequencyError>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('repeatFrequency', formDir, 'notUnique')"
- i18n>This schedule already exists for the selected directory.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('repeatFrequency', formDir, 'notUnique')"
+ i18n
+ >This schedule already exists for the selected directory.</span
+ >
</ng-template>
<ng-template #repeatIntervalError>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('repeatInterval', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.showError('repeatInterval', formDir, 'min')"
- i18n>Choose a value greater than 0.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('repeatInterval', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.showError('repeatInterval', formDir, 'min')"
+ i18n
+ >Choose a value greater than 0.</span
+ >
</ng-template>
</div>
</div>
<!-- Retention policies -->
- <ng-container formArrayName="retentionPolicies"
- *ngFor="let retentionPolicy of retentionPolicies.controls; index as i">
+ <ng-container
+ formArrayName="retentionPolicies"
+ *ngFor="let retentionPolicy of retentionPolicies.controls; index as i"
+ >
<ng-container [formGroupName]="i">
- <div cdsRow
- class="form-item form-item-append">
- <div cdsCol
- [columnNumbers]="{lg: 8}">
- <cds-number [id]="'retentionInterval' + i"
- [name]="'retentionInterval' + i"
- [formControlName]="'retentionInterval'"
- [label]="'Retention policy'"
- [min]="1"
- [invalid]="snapScheduleForm.controls['retentionPolicies'].controls[i].invalid && snapScheduleForm.controls['retentionPolicies'].dirty"
- [invalidText]="retentionPolicyError"></cds-number>
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 8 }"
+ >
+ <cds-number
+ [id]="'retentionInterval' + i"
+ [name]="'retentionInterval' + i"
+ [formControlName]="'retentionInterval'"
+ [label]="'Retention policy'"
+ [min]="1"
+ [invalid]="
+ snapScheduleForm.controls['retentionPolicies'].controls[i].invalid &&
+ snapScheduleForm.controls['retentionPolicies'].dirty
+ "
+ [invalidText]="retentionPolicyError"
+ ></cds-number>
</div>
- <div cdsCol
- [columnNumbers]="{lg: 7}">
- <cds-select id="retentionFrequency"
- name="retentionFrequency"
- formControlName="retentionFrequency"
- label="Frequency"
- *ngIf="retentionFrequencies">
- <option *ngFor="let freq of retentionFrequencies"
- [value]="freq[1]">{{ freq[0] }}</option>
-
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 7 }"
+ >
+ <cds-select
+ id="retentionFrequency"
+ name="retentionFrequency"
+ formControlName="retentionFrequency"
+ label="Frequency"
+ *ngIf="retentionFrequencies"
+ >
+ <option
+ *ngFor="let freq of retentionFrequencies"
+ [value]="freq[1]"
+ >
+ {{ freq[0] }}
+ </option>
</cds-select>
</div>
- <div cdsCol
- [columnNumbers]="{lg: 1}"
- class="item-action-btn">
- <cds-icon-button kind="danger"
- size="sm"
- (click)="removeRetentionPolicy(i)">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="sm"
+ (click)="removeRetentionPolicy(i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
</div>
<ng-template #retentionPolicyError>
- <span class="invalid-feedback"
- *ngIf="snapScheduleForm.controls['retentionPolicies'].controls[i].invalid"
- i18n>This retention policy already exists for the selected directory.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapScheduleForm.controls['retentionPolicies'].controls[i].invalid"
+ i18n
+ >This retention policy already exists for the selected directory.</span
+ >
</ng-template>
</ng-container>
</ng-container>
<div class="form-item">
- <button cdsButton="tertiary"
- type="button"
- (click)="addRetentionPolicy()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addRetentionPolicy()"
+ i18n
+ >
Add retention policy
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- icon></svg>
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
</button>
</div>
</form>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="snapScheduleForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="snapScheduleForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</ng-container>
</cds-modal>
<ng-template
#pathTpl
- let-row="data.row">
+ let-row="data.row"
+>
<span
class="fw-bold"
[ngbTooltip]="fullpathTpl"
- triggers="click:blur">
- {{ row.pathForSelection?.split?.("@")?.[0] | path }}
+ triggers="click:blur"
+ >
+ {{ row.pathForSelection?.split?.('@')?.[0] | path }}
</span>
- <span
- *ngIf="row.active; else inactiveStatusTpl">
+ <span *ngIf="row.active; else inactiveStatusTpl">
<i
[ngClass]="[icons.success, icons.size24]"
ngbTooltip="{{ row.pathForSelection?.split?.('@')?.[0] }} is active"
<ng-template
#retentionTpl
- let-row="data.row">
+ let-row="data.row"
+>
<ul *ngIf="row.retentionCopy.length; else noDataTpl">
<li *ngFor="let ret of row.retentionCopy">{{ ret }}</li>
</ul>
<ng-template
#subvolTpl
- let-row="data.row">
+ let-row="data.row"
+>
<span *ngIf="row.subvol; else noDataTpl">
- {{row.subvol}}
+ {{ row.subvol }}
</span>
</ng-template>
-
-
<ng-template #noDataTpl>-</ng-template>
<cd-table
-<cds-modal size="lg"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
<div cdsModalContent>
- <form name="subvolumeForm"
- #formDir="ngForm"
- [formGroup]="subvolumeForm"
- novalidate>
+ <form
+ name="subvolumeForm"
+ #formDir="ngForm"
+ [formGroup]="subvolumeForm"
+ novalidate
+ >
<div class="form-item">
- <cds-text-label label="Name"
- for="subvolumeName"
- [invalid]="subvolumeForm.controls.subvolumeName.invalid && (subvolumeForm.controls.subvolumeName.dirty)"
- [invalidText]="subvolumeNameError"
- cdRequiredField="Name"
- i18n>Name
- <input cdsText
- type="text"
- placeholder="Subvolume name..."
- id="subvolumeName"
- name="subvolumeName"
- formControlName="subvolumeName"
- [invalid]="subvolumeForm.controls.subvolumeName.invalid && (subvolumeForm.controls.subvolumeName.dirty)"
- [autofocus]="true"
- modal-primary-focus>
+ <cds-text-label
+ label="Name"
+ for="subvolumeName"
+ [invalid]="
+ subvolumeForm.controls.subvolumeName.invalid &&
+ subvolumeForm.controls.subvolumeName.dirty
+ "
+ [invalidText]="subvolumeNameError"
+ cdRequiredField="Name"
+ i18n
+ >Name
+ <input
+ cdsText
+ type="text"
+ placeholder="Subvolume name..."
+ id="subvolumeName"
+ name="subvolumeName"
+ formControlName="subvolumeName"
+ [invalid]="
+ subvolumeForm.controls.subvolumeName.invalid &&
+ subvolumeForm.controls.subvolumeName.dirty
+ "
+ [autofocus]="true"
+ modal-primary-focus
+ />
</cds-text-label>
<ng-template #subvolumeNameError>
- <span class="invalid-feedback"
- *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'notUnique')"
- i18n>The subvolume already exists.</span>
- <span *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Subvolume name can only contain letters, numbers, '.', '-' or '_'</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'notUnique')"
+ i18n
+ >The subvolume already exists.</span
+ >
+ <span
+ *ngIf="subvolumeForm.showError('subvolumeName', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Subvolume name can only contain letters, numbers, '.', '-' or '_'</span
+ >
</ng-template>
</div>
<!-- Volume name -->
<div class="form-item">
- <cds-text-label label="Volume name"
- for="volumeName"
- i18n>Volume name
- <input cdsText
- type="text"
- id="volumeName"
- name="volumeName"
- formControlName="volumeName">
- </cds-text-label>
- </div>
+ <cds-text-label
+ label="Volume name"
+ for="volumeName"
+ i18n
+ >Volume name
+ <input
+ cdsText
+ type="text"
+ id="volumeName"
+ name="volumeName"
+ formControlName="volumeName"
+ />
+ </cds-text-label>
+ </div>
- <!--Subvolume Group name -->
- <div class="form-item">
- <cds-select label="Subvolume group"
- for="subvolumeGroupName"
- formControlName="subvolumeGroupName"
- name="subvolumeGroupName"
- id="subvolumeGroupName"
- *ngIf="subVolumeGroups$ | async as subvolumeGroups">
- <option value=""
- i18n>Default</option>
- <option *ngFor="let subvolumegroup of subvolumeGroups"
- [value]="subvolumegroup.name">{{ subvolumegroup.name }}</option>
- </cds-select>
- </div>
+ <!--Subvolume Group name -->
+ <div class="form-item">
+ <cds-select
+ label="Subvolume group"
+ for="subvolumeGroupName"
+ formControlName="subvolumeGroupName"
+ name="subvolumeGroupName"
+ id="subvolumeGroupName"
+ *ngIf="subVolumeGroups$ | async as subvolumeGroups"
+ >
+ <option
+ value=""
+ i18n
+ >
+ Default
+ </option>
+ <option
+ *ngFor="let subvolumegroup of subvolumeGroups"
+ [value]="subvolumegroup.name"
+ >
+ {{ subvolumegroup.name }}
+ </option>
+ </cds-select>
+ </div>
<!-- Size -->
<div class="form-item">
- <cds-text-label label="Size"
- for="size"
- helperText="The size of the subvolume is specified by setting a quota on it.
+ <cds-text-label
+ label="Size"
+ for="size"
+ helperText="The size of the subvolume is specified by setting a quota on it.
If left blank or put 0, then quota will be infinite"
- i18n-helperText
- [invalid]="subvolumeForm.controls.size.invalid && (subvolumeForm.controls.size.dirty)"
- [invalidText]="sizeError"
- i18n>Size
- <input cdsText
- type="text"
- id="size"
- name="size"
- formControlName="size"
- i18n-placeholder
- placeholder="e.g., 10GiB"
- defaultUnit="GiB"
- [invalid]="subvolumeForm.controls.size.invalid && (subvolumeForm.controls.size.dirty)"
- cdDimlessBinary>
+ i18n-helperText
+ [invalid]="subvolumeForm.controls.size.invalid && subvolumeForm.controls.size.dirty"
+ [invalidText]="sizeError"
+ i18n
+ >Size
+ <input
+ cdsText
+ type="text"
+ id="size"
+ name="size"
+ formControlName="size"
+ i18n-placeholder
+ placeholder="e.g., 10GiB"
+ defaultUnit="GiB"
+ [invalid]="subvolumeForm.controls.size.invalid && subvolumeForm.controls.size.dirty"
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #sizeError>
- <span *ngIf="subvolumeForm.showError('size', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ *ngIf="subvolumeForm.showError('size', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
- <cd-alert-panel *ngIf="!showSnapshotVisibility"
- type="warning"
- class="cds-mb-6"
- i18n>
- To manage snapshot visibility, first enable
- client_respect_subvolume_snapshot_visibility.
+ <cd-alert-panel
+ *ngIf="!showSnapshotVisibility"
+ type="warning"
+ class="cds-mb-6"
+ i18n
+ >
+ To manage snapshot visibility, first enable client_respect_subvolume_snapshot_visibility.
</cd-alert-panel>
<!-- Snapshot visibility -->
<div class="form-item">
- <cds-checkbox id="snapshotVisibility"
- name="snapshotVisibility"
- formControlName="snapshotVisibility">
+ <cds-checkbox
+ id="snapshotVisibility"
+ name="snapshotVisibility"
+ formControlName="snapshotVisibility"
+ >
<span i18n>Allow snapshot browsing</span>
<cd-help-text>
<span i18n>
- When enabled, snapshots will be visible inside the subvolume directory under ".snap".
+ When enabled, snapshots will be visible inside the subvolume directory under
+ ".snap".
</span>
</cd-help-text>
</cds-checkbox>
<!-- CephFS Pools -->
<div class="form-item">
- <cds-select label="CephFS Pools"
- for="pool"
- formControlName="pool"
- name="pool"
- id="pool"
- helperText="By default, the data_pool_layout of the parent directory is selected."
- i18n-helperText>
- <option *ngFor="let pool of dataPools"
- [value]="pool.pool">{{ pool.pool }}</option>
+ <cds-select
+ label="CephFS Pools"
+ for="pool"
+ formControlName="pool"
+ name="pool"
+ id="pool"
+ helperText="By default, the data_pool_layout of the parent directory is selected."
+ i18n-helperText
+ >
+ <option
+ *ngFor="let pool of dataPools"
+ [value]="pool.pool"
+ >
+ {{ pool.pool }}
+ </option>
</cds-select>
</div>
<!-- UID -->
<div class="form-item">
- <cds-text-label label="UID"
- for="uid"
- i18n>UID
- <input cdsText
- type="number"
- placeholder="Subvolume UID..."
- id="uid"
- name="uid"
- formControlName="uid">
+ <cds-text-label
+ label="UID"
+ for="uid"
+ i18n
+ >UID
+ <input
+ cdsText
+ type="number"
+ placeholder="Subvolume UID..."
+ id="uid"
+ name="uid"
+ formControlName="uid"
+ />
</cds-text-label>
</div>
<!-- GID -->
<div class="form-item">
- <cds-text-label label="GID"
- for="gid"
- i18n>GID
- <input cdsText
- type="number"
- placeholder="Subvolume GID..."
- id="gid"
- name="gid"
- formControlName="gid">
+ <cds-text-label
+ label="GID"
+ for="gid"
+ i18n
+ >GID
+ <input
+ cdsText
+ type="number"
+ placeholder="Subvolume GID..."
+ id="gid"
+ name="gid"
+ formControlName="gid"
+ />
</cds-text-label>
</div>
<!-- Mode -->
<div class="form-item">
- <label class="cds--label"
- for="mode"
- i18n>Mode
+ <label
+ class="cds--label"
+ for="mode"
+ i18n
+ >Mode
</label>
- <cd-help-text>Permissions for the directory. Default mode is 755 which is rwxr-xr-x</cd-help-text>
- <cd-checked-table-form [data]="scopePermissions"
- [columns]="columns"
- [form]="subvolumeForm"
- inputField="mode"
- [isTableForOctalMode]="true"
- [initialValue]="initialMode"
- [scopes]="scopes"
- [isDisabled]="isEdit">
+ <cd-help-text
+ >Permissions for the directory. Default mode is 755 which is rwxr-xr-x</cd-help-text
+ >
+ <cd-checked-table-form
+ [data]="scopePermissions"
+ [columns]="columns"
+ [form]="subvolumeForm"
+ inputField="mode"
+ [isTableForOctalMode]="true"
+ [initialValue]="initialMode"
+ [scopes]="scopes"
+ [isDisabled]="isEdit"
+ >
</cd-checked-table-form>
</div>
<!-- Is namespace-isolated -->
<div class="form-item">
- <cds-checkbox id="isolatedNamespace"
- name="isolatedNamespace"
- formControlName="isolatedNamespace"
- i18n>Isolated Namespace
+ <cds-checkbox
+ id="isolatedNamespace"
+ name="isolatedNamespace"
+ formControlName="isolatedNamespace"
+ i18n
+ >Isolated Namespace
<cd-help-text>To create subvolume in a separate RADOS namespace.</cd-help-text>
</cds-checkbox>
</div>
</form>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="subvolumeForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="subvolumeForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</ng-container>
</cds-modal>
-
<ng-container *ngIf="subvolumeGroup$ | async as subvolumeGroup">
- <cd-table *ngIf="subvolumeGroup"
- [data]="subvolumeGroup"
- columnMode="flex"
- [columns]="columns"
- selectionType="single"
- [hasDetails]="false"
- (fetchData)="fetchData()"
- (updateSelection)="updateSelection($event)">
-
+ <cd-table
+ *ngIf="subvolumeGroup"
+ [data]="subvolumeGroup"
+ columnMode="flex"
+ [columns]="columns"
+ selectionType="single"
+ [hasDetails]="false"
+ (fetchData)="fetchData()"
+ (updateSelection)="updateSelection($event)"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permissions.cephfs"
- [selection]="selection"
- class="btn-group"
- id="cephfs-subvolumegropup-actions"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permissions.cephfs"
+ [selection]="selection"
+ class="btn-group"
+ id="cephfs-subvolumegropup-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</ng-container>
-<ng-template #quotaUsageTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.info.bytes_pcent && row.info.bytes_pcent !== 'undefined'; else noLimitTpl"
- [total]="row.info.bytes_quota"
- [used]="row.info.bytes_used"
- [title]="row.name"
- decimals="2"></cd-usage-bar>
+<ng-template
+ #quotaUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.info.bytes_pcent && row.info.bytes_pcent !== 'undefined'; else noLimitTpl"
+ [total]="row.info.bytes_quota"
+ [used]="row.info.bytes_used"
+ [title]="row.name"
+ decimals="2"
+ ></cd-usage-bar>
<ng-template #noLimitTpl>
- <span ngbTooltip="Quota limit is not set"
- *ngIf="row.info.bytes_pcent === 'undefined'"
- i18n-ngbTooltip>
- {{row.info.bytes_used | dimlessBinary}}</span>
+ <span
+ ngbTooltip="Quota limit is not set"
+ *ngIf="row.info.bytes_pcent === 'undefined'"
+ i18n-ngbTooltip
+ >
+ {{ row.info.bytes_used | dimlessBinary }}</span
+ >
</ng-template>
</ng-template>
-<ng-template #typeTpl
- let-value="data.value">
+<ng-template
+ #typeTpl
+ let-value="data.value"
+>
<cd-label [value]="value"></cd-label>
</ng-template>
-<ng-template #modeToHumanReadableTpl
- let-value="data.value">
- <cds-tag *ngFor="let result of (value | octalToHumanReadable)"
- [class]="result.class"
- [ngbTooltip]="result.toolTip">
+<ng-template
+ #modeToHumanReadableTpl
+ let-value="data.value"
+>
+ <cds-tag
+ *ngFor="let result of value | octalToHumanReadable"
+ [class]="result.class"
+ [ngbTooltip]="result.toolTip"
+ >
{{ result.content }}
-</cds-tag>
+ </cds-tag>
</ng-template>
<div class="row">
- <div class="col-sm-2"
- *ngIf="subVolumeGroups$ | async as subVolumeGroups">
- <cd-vertical-navigation title="Groups"
- [items]="subvolumeGroupList"
- inputIdentifier="group-filter"
- (emitActiveItem)="selectSubVolumeGroup($event)"></cd-vertical-navigation>
+ <div
+ class="col-sm-2"
+ *ngIf="subVolumeGroups$ | async as subVolumeGroups"
+ >
+ <cd-vertical-navigation
+ title="Groups"
+ [items]="subvolumeGroupList"
+ inputIdentifier="group-filter"
+ (emitActiveItem)="selectSubVolumeGroup($event)"
+ ></cd-vertical-navigation>
</div>
<div class="col-10 vertical-line">
- <cd-table [data]="subVolumes$ | async"
- columnMode="flex"
- [columns]="columns"
- selectionType="single"
- [hasDetails]="false"
- (fetchData)="fetchData()"
- (updateSelection)="updateSelection($event)">
-
+ <cd-table
+ [data]="subVolumes$ | async"
+ columnMode="flex"
+ [columns]="columns"
+ selectionType="single"
+ [hasDetails]="false"
+ (fetchData)="fetchData()"
+ (updateSelection)="updateSelection($event)"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permissions.cephfs"
- [selection]="selection"
- class="btn-group"
- id="cephfs-subvolume-actions"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permissions.cephfs"
+ [selection]="selection"
+ class="btn-group"
+ id="cephfs-subvolume-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</div>
</div>
-<ng-template #quotaUsageTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.info.bytes_pcent && row.info.bytes_pcent !== 'undefined'; else noLimitTpl"
- [total]="row.info.bytes_quota"
- [used]="row.info.bytes_used"
- [title]="row.name"
- decimals="2"></cd-usage-bar>
+<ng-template
+ #quotaUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.info.bytes_pcent && row.info.bytes_pcent !== 'undefined'; else noLimitTpl"
+ [total]="row.info.bytes_quota"
+ [used]="row.info.bytes_used"
+ [title]="row.name"
+ decimals="2"
+ ></cd-usage-bar>
<ng-template #noLimitTpl>
- <span ngbTooltip="Quota limit is not set"
- *ngIf="row.info.bytes_pcent === 'undefined'"
- i18n-ngbTooltip>
- {{row.info.bytes_used | dimlessBinary}}</span>
+ <span
+ ngbTooltip="Quota limit is not set"
+ *ngIf="row.info.bytes_pcent === 'undefined'"
+ i18n-ngbTooltip
+ >
+ {{ row.info.bytes_used | dimlessBinary }}</span
+ >
</ng-template>
</ng-template>
-<ng-template #typeTpl
- let-value="data.value">
+<ng-template
+ #typeTpl
+ let-value="data.value"
+>
<cd-label [value]="value"></cd-label>
</ng-template>
-<ng-template #modeToHumanReadableTpl
- let-value="data.value">
- <cds-tag *ngFor="let result of (value | octalToHumanReadable)"
- [class]="result.class"
- [ngbTooltip]="result.toolTip">
+<ng-template
+ #modeToHumanReadableTpl
+ let-value="data.value"
+>
+ <cds-tag
+ *ngFor="let result of value | octalToHumanReadable"
+ [class]="result.class"
+ [ngbTooltip]="result.toolTip"
+ >
{{ result.content }}
-</cds-tag>
+ </cds-tag>
</ng-template>
-<ng-template #nameTpl
- let-row="data.row">
- <span class="fw-bold">{{row.name}}</span>
+<ng-template
+ #nameTpl
+ let-row="data.row"
+>
+ <span class="fw-bold">{{ row.name }}</span>
<span *ngIf="row?.info?.state === 'complete'; else snapshotRetainedTpl">
- <i [ngClass]="[icons.success, icons.size24]"
- ngbTooltip="{{row.name}} is ready to use"
- class="text-success"></i>
+ <i
+ [ngClass]="[icons.success, icons.size24]"
+ ngbTooltip="{{ row.name }} is ready to use"
+ class="text-success"
+ ></i>
</span>
<ng-template #snapshotRetainedTpl>
- <i [ngClass]="[icons.warning, icons.size24]"
- class="text-warning"
- ngbTooltip="{{row.name}} is removed after retaining the snapshots"></i>
+ <i
+ [ngClass]="[icons.warning, icons.size24]"
+ class="text-warning"
+ ngbTooltip="{{ row.name }} is removed after retaining the snapshots"
+ ></i>
</ng-template>
- <cd-label [value]="row?.info?.type"
- *ngIf="row?.info?.type !== 'subvolume'"></cd-label>
+ <cd-label
+ [value]="row?.info?.type"
+ *ngIf="row?.info?.type !== 'subvolume'"
+ ></cd-label>
- <cd-label value="namespaced"
- *ngIf="row?.info?.pool_namespace"
- [tooltipText]="row?.info?.pool_namespace"></cd-label>
+ <cd-label
+ value="namespaced"
+ *ngIf="row?.info?.pool_namespace"
+ [tooltipText]="row?.info?.pool_namespace"
+ ></cd-label>
</ng-template>
-<ng-template #removeTmpl
- let-form="form">
+<ng-template
+ #removeTmpl
+ let-form="form"
+>
<ng-container [formGroup]="form">
<ng-container formGroupName="child">
- <cd-alert-panel *ngIf="errorMessage.length > 1"
- type="error">
- {{errorMessage}}
+ <cd-alert-panel
+ *ngIf="errorMessage.length > 1"
+ type="error"
+ >
+ {{ errorMessage }}
</cd-alert-panel>
<div class="form-item cds-pt-3">
- <cds-checkbox id="retainSnapshots"
- formControlName="retainSnapshots"
- autofocus
- [required]="true"
- modal-primary-focus
- ariaLabel="confirmation"
- i18n>Retain snapshots
- <cd-help-text>The subvolume can be removed retaining
- existing snapshots using this option.
- If snapshots are retained, the subvolume is considered empty for all
- operations not involving the retained snapshots.</cd-help-text>
+ <cds-checkbox
+ id="retainSnapshots"
+ formControlName="retainSnapshots"
+ autofocus
+ [required]="true"
+ modal-primary-focus
+ ariaLabel="confirmation"
+ i18n
+ >Retain snapshots
+ <cd-help-text
+ >The subvolume can be removed retaining existing snapshots using this option. If
+ snapshots are retained, the subvolume is considered empty for all operations not
+ involving the retained snapshots.</cd-help-text
+ >
</cds-checkbox>
</div>
</ng-container>
-<cds-modal size="lg"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
- <form name="snapshotForm"
- #formDir="ngForm"
- [formGroup]="snapshotForm"
- novalidate>
+ <form
+ name="snapshotForm"
+ #formDir="ngForm"
+ [formGroup]="snapshotForm"
+ novalidate
+ >
<div cdsModalContent>
<div class="form-item">
- <cds-text-label label="Name"
- for="snapshotName"
- cdRequiredField="Name"
- [invalid]="snapshotForm.controls.snapshotName.invalid && (snapshotForm.controls.snapshotName.dirty)"
- [invalidText]="snapshotNameError"
- i18n>
- <input cdsText
- type="text"
- placeholder="Snapshot name..."
- id="snapshotName"
- name="snapshotName"
- formControlName="snapshotName"
- [invalid]="snapshotForm.controls.snapshotName.invalid && (snapshotForm.controls.snapshotName.dirty)"
- autofocus
- modal-primary-focus>
+ <cds-text-label
+ label="Name"
+ for="snapshotName"
+ cdRequiredField="Name"
+ [invalid]="
+ snapshotForm.controls.snapshotName.invalid && snapshotForm.controls.snapshotName.dirty
+ "
+ [invalidText]="snapshotNameError"
+ i18n
+ >
+ <input
+ cdsText
+ type="text"
+ placeholder="Snapshot name..."
+ id="snapshotName"
+ name="snapshotName"
+ formControlName="snapshotName"
+ [invalid]="
+ snapshotForm.controls.snapshotName.invalid &&
+ snapshotForm.controls.snapshotName.dirty
+ "
+ autofocus
+ modal-primary-focus
+ />
</cds-text-label>
<ng-template #snapshotNameError>
- <span class="invalid-feedback"
- *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="snapshotForm.showError('snapshotName', formDir, 'notUnique')"
- i18n>The snapshot already exists.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="snapshotForm.showError('snapshotName', formDir, 'notUnique')"
+ i18n
+ >The snapshot already exists.</span
+ >
</ng-template>
</div>
<!-- Volume name -->
<div class="form-item">
- <cds-text-label label="Volume name"
- for="volumeName"
- i18n>Volume name
- <input cdsText
- type="text"
- id="volumeName"
- name="volumeName"
- formControlName="volumeName">
+ <cds-text-label
+ label="Volume name"
+ for="volumeName"
+ i18n
+ >Volume name
+ <input
+ cdsText
+ type="text"
+ id="volumeName"
+ name="volumeName"
+ formControlName="volumeName"
+ />
</cds-text-label>
</div>
<!--Subvolume Group name -->
<div class="form-item">
- <cds-select label="Subvolume group"
- for="subvolumeGroupName"
- formControlName="subvolumeGroupName"
- name="subvolumeGroupName"
- id="subvolumeGroupName"
- *ngIf="subVolumeGroups">
+ <cds-select
+ label="Subvolume group"
+ for="subvolumeGroupName"
+ formControlName="subvolumeGroupName"
+ name="subvolumeGroupName"
+ id="subvolumeGroupName"
+ *ngIf="subVolumeGroups"
+ >
<ng-container *ngFor="let subvolumegroup of subVolumeGroups">
- <option *ngIf="subvolumegroup == ''"
- value="">Default</option>
- <option [value]="subvolumegroup"
- *ngIf="subvolumegroup !== ''">{{ subvolumegroup }}</option>
+ <option
+ *ngIf="subvolumegroup == ''"
+ value=""
+ >
+ Default
+ </option>
+ <option
+ [value]="subvolumegroup"
+ *ngIf="subvolumegroup !== ''"
+ >
+ {{ subvolumegroup }}
+ </option>
</ng-container>
</cds-select>
</div>
<!--Subvolume name -->
- <div class="form-item"
- *ngIf="subVolumes$ | async as subVolumes">
- <cds-select label="Subvolume"
- id="subVolumeName"
- name="subVolumeName"
- formControlName="subVolumeName"
- (registerOnChange)="resetValidators(selection.value)">
- <option *ngFor="let subVolume of subVolumes"
- [value]="subVolume.name">{{ subVolume.name }}</option>
+ <div
+ class="form-item"
+ *ngIf="subVolumes$ | async as subVolumes"
+ >
+ <cds-select
+ label="Subvolume"
+ id="subVolumeName"
+ name="subVolumeName"
+ formControlName="subVolumeName"
+ (registerOnChange)="resetValidators(selection.value)"
+ >
+ <option
+ *ngFor="let subVolume of subVolumes"
+ [value]="subVolume.name"
+ >
+ {{ subVolume.name }}
+ </option>
</cds-select>
</div>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="snapshotForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="snapshotForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</ng-container>
</cds-modal>
</cd-loading-panel>
</ng-container>
-<div class="row"
- *ngIf="isSubVolumesAvailable; else noGroupsTpl">
+<div
+ class="row"
+ *ngIf="isSubVolumesAvailable; else noGroupsTpl"
+>
<div class="col-sm-2">
- <cd-vertical-navigation title="Groups"
- [items]="subvolumeGroupList"
- inputIdentifier="group-filter"
- (emitActiveItem)="selectSubVolumeGroup($event)"></cd-vertical-navigation>
+ <cd-vertical-navigation
+ title="Groups"
+ [items]="subvolumeGroupList"
+ inputIdentifier="group-filter"
+ (emitActiveItem)="selectSubVolumeGroup($event)"
+ ></cd-vertical-navigation>
</div>
- <div class="col-sm-2 vertical-line"
- *ngIf="subVolumes$ | async">
- <cd-vertical-navigation title="Subvolumes"
- [items]="subVolumesList"
- (emitActiveItem)="selectSubVolume($event)"
- inputIdentifier="subvol-filter"></cd-vertical-navigation>
+ <div
+ class="col-sm-2 vertical-line"
+ *ngIf="subVolumes$ | async"
+ >
+ <cd-vertical-navigation
+ title="Subvolumes"
+ [items]="subVolumesList"
+ (emitActiveItem)="selectSubVolume($event)"
+ inputIdentifier="subvol-filter"
+ ></cd-vertical-navigation>
</div>
- <div class="col-8 vertical-line"
- *ngIf="isSubVolumesAvailable">
- <cd-table [data]="snapshots$ | async"
- columnMode="flex"
- [columns]="columns"
- selectionType="single"
- [hasDetails]="false"
- (fetchData)="fetchData()"
- (updateSelection)="updateSelection($event)">
-
+ <div
+ class="col-8 vertical-line"
+ *ngIf="isSubVolumesAvailable"
+ >
+ <cd-table
+ [data]="snapshots$ | async"
+ columnMode="flex"
+ [columns]="columns"
+ selectionType="single"
+ [hasDetails]="false"
+ (fetchData)="fetchData()"
+ (updateSelection)="updateSelection($event)"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permissions.cephfs"
- [selection]="selection"
- class="btn-group"
- id="cephfs-snapshot-actions"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permissions.cephfs"
+ [selection]="selection"
+ class="btn-group"
+ id="cephfs-snapshot-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</div>
</div>
<ng-template #noGroupsTpl>
- <cd-alert-panel type="info"
- i18n
- *ngIf="!isLoading">No subvolumes are present. Please create subvolumes to manage snapshots.</cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ i18n
+ *ngIf="!isLoading"
+ >No subvolumes are present. Please create subvolumes to manage snapshots.</cd-alert-panel
+ >
</ng-template>
-<cds-modal size="lg"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
<div cdsModalContent>
- <form name="subvolumegroupForm"
- #formDir="ngForm"
- [formGroup]="subvolumegroupForm"
- novalidate>
+ <form
+ name="subvolumegroupForm"
+ #formDir="ngForm"
+ [formGroup]="subvolumegroupForm"
+ novalidate
+ >
<div class="form-item">
- <cds-text-label label="Name"
- for="subvolumegroupName"
- [invalid]="subvolumegroupForm.controls.subvolumegroupName.invalid && (subvolumegroupForm.controls.subvolumegroupName.dirty)"
- [invalidText]="subvolumegroupNameError"
- cdRequiredField="Name"
- i18n>Name
- <input cdsText
- type="text"
- placeholder="Subvolume group name..."
- i18n-placeholder
- id="subvolumegroupName"
- name="subvolumegroupName"
- [invalid]="subvolumegroupForm.controls.subvolumegroupName.invalid && (subvolumegroupForm.controls.subvolumegroupName.dirty)"
- formControlName="subvolumegroupName"
- modal-primary-focus>
+ <cds-text-label
+ label="Name"
+ for="subvolumegroupName"
+ [invalid]="
+ subvolumegroupForm.controls.subvolumegroupName.invalid &&
+ subvolumegroupForm.controls.subvolumegroupName.dirty
+ "
+ [invalidText]="subvolumegroupNameError"
+ cdRequiredField="Name"
+ i18n
+ >Name
+ <input
+ cdsText
+ type="text"
+ placeholder="Subvolume group name..."
+ i18n-placeholder
+ id="subvolumegroupName"
+ name="subvolumegroupName"
+ [invalid]="
+ subvolumegroupForm.controls.subvolumegroupName.invalid &&
+ subvolumegroupForm.controls.subvolumegroupName.dirty
+ "
+ formControlName="subvolumegroupName"
+ modal-primary-focus
+ />
</cds-text-label>
<ng-template #subvolumegroupNameError>
- <span class="invalid-feedback"
- *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'notUnique')"
- i18n>The subvolume group already exists.</span>
- <span *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Subvolume name can only contain letters, numbers, '.', '-' or '_'</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'notUnique')"
+ i18n
+ >The subvolume group already exists.</span
+ >
+ <span
+ *ngIf="subvolumegroupForm.showError('subvolumegroupName', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Subvolume name can only contain letters, numbers, '.', '-' or '_'</span
+ >
</ng-template>
</div>
<!-- Volume name -->
<div class="form-item">
- <cds-text-label label="Volume name"
- for="volumeName"
- i18n>Volume name
- <input cdsText
- type="text"
- id="volumeName"
- name="volumeName"
- formControlName="volumeName">
+ <cds-text-label
+ label="Volume name"
+ for="volumeName"
+ i18n
+ >Volume name
+ <input
+ cdsText
+ type="text"
+ id="volumeName"
+ name="volumeName"
+ formControlName="volumeName"
+ />
</cds-text-label>
</div>
<!-- Size -->
<div class="form-item">
- <cds-text-label label="Size"
- for="size"
- helperText="The size of the subvolume is specified by setting a quota on it.
+ <cds-text-label
+ label="Size"
+ for="size"
+ helperText="The size of the subvolume is specified by setting a quota on it.
If left blank or put 0, then quota will be infinite"
- i18n-helperText
- [invalid]="subvolumegroupForm.controls.size.invalid && (subvolumegroupForm.controls.size.dirty)"
- [invalidText]="sizeError"
- i18n>Size
- <input cdsText
- type="text"
- id="size"
- name="size"
- formControlName="size"
- i18n-placeholder
- placeholder="e.g., 10GiB"
- defaultUnit="GiB"
- [invalid]="subvolumegroupForm.controls.size.invalid && (subvolumegroupForm.controls.size.dirty)"
- cdDimlessBinary>
+ i18n-helperText
+ [invalid]="
+ subvolumegroupForm.controls.size.invalid && subvolumegroupForm.controls.size.dirty
+ "
+ [invalidText]="sizeError"
+ i18n
+ >Size
+ <input
+ cdsText
+ type="text"
+ id="size"
+ name="size"
+ formControlName="size"
+ i18n-placeholder
+ placeholder="e.g., 10GiB"
+ defaultUnit="GiB"
+ [invalid]="
+ subvolumegroupForm.controls.size.invalid && subvolumegroupForm.controls.size.dirty
+ "
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #sizeError>
- <span *ngIf="subvolumegroupForm.showError('size', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ *ngIf="subvolumegroupForm.showError('size', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
<!-- CephFS Pools -->
<div class="form-item">
- <cds-select label="CephFS Pools"
- for="pool"
- formControlName="pool"
- name="pool"
- id="pool"
- helperText="By default, the data_pool_layout of the parent directory is selected."
- i18n-helperText>
- <option *ngFor="let pool of dataPools"
- [value]="pool.pool">{{ pool.pool }}</option>
+ <cds-select
+ label="CephFS Pools"
+ for="pool"
+ formControlName="pool"
+ name="pool"
+ id="pool"
+ helperText="By default, the data_pool_layout of the parent directory is selected."
+ i18n-helperText
+ >
+ <option
+ *ngFor="let pool of dataPools"
+ [value]="pool.pool"
+ >
+ {{ pool.pool }}
+ </option>
</cds-select>
</div>
<!-- UID -->
<div class="form-item">
- <cds-text-label label="UID"
- for="uid"
- i18n>UID
- <input cdsText
- type="number"
- placeholder="Subvolume UID..."
- id="uid"
- name="uid"
- formControlName="uid">
+ <cds-text-label
+ label="UID"
+ for="uid"
+ i18n
+ >UID
+ <input
+ cdsText
+ type="number"
+ placeholder="Subvolume UID..."
+ id="uid"
+ name="uid"
+ formControlName="uid"
+ />
</cds-text-label>
</div>
<!-- GID -->
<div class="form-item">
- <cds-text-label label="GID"
- for="gid"
- i18n>GID
- <input cdsText
- type="number"
- placeholder="Subvolume group GID..."
- id="gid"
- name="gid"
- formControlName="gid">
+ <cds-text-label
+ label="GID"
+ for="gid"
+ i18n
+ >GID
+ <input
+ cdsText
+ type="number"
+ placeholder="Subvolume group GID..."
+ id="gid"
+ name="gid"
+ formControlName="gid"
+ />
</cds-text-label>
</div>
<!-- Mode -->
<div class="form-item">
- <label class="cds--label"
- for="mode"
- i18n>Mode
+ <label
+ class="cds--label"
+ for="mode"
+ i18n
+ >Mode
</label>
- <cd-help-text>Permissions for the directory. Default mode is 755 which is rwxr-xr-x</cd-help-text>
+ <cd-help-text
+ >Permissions for the directory. Default mode is 755 which is rwxr-xr-x</cd-help-text
+ >
- <cd-checked-table-form [data]="scopePermissions"
- [columns]="columns"
- [form]="subvolumegroupForm"
- inputField="mode"
- [isTableForOctalMode]="true"
- [initialValue]="initialMode"
- [scopes]="scopes"
- [isDisabled]="isEdit"></cd-checked-table-form>
+ <cd-checked-table-form
+ [data]="scopePermissions"
+ [columns]="columns"
+ [form]="subvolumegroupForm"
+ inputField="mode"
+ [isTableForOctalMode]="true"
+ [initialValue]="initialMode"
+ [scopes]="scopes"
+ [isDisabled]="isEdit"
+ ></cd-checked-table-form>
</div>
</form>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="subvolumegroupForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="subvolumegroupForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</ng-container>
</cds-modal>
<ng-container ngbNavItem="details">
<a
ngbNavLink
- i18n>Details</a>
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-detail [data]="details"> </cd-cephfs-detail>
</ng-template>
</ng-container>
<ng-container ngbNavItem="directories">
- <a ngbNavLink
- i18n>Directories</a>
+ <a
+ ngbNavLink
+ i18n
+ >Directories</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-directories [id]="id"></cd-cephfs-directories>
</ng-template>
</ng-container>
<ng-container ngbNavItem="subvolumes">
<a
- ngbNavLink
- i18n>Subvolumes</a>
+ ngbNavLink
+ i18n
+ >Subvolumes</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-subvolume-list
[fsName]="selection.mdsmap.fs_name"
</ng-container>
<ng-container ngbNavItem="subvolume-groups">
<a
- ngbNavLink
- i18n>Subvolume groups</a>
+ ngbNavLink
+ i18n
+ >Subvolume groups</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-subvolume-group
- [fsName]="selection.mdsmap.fs_name"
- [pools]="details.pools">
+ [fsName]="selection.mdsmap.fs_name"
+ [pools]="details.pools"
+ >
</cd-cephfs-subvolume-group>
</ng-template>
</ng-container>
<ng-container ngbNavItem="snapshots">
<a
- ngbNavLink
- i18n>Snapshots</a>
+ ngbNavLink
+ i18n
+ >Snapshots</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-subvolume-snapshots-list [fsName]="selection.mdsmap.fs_name">
</cd-cephfs-subvolume-snapshots-list>
</ng-container>
<ng-container ngbNavItem="snapshot-schedules">
<a
- ngbNavLink
- i18n>Snapshot schedules</a>
+ ngbNavLink
+ i18n
+ >Snapshot schedules</a
+ >
<ng-template ngbNavContent>
<cd-cephfs-snapshotschedule-list
[fsName]="selection.mdsmap.fs_name"
</a>
<ng-template ngbNavContent>
<cd-cephfs-clients
- [id]="id"
- [clients]="clients"
- (triggerApiUpdate)="refresh()">
+ [id]="id"
+ [clients]="clients"
+ (triggerApiUpdate)="refresh()"
+ >
</cd-cephfs-clients>
</ng-template>
</ng-container>
<ng-container ngbNavItem="performance-details">
<a
- ngbNavLink
- i18n>Overview</a>
+ ngbNavLink
+ i18n
+ >Overview</a
+ >
<ng-template ngbNavContent>
<cd-grafana
i18n-title
<ng-container *ngIf="selection">
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="config-details-table">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="config-details-table"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Name</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Name
+ </td>
<td class="w-75">{{ selection.name }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Description</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Description
+ </td>
<td>{{ selection.desc }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Long description</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Long description
+ </td>
<td>{{ selection.long_desc }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Current values</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Current values
+ </td>
<td>
<span *ngFor="let conf of selection.value; last as isLast">
- {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br />
+ {{ conf.section }}: {{ conf.value }}{{ !isLast ? ',' : '' }}<br />
</span>
</td>
</tr>
<tr>
- <td i18n
- class="bold">Default</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Default
+ </td>
<td>{{ selection.default }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Daemon default</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Daemon default
+ </td>
<td>{{ selection.daemon_default }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Type</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Type
+ </td>
<td>{{ selection.type }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Min</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Min
+ </td>
<td>{{ selection.min }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Max</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Max
+ </td>
<td>{{ selection.max }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Flags</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Flags
+ </td>
<td>
<span *ngFor="let flag of selection.flags">
<span title="{{ flags[flag] }}">
</td>
</tr>
<tr>
- <td i18n
- class="bold">
- Services
+ <td
+ i18n
+ class="bold"
+ >
+ Services
</td>
<td>
<span *ngFor="let service of selection.services">
<cds-tag
- *ngIf="service"
- class="tag-dark me-2">
- {{ service }}
- </cds-tag>
+ *ngIf="service"
+ class="tag-dark me-2"
+ >
+ {{ service }}
+ </cds-tag>
</span>
</td>
</tr>
<tr>
- <td i18n
- class="bold">Source</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Source
+ </td>
<td>{{ selection.source }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Level</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Level
+ </td>
<td>{{ selection.level }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Can be updated at runtime (editable)</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Can be updated at runtime (editable)
+ </td>
<td>{{ selection.can_update_at_runtime | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Tags</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Tags
+ </td>
<td>{{ selection.tags }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Enum values</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Enum values
+ </td>
<td>{{ selection.enum_values }}</td>
</tr>
<tr>
- <td i18n
- class="bold">See also</td>
+ <td
+ i18n
+ class="bold"
+ >
+ See also
+ </td>
<td>{{ selection.see_also }}</td>
</tr>
</tbody>
<!-- Long description -->
@if (response?.long_desc) {
- <div
- cdsRow
- class="form-item"
- >
- <legend
- class="cds--label"
- i18n
- >Description</legend>
- <p class="cds--type-body-01 mb-0">{{ response.long_desc }}</p>
- </div>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Description
+ </legend>
+ <p class="cds--type-body-01 mb-0">{{ response.long_desc }}</p>
+ </div>
}
<!-- Default -->
@if (configForm.getValue('default') !== '') {
- <div
- cdsRow
- class="form-item"
- >
- <cds-text-label
- labelInputID="default"
- i18n
+ <div
+ cdsRow
+ class="form-item"
>
- Default
- <input
- cdsText
- type="text"
- id="default"
- formControlName="default"
- readonly
- />
- </cds-text-label>
- </div>
+ <cds-text-label
+ labelInputID="default"
+ i18n
+ >
+ Default
+ <input
+ cdsText
+ type="text"
+ id="default"
+ formControlName="default"
+ readonly
+ />
+ </cds-text-label>
+ </div>
}
<!-- Daemon default -->
@if (configForm.getValue('daemon_default') !== '') {
- <div
- cdsRow
- class="form-item"
- >
- <cds-text-label
- labelInputID="daemon_default"
- i18n
+ <div
+ cdsRow
+ class="form-item"
>
- Daemon default
- <input
- cdsText
- type="text"
- id="daemon_default"
- formControlName="daemon_default"
- readonly
- />
- </cds-text-label>
- </div>
+ <cds-text-label
+ labelInputID="daemon_default"
+ i18n
+ >
+ Daemon default
+ <input
+ cdsText
+ type="text"
+ id="daemon_default"
+ formControlName="daemon_default"
+ readonly
+ />
+ </cds-text-label>
+ </div>
}
<!-- Services -->
@if (configForm.getValue('services')?.length > 0) {
- <div
- cdsRow
- class="form-item form-item-append align-items-center"
- >
<div
- cdsCol
- [columnNumbers]="{ sm: 2, md: 2, lg: 2 }"
- >
- <legend
- class="cds--label mb-0"
- i18n
- >Services</legend>
- </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 6, md: 6, lg: 6 }"
+ cdsRow
+ class="form-item form-item-append align-items-center"
>
- @for (service of configForm.getValue('services'); track service) {
- <cds-tag
- [size]="'md'"
- class="tag-dark me-2"
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 2, lg: 2 }"
>
- {{ service }}
- </cds-tag>
- }
+ <legend
+ class="cds--label mb-0"
+ i18n
+ >
+ Services
+ </legend>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 6, md: 6, lg: 6 }"
+ >
+ @for (service of configForm.getValue('services'); track service) {
+ <cds-tag
+ [size]="'md'"
+ class="tag-dark me-2"
+ >
+ {{ service }}
+ </cds-tag>
+ }
+ </div>
</div>
- </div>
}
<!-- Values -->
@for (section of availSections; track section) {
@if (type === 'bool') {
- <div
- cdsRow
- class="form-item"
- >
- <cds-select
- [formControlName]="section"
- [label]="section"
- [id]="section"
- [labelInputID]="section"
- cdValidate
- #sectionValidate="cdValidate"
- [invalid]="sectionValidate.isInvalid"
- [invalidText]="sectionErrors"
+ <div
+ cdsRow
+ class="form-item"
>
- <option
- [ngValue]="null"
- i18n
- >-- Default --</option>
- <option
- [ngValue]="true"
- i18n
- >true</option>
- <option
- [ngValue]="false"
- i18n
- >false</option>
- </cds-select>
- <ng-template #sectionErrors>
- <ng-container
- *ngTemplateOutlet="validationErrors; context: { control: configForm.get(section) }"
- ></ng-container>
- </ng-template>
- </div>
+ <cds-select
+ [formControlName]="section"
+ [label]="section"
+ [id]="section"
+ [labelInputID]="section"
+ cdValidate
+ #sectionValidate="cdValidate"
+ [invalid]="sectionValidate.isInvalid"
+ [invalidText]="sectionErrors"
+ >
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- Default --
+ </option>
+ <option
+ [ngValue]="true"
+ i18n
+ >
+ true
+ </option>
+ <option
+ [ngValue]="false"
+ i18n
+ >
+ false
+ </option>
+ </cds-select>
+ <ng-template #sectionErrors>
+ <ng-container
+ *ngTemplateOutlet="
+ validationErrors;
+ context: { control: configForm.get(section) }
+ "
+ ></ng-container>
+ </ng-template>
+ </div>
}
@if (type !== 'bool' && inputType === 'number') {
- <div
- cdsRow
- class="form-item"
- >
- <cds-number
- [formControlName]="section"
- [label]="section"
- [id]="section"
- [step]="getStep(type, configForm.getValue(section))"
- [min]="minValue"
- [max]="maxValue"
- cdValidate
- #sectionValidate="cdValidate"
- [invalid]="sectionValidate.isInvalid"
- [invalidText]="sectionErrors"
+ <div
+ cdsRow
+ class="form-item"
>
- </cds-number>
- <ng-template #sectionErrors>
- <ng-container
- *ngTemplateOutlet="validationErrors; context: { control: configForm.get(section) }"
- ></ng-container>
- </ng-template>
- </div>
+ <cds-number
+ [formControlName]="section"
+ [label]="section"
+ [id]="section"
+ [step]="getStep(type, configForm.getValue(section))"
+ [min]="minValue"
+ [max]="maxValue"
+ cdValidate
+ #sectionValidate="cdValidate"
+ [invalid]="sectionValidate.isInvalid"
+ [invalidText]="sectionErrors"
+ >
+ </cds-number>
+ <ng-template #sectionErrors>
+ <ng-container
+ *ngTemplateOutlet="
+ validationErrors;
+ context: { control: configForm.get(section) }
+ "
+ ></ng-container>
+ </ng-template>
+ </div>
}
@if (type !== 'bool' && inputType !== 'number') {
- <div
- cdsRow
- class="form-item"
- >
- <cds-text-label
- [labelInputID]="section"
- [invalid]="sectionValidate.isInvalid"
- [invalidText]="sectionErrors"
+ <div
+ cdsRow
+ class="form-item"
>
- {{ section }}
- <input
- cdsText
- cdValidate
- #sectionValidate="cdValidate"
- [type]="inputType"
- [id]="section"
- [formControlName]="section"
+ <cds-text-label
+ [labelInputID]="section"
[invalid]="sectionValidate.isInvalid"
- />
- </cds-text-label>
- <ng-template #sectionErrors>
- <ng-container
- *ngTemplateOutlet="validationErrors; context: { control: configForm.get(section) }"
- ></ng-container>
- </ng-template>
- </div>
+ [invalidText]="sectionErrors"
+ >
+ {{ section }}
+ <input
+ cdsText
+ cdValidate
+ #sectionValidate="cdValidate"
+ [type]="inputType"
+ [id]="section"
+ [formControlName]="section"
+ [invalid]="sectionValidate.isInvalid"
+ />
+ </cds-text-label>
+ <ng-template #sectionErrors>
+ <ng-container
+ *ngTemplateOutlet="
+ validationErrors;
+ context: { control: configForm.get(section) }
+ "
+ ></ng-container>
+ </ng-template>
+ </div>
}
}
</div>
>
@if (control?.invalid && (control.dirty || control.touched)) {
@if (control.hasError('min')) {
- <span
- class="invalid-feedback"
- i18n
- >The entered value is too low! It must not be lower than {{ minValue }}.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The entered value is too low! It must not be lower than {{ minValue }}.</span
+ >
}
@if (control.hasError('max')) {
- <span
- class="invalid-feedback"
- i18n
- >The entered value is too high! It must not be greater than {{ maxValue }}.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The entered value is too high! It must not be greater than {{ maxValue }}.</span
+ >
}
@if (control.hasError('pattern') || control.hasError('invalidUuid')) {
- <span class="invalid-feedback">{{ patternHelpText }}</span>
+ <span class="invalid-feedback">{{ patternHelpText }}</span>
}
}
</ng-template>
-<cd-table [data]="data"
- (fetchData)="getConfigurationList($event)"
- [columns]="columns"
- [extraFilterableColumns]="filters"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="data"
+ (fetchData)="getConfigurationList($event)"
+ [columns]="columns"
+ [extraFilterableColumns]="filters"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-configuration-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-configuration-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-configuration-details>
</cd-table>
-<ng-template #confValTpl
- let-value="data.value">
+<ng-template
+ #confValTpl
+ let-value="data.value"
+>
<span *ngIf="value">
<span *ngFor="let conf of value; last as isLast">
- {{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br />
+ {{ conf.section }}: {{ conf.value }}{{ !isLast ? ',' : '' }}<br />
</span>
</span>
</ng-template>
<div cdsRow>
<div cdsCol>
<fieldset>
- <legend class="cd-header"
- i18n>Cluster Resources</legend>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Cluster Resources
+ </legend>
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr>
- <td i18n
- class="bold">Hosts</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Hosts
+ </td>
<td>{{ hostsCount }}</td>
</tr>
<tr *ngIf="!isSimpleDeployment; else simpleDeploymentTextTpl">
</dd>
</dl>
</td>
- <td class="pt-5"><p>{{ totalDevices }}</p><p>
- {{ totalCapacity | dimlessBinary }}</p></td>
+ <td class="pt-5">
+ <p>{{ totalDevices }}</p>
+ <p>
+ {{ totalCapacity | dimlessBinary }}
+ </p>
+ </td>
</tr>
<tr>
- <td i18n
- class="bold">CPUs</td>
+ <td
+ i18n
+ class="bold"
+ >
+ CPUs
+ </td>
<td>{{ totalCPUs | empty }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Memory</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Memory
+ </td>
<td>{{ totalMemory | empty }}</td>
</tr>
</tbody>
</div>
<div cdsRow>
<div cdsCol>
- <legend i18n
- class="cd-header">Host Details</legend>
- <cd-hosts [hiddenColumns]="['service_instances', 'status']"
- [hideToolHeader]="true"
- [hasTableDetails]="false"
- [showGeneralActionsOnly]="true"
- [showExpandClusterBtn]="false"
- [showInlineActions]="false">
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Host Details
+ </legend>
+ <cd-hosts
+ [hiddenColumns]="['service_instances', 'status']"
+ [hideToolHeader]="true"
+ [hasTableDetails]="false"
+ [showGeneralActionsOnly]="true"
+ [showExpandClusterBtn]="false"
+ [showInlineActions]="false"
+ >
</cd-hosts>
</div>
</div>
<span i18n>Storage Capacity</span>
</td>
<td>
- <span i18n>{{deploymentDescText}}</span>
+ <span i18n>{{ deploymentDescText }}</span>
</td>
</tr>
</ng-template>
-<div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 16}">
- <h4 i18n>Add Hosts</h4>
+<div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 16 }"
+ >
+ <h4 i18n>Add Hosts</h4>
- <cd-hosts [hiddenColumns]="['service_instances']"
- [hideMaintenance]="true"
- [hasTableDetails]="false"
- [showGeneralActionsOnly]="true"
- [showExpandClusterBtn]="false"></cd-hosts>
- </div>
-</div>
\ No newline at end of file
+ <cd-hosts
+ [hiddenColumns]="['service_instances']"
+ [hideMaintenance]="true"
+ [hasTableDetails]="false"
+ [showGeneralActionsOnly]="true"
+ [showExpandClusterBtn]="false"
+ ></cd-hosts>
+ </div>
+</div>
-<div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 16}">
-
+<div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 16 }"
+ >
<h4 i18n>Create OSDs</h4>
<div>
@if (showForm) {
- <cd-osd-form [hideTitle]="true"
- (emitDriveGroup)="setDriveGroup($event)"
- (emitDeploymentOption)="setDeploymentOptions($event)"
- (emitMode)="setDeploymentMode($event)"
- (osdCreated)="onOsdCreated()"
- (cancelled)="onFormCancelled()"></cd-osd-form>
+ <cd-osd-form
+ [hideTitle]="true"
+ (emitDriveGroup)="setDriveGroup($event)"
+ (emitDeploymentOption)="setDeploymentOptions($event)"
+ (emitMode)="setDeploymentMode($event)"
+ (osdCreated)="onOsdCreated()"
+ (cancelled)="onFormCancelled()"
+ ></cd-osd-form>
} @else {
- <cd-osd-list [showTabs]="false"
- [inlineCreate]="true"
- (createAction)="onCreateAction()"></cd-osd-list>
+ <cd-osd-list
+ [showTabs]="false"
+ [inlineCreate]="true"
+ (createAction)="onCreateAction()"
+ ></cd-osd-list>
}
</div>
- <button cdsButton="secondary"
- class="cds-mt-4"
- id="skipStepBtn"
- (click)="onSkip()"
- aria-label="Skip this step"
- type="button"
- i18n>Skip</button>
+ <button
+ type="button"
+ cdsButton="secondary"
+ class="cds-mt-4"
+ id="skipStepBtn"
+ (click)="onSkip()"
+ aria-label="Skip this step"
+ i18n
+ >
+ Skip
+ </button>
</div>
</div>
-<div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 16}">
-
+<div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 16 }"
+ >
<h4 18n>Create Services</h4>
- <cd-services [hasDetails]="false"
- [hiddenServices]="['mon', 'mgr', 'crash', 'agent']"
- [hiddenColumns]="['status.running', 'status.size', 'status.last_refresh']"
- [routedModal]="false"></cd-services>
+ <cd-services
+ [hasDetails]="false"
+ [hiddenServices]="['mon', 'mgr', 'crash', 'agent']"
+ [hiddenColumns]="['status.running', 'status.size', 'status.last_refresh']"
+ [routedModal]="false"
+ ></cd-services>
</div>
</div>
-<div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8, lg: 16}">
+<div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 16 }"
+ >
<cd-create-cluster-review></cd-create-cluster-review>
</div>
-</div>
\ No newline at end of file
+</div>
@if (startClusterCreation) {
-<div class="container-fluid-main">
- <div cdsRow
- class="cds-ml-5 cds-mt-6">
- <div cdsCol
- [columnNumbers]="{'lg': 13, 'md': 8, 'sm': 8}">
- <div class="mb-4">
- <!-- htmllint img-req-src="false" -->
- <img [src]="projectConstants.cephLogo"
- alt="Ceph"
- class="ceph-logo">
- </div>
-
- <div class="mb-4">
- <span class="cds--type-fluid-heading-05"
- i18n>Welcome to {{ projectConstants.projectName }}
- </span>
- </div>
-
- <div class="mb-2">
- <span class="cds--type-fluid-heading-04"
- i18n>Your Ceph cluster is initialized and running.
- </span>
- </div>
+ <div class="container-fluid-main">
+ <div
+ cdsRow
+ class="cds-ml-5 cds-mt-6"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 13, md: 8, sm: 8 }"
+ >
+ <div class="mb-4">
+ <!-- htmllint img-req-src="false" -->
+ <img
+ [src]="projectConstants.cephLogo"
+ alt="Ceph"
+ class="ceph-logo"
+ />
+ </div>
- <div class="mb-5">
- <span class="cds--type-body-compact-01"
- i18n>
- <cd-icon type="success"
- [size]="icons.size20">
- </cd-icon>
- The cluster control plane is ready.
- </span>
- </div>
+ <div class="mb-4">
+ <span
+ class="cds--type-fluid-heading-05"
+ i18n
+ >Welcome to {{ projectConstants.projectName }}
+ </span>
+ </div>
- <div class="mb-2">
- <span class="cds--type-fluid-heading-03"
- i18n>
- <cd-icon type="ibmCloudBareMetalServer"
- [size]="icons.size20">
- </cd-icon>
- Add storage to begin using your cluster.
- </span>
- </div>
+ <div class="mb-2">
+ <span
+ class="cds--type-fluid-heading-04"
+ i18n
+ >Your Ceph cluster is initialized and running.
+ </span>
+ </div>
- <div class="mb-2">
- <span class="cds--type-body-01"
- i18n>Set up storage for your cluster to run workloads and store data. You can configure storage and data services now, or skip and configure them later.</span>
- </div>
+ <div class="mb-5">
+ <span
+ class="cds--type-body-compact-01"
+ i18n
+ >
+ <cd-icon
+ type="success"
+ [size]="icons.size20"
+ >
+ </cd-icon>
+ The cluster control plane is ready.
+ </span>
+ </div>
- <cds-tile class="border-subtle no-border-bottom"
- [cdsLayer]="1">
- <div cdsStack="horizontal"
- gap="3">
- <span class="cds--type-heading-compact-02"
- i18n>
- Storage requirements
+ <div class="mb-2">
+ <span
+ class="cds--type-fluid-heading-03"
+ i18n
+ >
+ <cd-icon
+ type="ibmCloudBareMetalServer"
+ [size]="icons.size20"
+ >
+ </cd-icon>
+ Add storage to begin using your cluster.
</span>
- <cd-icon type="infoCircle"
- [size]="icons.size20">
- </cd-icon>
</div>
- </cds-tile>
-
- <cds-tile class="border-subtle mb-3"
- [cdsLayer]="2">
- <div cdsStack="horizontal"
- gap="4">
- <cd-icon type="ibmCloudDedicatedHost"
- [size]="icons.size20">
- </cd-icon>
- <div cdsStack="vertical"
- gap="1">
- <span class="cds--type-heading-compact-01"
- i18n>
- Hosts
- </span>
- <span class="cds--type-body-compact-01 text-secondary"
- i18n>
- Minimum 3 hosts required
+
+ <div class="mb-2">
+ <span
+ class="cds--type-body-01"
+ i18n
+ >Set up storage for your cluster to run workloads and store data. You can configure
+ storage and data services now, or skip and configure them later.</span
+ >
+ </div>
+
+ <cds-tile
+ class="border-subtle no-border-bottom"
+ [cdsLayer]="1"
+ >
+ <div
+ cdsStack="horizontal"
+ gap="3"
+ >
+ <span
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Storage requirements
</span>
+ <cd-icon
+ type="infoCircle"
+ [size]="icons.size20"
+ >
+ </cd-icon>
</div>
- </div>
+ </cds-tile>
- <hr/>
+ <cds-tile
+ class="border-subtle mb-3"
+ [cdsLayer]="2"
+ >
+ <div
+ cdsStack="horizontal"
+ gap="4"
+ >
+ <cd-icon
+ type="ibmCloudDedicatedHost"
+ [size]="icons.size20"
+ >
+ </cd-icon>
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <span
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Hosts
+ </span>
+ <span
+ class="cds--type-body-compact-01 text-secondary"
+ i18n
+ >
+ Minimum 3 hosts required
+ </span>
+ </div>
+ </div>
- <div cdsStack="horizontal"
- gap="4">
- <cd-icon type="vmdkDisk"
- [size]="icons.size20">
- </cd-icon>
+ <hr />
- <div cdsStack="vertical"
- gap="1">
- <span class="cds--type-heading-compact-01"
- i18n>
- Disks
- </span>
+ <div
+ cdsStack="horizontal"
+ gap="4"
+ >
+ <cd-icon
+ type="vmdkDisk"
+ [size]="icons.size20"
+ >
+ </cd-icon>
- <span class="cds--type-body-compact-01 text-secondary"
- i18n>
- At least 1 disk per host
- </span>
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <span
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Disks
+ </span>
+
+ <span
+ class="cds--type-body-compact-01 text-secondary"
+ i18n
+ >
+ At least 1 disk per host
+ </span>
+ </div>
</div>
- </div>
- <hr/>
+ <hr />
- <div cdsStack="horizontal"
- gap="4">
- <cd-icon type="clusterIcon"
- [size]="icons.size20">
- </cd-icon>
+ <div
+ cdsStack="horizontal"
+ gap="4"
+ >
+ <cd-icon
+ type="clusterIcon"
+ [size]="icons.size20"
+ >
+ </cd-icon>
- <div cdsStack="vertical"
- gap="1">
- <span class="cds--type-heading-compact-01"
- i18n>
- Data services (optional)
- </span>
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <span
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Data services (optional)
+ </span>
- <span class="cds--type-body-compact-01 text-secondary"
- i18n>
- Configure Object, Block, or File services
- </span>
+ <span
+ class="cds--type-body-compact-01 text-secondary"
+ i18n
+ >
+ Configure Object, Block, or File services
+ </span>
+ </div>
</div>
- </div>
- </cds-tile>
+ </cds-tile>
- <div class="mb-3">
- <cd-alert-panel type="info"
- [showTitle]="false">
- <span class="cds--type-body-compact-01">
- The cluster cannot store data until storage is added. If storage is already configured, continue to the cluster overview.
- </span>
- </cd-alert-panel>
- </div>
+ <div class="mb-3">
+ <cd-alert-panel
+ type="info"
+ [showTitle]="false"
+ >
+ <span class="cds--type-body-compact-01">
+ The cluster cannot store data until storage is added. If storage is already
+ configured, continue to the cluster overview.
+ </span>
+ </cd-alert-panel>
+ </div>
- <div class="mb-5">
- <button cdsButton="primary"
- class="me-3"
- (click)="createCluster()"
- aria-label="Add Storage"
- type="button"
- i18n>
- Add storage
- <cd-icon
- [cdsIcon]="icons.add"
- [size]="icons.size20"
- class="cds--btn__icon">
- </cd-icon>
- </button>
- <button cdsButton="tertiary"
- (click)="skipClusterCreation()"
- aria-label="View cluster overview"
- type="button"
- i18n>
- View cluster overview
- <cd-icon
- [cdsIcon]="icons.right"
- [size]="icons.size20"
- class="cds--btn__icon">
- </cd-icon>
- </button>
+ <div class="mb-5">
+ <button
+ cdsButton="primary"
+ class="me-3"
+ (click)="createCluster()"
+ aria-label="Add Storage"
+ type="button"
+ i18n
+ >
+ Add storage
+ <cd-icon
+ [cdsIcon]="icons.add"
+ [size]="icons.size20"
+ class="cds--btn__icon"
+ >
+ </cd-icon>
+ </button>
+ <button
+ cdsButton="tertiary"
+ (click)="skipClusterCreation()"
+ aria-label="View cluster overview"
+ type="button"
+ i18n
+ >
+ View cluster overview
+ <cd-icon
+ [cdsIcon]="icons.right"
+ [size]="icons.size20"
+ class="cds--btn__icon"
+ >
+ </cd-icon>
+ </button>
+ </div>
</div>
</div>
</div>
-</div>
-}
-@else {
-<cd-tearsheet
- type="full"
- [steps]="steps"
- [title]="title"
- [description]="description"
- [submitButtonLabel]="submitButtonLabel"
- [isSubmitLoading]="isSubmitLoading"
- (submitRequested)="onSubmit()"
- [overflowScroll]="'auto'">
- <cd-tearsheet-step>
- <cd-create-cluster-step-1 #tearsheetStep></cd-create-cluster-step-1>
- </cd-tearsheet-step>
- <cd-tearsheet-step>
- <cd-create-cluster-step-2
- #tearsheetStep
- (skipStep)="onSkipOsdStep()"></cd-create-cluster-step-2>
- </cd-tearsheet-step>
- <cd-tearsheet-step>
- <cd-create-cluster-step-3 #tearsheetStep></cd-create-cluster-step-3>
- </cd-tearsheet-step>
- <cd-tearsheet-step>
- <cd-create-cluster-step-4 #tearsheetStep></cd-create-cluster-step-4>
- </cd-tearsheet-step>
-</cd-tearsheet>
+} @else {
+ <cd-tearsheet
+ type="full"
+ [steps]="steps"
+ [title]="title"
+ [description]="description"
+ [submitButtonLabel]="submitButtonLabel"
+ [isSubmitLoading]="isSubmitLoading"
+ (submitRequested)="onSubmit()"
+ [overflowScroll]="'auto'"
+ >
+ <cd-tearsheet-step>
+ <cd-create-cluster-step-1 #tearsheetStep></cd-create-cluster-step-1>
+ </cd-tearsheet-step>
+ <cd-tearsheet-step>
+ <cd-create-cluster-step-2
+ #tearsheetStep
+ (skipStep)="onSkipOsdStep()"
+ ></cd-create-cluster-step-2>
+ </cd-tearsheet-step>
+ <cd-tearsheet-step>
+ <cd-create-cluster-step-3 #tearsheetStep></cd-create-cluster-step-3>
+ </cd-tearsheet-step>
+ <cd-tearsheet-step>
+ <cd-create-cluster-step-4 #tearsheetStep></cd-create-cluster-step-4>
+ </cd-tearsheet-step>
+ </cd-tearsheet>
}
<ng-template #skipConfirmTpl>
- <span i18n>You are about to skip the storage setup process.
- You'll need to <strong>navigate through the menu to add hosts and services.</strong></span>
+ <span i18n
+ >You are about to skip the storage setup process. You'll need to
+ <strong>navigate through the menu to add hosts and services.</strong></span
+ >
- <div class="cds-mt-4"
- i18n>Are you sure you want to continue?</div>
+ <div
+ class="cds-mt-4"
+ i18n
+ >
+ Are you sure you want to continue?
+ </div>
</ng-template>
<div class="row">
<div class="col-sm-12 col-lg-12">
<div class="card">
- <div class="card-header"
- i18n>CRUSH map viewer</div>
+ <div
+ class="card-header"
+ i18n
+ >
+ CRUSH map viewer
+ </div>
<div class="card-body">
<div class="row">
<div class="col-sm-6 col-lg-6 tree-container">
- <cds-loading *ngIf="loadingIndicator"
- [isActive]="true"
- [overlay]="false"
- size="sm"></cds-loading>
- <cds-tree-view #tree
- [isMultiSelect]="false"
- (select)="onNodeSelected($event)">
- <ng-template #nodeTemplateRef
- let-node="node"
- let-depth="depth">
- <cds-tree-node [node]="node"
- [depth]="depth">
+ <cds-loading
+ *ngIf="loadingIndicator"
+ [isActive]="true"
+ [overlay]="false"
+ size="sm"
+ ></cds-loading>
+ <cds-tree-view
+ #tree
+ [isMultiSelect]="false"
+ (select)="onNodeSelected($event)"
+ >
+ <ng-template
+ #nodeTemplateRef
+ let-node="node"
+ let-depth="depth"
+ >
+ <cds-tree-node
+ [node]="node"
+ [depth]="depth"
+ >
<ng-container *ngIf="node?.children && node?.children?.length">
- <ng-container *ngFor="let child of node.children; let i = index;">
+ <ng-container *ngFor="let child of node.children; let i = index">
<!-- Increase the depth by 1 -->
- <ng-container *ngTemplateOutlet="nodeTemplateRef; context: { node: child, depth: depth + 1 };">
+ <ng-container
+ *ngTemplateOutlet="
+ nodeTemplateRef;
+ context: { node: child, depth: depth + 1 }
+ "
+ >
</ng-container>
</ng-container>
</ng-container>
</cds-tree-node>
</ng-template>
- <ng-template #tag
- let-data>
- <cds-tag *ngIf="data?.status"
- [class]="getStatusClasses(data.status)">
+ <ng-template
+ #tag
+ let-data
+ >
+ <cds-tag
+ *ngIf="data?.status"
+ [class]="getStatusClasses(data.status)"
+ >
{{ data?.status }}
</cds-tag>
<span> </span>
- <span class="node-name"
- [ngClass]="{'type-osd': data?.type === 'osd'}"
- [innerHTML]="data?.name"></span>
+ <span
+ class="node-name"
+ [ngClass]="{ 'type-osd': data?.type === 'osd' }"
+ [innerHTML]="data?.name"
+ ></span>
</ng-template>
<ng-container *ngFor="let node of nodes">
- <ng-container *ngTemplateOutlet="nodeTemplateRef; context: { node: node, depth: 0 };">
+ <ng-container
+ *ngTemplateOutlet="nodeTemplateRef; context: { node: node, depth: 0 }"
+ >
</ng-container>
</ng-container>
</cds-tree-view>
</div>
- <div class="col-sm-6 col-lg-6 metadata"
- *ngIf="metadata">
+ <div
+ class="col-sm-6 col-lg-6 metadata"
+ *ngIf="metadata"
+ >
<legend>{{ metadataTitle }}</legend>
<div>
<cd-table-key-value [data]="metadata"></cd-table-key-value>
<cd-inventory [hostname]="hostname"></cd-inventory>
}
@case ('daemons') {
- <cd-service-daemon-list [hostname]="hostname"
- flag="hostDetails"
- [hiddenColumns]="['hostname']">
+ <cd-service-daemon-list
+ [hostname]="hostname"
+ flag="hostDetails"
+ [hiddenColumns]="['hostname']"
+ >
</cd-service-daemon-list>
}
@case ('performance-details') {
- <cd-grafana i18n-title
- title="Host details"
- [grafanaPath]="'ceph-host-details?var-ceph_hosts=' + hostname"
- [type]="'metrics'"
- uid="rtOg0AiWz"
- grafanaStyle="five">
+ <cd-grafana
+ i18n-title
+ title="Host details"
+ [grafanaPath]="'ceph-host-details?var-ceph_hosts=' + hostname"
+ [type]="'metrics'"
+ uid="rtOg0AiWz"
+ grafanaStyle="five"
+ >
</cd-grafana>
}
@case ('device-health') {
}
}
} @else {
- <cd-alert-panel type="error"
- i18n>No hostname found.</cd-alert-panel>
+ <cd-alert-panel
+ type="error"
+ i18n
+ >No hostname found.</cd-alert-panel
+ >
}
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="true">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="true"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
- <form name="hostForm"
- #formDir="ngForm"
- [formGroup]="hostForm"
- novalidate>
- <div cdsModalContent>
- <!-- Hostname -->
- <div class="form-item">
- <cds-text-label for="hostname"
- [invalid]="!hostForm.controls.hostname.valid && hostForm.controls.hostname.dirty"
- [invalidText]="hostnameError">
- <ng-container i18n>Hostname (required)</ng-container>
- <input cdsText
- type="text"
- placeholder="mon-123"
- id="hostname"
- name="hostname"
- formControlName="hostname"
- autofocus
- [invalid]="!hostForm.controls.hostname.valid && hostForm.controls.hostname.dirty"
- (keyup)="checkHostNameValue()">
- </cds-text-label>
- <ng-template #hostnameError>
- <span *ngIf="hostForm.showError('hostname', formDir, 'required')"
- class="invalid-feedback">
- <ng-container i18n> This field is required. </ng-container>
- </span>
- <span *ngIf="hostForm.showError('hostname', formDir, 'uniqueName')"
- class="invalid-feedback">
- <ng-container i18n> The chosen hostname is already in use. </ng-container>
- </span>
- </ng-template>
- <cd-help-text>
- To add multiple hosts at once, you can enter:
- <ul cdsList>
- <li cdsListItem
- i18n>a comma-separated list of hostnames <b>(e.g.: example-01,example-02,example-03)</b>,</li>
- <li cdsListItem
- i18n>a range expression <b>(e.g.: example-[01-03].ceph)</b>,</li>
- <li cdsListItem
- i18n>a comma separated range expression <b>(e.g.: example-[01-05].lab.com,example2-[1-4].lab.com,example3-[001-006].lab.com)</b></li>
- </ul>
- </cd-help-text>
+ <form
+ name="hostForm"
+ #formDir="ngForm"
+ [formGroup]="hostForm"
+ novalidate
+ >
+ <div cdsModalContent>
+ <!-- Hostname -->
+ <div class="form-item">
+ <cds-text-label
+ for="hostname"
+ [invalid]="!hostForm.controls.hostname.valid && hostForm.controls.hostname.dirty"
+ [invalidText]="hostnameError"
+ >
+ <ng-container i18n>Hostname (required)</ng-container>
+ <input
+ cdsText
+ type="text"
+ placeholder="mon-123"
+ id="hostname"
+ name="hostname"
+ formControlName="hostname"
+ autofocus
+ [invalid]="!hostForm.controls.hostname.valid && hostForm.controls.hostname.dirty"
+ (keyup)="checkHostNameValue()"
+ />
+ </cds-text-label>
+ <ng-template #hostnameError>
+ <span
+ *ngIf="hostForm.showError('hostname', formDir, 'required')"
+ class="invalid-feedback"
+ >
+ <ng-container i18n> This field is required. </ng-container>
+ </span>
+ <span
+ *ngIf="hostForm.showError('hostname', formDir, 'uniqueName')"
+ class="invalid-feedback"
+ >
+ <ng-container i18n> The chosen hostname is already in use. </ng-container>
+ </span>
+ </ng-template>
+ <cd-help-text>
+ To add multiple hosts at once, you can enter:
+ <ul cdsList>
+ <li
+ cdsListItem
+ i18n
+ >
+ a comma-separated list of hostnames <b>(e.g.: example-01,example-02,example-03)</b>,
+ </li>
+ <li
+ cdsListItem
+ i18n
+ >
+ a range expression <b>(e.g.: example-[01-03].ceph)</b>,
+ </li>
+ <li
+ cdsListItem
+ i18n
+ >
+ a comma separated range expression
+ <b
+ >(e.g.:
+ example-[01-05].lab.com,example2-[1-4].lab.com,example3-[001-006].lab.com)</b
+ >
+ </li>
+ </ul>
+ </cd-help-text>
+ </div>
+ <!-- Address -->
+ <div
+ class="form-item"
+ *ngIf="!hostPattern"
+ >
+ <cds-text-label
+ label="Network address"
+ for="addr"
+ i18n
+ >Network address
+ <input
+ cdsText
+ type="text"
+ placeholder="192.168.0.1"
+ id="addr"
+ name="addr"
+ formControlName="addr"
+ />
+ </cds-text-label>
+ <ng-template #hostaddrError>
+ <span *ngIf="hostForm.showError('addr', formDir, 'pattern')">
+ <ng-container i18n> The value is not a valid IP address. </ng-container>
+ </span>
+ </ng-template>
+ </div>
+ <!-- Labels -->
+ <div class="form-item">
+ <cds-combo-box
+ label="Labels"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ for="labels"
+ name="labels"
+ formControlName="labels"
+ placeholder="Select Labels..."
+ i18n-placeholder
+ [appendInline]="true"
+ [items]="labelsOption"
+ itemValueKey="content"
+ id="labels"
+ cdDynamicInputCombobox
+ (updatedItems)="labelsOption = $event"
+ i18n
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ </div>
+ <!-- Maintenance Mode -->
+ <div *ngIf="!hideMaintenance">
+ <cds-checkbox
+ id="maintenance"
+ type="checkbox"
+ formControlName="maintenance"
+ i18n
+ >Maintenance Mode
+ </cds-checkbox>
+ </div>
</div>
- <!-- Address -->
- <div class="form-item"
- *ngIf="!hostPattern">
- <cds-text-label label="Network address"
- for="addr"
- i18n>Network address
- <input cdsText
- type="text"
- placeholder="192.168.0.1"
- id="addr"
- name="addr"
- formControlName="addr"/>
- </cds-text-label>
- <ng-template #hostaddrError>
- <span *ngIf="hostForm.showError('addr', formDir, 'pattern')">
- <ng-container i18n> The value is not a valid IP address. </ng-container>
- </span>
- </ng-template>
- </div>
- <!-- Labels -->
- <div class="form-item">
- <cds-combo-box label="Labels"
- type="multi"
- selectionFeedback="top-after-reopen"
- for="labels"
- name="labels"
- formControlName="labels"
- placeholder="Select Labels..."
- i18n-placeholder
- [appendInline]="true"
- [items]="labelsOption"
- itemValueKey="content"
- id="labels"
- cdDynamicInputCombobox
- (updatedItems)="labelsOption = $event"
- i18n>
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- </div>
- <!-- Maintenance Mode -->
- <div *ngIf="!hideMaintenance">
- <cds-checkbox id="maintenance"
- type="checkbox"
- formControlName="maintenance"
- i18n>Maintenance Mode
- </cds-checkbox>
- </div>
- </div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="hostForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true">
- </cd-form-button-panel>
- </form>
-</ng-container>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="hostForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ >
+ </cd-form-button-panel>
+ </form>
+ </ng-container>
</cds-modal>
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+<nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+>
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>Hosts List</a>
+ <a
+ ngbNavLink
+ i18n
+ >Hosts List</a
+ >
<ng-template ngbNavContent>
- <cd-table #table
- [data]="hosts"
- [columns]="columns"
- columnMode="flex"
- (fetchData)="getHosts($event)"
- selectionType="single"
- [searchableObjects]="true"
- [serverSide]="true"
- [count]="count"
- [maxLimit]="25"
- (updateSelection)="updateSelection($event)"
- [toolHeader]="!hideToolHeader">
+ <cd-table
+ #table
+ [data]="hosts"
+ [columns]="columns"
+ columnMode="flex"
+ (fetchData)="getHosts($event)"
+ selectionType="single"
+ [searchableObjects]="true"
+ [serverSide]="true"
+ [count]="count"
+ [maxLimit]="25"
+ (updateSelection)="updateSelection($event)"
+ [toolHeader]="!hideToolHeader"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permissions.hosts"
- [selection]="selection"
- class="btn-group"
- id="host-actions"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permissions.hosts"
+ [selection]="selection"
+ class="btn-group"
+ id="host-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-table-actions [permission]="permissions.hosts"
- [selection]="selection"
- btnColor="light"
- class="btn-group"
- [tableActions]="expandClusterActions">
+ <cd-table-actions
+ [permission]="permissions.hosts"
+ [selection]="selection"
+ btnColor="light"
+ class="btn-group"
+ [tableActions]="expandClusterActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</ng-template>
</ng-container>
- <ng-container ngbNavItem
- *ngIf="permissions.grafana.read">
+ <ng-container
+ ngbNavItem
+ *ngIf="permissions.grafana.read"
+ >
</ng-container>
- <ng-container ngbNavItem
- *ngIf="permissions.grafana.read">
- <a ngbNavLink
- i18n>Overall Performance</a>
+ <ng-container
+ ngbNavItem
+ *ngIf="permissions.grafana.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Overall Performance</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Host overview"
- [grafanaPath]="'ceph-hosts-overview?'"
- [type]="'metrics'"
- uid="y0KGL0iZz"
- grafanaStyle="two">
+ <cd-grafana
+ i18n-title
+ title="Host overview"
+ [grafanaPath]="'ceph-hosts-overview?'"
+ [type]="'metrics'"
+ uid="y0KGL0iZz"
+ grafanaStyle="two"
+ >
</cd-grafana>
</ng-template>
</ng-container>
<div [ngbNavOutlet]="nav"></div>
-<ng-template #servicesTpl
- let-services="data.value">
+<ng-template
+ #servicesTpl
+ let-services="data.value"
+>
<span *ngFor="let service of services">
- <cd-label [key]="service['type']"
- [value]="service['count']"
- class="me-1"></cd-label>
+ <cd-label
+ [key]="service['type']"
+ [value]="service['count']"
+ class="me-1"
+ ></cd-label>
</span>
</ng-template>
-<ng-template #hostNameTpl
- let-row="data.row">
+<ng-template
+ #hostNameTpl
+ let-row="data.row"
+>
<span data-testid="hostname">
- <a cdsLink
- [routerLink]="[viewUrl, row.hostname | encodeUri]"
- (click)="$event.stopPropagation()">
+ <a
+ cdsLink
+ [routerLink]="[viewUrl, row.hostname | encodeUri]"
+ (click)="$event.stopPropagation()"
+ >
{{ row.hostname }}
- </a>
- </span><br>
- <span class="text-muted fst-italic"
- *ngIf="row.addr"
- data-testid="ip-address">
+ </a> </span
+ ><br />
+ <span
+ class="text-muted fst-italic"
+ *ngIf="row.addr"
+ data-testid="ip-address"
+ >
({{ row.addr }})
</span>
</ng-template>
<ng-template #maintenanceConfirmTpl>
- <div *ngFor="let msg of errorMessage; let last=last">
+ <div *ngFor="let msg of errorMessage; let last = last">
<ul *ngIf="!last || errorMessage.length === '1'">
<li i18n>{{ msg }}</li>
</ul>
</div>
- <ng-container i18n
- *ngIf="showSubmit">Are you sure you want to continue?</ng-container>
+ <ng-container
+ i18n
+ *ngIf="showSubmit"
+ >Are you sure you want to continue?</ng-container
+ >
</ng-template>
-
-<ng-template #hostMetricTmpl
- let-value="data.value">
+<ng-template
+ #hostMetricTmpl
+ let-value="data.value"
+>
<div *ngIf="validValue(value)">
<span>{{ value }}</span>
</div>
</div>
</ng-template>
-<ng-template #hostDimlessTmpl
- let-value="data.value">
+<ng-template
+ #hostDimlessTmpl
+ let-value="data.value"
+>
<div *ngIf="!validValue(value)">
<span ngbTooltip="Not available. Data could not be fetched from Ceph">-</span>
</div>
</ng-template>
<ng-template #orchTmpl>
- <span i18n
- i18n-ngbTooltip
- ngbTooltip="Data will be available only if Orchestrator is available.">-</span>
+ <span
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="Data will be available only if Orchestrator is available."
+ >-</span
+ >
</ng-template>
<ng-template #flashTmpl>
- <span i18n
- i18n-ngbTooltip
- ngbTooltip="SSD, NVMEs">Flash</span>
+ <span
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="SSD, NVMEs"
+ >Flash</span
+ >
</ng-template>
<router-outlet name="modal"></router-outlet>
-<cd-table [data]="devices"
- [columns]="columns"
- identifier="uid"
- [forceIdentifier]="true"
- [selectionType]="selectionType"
- columnMode="flex"
- (fetchData)="getDevices()"
- [searchField]="false"
- (updateSelection)="updateSelection($event)"
- (columnFiltersChanged)="onColumnFiltersChanged($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="devices"
+ [columns]="columns"
+ identifier="uid"
+ [forceIdentifier]="true"
+ [selectionType]="selectionType"
+ columnMode="flex"
+ (fetchData)="getDevices()"
+ [searchField]="false"
+ (updateSelection)="updateSelection($event)"
+ (columnFiltersChanged)="onColumnFiltersChanged($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
<legend i18n>Physical Disks</legend>
<div class="row">
<div class="col-md-12">
- <cd-inventory-devices [devices]="devices"
- [hiddenColumns]="hostname === undefined ? [] : ['hostname']"
- selectionType="single"
- (fetchInventory)="refresh()"
- [orchStatus]="orchStatus">
+ <cd-inventory-devices
+ [devices]="devices"
+ [hiddenColumns]="hostname === undefined ? [] : ['hostname']"
+ selectionType="single"
+ (fetchInventory)="refresh()"
+ [orchStatus]="orchStatus"
+ >
</cd-inventory-devices>
</div>
</div>
<div *ngIf="contentData">
<ng-container *ngTemplateOutlet="logFiltersTpl"></ng-container>
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="logs"
- [cdStatefulTabDefault]="defaultTab"
- [hidden]="!showNavLinks">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="logs"
+ [cdStatefulTabDefault]="defaultTab"
+ [hidden]="!showNavLinks"
+ >
<ng-container ngbNavItem="cluster-logs">
- <a ngbNavLink
- i18n>Cluster Logs</a>
+ <a
+ ngbNavLink
+ i18n
+ >Cluster Logs</a
+ >
<ng-template ngbNavContent>
@if (clog) {
- <div class="log-viewer"
- [class.log-viewer--scrollable]="scrollable">
- @if (clog.length && showClusterLogs && showDownloadCopyButton) {
- <div class="log-actions">
- <cd-download-button [objectItem]="clog"
- [textItem]="clogText"
- fileName="cluster_log">
- </cd-download-button>
- <cd-copy-2-clipboard-button [source]="clogText"
- [byId]="false">
- </cd-copy-2-clipboard-button>
- </div>
- }
-
- <div class="log-entries">
- @for (line of clog; track trackByLogEntry($index, line)) {
- <div class="log-entry cds--type-code-01">
- <span class="log-entry__timestamp ">{{ line.stamp | cdDate }}</span>
- <span class="log-entry__priority"
- [ngClass]="'log-entry__priority--' + (line.priority | logPriority)">
- {{ line.priority }}
- </span>
- <span class="log-entry__message"
- [innerHTML]="line.message | searchHighlight: search">
- </span>
- </div>
+ <div
+ class="log-viewer"
+ [class.log-viewer--scrollable]="scrollable"
+ >
+ @if (clog.length && showClusterLogs && showDownloadCopyButton) {
+ <div class="log-actions">
+ <cd-download-button
+ [objectItem]="clog"
+ [textItem]="clogText"
+ fileName="cluster_log"
+ >
+ </cd-download-button>
+ <cd-copy-2-clipboard-button
+ [source]="clogText"
+ [byId]="false"
+ >
+ </cd-copy-2-clipboard-button>
+ </div>
}
- @if (clog.length === 0) {
- <div class="log-viewer__empty">
- <ng-container *ngTemplateOutlet="noEntriesTpl"></ng-container>
+ <div class="log-entries">
+ @for (line of clog; track trackByLogEntry($index, line)) {
+ <div class="log-entry cds--type-code-01">
+ <span class="log-entry__timestamp">{{ line.stamp | cdDate }}</span>
+ <span
+ class="log-entry__priority"
+ [ngClass]="'log-entry__priority--' + (line.priority | logPriority)"
+ >
+ {{ line.priority }}
+ </span>
+ <span
+ class="log-entry__message"
+ [innerHTML]="line.message | searchHighlight: search"
+ >
+ </span>
+ </div>
+ }
+
+ @if (clog.length === 0) {
+ <div class="log-viewer__empty">
+ <ng-container *ngTemplateOutlet="noEntriesTpl"></ng-container>
+ </div>
+ }
</div>
- }
</div>
- </div>
}
</ng-template>
</ng-container>
<ng-container ngbNavItem="audit-logs">
- <a ngbNavLink
- i18n>Audit Logs</a>
+ <a
+ ngbNavLink
+ i18n
+ >Audit Logs</a
+ >
<ng-template ngbNavContent>
@if (audit_log && showAuditLogs) {
- <div class="log-viewer">
- @if (audit_log.length && showDownloadCopyButton) {
- <div class="log-actions">
- <cd-download-button [objectItem]="audit_log"
- [textItem]="auditLogText"
- fileName="audit_log">
- </cd-download-button>
- <cd-copy-2-clipboard-button [source]="auditLogText"
- [byId]="false">
- </cd-copy-2-clipboard-button>
- </div>
- }
-
- <div class="log-entries">
- @for (line of audit_log; track trackByLogEntry($index, line)) {
- <div class="log-entry cds--type-code-01">
- <span class="log-entry__timestamp">{{ line.stamp | cdDate }}</span>
- <span class="log-entry__priority"
- [ngClass]="'log-entry__priority--' + (line.priority | logPriority)">
- {{ line.priority }}
- </span>
- <span class="log-entry__message"
- [innerHTML]="line.message | searchHighlight: search">
- </span>
- </div>
+ <div class="log-viewer">
+ @if (audit_log.length && showDownloadCopyButton) {
+ <div class="log-actions">
+ <cd-download-button
+ [objectItem]="audit_log"
+ [textItem]="auditLogText"
+ fileName="audit_log"
+ >
+ </cd-download-button>
+ <cd-copy-2-clipboard-button
+ [source]="auditLogText"
+ [byId]="false"
+ >
+ </cd-copy-2-clipboard-button>
+ </div>
}
- @if (audit_log.length === 0) {
- <div class="log-viewer__empty">
- <ng-container *ngTemplateOutlet="noEntriesTpl"></ng-container>
+ <div class="log-entries">
+ @for (line of audit_log; track trackByLogEntry($index, line)) {
+ <div class="log-entry cds--type-code-01">
+ <span class="log-entry__timestamp">{{ line.stamp | cdDate }}</span>
+ <span
+ class="log-entry__priority"
+ [ngClass]="'log-entry__priority--' + (line.priority | logPriority)"
+ >
+ {{ line.priority }}
+ </span>
+ <span
+ class="log-entry__message"
+ [innerHTML]="line.message | searchHighlight: search"
+ >
+ </span>
+ </div>
+ }
+
+ @if (audit_log.length === 0) {
+ <div class="log-viewer__empty">
+ <ng-container *ngTemplateOutlet="noEntriesTpl"></ng-container>
+ </div>
+ }
</div>
- }
</div>
- </div>
}
</ng-template>
</ng-container>
<ng-container ngbNavItem="daemon-logs">
- <a ngbNavLink
- i18n>Daemon Logs</a>
+ <a
+ ngbNavLink
+ i18n
+ >Daemon Logs</a
+ >
<ng-template ngbNavContent>
- <ng-container *ngIf="showDaemonLogs && lokiServiceStatus$ | async as lokiServiceStatus ; else daemonLogsTpl ">
+ <ng-container
+ *ngIf="
+ showDaemonLogs && lokiServiceStatus$ | async as lokiServiceStatus;
+ else daemonLogsTpl
+ "
+ >
<div *ngIf="alloyServiceStatus$ | async as alloyServiceStatus; else daemonLogsTpl">
- <cd-grafana i18n-title
- title="Daemon logs"
- [grafanaPath]="'explore?'"
- [type]="'logs'"
- uid="CrAHE0iZz"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="Daemon logs"
+ [grafanaPath]="'explore?'"
+ [type]="'logs'"
+ uid="CrAHE0iZz"
+ grafanaStyle="three"
+ >
</cd-grafana>
</div>
</ng-container>
</div>
<ng-template #logFiltersTpl>
- <div class="row mb-3"
- *ngIf="showFilterTools">
- <div class="col-lg-10 d-flex">
- <div class="col-sm-1 me-3">
- <label for="logs-priority"
- class="fw-bold"
- i18n>Priority:</label>
- <select id="logs-priority"
- class="form-select"
- [(ngModel)]="priority"
- (ngModelChange)="filterLogs()">
- <option *ngFor="let prio of priorities"
- [value]="prio.value">{{ prio.name }}</option>
- </select>
- </div>
+ <div
+ class="row mb-3"
+ *ngIf="showFilterTools"
+ >
+ <div class="col-lg-10 d-flex">
+ <div class="col-sm-1 me-3">
+ <label
+ for="logs-priority"
+ class="fw-bold"
+ i18n
+ >Priority:</label
+ >
+ <select
+ id="logs-priority"
+ class="form-select"
+ [(ngModel)]="priority"
+ (ngModelChange)="filterLogs()"
+ >
+ <option
+ *ngFor="let prio of priorities"
+ [value]="prio.value"
+ >
+ {{ prio.name }}
+ </option>
+ </select>
+ </div>
- <div class="col-md-3 me-3">
- <label for="logs-keyword"
- class="fw-bold"
- i18n>Keyword:</label>
- <div class="input-group">
- <span class="input-group-text">
- <svg [cdsIcon]="icons.search"
- [size]="icons.size16"
- ></svg>
- </span>
-
- <input class="form-control"
- id="logs-keyword"
- type="text"
- [(ngModel)]="search"
- (keyup)="filterLogs()">
-
- <button type="button"
- class="btn btn-light"
- (click)="clearSearchKey()"
- title="Clear">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
- </button>
+ <div class="col-md-3 me-3">
+ <label
+ for="logs-keyword"
+ class="fw-bold"
+ i18n
+ >Keyword:</label
+ >
+ <div class="input-group">
+ <span class="input-group-text">
+ <svg
+ [cdsIcon]="icons.search"
+ [size]="icons.size16"
+ ></svg>
+ </span>
+
+ <input
+ class="form-control"
+ id="logs-keyword"
+ type="text"
+ [(ngModel)]="search"
+ (keyup)="filterLogs()"
+ />
+
+ <button
+ type="button"
+ class="btn btn-light"
+ (click)="clearSearchKey()"
+ title="Clear"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
+ </button>
+ </div>
</div>
- </div>
- <div class="col-md-3 me-3">
- <label for="logs-date"
- class="fw-bold"
- i18n>Date:</label>
- <div class="input-group">
- <input class="form-control"
- id="logs-date"
- placeholder="YYYY-MM-DD"
- ngbDatepicker
- [maxDate]="maxDate"
- #d="ngbDatepicker"
- (click)="d.open()"
- [(ngModel)]="selectedDate"
- (ngModelChange)="filterLogs()">
- <button type="button"
- class="btn btn-light"
- (click)="clearDate()"
- title="Clear">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- ></svg>
- </button>
+ <div class="col-md-3 me-3">
+ <label
+ for="logs-date"
+ class="fw-bold"
+ i18n
+ >Date:</label
+ >
+ <div class="input-group">
+ <input
+ class="form-control"
+ id="logs-date"
+ placeholder="YYYY-MM-DD"
+ ngbDatepicker
+ [maxDate]="maxDate"
+ #d="ngbDatepicker"
+ (click)="d.open()"
+ [(ngModel)]="selectedDate"
+ (ngModelChange)="filterLogs()"
+ />
+ <button
+ type="button"
+ class="btn btn-light"
+ (click)="clearDate()"
+ title="Clear"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ ></svg>
+ </button>
+ </div>
</div>
- </div>
- <div class="col-md-5">
- <legend i18n
- class="cds--label fw-bold">Time range:</legend>
- <div class="d-flex">
- <ngb-timepicker [spinners]="false"
- [(ngModel)]="startTime"
- (ngModelChange)="filterLogs()"></ngb-timepicker>
-
- <span class="mt-2"> — </span>
-
- <ngb-timepicker [spinners]="false"
- [(ngModel)]="endTime"
- (ngModelChange)="filterLogs()"></ngb-timepicker>
- </div></div>
- </div></div>
+ <div class="col-md-5">
+ <legend
+ i18n
+ class="cds--label fw-bold"
+ >
+ Time range:
+ </legend>
+ <div class="d-flex">
+ <ngb-timepicker
+ [spinners]="false"
+ [(ngModel)]="startTime"
+ (ngModelChange)="filterLogs()"
+ ></ngb-timepicker>
+
+ <span class="mt-2"> — </span>
+
+ <ngb-timepicker
+ [spinners]="false"
+ [(ngModel)]="endTime"
+ (ngModelChange)="filterLogs()"
+ ></ngb-timepicker>
+ </div>
+ </div>
+ </div>
+ </div>
</ng-template>
<ng-template #noEntriesTpl>
<span i18n>No log entries found. Please try to select different filter options.</span>
<span> </span>
- <a href="#"
- (click)="resetFilter()"
- i18n>Reset filter.</a>
+ <a
+ href="#"
+ (click)="resetFilter()"
+ i18n
+ >Reset filter.</a
+ >
</ng-template>
<ng-template #daemonLogsTpl>
- <cd-alert-panel type="info"
- title="Loki/Alloy service not running"
- i18n-title>
- <ng-container i18n>Please start the loki and alloy services to see these logs.</ng-container>
+ <cd-alert-panel
+ type="info"
+ title="Loki/Alloy service not running"
+ i18n-title
+ >
+ <ng-container i18n>Please start the loki and alloy services to see these logs.</ng-container>
</cd-alert-panel>
</ng-template>
<ng-container *ngIf="selection">
- <cd-table-key-value [data]="module_config">
- </cd-table-key-value>
+ <cd-table-key-value [data]="module_config"> </cd-table-key-value>
</ng-container>
-<div class="cd-col-form"
- *cdFormLoading="loading">
- <form name="mgrModuleForm"
- #frm="ngForm"
- [formGroup]="mgrModuleForm"
- novalidate>
+<div
+ class="cd-col-form"
+ *cdFormLoading="loading"
+>
+ <form
+ name="mgrModuleForm"
+ #frm="ngForm"
+ [formGroup]="mgrModuleForm"
+ novalidate
+ >
<div class="card">
- <div class="card-header"
- i18n>Edit Manager module</div>
+ <div
+ class="card-header"
+ i18n
+ >
+ Edit Manager module
+ </div>
<div class="card-body">
- <div class="form-group row"
- *ngFor="let moduleOption of moduleOptions | keyvalue">
-
+ <div
+ class="form-group row"
+ *ngFor="let moduleOption of moduleOptions | keyvalue"
+ >
<!-- Field label -->
- <label class="cd-col-form-label"
- for="{{ moduleOption.value.name }}">
+ <label
+ class="cd-col-form-label"
+ for="{{ moduleOption.value.name }}"
+ >
{{ moduleOption.value.name }}
<cd-helper *ngIf="moduleOption.value.long_desc || moduleOption.value.desc">
{{ moduleOption.value.long_desc || moduleOption.value.desc | upperFirst }}
<!-- Field control -->
<!-- bool -->
- <div class="cd-col-form-input"
- *ngIf="moduleOption.value.type === 'bool'">
+ <div
+ class="cd-col-form-input"
+ *ngIf="moduleOption.value.type === 'bool'"
+ >
<div class="custom-control custom-checkbox">
- <input id="{{ moduleOption.value.name }}"
- type="checkbox"
- class="custom-control-input"
- formControlName="{{ moduleOption.value.name }}">
- <label class="custom-control-label"
- for="{{ moduleOption.value.name }}"></label>
+ <input
+ id="{{ moduleOption.value.name }}"
+ type="checkbox"
+ class="custom-control-input"
+ formControlName="{{ moduleOption.value.name }}"
+ />
+ <label
+ class="custom-control-label"
+ for="{{ moduleOption.value.name }}"
+ ></label>
</div>
</div>
<!-- addr|str|uuid -->
- <div class="cd-col-form-input"
- *ngIf="['addr', 'str', 'uuid'].includes(moduleOption.value.type)">
- <input id="{{ moduleOption.value.name }}"
- class="form-control"
- type="text"
- formControlName="{{ moduleOption.value.name }}"
- *ngIf="moduleOption.value.enum_allowed.length === 0">
- <select id="{{ moduleOption.value.name }}"
- class="form-select"
- formControlName="{{ moduleOption.value.name }}"
- *ngIf="moduleOption.value.enum_allowed.length > 0">
- <option *ngFor="let value of moduleOption.value.enum_allowed"
- [ngValue]="value">
+ <div
+ class="cd-col-form-input"
+ *ngIf="['addr', 'str', 'uuid'].includes(moduleOption.value.type)"
+ >
+ <input
+ id="{{ moduleOption.value.name }}"
+ class="form-control"
+ type="text"
+ formControlName="{{ moduleOption.value.name }}"
+ *ngIf="moduleOption.value.enum_allowed.length === 0"
+ />
+ <select
+ id="{{ moduleOption.value.name }}"
+ class="form-select"
+ formControlName="{{ moduleOption.value.name }}"
+ *ngIf="moduleOption.value.enum_allowed.length > 0"
+ >
+ <option
+ *ngFor="let value of moduleOption.value.enum_allowed"
+ [ngValue]="value"
+ >
{{ value }}
</option>
</select>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'invalidUuid')"
- i18n>The entered value is not a valid UUID, e.g.: 67dcac9f-2c03-4d6c-b7bd-1210b3a259a8</span>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
- i18n>The entered value needs to be a valid IP address.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'invalidUuid')"
+ i18n
+ >The entered value is not a valid UUID, e.g.:
+ 67dcac9f-2c03-4d6c-b7bd-1210b3a259a8</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
+ i18n
+ >The entered value needs to be a valid IP address.</span
+ >
</div>
<!-- uint|int|size|secs -->
- <div class="cd-col-form-input"
- *ngIf="['uint', 'int', 'size', 'secs'].includes(moduleOption.value.type)">
- <input id="{{ moduleOption.value.name }}"
- class="form-control"
- type="number"
- formControlName="{{ moduleOption.value.name }}"
- min="{{ moduleOption.value.min }}"
- max="{{ moduleOption.value.max }}">
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'max')"
- i18n>The entered value is too high! It must be lower or equal to {{ moduleOption.value.max }}.</span>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'min')"
- i18n>The entered value is too low! It must be greater or equal to {{ moduleOption.value.min }}.</span>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
- i18n>The entered value needs to be a number.</span>
+ <div
+ class="cd-col-form-input"
+ *ngIf="['uint', 'int', 'size', 'secs'].includes(moduleOption.value.type)"
+ >
+ <input
+ id="{{ moduleOption.value.name }}"
+ class="form-control"
+ type="number"
+ formControlName="{{ moduleOption.value.name }}"
+ min="{{ moduleOption.value.min }}"
+ max="{{ moduleOption.value.max }}"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'max')"
+ i18n
+ >The entered value is too high! It must be lower or equal to
+ {{ moduleOption.value.max }}.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'min')"
+ i18n
+ >The entered value is too low! It must be greater or equal to
+ {{ moduleOption.value.min }}.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
+ i18n
+ >The entered value needs to be a number.</span
+ >
</div>
<!-- float -->
- <div class="cd-col-form-input"
- *ngIf="moduleOption.value.type === 'float'">
- <input id="{{ moduleOption.value.name }}"
- class="form-control"
- type="number"
- formControlName="{{ moduleOption.value.name }}">
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
- i18n>The entered value needs to be a number or decimal.</span>
+ <div
+ class="cd-col-form-input"
+ *ngIf="moduleOption.value.type === 'float'"
+ >
+ <input
+ id="{{ moduleOption.value.name }}"
+ class="form-control"
+ type="number"
+ formControlName="{{ moduleOption.value.name }}"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
+ i18n
+ >The entered value needs to be a number or decimal.</span
+ >
</div>
-
</div>
</div>
<div class="card-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="mgrModuleForm"
- [submitText]="actionLabels.UPDATE"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="mgrModuleForm"
+ [submitText]="actionLabels.UPDATE"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</div>
</div>
</form>
-<cd-table #table
- [autoReload]="false"
- [data]="modules"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- identifier="module"
- (fetchData)="getModuleList($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [autoReload]="false"
+ [data]="modules"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ identifier="module"
+ (fetchData)="getModuleList($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-mgr-module-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-mgr-module-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-mgr-module-details>
</cd-table>
<fieldset>
- @if(mon_status) {
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
- <tbody>
- <tr>
- <td i18n><B>Cluster ID</B></td>
- <td>{{ mon_status.monmap.fsid }}</td>
- </tr>
- <tr>
- <td i18n><B>monmap modified</B></td>
- <td>{{ mon_status.monmap.modified | relativeDate }}</td>
- </tr>
- <tr>
- <td i18n><B>monmap epoch</B></td>
- <td>{{ mon_status.monmap.epoch }}</td>
- </tr>
- <tr>
- <td i18n><B>quorum con</B></td>
- <td>{{ mon_status.features.quorum_con }}</td>
- </tr>
- <tr>
- <td i18n><B>quorum mon</B></td>
- <td>{{ mon_status.features.quorum_mon }}</td>
- </tr>
- <tr>
- <td i18n><B>required con</B></td>
- <td>{{ mon_status.features.required_con }}</td>
- </tr>
- <tr>
- <td i18n><B>required mon</B></td>
- <td>{{ mon_status.features.required_mon }}</td>
- </tr>
- </tbody>
+ @if (mon_status) {
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
+ <tbody>
+ <tr>
+ <td i18n><B>Cluster ID</B></td>
+ <td>{{ mon_status.monmap.fsid }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>monmap modified</B></td>
+ <td>{{ mon_status.monmap.modified | relativeDate }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>monmap epoch</B></td>
+ <td>{{ mon_status.monmap.epoch }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>quorum con</B></td>
+ <td>{{ mon_status.features.quorum_con }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>quorum mon</B></td>
+ <td>{{ mon_status.features.quorum_mon }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>required con</B></td>
+ <td>{{ mon_status.features.required_con }}</td>
+ </tr>
+ <tr>
+ <td i18n><B>required mon</B></td>
+ <td>{{ mon_status.features.required_mon }}</td>
+ </tr>
+ </tbody>
</table>
- }
+ }
</fieldset>
<div class="cds-mt-4">
- <cd-table [data]="quorum.data"
- [columns]="quorum.columns"
- [headerTitle]="title"
- [headerDescription]="description"
- (fetchData)="refresh()">
- </cd-table>
+ <cd-table
+ [data]="quorum.data"
+ [columns]="quorum.columns"
+ [headerTitle]="title"
+ [headerDescription]="description"
+ (fetchData)="refresh()"
+ >
+ </cd-table>
</div>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- id="tabset-multi-cluster-details"
- class="nav-tabs"
- cdStatefulTab="multi-cluster-details">
- <ng-container ngbNavItem="performance-details"
- *ngIf="permissions.grafana.read">
- <a ngbNavLink
- routerLink="performance-details"
- i18n>Performance Details</a>
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ id="tabset-multi-cluster-details"
+ class="nav-tabs"
+ cdStatefulTab="multi-cluster-details"
+ >
+ <ng-container
+ ngbNavItem="performance-details"
+ *ngIf="permissions.grafana.read"
+ >
+ <a
+ ngbNavLink
+ routerLink="performance-details"
+ i18n
+ >Performance Details</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Cluster details"
- [grafanaPath]="'ceph-cluster-overview?var-cluster=' + selectedClusterFsid"
- [type]="'metrics'"
- uid="edtb0oxdq"
- grafanaStyle="four">
+ <cd-grafana
+ i18n-title
+ title="Cluster details"
+ [grafanaPath]="'ceph-cluster-overview?var-cluster=' + selectedClusterFsid"
+ [type]="'metrics'"
+ uid="edtb0oxdq"
+ grafanaStyle="four"
+ >
</cd-grafana>
</ng-template>
</ng-container>
-<form name="remoteClusterForm"
- #frm="ngForm"
- [formGroup]="remoteClusterForm"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8}">
- <div cdsRow
- class="form-heading">
+<form
+ name="remoteClusterForm"
+ #frm="ngForm"
+ [formGroup]="remoteClusterForm"
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8 }"
+ >
+ <div
+ cdsRow
+ class="form-heading"
+ >
<h3>{{ action | titlecase }} Cluster</h3>
</div>
<cds-inline-notification
- *ngIf="connectionVerified !== undefined && !connectionVerified && connectionMessage !== 'Connection refused'"
+ *ngIf="
+ connectionVerified !== undefined &&
+ !connectionVerified &&
+ connectionMessage !== 'Connection refused'
+ "
kind="error"
title=""
- [subtitle]="connectionMessage">
+ [subtitle]="connectionMessage"
+ >
</cds-inline-notification>
<cds-inline-notification
*ngIf="connectionVerified !== undefined && connectionVerified"
kind="success"
title=""
- [subtitle]="connectionMessage">
+ [subtitle]="connectionMessage"
+ >
</cds-inline-notification>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-text-label
cdRequiredField="Cluster API URL"
- [invalid]="remoteClusterForm.controls.remoteClusterUrl.invalid && remoteClusterForm.controls.remoteClusterUrl.dirty"
+ [invalid]="
+ remoteClusterForm.controls.remoteClusterUrl.invalid &&
+ remoteClusterForm.controls.remoteClusterUrl.dirty
+ "
[invalidText]="urlErrorTpl"
for="remoteClusterUrl"
- i18n>
+ i18n
+ >
Cluster API URL
- <input cdsText
- type="text"
- id="remoteClusterUrl"
- name="remoteClusterUrl"
- placeholder="https://localhost:4202"
- formControlName="remoteClusterUrl"
- [invalid]="remoteClusterForm.controls.remoteClusterUrl.invalid && remoteClusterForm.controls.remoteClusterUrl.dirty">
+ <input
+ cdsText
+ type="text"
+ id="remoteClusterUrl"
+ name="remoteClusterUrl"
+ placeholder="https://localhost:4202"
+ formControlName="remoteClusterUrl"
+ [invalid]="
+ remoteClusterForm.controls.remoteClusterUrl.invalid &&
+ remoteClusterForm.controls.remoteClusterUrl.dirty
+ "
+ />
</cds-text-label>
<ng-template #urlErrorTpl>
- <span class="invalid-feedback"
- *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'required')"
- i18n>This field is required.
+ <span
+ class="invalid-feedback"
+ *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'required')"
+ i18n
+ >This field is required.
</span>
- <span class="invalid-feedback"
- *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'invalidURL')"
- i18n>Please enter a valid URL.
+ <span
+ class="invalid-feedback"
+ *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'invalidURL')"
+ i18n
+ >Please enter a valid URL.
</span>
- <span class="invalid-feedback"
- *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'hubUrlCheck')"
- i18n>The hub cluster cannot be connected.
+ <span
+ class="invalid-feedback"
+ *ngIf="remoteClusterForm.showError('remoteClusterUrl', frm, 'hubUrlCheck')"
+ i18n
+ >The hub cluster cannot be connected.
</span>
</ng-template>
<cd-help-text>
</cd-help-text>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-text-label
cdRequiredField="Alias Name"
[invalid]="remoteClusterForm.showError('clusterAlias', frm)"
[invalidText]="aliasErrorTpl"
for="clusterAlias"
- i18n>
+ i18n
+ >
Alias Name
- <input cdsText
- id="clusterAlias"
- name="clusterAlias"
- placeholder="Name/Text to uniquely identify cluster"
- formControlName="clusterAlias">
+ <input
+ cdsText
+ id="clusterAlias"
+ name="clusterAlias"
+ placeholder="Name/Text to uniquely identify cluster"
+ formControlName="clusterAlias"
+ />
</cds-text-label>
<ng-template #aliasErrorTpl>
- <span *ngIf="remoteClusterForm.showError('clusterAlias', frm, 'required')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('clusterAlias', frm, 'required')"
+ i18n
+ >
This field is required.
</span>
- <span *ngIf="remoteClusterForm.showError('clusterAlias', frm, 'uniqueName')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('clusterAlias', frm, 'uniqueName')"
+ i18n
+ >
The chosen alias name is already in use.
</span>
</ng-template>
</div>
- <div cdsRow
- class="form-item"
- *ngIf="action !== 'edit'">
+ <div
+ cdsRow
+ class="form-item"
+ *ngIf="action !== 'edit'"
+ >
<cds-text-label
cdRequiredField="Username"
[invalid]="remoteClusterForm.showError('username', frm)"
[invalidText]="usernameErrorTpl"
for="username"
- i18n>
+ i18n
+ >
Username
- <input cdsText
- id="username"
- name="username"
- formControlName="username">
+ <input
+ cdsText
+ id="username"
+ name="username"
+ formControlName="username"
+ />
</cds-text-label>
<ng-template #usernameErrorTpl>
- <span *ngIf="remoteClusterForm.showError('username', frm, 'required')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('username', frm, 'required')"
+ i18n
+ >
This field is required.
</span>
- <span *ngIf="remoteClusterForm.showError('username', frm, 'uniqueUrlandUser')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('username', frm, 'uniqueUrlandUser')"
+ i18n
+ >
A cluster with the chosen user is already connected.
</span>
</ng-template>
</div>
- <div cdsRow
- class="form-item"
- *ngIf="action !== 'edit'">
- <cds-password-label labelInputID="password"
- label="Password..."
- i18n>Password
- <input cdsPassword
- type="password"
- placeholder="Password..."
- id="password"
- name="password"
- autocomplete="new-password"
- formControlName="password">
+ <div
+ cdsRow
+ class="form-item"
+ *ngIf="action !== 'edit'"
+ >
+ <cds-password-label
+ labelInputID="password"
+ label="Password..."
+ i18n
+ >Password
+ <input
+ cdsPassword
+ type="password"
+ placeholder="Password..."
+ id="password"
+ name="password"
+ autocomplete="new-password"
+ formControlName="password"
+ />
</cds-password-label>
</div>
- <div cdsRow
- class="form-item"
- *ngIf="action !== 'edit'">
- <cds-select formControlName="ttl"
- name="ttl"
- for="ttl"
- label="Login Expiration"
- id="ttl"
- i18n>
+ <div
+ cdsRow
+ class="form-item"
+ *ngIf="action !== 'edit'"
+ >
+ <cds-select
+ formControlName="ttl"
+ name="ttl"
+ for="ttl"
+ label="Login Expiration"
+ id="ttl"
+ i18n
+ >
<option value="1">1 day</option>
<option value="7">1 week</option>
<option value="15">15 days</option>
</cds-select>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-checkbox
formControlName="ssl"
id="ssl"
- i18n>
+ i18n
+ >
SSL
</cds-checkbox>
</div>
- <div cdsRow
- class="form-item"
- *ngIf="remoteClusterForm.get('ssl').value">
+ <div
+ cdsRow
+ class="form-item"
+ *ngIf="remoteClusterForm.get('ssl').value"
+ >
<cds-text-label
label="Certificate"
[helperText]="sslHelpTpl"
[invalid]="remoteClusterForm.showError('ssl_cert', frm)"
[invalidText]="sslCertErrorTpl"
- i18n>
- <div cdsStack="vertical"
- gap="3">
- <textarea cdsTextArea
- id="ssl_cert"
- rows="5"
- formControlName="ssl_cert"></textarea>
- <input type="file"
- (change)="fileUpload($event.target.files, 'ssl_cert')">
+ i18n
+ >
+ <div
+ cdsStack="vertical"
+ gap="3"
+ >
+ <textarea
+ cdsTextArea
+ id="ssl_cert"
+ rows="5"
+ formControlName="ssl_cert"
+ ></textarea>
+ <input
+ type="file"
+ (change)="fileUpload($event.target.files, 'ssl_cert')"
+ />
</div>
</cds-text-label>
<ng-template #sslHelpTpl>
<span i18n>The SSL certificate in PEM format.</span>
</ng-template>
<ng-template #sslCertErrorTpl>
- <span *ngIf="remoteClusterForm.showError('ssl_cert', frm, 'required')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('ssl_cert', frm, 'required')"
+ i18n
+ >
This field is required.
</span>
- <span *ngIf="remoteClusterForm.showError('ssl_cert', frm, 'pattern')"
- i18n>
+ <span
+ *ngIf="remoteClusterForm.showError('ssl_cert', frm, 'pattern')"
+ i18n
+ >
Invalid SSL certificate.
</span>
</ng-template>
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="frm"
- [submitText]="(action | titlecase) + ' ' + 'Cluster'"
- wrappingClass="text-right"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="frm"
+ [submitText]="(action | titlecase) + ' ' + 'Cluster'"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</div>
</div>
</form>
<ng-template #emptyCluster>
- <ng-container class="container h-75"
- *ngIf="managedByConfig$ | async as managedByConfig">
+ <ng-container
+ class="container h-75"
+ *ngIf="managedByConfig$ | async as managedByConfig"
+ >
<div class="row h-100 justify-content-center align-items-center">
<div class="blank-page">
- <i class="mx-auto d-block"
- [ngClass]="[icons.size24, icons.wrench]">
+ <i
+ class="mx-auto d-block"
+ [ngClass]="[icons.size24, icons.wrench]"
+ >
</i>
- <div class="mt-4 text-center">
- <h4 class="mt-3">This cluster is already managed by cluster -
- <a target="_blank"
- [href]="managedByConfig['MANAGED_BY_CLUSTERS'][0]['url']">
- {{ managedByConfig['MANAGED_BY_CLUSTERS'][0]['fsid'] }}
- <cd-icon type="launch"></cd-icon>
- </a>
- </h4>
- </div>
+ <div class="mt-4 text-center">
+ <h4 class="mt-3">
+ This cluster is already managed by cluster -
+ <a
+ target="_blank"
+ [href]="managedByConfig['MANAGED_BY_CLUSTERS'][0]['url']"
+ >
+ {{ managedByConfig['MANAGED_BY_CLUSTERS'][0]['fsid'] }}
+ <cd-icon type="launch"></cd-icon>
+ </a>
+ </h4>
+ </div>
</div>
</div>
</ng-container>
<ng-container *ngIf="managedByConfig$ | async as managedByConfig">
<div *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length === 0; else emptyCluster">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ >
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>Clusters List</a>
+ <a
+ ngbNavLink
+ i18n
+ >Clusters List</a
+ >
<ng-template ngbNavContent>
- <cd-table #table
- [data]="data"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- (fetchData)="refresh()"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- [maxLimit]="25"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions [permission]="permissions.user"
- [selection]="selection"
- class="table-actions"
- id="cluster-actions"
- [tableActions]="tableActions">
+ <cd-table
+ #table
+ [data]="data"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ (fetchData)="refresh()"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ [maxLimit]="25"
+ (updateSelection)="updateSelection($event)"
+ >
+ <cd-table-actions
+ [permission]="permissions.user"
+ [selection]="selection"
+ class="table-actions"
+ id="cluster-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-multi-cluster-details *cdTableDetail
- [permissions]="permissions"
- [selection]="expandedRow">
+ <cd-multi-cluster-details
+ *cdTableDetail
+ [permissions]="permissions"
+ [selection]="expandedRow"
+ >
</cd-multi-cluster-details>
</cd-table>
</ng-template>
</div>
</ng-container>
-<ng-template #urlTpl
- let-row="data.row">
- <a target="_blank"
- [href]="row.url">
- {{ row?.url?.endsWith('/') ? row?.url?.slice(0, -1) : row.url }}
+<ng-template
+ #urlTpl
+ let-row="data.row"
+>
+ <a
+ target="_blank"
+ [href]="row.url"
+ >
+ {{ row?.url?.endsWith('/') ? row?.url?.slice(0, -1) : row.url }}
<cd-icon type="launch"></cd-icon>
</a>
</ng-template>
-<ng-template #durationTpl
- let-column="data.column"
- let-value="data.value"
- let-row="data.row">
+<ng-template
+ #durationTpl
+ let-column="data.column"
+ let-value="data.value"
+ let-row="data.row"
+>
<span *ngIf="row.remainingTimeWithoutSeconds > 0 && row.cluster_alias !== 'local-cluster'">
- <i *ngIf="row.remainingDays < 8"
- i18n-title
- title="Cluster's token is about to expire"
- [class.icon-danger-color]="row.remainingDays < 2"
- [class.icon-warning-color]="row.remainingDays < 8"
- class="{{ icons.warning }}"></i>
- <span title="{{ row.expiryDate }}">{{ row.remainingTimeWithoutSeconds / 1000 | duration }}</span>
+ <i
+ *ngIf="row.remainingDays < 8"
+ i18n-title
+ title="Cluster's token is about to expire"
+ [class.icon-danger-color]="row.remainingDays < 2"
+ [class.icon-warning-color]="row.remainingDays < 8"
+ class="{{ icons.warning }}"
+ ></i>
+ <span title="{{ row.expiryDate }}">{{
+ row.remainingTimeWithoutSeconds / 1000 | duration
+ }}</span>
</span>
- <span *ngIf="row.remainingTimeWithoutSeconds <= 0 && row.remainingDays <=0 && row.cluster_alias !== 'local-cluster'">
- <i i18n-title
- title="Cluster's token has expired"
- class="{{ icons.danger }}"></i>
+ <span
+ *ngIf="
+ row.remainingTimeWithoutSeconds <= 0 &&
+ row.remainingDays <= 0 &&
+ row.cluster_alias !== 'local-cluster'
+ "
+ >
+ <i
+ i18n-title
+ title="Cluster's token has expired"
+ class="{{ icons.danger }}"
+ ></i>
<span class="text-danger">Token expired</span>
</span>
<span *ngIf="row.cluster_alias === 'local-cluster'">N/A</span>
<ng-template #emptyCluster>
- <ng-container class="container h-75"
- *ngIf="managedByConfig$ | async as managedByConfig">
+ <ng-container
+ class="container h-75"
+ *ngIf="managedByConfig$ | async as managedByConfig"
+ >
<div class="row h-100 justify-content-center align-items-center">
<div class="blank-page">
- <svg cdsIcon="connect"
- size="32"
- class="mx-auto d-block"></svg>
- <div class="mt-4 text-center"
- *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length === 0">
+ <svg
+ cdsIcon="connect"
+ size="32"
+ class="mx-auto d-block"
+ ></svg>
+ <div
+ class="mt-4 text-center"
+ *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length === 0"
+ >
<h3 class="fw-bold">Connect Cluster</h3>
- <h4 class="mt-3">Upgrade your current cluster to a multi-cluster setup effortlessly.
- Click on the "Connect Cluster" button to begin the process.</h4>
+ <h4 class="mt-3">
+ Upgrade your current cluster to a multi-cluster setup effortlessly. Click on the
+ "Connect Cluster" button to begin the process.
+ </h4>
</div>
- <div class="mt-4 text-center"
- *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length > 0">
- <h4 class="mt-3">This cluster is already managed by cluster -
- <a target="_blank"
- [href]="managedByConfig['MANAGED_BY_CLUSTERS'][0]['url']">
- {{ managedByConfig['MANAGED_BY_CLUSTERS'][0]['fsid'] }}
+ <div
+ class="mt-4 text-center"
+ *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length > 0"
+ >
+ <h4 class="mt-3">
+ This cluster is already managed by cluster -
+ <a
+ target="_blank"
+ [href]="managedByConfig['MANAGED_BY_CLUSTERS'][0]['url']"
+ >
+ {{ managedByConfig['MANAGED_BY_CLUSTERS'][0]['fsid'] }}
<cd-icon type="launch"></cd-icon>
</a>
</h4>
</div>
- <div class="mt-4"
- *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length === 0">
+ <div
+ class="mt-4"
+ *ngIf="managedByConfig['MANAGED_BY_CLUSTERS'].length === 0"
+ >
<div class="text-center">
- <button class="btn btn-primary"
- (click)="openConnectClusterForm()"
- type="button">
- <i class="mx-auto"
- [ngClass]="icons.add">
- </i> Connect Cluster
+ <button
+ class="btn btn-primary"
+ (click)="openConnectClusterForm()"
+ type="button"
+ >
+ <i
+ class="mx-auto"
+ [ngClass]="icons.add"
+ >
+ </i>
+ Connect Cluster
</button>
</div>
</div>
<ng-template #nametpl>
<div cdstabledata>
- <span title="{{cluster}}">
+ <span title="{{ cluster }}">
<a href="#">
- {{cluster}}
+ {{ cluster }}
</a>
</span>
</div>
<div class="container h-75">
<div class="row h-100 justify-content-center align-items-center">
<div class="blank-page">
- <cds-loading class="mx-auto d-block"
- [isActive]="true"
- [overlay]="false"
- size="lg"></cds-loading>
- <p class="text-center mt-3"
- i18n>Loading data, Please wait...</p>
+ <cds-loading
+ class="mx-auto d-block"
+ [isActive]="true"
+ [overlay]="false"
+ size="lg"
+ ></cds-loading>
+ <p
+ class="text-center mt-3"
+ i18n
+ >
+ Loading data, Please wait...
+ </p>
</div>
</div>
</div>
</ng-template>
<ng-container *ngIf="managedByConfig$ | async as managedByConfig">
- <div class="container-fluid h-100 p-4"
- *ngIf="isMultiCluster && managedByConfig['MANAGED_BY_CLUSTERS'].length === 0; else emptyCluster">
+ <div
+ class="container-fluid h-100 p-4"
+ *ngIf="isMultiCluster && managedByConfig['MANAGED_BY_CLUSTERS'].length === 0; else emptyCluster"
+ >
<ng-container *ngIf="!loading; else loadingTpl">
- <cd-alert-panel type="error"
- spacingClass="mb-3"
- [showTitle]="false"
- size="slim"
- *ngIf="prometheusConnectionErrors.length > 0"
- (dismissed)="onDismissed()"
- [dismissible]="true"
- i18n>
- <div>
- <p><strong>Could not retrieve metrics from the following clusters:</strong></p>
- <div *ngFor="let cluster of prometheusConnectionErrors">
- <p>
- <strong>Cluster Name:</strong> {{ cluster['cluster_alias'] }}<br>
- <strong>Cluster ID:</strong> {{ cluster['cluster_name'] }}<br>
- <strong>Issue:</strong> {{ cluster.reconnectionError ? cluster.reconnectionError : 'Security configuration error' }}<br>
- </p>
+ <cd-alert-panel
+ type="error"
+ spacingClass="mb-3"
+ [showTitle]="false"
+ size="slim"
+ *ngIf="prometheusConnectionErrors.length > 0"
+ (dismissed)="onDismissed()"
+ [dismissible]="true"
+ i18n
+ >
+ <div>
+ <p><strong>Could not retrieve metrics from the following clusters:</strong></p>
+ <div *ngFor="let cluster of prometheusConnectionErrors">
+ <p>
+ <strong>Cluster Name:</strong> {{ cluster['cluster_alias'] }}<br />
+ <strong>Cluster ID:</strong> {{ cluster['cluster_name'] }}<br />
+ <strong>Issue:</strong>
+ {{
+ cluster.reconnectionError
+ ? cluster.reconnectionError
+ : 'Security configuration error'
+ }}<br />
+ </p>
+ </div>
</div>
- </div>
</cd-alert-panel>
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- [showTitle]="false"
- size="slim"
- *ngIf="showDeletionMessage"
- (dismissed)="onDismissed()"
- [dismissible]="true"
- i18n>
- <p>Please note that the data for the disconnected cluster will be visible for a duration of ~ 5 minutes. After this period, it will be automatically removed.</p>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ [showTitle]="false"
+ size="slim"
+ *ngIf="showDeletionMessage"
+ (dismissed)="onDismissed()"
+ [dismissible]="true"
+ i18n
+ >
+ <p>
+ Please note that the data for the disconnected cluster will be visible for a duration of ~
+ 5 minutes. After this period, it will be automatically removed.
+ </p>
</cd-alert-panel>
<cd-card-group>
<div class="col-lg-4">
<div class="row">
- <cd-card cardTitle="Clusters"
- i18n-title
- class="col-sm-6 m-0 p-0 ps-4 pe-2"
- aria-label="Clusters"
- [fullHeight]="true"
- *ngIf="queriesResults.CLUSTER_COUNT && queriesResults.CLUSTER_COUNT[0]">
+ <cd-card
+ cardTitle="Clusters"
+ i18n-title
+ class="col-sm-6 m-0 p-0 ps-4 pe-2"
+ aria-label="Clusters"
+ [fullHeight]="true"
+ *ngIf="queriesResults.CLUSTER_COUNT && queriesResults.CLUSTER_COUNT[0]"
+ >
<span class="text-center">
- <h3 *ngIf="queriesResults['HEALTH_ERROR_COUNT'][0][1] === '0' && queriesResults['HEALTH_OK_COUNT'][0][1] === '0' && queriesResults['HEALTH_WARNING_COUNT'][0][1] === '0'">{{ queriesResults.CLUSTER_COUNT[0][1] }}</h3>
- <h3 class="text-danger"
- *ngIf="queriesResults.HEALTH_ERROR_COUNT[0][1] !== '0'">
+ <h3
+ *ngIf="
+ queriesResults['HEALTH_ERROR_COUNT'][0][1] === '0' &&
+ queriesResults['HEALTH_OK_COUNT'][0][1] === '0' &&
+ queriesResults['HEALTH_WARNING_COUNT'][0][1] === '0'
+ "
+ >
+ {{ queriesResults.CLUSTER_COUNT[0][1] }}
+ </h3>
+ <h3
+ class="text-danger"
+ *ngIf="queriesResults.HEALTH_ERROR_COUNT[0][1] !== '0'"
+ >
<i [ngClass]="icons.danger"></i>
{{ queriesResults.HEALTH_ERROR_COUNT[0][1] }}
</h3>
- <h3 class="text-warning"
- *ngIf="queriesResults.HEALTH_WARNING_COUNT[0][1] !== '0'">
+ <h3
+ class="text-warning"
+ *ngIf="queriesResults.HEALTH_WARNING_COUNT[0][1] !== '0'"
+ >
<i [ngClass]="icons.warning"></i>
- {{ queriesResults.HEALTH_WARNING_COUNT[0][1] }}
+ {{ queriesResults.HEALTH_WARNING_COUNT[0][1] }}
</h3>
- <h3 class="text-danger"
- *ngIf="queriesResults.HEALTH_ERROR_COUNT[0][1] !== '0'">
+ <h3
+ class="text-danger"
+ *ngIf="queriesResults.HEALTH_ERROR_COUNT[0][1] !== '0'"
+ >
<i [ngClass]="icons.danger"></i>
{{ queriesResults.HEALTH_ERROR_COUNT[0][1] }}
</h3>
- <h3 class="text-success"
- *ngIf="queriesResults.HEALTH_OK_COUNT[0][1] !== '0'">
+ <h3
+ class="text-success"
+ *ngIf="queriesResults.HEALTH_OK_COUNT[0][1] !== '0'"
+ >
<i [ngClass]="icons.success"></i>
- {{ queriesResults.HEALTH_OK_COUNT[0][1] }}
+ {{ queriesResults.HEALTH_OK_COUNT[0][1] }}
</h3>
</span>
</cd-card>
- <cd-card cardTitle="Alerts"
- i18n-title
- class="col-sm-6 m-0 p-0 ps-2 pe-2"
- aria-label="Alerts"
- [fullHeight]="true"
- *ngIf="queriesResults['ALERTS_COUNT'] && queriesResults['ALERTS_COUNT'][0]">
+ <cd-card
+ cardTitle="Alerts"
+ i18n-title
+ class="col-sm-6 m-0 p-0 ps-2 pe-2"
+ aria-label="Alerts"
+ [fullHeight]="true"
+ *ngIf="queriesResults['ALERTS_COUNT'] && queriesResults['ALERTS_COUNT'][0]"
+ >
<span class="text-center">
- <h3 *ngIf="queriesResults['CRITICAL_ALERTS_COUNT'][0][1] === '0' && queriesResults['WARNING_ALERTS_COUNT'][0][1] === '0'">
- {{ queriesResults['ALERTS_COUNT'][0][1] }}
+ <h3
+ *ngIf="
+ queriesResults['CRITICAL_ALERTS_COUNT'][0][1] === '0' &&
+ queriesResults['WARNING_ALERTS_COUNT'][0][1] === '0'
+ "
+ >
+ {{ queriesResults['ALERTS_COUNT'][0][1] }}
</h3>
- <h3 class="text-danger"
- *ngIf="queriesResults['CRITICAL_ALERTS_COUNT'][0][1] !== '0'">
+ <h3
+ class="text-danger"
+ *ngIf="queriesResults['CRITICAL_ALERTS_COUNT'][0][1] !== '0'"
+ >
<i [ngClass]="icons.danger"></i>
{{ queriesResults['CRITICAL_ALERTS_COUNT'][0][1] }}
</h3>
- <h3 class="text-warning"
- *ngIf="queriesResults['WARNING_ALERTS_COUNT'][0][1] !== '0'">
+ <h3
+ class="text-warning"
+ *ngIf="queriesResults['WARNING_ALERTS_COUNT'][0][1] !== '0'"
+ >
<i [ngClass]="icons.warning"></i>
- {{ queriesResults['WARNING_ALERTS_COUNT'][0][1] }}
+ {{ queriesResults['WARNING_ALERTS_COUNT'][0][1] }}
</h3>
</span>
</cd-card>
</div>
<div class="row pt-3">
- <cd-card cardTitle="Connection Errors"
- i18n-title
- class="col-sm-6 m-0 p-0 ps-4 pe-2"
- aria-label="Connection Errors">
+ <cd-card
+ cardTitle="Connection Errors"
+ i18n-title
+ class="col-sm-6 m-0 p-0 ps-4 pe-2"
+ aria-label="Connection Errors"
+ >
<span class="text-center">
- <h3 [ngClass]="{'text-danger': connectionErrorsCount > 0}">
- <i [ngClass]="icons.danger"
- *ngIf="connectionErrorsCount > 0"></i>
+ <h3 [ngClass]="{ 'text-danger': connectionErrorsCount > 0 }">
+ <i
+ [ngClass]="icons.danger"
+ *ngIf="connectionErrorsCount > 0"
+ ></i>
{{ connectionErrorsCount }}
</h3>
</span>
</cd-card>
- <cd-card cardTitle="Hosts"
- i18n-title
- class="col-sm-6 m-0 p-0 ps-2 pe-2"
- aria-label="Total number of hosts"
- *ngIf="queriesResults['TOTAL_HOSTS'] && queriesResults['TOTAL_HOSTS'][0]">
+ <cd-card
+ cardTitle="Hosts"
+ i18n-title
+ class="col-sm-6 m-0 p-0 ps-2 pe-2"
+ aria-label="Total number of hosts"
+ *ngIf="queriesResults['TOTAL_HOSTS'] && queriesResults['TOTAL_HOSTS'][0]"
+ >
<span class="text-center">
<h3>{{ queriesResults['TOTAL_HOSTS'][0][1] }}</h3>
</span>
</div>
<div class="row pt-3">
- <cd-card cardTitle="Capacity"
- i18n-title
- class="col-sm-12 m-0 p-0 ps-4 pe-2"
- aria-label="Capacity card"
- *ngIf="queriesResults['TOTAL_CLUSTERS_CAPACITY'] && queriesResults['TOTAL_CLUSTERS_CAPACITY'][0] && queriesResults['TOTAL_USED_CAPACITY'] && queriesResults['TOTAL_USED_CAPACITY'][0]">
+ <cd-card
+ cardTitle="Capacity"
+ i18n-title
+ class="col-sm-12 m-0 p-0 ps-4 pe-2"
+ aria-label="Capacity card"
+ *ngIf="
+ queriesResults['TOTAL_CLUSTERS_CAPACITY'] &&
+ queriesResults['TOTAL_CLUSTERS_CAPACITY'][0] &&
+ queriesResults['TOTAL_USED_CAPACITY'] &&
+ queriesResults['TOTAL_USED_CAPACITY'][0]
+ "
+ >
<ng-container class="ms-4 me-4">
- <cd-dashboard-pie [data]="{max: queriesResults['TOTAL_CLUSTERS_CAPACITY'][0][1], current: queriesResults['TOTAL_USED_CAPACITY'][0][1]}"
- lowThreshold=".95"
- highThreshold=".99">
+ <cd-dashboard-pie
+ [data]="{
+ max: queriesResults['TOTAL_CLUSTERS_CAPACITY'][0][1],
+ current: queriesResults['TOTAL_USED_CAPACITY'][0][1]
+ }"
+ lowThreshold=".95"
+ highThreshold=".99"
+ >
</cd-dashboard-pie>
</ng-container>
</cd-card>
</div>
<div class="col-sm-8 ps-2">
- <cd-card [cardTitle]="'Top ' + COUNT_OF_UTILIZATION_CHARTS + ' Cluster Utilization'"
- i18n-title
- [fullHeight]="true"
- aria-label="Cluster Utilization card"
- *ngIf="clusters">
+ <cd-card
+ [cardTitle]="'Top ' + COUNT_OF_UTILIZATION_CHARTS + ' Cluster Utilization'"
+ i18n-title
+ [fullHeight]="true"
+ aria-label="Cluster Utilization card"
+ *ngIf="clusters"
+ >
<div class="ms-4 me-4 mt-0">
- <cd-dashboard-time-selector (selectedTime)="getPrometheusData($event, 'clusterUtilization')">
+ <cd-dashboard-time-selector
+ (selectedTime)="getPrometheusData($event, 'clusterUtilization')"
+ >
</cd-dashboard-time-selector>
- <cd-dashboard-area-chart chartTitle="Capacity"
- [labelsArray]="capacityLabels"
- isMultiCluster="true"
- dataUnits="B"
- [dataArray]="capacityValues"
- [truncateLabel]="true"
- *ngIf="capacityLabels && capacityValues">
+ <cd-dashboard-area-chart
+ chartTitle="Capacity"
+ [labelsArray]="capacityLabels"
+ isMultiCluster="true"
+ dataUnits="B"
+ [dataArray]="capacityValues"
+ [truncateLabel]="true"
+ *ngIf="capacityLabels && capacityValues"
+ >
</cd-dashboard-area-chart>
- <cd-dashboard-area-chart chartTitle="IOPS"
- [labelsArray]="iopsLabels"
- isMultiCluster="true"
- dataUnits=""
- decimals="0"
- [dataArray]="iopsValues"
- [truncateLabel]="true"
- *ngIf="iopsLabels && iopsValues">
+ <cd-dashboard-area-chart
+ chartTitle="IOPS"
+ [labelsArray]="iopsLabels"
+ isMultiCluster="true"
+ dataUnits=""
+ decimals="0"
+ [dataArray]="iopsValues"
+ [truncateLabel]="true"
+ *ngIf="iopsLabels && iopsValues"
+ >
</cd-dashboard-area-chart>
- <cd-dashboard-area-chart chartTitle="Throughput"
- [labelsArray]="throughputLabels"
- isMultiCluster="true"
- dataUnits="B/s"
- decimals="2"
- [dataArray]="throughputValues"
- [truncateLabel]="true"
- *ngIf="throughputLabels && throughputLabels">
+ <cd-dashboard-area-chart
+ chartTitle="Throughput"
+ [labelsArray]="throughputLabels"
+ isMultiCluster="true"
+ dataUnits="B/s"
+ decimals="2"
+ [dataArray]="throughputValues"
+ [truncateLabel]="true"
+ *ngIf="throughputLabels && throughputLabels"
+ >
</cd-dashboard-area-chart>
</div>
</cd-card>
<cd-card-group>
<div class="col-lg-12 mt-3 m-0 p-0 ps-4 pe-4">
- <cd-table [data]="clusters"
- [columns]="columns"
- [limit]="5"
- *ngIf="clusters">
+ <cd-table
+ [data]="clusters"
+ [columns]="columns"
+ [limit]="5"
+ *ngIf="clusters"
+ >
</cd-table>
</div>
</cd-card-group>
<cd-card-group>
<div class="col-lg-12 mb-4 m-0 p-0 ps-4 pe-4">
<div class="row">
- <cd-card [cardTitle]="'Top ' + COUNT_OF_UTILIZATION_CHARTS + ' Pools Utilization'"
- i18n-title
- aria-label="Pools Utilization card"
- *ngIf="clusters">
+ <cd-card
+ [cardTitle]="'Top ' + COUNT_OF_UTILIZATION_CHARTS + ' Pools Utilization'"
+ i18n-title
+ aria-label="Pools Utilization card"
+ *ngIf="clusters"
+ >
<div class="ms-4 me-4 mt-0">
- <cd-dashboard-time-selector (selectedTime)="getPrometheusData($event, 'poolUtilization')">
+ <cd-dashboard-time-selector
+ (selectedTime)="getPrometheusData($event, 'poolUtilization')"
+ >
</cd-dashboard-time-selector>
- <cd-dashboard-area-chart chartTitle="Capacity"
- [labelsArray]="poolCapacityLabels"
- dataUnits="B"
- isMultiCluster="true"
- [dataArray]="poolCapacityValues"
- *ngIf="poolCapacityLabels && poolCapacityValues"
- [truncateLabel]="true">
+ <cd-dashboard-area-chart
+ chartTitle="Capacity"
+ [labelsArray]="poolCapacityLabels"
+ dataUnits="B"
+ isMultiCluster="true"
+ [dataArray]="poolCapacityValues"
+ *ngIf="poolCapacityLabels && poolCapacityValues"
+ [truncateLabel]="true"
+ >
</cd-dashboard-area-chart>
- <cd-dashboard-area-chart chartTitle="IOPS"
- [labelsArray]="poolIOPSLabels"
- dataUnits=""
- decimals="0"
- isMultiCluster="true"
- [dataArray]="poolIOPSValues"
- *ngIf="poolIOPSLabels && poolIOPSValues"
- [truncateLabel]="true">
+ <cd-dashboard-area-chart
+ chartTitle="IOPS"
+ [labelsArray]="poolIOPSLabels"
+ dataUnits=""
+ decimals="0"
+ isMultiCluster="true"
+ [dataArray]="poolIOPSValues"
+ *ngIf="poolIOPSLabels && poolIOPSValues"
+ [truncateLabel]="true"
+ >
</cd-dashboard-area-chart>
- <cd-dashboard-area-chart chartTitle="Client Throughput"
- [labelsArray]="poolThroughputLabels"
- dataUnits="B/s"
- decimals="2"
- isMultiCluster="true"
- [dataArray]="poolThroughputValues"
- *ngIf="poolThroughputLabels && poolThroughputValues"
- [truncateLabel]="true">
+ <cd-dashboard-area-chart
+ chartTitle="Client Throughput"
+ [labelsArray]="poolThroughputLabels"
+ dataUnits="B/s"
+ decimals="2"
+ isMultiCluster="true"
+ [dataArray]="poolThroughputValues"
+ *ngIf="poolThroughputLabels && poolThroughputValues"
+ [truncateLabel]="true"
+ >
</cd-dashboard-area-chart>
</div>
</cd-card>
</div>
</ng-container>
-<ng-template #clusterUsageTpl
- let-row="data.row">
- <cd-usage-bar [total]="row.total_capacity"
- [used]="row.used_capacity">
+<ng-template
+ #clusterUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ [total]="row.total_capacity"
+ [used]="row.used_capacity"
+ >
</cd-usage-bar>
</ng-template>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>OSD creation preview</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >OSD creation preview</ng-container
+ >
<ng-container class="modal-content">
- <form #frm="ngForm"
- [formGroup]="formGroup"
- novalidate>
+ <form
+ #frm="ngForm"
+ [formGroup]="formGroup"
+ novalidate
+ >
<div class="modal-body">
<h4 i18n>DriveGroups</h4>
- <pre>{{ driveGroups | json}}</pre>
+ <pre>{{ driveGroups | json }}</pre>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="formGroup"
- [submitText]="action | titlecase"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="action | titlecase"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- id="tabset-osd-details"
- class="nav-tabs"
- cdStatefulTab="osd-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ id="tabset-osd-details"
+ class="nav-tabs"
+ cdStatefulTab="osd-details"
+ >
<ng-container ngbNavItem="devices">
- <a ngbNavLink
- i18n>Devices</a>
+ <a
+ ngbNavLink
+ i18n
+ >Devices</a
+ >
<ng-template ngbNavContent>
- <cd-device-list [osdId]="osd?.id"
- [hostname]="selection?.host.name"
- [osdList]="true"></cd-device-list>
+ <cd-device-list
+ [osdId]="osd?.id"
+ [hostname]="selection?.host.name"
+ [osdList]="true"
+ ></cd-device-list>
</ng-template>
</ng-container>
<ng-container ngbNavItem="attributes">
- <a ngbNavLink
- i18n>Attributes (OSD map)</a>
+ <a
+ ngbNavLink
+ i18n
+ >Attributes (OSD map)</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [data]="osd?.details?.osd_map">
- </cd-table-key-value>
+ <cd-table-key-value [data]="osd?.details?.osd_map"> </cd-table-key-value>
</ng-template>
</ng-container>
<ng-container ngbNavItem="metadata">
- <a ngbNavLink
- i18n>Metadata</a>
+ <a
+ ngbNavLink
+ i18n
+ >Metadata</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value *ngIf="osd?.details?.osd_metadata; else noMetaData"
- (fetchData)="refresh()"
- [data]="osd?.details?.osd_metadata">
+ <cd-table-key-value
+ *ngIf="osd?.details?.osd_metadata; else noMetaData"
+ (fetchData)="refresh()"
+ [data]="osd?.details?.osd_metadata"
+ >
</cd-table-key-value>
<ng-template #noMetaData>
- <cd-alert-panel type="warning"
- i18n>Metadata not available</cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ i18n
+ >Metadata not available</cd-alert-panel
+ >
</ng-template>
</ng-template>
</ng-container>
<ng-container ngbNavItem="device-health">
- <a ngbNavLink
- i18n>Device health</a>
+ <a
+ ngbNavLink
+ i18n
+ >Device health</a
+ >
<ng-template ngbNavContent>
<cd-smart-list [osdId]="osd?.id"></cd-smart-list>
</ng-template>
</ng-container>
<ng-container ngbNavItem="performance-counter">
- <a ngbNavLink
- i18n>Performance counter</a>
+ <a
+ ngbNavLink
+ i18n
+ >Performance counter</a
+ >
<ng-template ngbNavContent>
- <cd-table-performance-counter *ngIf="osd?.details"
- serviceType="osd"
- [serviceId]="osd?.id">
+ <cd-table-performance-counter
+ *ngIf="osd?.details"
+ serviceType="osd"
+ [serviceId]="osd?.id"
+ >
</cd-table-performance-counter>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="performance-details"
- *ngIf="grafanaPermission.read">
- <a ngbNavLink
- i18n>Performance Details</a>
+ <ng-container
+ ngbNavItem="performance-details"
+ *ngIf="grafanaPermission.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Performance Details</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="OSD details"
- [grafanaPath]="'ceph-osd-device-overview?var-osd=osd.' + osd['id']"
- [type]="'metrics'"
- uid="CrAHE0iZz"
- scrollable="no"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="OSD details"
+ [grafanaPath]="'ceph-osd-device-overview?var-osd=osd.' + osd['id']"
+ [type]="'metrics'"
+ uid="CrAHE0iZz"
+ scrollable="no"
+ grafanaStyle="three"
+ >
</cd-grafana>
</ng-template>
</ng-container>
<div class="form-group row osd-devices-selection-row">
- <label class="cd-form-label"
- for="createDeleteButton">
+ <label
+ class="cd-form-label"
+ for="createDeleteButton"
+ >
<ng-container i18n>{{ name }} devices</ng-container>
<cd-helper>
@if (type === 'data') {
- <span i18n>The primary storage devices. These devices contain all OSD data.</span>
+ <span i18n>The primary storage devices. These devices contain all OSD data.</span>
}
@if (type === 'wal') {
- <span i18n>Write-Ahead-Log devices. These devices are used for BlueStore’s internal journal. It is only useful to use a WAL device if the device is faster than the primary device (e.g. NVME devices or SSDs). If there is only a small amount of fast storage available (e.g., less than a gigabyte), we recommend using it as a WAL device.</span>
+ <span i18n
+ >Write-Ahead-Log devices. These devices are used for BlueStore’s internal journal. It is
+ only useful to use a WAL device if the device is faster than the primary device (e.g. NVME
+ devices or SSDs). If there is only a small amount of fast storage available (e.g., less
+ than a gigabyte), we recommend using it as a WAL device.</span
+ >
}
@if (type === 'db') {
- <span i18n>DB devices can be used for storing BlueStore’s internal metadata. It is only helpful to provision a DB device if it is faster than the primary device (e.g. NVME devices or SSD).</span>
+ <span i18n
+ >DB devices can be used for storing BlueStore’s internal metadata. It is only helpful to
+ provision a DB device if it is faster than the primary device (e.g. NVME devices or
+ SSD).</span
+ >
}
</cd-helper>
</label>
<div class="cd-col-form-input">
@if (inlineSelection) {
- @if (showAddPrimaryFirstAlert) {
- <cd-alert-panel type="info"
- size="slim"
- [showTitle]="false">
- <ng-container i18n>{{ tooltips.addPrimaryFirst }}</ng-container>
- </cd-alert-panel>
- }
- @if (showNoAvailDevicesAlert) {
- <cd-alert-panel type="warning"
- size="slim"
- [showTitle]="false">
- <ng-container i18n>No available devices</ng-container>
- </cd-alert-panel>
- }
- @if (showFilterSection) {
- @if (!canInlineSubmit) {
- <cd-alert-panel type="warning"
- size="slim"
- [showTitle]="false">
- <ng-container i18n>Select at least one of these filters to fetch the data:</ng-container>
- @for (filter of requiredFilters; track filter) {
- <cds-tag class="tag-dark ms-2">{{ filter }}</cds-tag>
+ @if (showAddPrimaryFirstAlert) {
+ <cd-alert-panel
+ type="info"
+ size="slim"
+ [showTitle]="false"
+ >
+ <ng-container i18n>{{ tooltips.addPrimaryFirst }}</ng-container>
+ </cd-alert-panel>
}
- </cd-alert-panel>
- }
- <div class="device-filter-form">
- <div class="filter-dropdown-row">
- @for (field of filterFields; track field.prop) {
- <div class="filter-dropdown">
- <cds-select (valueChange)="onFilterFieldChange(field.prop, $event)"
- [id]="'device_filter_' + field.prop"
- [label]="field.name"
- size="md"
- [attr.data-testid]="'device-filter-' + field.prop">
- <option value=""
- i18n>Any</option>
- @for (option of field.options; track option.raw) {
- <option [value]="option.raw"
- [selected]="selectedFilters[field.prop] === option.raw">
- {{ option.formatted }}
- </option>
+ @if (showNoAvailDevicesAlert) {
+ <cd-alert-panel
+ type="warning"
+ size="slim"
+ [showTitle]="false"
+ >
+ <ng-container i18n>No available devices</ng-container>
+ </cd-alert-panel>
+ }
+ @if (showFilterSection) {
+ @if (!canInlineSubmit) {
+ <cd-alert-panel
+ type="warning"
+ size="slim"
+ [showTitle]="false"
+ >
+ <ng-container i18n
+ >Select at least one of these filters to fetch the data:</ng-container
+ >
+ @for (filter of requiredFilters; track filter) {
+ <cds-tag class="tag-dark ms-2">{{ filter }}</cds-tag>
}
- </cds-select>
+ </cd-alert-panel>
+ }
+ <div class="device-filter-form">
+ <div class="filter-dropdown-row">
+ @for (field of filterFields; track field.prop) {
+ <div class="filter-dropdown">
+ <cds-select
+ (valueChange)="onFilterFieldChange(field.prop, $event)"
+ [id]="'device_filter_' + field.prop"
+ [label]="field.name"
+ size="md"
+ [attr.data-testid]="'device-filter-' + field.prop"
+ >
+ <option
+ value=""
+ i18n
+ >
+ Any
+ </option>
+ @for (option of field.options; track option.raw) {
+ <option
+ [value]="option.raw"
+ [selected]="selectedFilters[field.prop] === option.raw"
+ >
+ {{ option.formatted }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ }
+ </div>
</div>
+ @if (showSelectionSummary) {
+ <div class="selection-summary pb-2 my-2 border-bottom">
+ @for (filter of displayedFilters; track filter.prop) {
+ <cds-tag class="tag-dark me-2"
+ >{{ filter.name }}: {{ filter.value.formatted }}</cds-tag
+ >
+ }
+ <a
+ class="tc_clearSelections"
+ href=""
+ (click)="clearDevices(); (false)"
+ >
+ <svg
+ [cdsIcon]="icons.clearFilters"
+ [size]="icons.size16"
+ ></svg>
+ <ng-container i18n>Clear</ng-container>
+ </a>
+ <div class="selection-capacity cds-mt-2">
+ <span i18n>Raw capacity: {{ inlineCapacity | dimlessBinary }}.</span>
+ </div>
+ </div>
}
- </div>
- </div>
- @if (showSelectionSummary) {
- <div class="selection-summary pb-2 my-2 border-bottom">
- @for (filter of displayedFilters; track filter.prop) {
- <cds-tag class="tag-dark me-2">{{ filter.name }}: {{ filter.value.formatted }}</cds-tag>
+ <cd-inventory-devices
+ [devices]="tableDevices"
+ [hostname]="hostname"
+ [diskType]="name === 'Primary' ? 'hdd' : 'ssd'"
+ [hiddenColumns]="['available', 'osd_ids']"
+ [filterColumns]="[]"
+ >
+ </cd-inventory-devices>
}
- <a class="tc_clearSelections"
- href=""
- (click)="clearDevices(); false">
- <svg [cdsIcon]="icons.clearFilters"
- [size]="icons.size16"></svg>
- <ng-container i18n>Clear</ng-container>
- </a>
- <div class="selection-capacity cds-mt-2">
- <span i18n>Raw capacity: {{ inlineCapacity | dimlessBinary }}.</span>
- </div>
- </div>
- }
- <cd-inventory-devices [devices]="tableDevices"
- [hostname]="hostname"
- [diskType]="name === 'Primary' ? 'hdd' : 'ssd'"
- [hiddenColumns]="['available', 'osd_ids']"
- [filterColumns]="[]">
- </cd-inventory-devices>
- }
} @else {
- @if (devices.length === 0) {
- <button type="button"
- class="btn btn-light"
- (click)="showSelectionModal()"
- data-toggle="tooltip"
- [title]="addButtonTooltip"
- [disabled]="availDevices.length === 0 || !canSelect || expansionCanSelect">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"></svg>
- <ng-container i18n>Add</ng-container>
- </button>
- } @else {
- <div class="pb-2 my-2 border-bottom">
- <span *ngFor="let filter of appliedFilters">
- <cds-tag class="tag-dark me-2">{{ filter.name }}: {{ filter.value.formatted }}</cds-tag>
- </span>
- <a class="tc_clearSelections"
- href=""
- (click)="clearDevices(); false">
- <svg [cdsIcon]="icons.clearFilters"
- [size]="icons.size16"></svg>
- <ng-container i18n>Clear</ng-container>
- </a>
- </div>
- <div>
- <cd-inventory-devices [devices]="devices"
- [hiddenColumns]="['available', 'osd_ids']"
- [filterColumns]="[]">
- </cd-inventory-devices>
- </div>
- }
+ @if (devices.length === 0) {
+ <button
+ type="button"
+ class="btn btn-light"
+ (click)="showSelectionModal()"
+ data-toggle="tooltip"
+ [title]="addButtonTooltip"
+ [disabled]="availDevices.length === 0 || !canSelect || expansionCanSelect"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
+ <ng-container i18n>Add</ng-container>
+ </button>
+ } @else {
+ <div class="pb-2 my-2 border-bottom">
+ <span *ngFor="let filter of appliedFilters">
+ <cds-tag class="tag-dark me-2">{{ filter.name }}: {{ filter.value.formatted }}</cds-tag>
+ </span>
+ <a
+ class="tc_clearSelections"
+ href=""
+ (click)="clearDevices(); (false)"
+ >
+ <svg
+ [cdsIcon]="icons.clearFilters"
+ [size]="icons.size16"
+ ></svg>
+ <ng-container i18n>Clear</ng-container>
+ </a>
+ </div>
+ <div>
+ <cd-inventory-devices
+ [devices]="devices"
+ [hiddenColumns]="['available', 'osd_ids']"
+ [filterColumns]="[]"
+ >
+ </cd-inventory-devices>
+ </div>
+ }
}
</div>
</div>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>{{ deviceType }} devices</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >{{ deviceType }} devices</ng-container
+ >
<ng-container class="modal-content">
- <form #frm="ngForm"
- [formGroup]="formGroup"
- novalidate>
+ <form
+ #frm="ngForm"
+ [formGroup]="formGroup"
+ novalidate
+ >
<div class="modal-body">
- <cd-alert-panel *ngIf="!canSubmit"
- type="warning"
- size="slim"
- [showTitle]="false">
- <ng-container i18n>At least one of these filters must be applied in order to proceed:</ng-container>
- <cds-tag *ngFor="let filter of requiredFilters"
- class="tag-dark ms-2">
- {{ filter }}
+ <cd-alert-panel
+ *ngIf="!canSubmit"
+ type="warning"
+ size="slim"
+ [showTitle]="false"
+ >
+ <ng-container i18n
+ >At least one of these filters must be applied in order to proceed:</ng-container
+ >
+ <cds-tag
+ *ngFor="let filter of requiredFilters"
+ class="tag-dark ms-2"
+ >
+ {{ filter }}
</cds-tag>
</cd-alert-panel>
- <cd-inventory-devices #inventoryDevices
- [devices]="devices"
- [filterColumns]="filterColumns"
- [hostname]="hostname"
- [diskType]="diskType"
- [hiddenColumns]="['available', 'osd_ids']"
- (filterChange)="onFilterChange($event)">
+ <cd-inventory-devices
+ #inventoryDevices
+ [devices]="devices"
+ [filterColumns]="filterColumns"
+ [hostname]="hostname"
+ [diskType]="diskType"
+ [hiddenColumns]="['available', 'osd_ids']"
+ (filterChange)="onFilterChange($event)"
+ >
</cd-inventory-devices>
<div *ngIf="canSubmit">
<p class="text-center">
- <span i18n>Number of devices: {{ filteredDevices.length }}. Raw capacity:
- {{ capacity | dimlessBinary }}.</span>
+ <span i18n
+ >Number of devices: {{ filteredDevices.length }}. Raw capacity:
+ {{ capacity | dimlessBinary }}.</span
+ >
</p>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="formGroup"
- [disabled]="!canSubmit || filteredDevices.length === 0"
- [submitText]="action | titlecase"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [disabled]="!canSubmit || filteredDevices.length === 0"
+ [submitText]="action | titlecase"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
-<cds-modal size="sm"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- modal-primary-focus
- i18n>Individual OSD flags</h3>
+ <h3
+ cdsModalHeaderHeading
+ modal-primary-focus
+ i18n
+ >
+ Individual OSD flags
+ </h3>
</cds-modal-header>
<div cdsModalContent>
- <form name="osdFlagsForm"
- [formGroup]="osdFlagsForm"
- novalidate>
+ <form
+ name="osdFlagsForm"
+ [formGroup]="osdFlagsForm"
+ novalidate
+ >
<div>
@for (flag of flags; track flag.code; let last = $last) {
- <div>
- <cds-checkbox
- [checked]="flag.value"
- [indeterminate]="flag.indeterminate"
- (checkedChange)="changeValue(flag)"
- [name]="flag.code"
- [id]="flag.code"
- >
- <strong>{{ flag.name }}</strong>
- @if (flag.clusterWide) {
- <cds-tag class="cds-ml-3"
- [cdsTooltip]="clusterWideTooltip"
- trigger="hover"
- i18n>Cluster-wide</cds-tag>
- }
+ <div>
+ <cds-checkbox
+ [checked]="flag.value"
+ [indeterminate]="flag.indeterminate"
+ (checkedChange)="changeValue(flag)"
+ [name]="flag.code"
+ [id]="flag.code"
+ >
+ <strong>{{ flag.name }}</strong>
+ @if (flag.clusterWide) {
+ <cds-tag
+ class="cds-ml-3"
+ [cdsTooltip]="clusterWideTooltip"
+ trigger="hover"
+ i18n
+ >Cluster-wide</cds-tag
+ >
+ }
- <div class="cds-mt-4">
- <cd-help-text>{{ flag.description }}</cd-help-text>
- </div>
- </cds-checkbox>
- @if (!last) {
- <hr class="cds-m-2" />
- }
- </div>
+ <div class="cds-mt-4">
+ <cd-help-text>{{ flag.description }}</cd-help-text>
+ </div>
+ </cds-checkbox>
+ @if (!last) {
+ <hr class="cds-m-2" />
+ }
+ </div>
}
</div>
</form>
<cds-modal-footer class="osd-footer">
<cds-button-set>
- <button cdsButton="secondary"
- (click)="closeModal()"
- type="button"
- i18n>
+ <button
+ cdsButton="secondary"
+ (click)="closeModal()"
+ type="button"
+ i18n
+ >
Cancel
</button>
- <button cdsButton="secondary"
- (click)="resetSelection()"
- type="button"
- i18n>
+ <button
+ cdsButton="secondary"
+ (click)="resetSelection()"
+ type="button"
+ i18n
+ >
Reset
</button>
@if (permissions.osd.update) {
- <cd-submit-button
- (submitAction)="submitAction()"
- [form]="osdFlagsForm"
- [submitText]="actionLabels.UPDATE">
- {{ actionLabels.UPDATE }}</cd-submit-button>
+ <cd-submit-button
+ (submitAction)="submitAction()"
+ [form]="osdFlagsForm"
+ [submitText]="actionLabels.UPDATE"
+ >
+ {{ actionLabels.UPDATE }}</cd-submit-button
+ >
}
</cds-button-set>
</cds-modal-footer>
-<cds-modal size="sm"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- modal-primary-focus
- i18n>Cluster-wide OSD Flags</h3>
+ <h3
+ cdsModalHeaderHeading
+ modal-primary-focus
+ i18n
+ >
+ Cluster-wide OSD Flags
+ </h3>
</cds-modal-header>
<div cdsModalContent>
- <form name="osdFlagsForm"
- [formGroup]="osdFlagsForm"
- novalidate>
+ <form
+ name="osdFlagsForm"
+ [formGroup]="osdFlagsForm"
+ novalidate
+ >
<div>
@for (flag of flags; track flag.code; let last = $last) {
- <div>
- <cds-checkbox
- [checked]="flag.value"
- (checkedChange)="flag.value = !flag.value"
- [name]="flag.code"
- [id]="flag.code"
- [disabled]="flag.disabled"
- >
- <strong>{{ flag.name }}</strong>
+ <div>
+ <cds-checkbox
+ [checked]="flag.value"
+ (checkedChange)="flag.value = !flag.value"
+ [name]="flag.code"
+ [id]="flag.code"
+ [disabled]="flag.disabled"
+ >
+ <strong>{{ flag.name }}</strong>
- <div class="cds-mt-4">
- <cd-help-text>{{ flag.description }}</cd-help-text>
- </div>
- </cds-checkbox>
- @if (!last) {
- <hr class="cds-m-2" />
- }
- </div>
+ <div class="cds-mt-4">
+ <cd-help-text>{{ flag.description }}</cd-help-text>
+ </div>
+ </cds-checkbox>
+ @if (!last) {
+ <hr class="cds-m-2" />
+ }
+ </div>
}
</div>
</form>
<cds-modal-footer>
<cds-button-set>
- <button cdsButton="secondary"
- (click)="closeModal()"
- type="button"
- i18n>
+ <button
+ cdsButton="secondary"
+ (click)="closeModal()"
+ type="button"
+ i18n
+ >
Cancel
</button>
@if (permissions.osd.update) {
- <cd-submit-button
- (submitAction)="submitAction()"
- [form]="osdFlagsForm"
- [submitText]="actionLabels.UPDATE">
- {{ actionLabels.UPDATE }}</cd-submit-button>
+ <cd-submit-button
+ (submitAction)="submitAction()"
+ [form]="osdFlagsForm"
+ [submitText]="actionLabels.UPDATE"
+ >
+ {{ actionLabels.UPDATE }}</cd-submit-button
+ >
}
</cds-button-set>
</cds-modal-footer>
(closeRequested)="onCancel()"
(stepChanged)="populateReviewData()"
[isSubmitLoading]="isSubmitLoading"
- [submitButtonLabel]="createOsdsLabel">
+ [submitButtonLabel]="createOsdsLabel"
+>
type="wide">
-<!-- [submitButtonLabel]="simpleDeployment ? createOsdsLabel : actionLabels.PREVIEW" -->
+ <!-- [submitButtonLabel]="simpleDeployment ? createOsdsLabel : actionLabels.PREVIEW" -->
<cd-tearsheet-step>
- <div class="osd-tearsheet-content">
- <form
- [formGroup]="form"
- cdsStack="vertical"
- [gap]="6">
-
- @if (!hasEligibleDevices) {
- <cd-alert-panel
- type="warning"
- class="osd-alert-block"
- i18n>
- <div
- cdsStack="vertical"
- [gap]="2">
- <span class="cds--type-heading-compact-01">
- No eligible devices found for OSD creation.
- </span>
- <span class="cds--type-body-compact-01">
- Physical disks may be present, but none meet the requirements
- (unused, unformatted, and not already configured by Ceph).
- </span>
- </div>
- </cd-alert-panel>
- }
-
- <div>
- <cds-text-label
- class="cds--type-heading-compact-02 cds-mb-5"
- i18n>
- Deployment Options
- </cds-text-label>
-
- <div cdsStack="vertical"
- [gap]="4">
- <cds-radio-group
- formControlName="deploymentMode"
- orientation="vertical">
-
- <cds-radio value="automatic"
- [disabled]="!hasEligibleDevices ? true : null">
- <div class="osd-radio-label-wrapper">
- <span
- class="cds--type-body-short-01"
- i18n>
- Automatic
+ <div class="osd-tearsheet-content">
+ <form
+ [formGroup]="form"
+ cdsStack="vertical"
+ [gap]="6"
+ >
+ @if (!hasEligibleDevices) {
+ <cd-alert-panel
+ type="warning"
+ class="osd-alert-block"
+ i18n
+ >
+ <div
+ cdsStack="vertical"
+ [gap]="2"
+ >
+ <span class="cds--type-heading-compact-01">
+ No eligible devices found for OSD creation.
+ </span>
+ <span class="cds--type-body-compact-01">
+ Physical disks may be present, but none meet the requirements (unused, unformatted,
+ and not already configured by Ceph).
</span>
- <div
- class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2"
- i18n>
- Choose a pre-configured profile for you.
- </div>
</div>
- </cds-radio>
+ </cd-alert-panel>
+ }
- @if (form.get('deploymentMode').value !== 'manual') {
- <div class="cds-pl-7 cds-mb-5"
- cdsStack="vertical"
- [gap]="4">
+ <div>
<cds-text-label
- class="cds--type-heading-compact-02"
- i18n>
- Pre-configured profiles
+ class="cds--type-heading-compact-02 cds-mb-5"
+ i18n
+ >
+ Deployment Options
</cds-text-label>
- <cds-radio-group
- formControlName="deploymentOption"
- (change)="emitDeploymentSelection()"
- orientation="vertical">
-
- @for (optionName of optionNames; track optionName; let isLast = $last) {
- <cds-radio
- [value]="optionName"
- [class.cds-mb-5]="!isLast"
- [disabled]="!hasEligibleDevices || !deploymentOptions?.options[optionName].available ? true : null">
-
- <div class="osd-radio-label-wrapper">
- <span class="cds--type-body-short-01">
- {{ deploymentOptions?.options[optionName].title }}
- @if (deploymentOptions?.recommended_option === optionName) {
- <strong i18n>(Recommended)</strong>
- }
- </span>
-
- <div class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2">
- {{ deploymentOptions?.options[optionName].desc }}
- </div>
- </div>
- </cds-radio>
- }
- </cds-radio-group>
+ <div
+ cdsStack="vertical"
+ [gap]="4"
+ >
+ <cds-radio-group
+ formControlName="deploymentMode"
+ orientation="vertical"
+ >
+ <cds-radio
+ value="automatic"
+ [disabled]="!hasEligibleDevices ? true : null"
+ >
+ <div class="osd-radio-label-wrapper">
+ <span
+ class="cds--type-body-short-01"
+ i18n
+ >
+ Automatic
+ </span>
+ <div
+ class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2"
+ i18n
+ >
+ Choose a pre-configured profile for you.
+ </div>
+ </div>
+ </cds-radio>
+
+ @if (form.get('deploymentMode').value !== 'manual') {
+ <div
+ class="cds-pl-7 cds-mb-5"
+ cdsStack="vertical"
+ [gap]="4"
+ >
+ <cds-text-label
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Pre-configured profiles
+ </cds-text-label>
+
+ <cds-radio-group
+ formControlName="deploymentOption"
+ (change)="emitDeploymentSelection()"
+ orientation="vertical"
+ >
+ @for (optionName of optionNames; track optionName; let isLast = $last) {
+ <cds-radio
+ [value]="optionName"
+ [class.cds-mb-5]="!isLast"
+ [disabled]="
+ !hasEligibleDevices || !deploymentOptions?.options[optionName].available
+ ? true
+ : null
+ "
+ >
+ <div class="osd-radio-label-wrapper">
+ <span class="cds--type-body-short-01">
+ {{ deploymentOptions?.options[optionName].title }}
+ @if (deploymentOptions?.recommended_option === optionName) {
+ <strong i18n>(Recommended)</strong>
+ }
+ </span>
+
+ <div class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2">
+ {{ deploymentOptions?.options[optionName].desc }}
+ </div>
+ </div>
+ </cds-radio>
+ }
+ </cds-radio-group>
+ </div>
+ }
+
+ <cds-radio
+ value="manual"
+ [disabled]="!hasEligibleDevices ? true : null"
+ >
+ <div class="osd-radio-label-wrapper">
+ <span
+ class="cds--type-body-short-01"
+ i18n
+ >
+ Manual selection
+ </span>
+ <div
+ class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2"
+ i18n
+ >
+ Custom Configuration
+ </div>
+ </div>
+ </cds-radio>
+ </cds-radio-group>
+ </div>
</div>
- }
-
- <cds-radio value="manual"
- [disabled]="!hasEligibleDevices ? true : null">
- <div class="osd-radio-label-wrapper">
- <span
- class="cds--type-body-short-01"
- i18n>
- Manual selection
- </span>
- <div
- class="cds--type-helper-text-01 osd-radio-helper-text cds-mt-2"
- i18n>
- Custom Configuration
- </div>
- </div>
- </cds-radio>
- </cds-radio-group>
- </div>
- </div>
- <div formGroupName="features">
- <cds-text-label
- class="cds--type-heading-compact-02 cds-mb-5"
- i18n>
- Features
- </cds-text-label>
+ <div formGroupName="features">
+ <cds-text-label
+ class="cds--type-heading-compact-02 cds-mb-5"
+ i18n
+ >
+ Features
+ </cds-text-label>
- @for (feature of featureList; track feature.key) {
- <cds-checkbox
- [name]="feature.key"
- formControlName="{{ feature.key }}"
- (checkedChange)="emitDeploymentSelection()">
- {{ feature.desc }}
- </cds-checkbox>
- }
+ @for (feature of featureList; track feature.key) {
+ <cds-checkbox
+ [name]="feature.key"
+ formControlName="{{ feature.key }}"
+ (checkedChange)="emitDeploymentSelection()"
+ >
+ {{ feature.desc }}
+ </cds-checkbox>
+ }
+ </div>
+ </form>
</div>
-
- </form>
- </div>
</cd-tearsheet-step>
@if (form.get('deploymentMode').value === 'manual') {
- <cd-tearsheet-step>
- <div class="osd-tearsheet-content">
- <form
- [formGroup]="form"
- cdsStack="vertical"
- [gap]="7">
-
- <div>
- <cds-text-label
- class="cds--type-heading-compact-02 cds-mb-5"
- i18n>
- Select data devices
- </cds-text-label>
- <cd-osd-devices-selection-groups
- #dataDeviceSelectionGroups
- name="Primary"
- i18n-name
- type="data"
- [availDevices]="availDevices"
- [canSelect]="availDevices.length !== 0"
- [inlineSelection]="true"
- (selected)="onDevicesSelected($event)"
- (cleared)="onDevicesCleared($event)">
- </cd-osd-devices-selection-groups>
- </div>
-
- </form>
- </div>
- </cd-tearsheet-step>
-
- <cd-tearsheet-step>
- <div class="osd-tearsheet-content">
- <form
- [formGroup]="form"
- cdsStack="vertical"
- [gap]="7">
-
- <div>
- <cds-text-label
- class="cds--type-heading-compact-02 cds-mb-5"
- i18n>
- Select DB/WAL devices (optional)
- </cds-text-label>
-
- <div
- cdsStack="vertical"
- [gap]="6">
- <cd-osd-devices-selection-groups
- #walDeviceSelectionGroups
- name="WAL"
- i18n-name
- type="wal"
- [availDevices]="availDevices"
- [canSelect]="dataDeviceSelectionGroups.devices.length !== 0"
- [inlineSelection]="true"
- (selected)="onDevicesSelected($event)"
- (cleared)="onDevicesCleared($event)"
- [hostname]="hostname">
- </cd-osd-devices-selection-groups>
-
- @if (walDeviceSelectionGroups.devices.length !== 0) {
+ <cd-tearsheet-step>
+ <div class="osd-tearsheet-content">
+ <form
+ [formGroup]="form"
+ cdsStack="vertical"
+ [gap]="7"
+ >
<div>
- <cds-number
- label="WAL slots"
- i18n-label
- helperText="How many OSDs per WAL device. Specify 0 to let Orchestrator backend decide it."
- i18n-helperText
- id="walSlots"
- formControlName="walSlots"
- min="0">
- </cds-number>
+ <cds-text-label
+ class="cds--type-heading-compact-02 cds-mb-5"
+ i18n
+ >
+ Select data devices
+ </cds-text-label>
+ <cd-osd-devices-selection-groups
+ #dataDeviceSelectionGroups
+ name="Primary"
+ i18n-name
+ type="data"
+ [availDevices]="availDevices"
+ [canSelect]="availDevices.length !== 0"
+ [inlineSelection]="true"
+ (selected)="onDevicesSelected($event)"
+ (cleared)="onDevicesCleared($event)"
+ >
+ </cd-osd-devices-selection-groups>
</div>
- }
-
- <cd-osd-devices-selection-groups
- #dbDeviceSelectionGroups
- name="DB"
- i18n-name
- type="db"
- [availDevices]="availDevices"
- [canSelect]="dataDeviceSelectionGroups.devices.length !== 0"
- [inlineSelection]="true"
- (selected)="onDevicesSelected($event)"
- (cleared)="onDevicesCleared($event)"
- [hostname]="hostname">
- </cd-osd-devices-selection-groups>
+ </form>
+ </div>
+ </cd-tearsheet-step>
- @if (dbDeviceSelectionGroups.devices.length !== 0) {
+ <cd-tearsheet-step>
+ <div class="osd-tearsheet-content">
+ <form
+ [formGroup]="form"
+ cdsStack="vertical"
+ [gap]="7"
+ >
<div>
- <cds-number
- label="DB slots"
- i18n-label
- helperText="How many OSDs per DB device. Specify 0 to let Orchestrator backend decide it."
- i18n-helperText
- id="dbSlots"
- formControlName="dbSlots"
- min="0">
- </cds-number>
+ <cds-text-label
+ class="cds--type-heading-compact-02 cds-mb-5"
+ i18n
+ >
+ Select DB/WAL devices (optional)
+ </cds-text-label>
+
+ <div
+ cdsStack="vertical"
+ [gap]="6"
+ >
+ <cd-osd-devices-selection-groups
+ #walDeviceSelectionGroups
+ name="WAL"
+ i18n-name
+ type="wal"
+ [availDevices]="availDevices"
+ [canSelect]="dataDeviceSelectionGroups.devices.length !== 0"
+ [inlineSelection]="true"
+ (selected)="onDevicesSelected($event)"
+ (cleared)="onDevicesCleared($event)"
+ [hostname]="hostname"
+ >
+ </cd-osd-devices-selection-groups>
+
+ @if (walDeviceSelectionGroups.devices.length !== 0) {
+ <div>
+ <cds-number
+ label="WAL slots"
+ i18n-label
+ helperText="How many OSDs per WAL device. Specify 0 to let Orchestrator backend decide it."
+ i18n-helperText
+ id="walSlots"
+ formControlName="walSlots"
+ min="0"
+ >
+ </cds-number>
+ </div>
+ }
+
+ <cd-osd-devices-selection-groups
+ #dbDeviceSelectionGroups
+ name="DB"
+ i18n-name
+ type="db"
+ [availDevices]="availDevices"
+ [canSelect]="dataDeviceSelectionGroups.devices.length !== 0"
+ [inlineSelection]="true"
+ (selected)="onDevicesSelected($event)"
+ (cleared)="onDevicesCleared($event)"
+ [hostname]="hostname"
+ >
+ </cd-osd-devices-selection-groups>
+
+ @if (dbDeviceSelectionGroups.devices.length !== 0) {
+ <div>
+ <cds-number
+ label="DB slots"
+ i18n-label
+ helperText="How many OSDs per DB device. Specify 0 to let Orchestrator backend decide it."
+ i18n-helperText
+ id="dbSlots"
+ formControlName="dbSlots"
+ min="0"
+ >
+ </cds-number>
+ </div>
+ }
+ </div>
</div>
- }
- </div>
-
+ </form>
</div>
- </form>
- </div>
- </cd-tearsheet-step>
+ </cd-tearsheet-step>
}
-
- <cd-tearsheet-step>
+ <cd-tearsheet-step>
<div class="osd-tearsheet-content">
<div
cdsGrid
[useCssGrid]="true"
[narrow]="true"
- [fullWidth]="true">
- <div
+ [fullWidth]="true"
+ >
+ <div
cdsCol
- [columnNumbers]="{ sm: 4, md: 8, lg: 12 }">
- <h3
- class="cds--type-heading-03 cds-mb-5"
- i18n>Review summary</h3>
- </div>
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ >
+ <h3
+ class="cds--type-heading-03 cds-mb-5"
+ i18n
+ >
+ Review summary
+ </h3>
+ </div>
- <div
+ <div
cdsCol
[columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Deployment mode</p>
- <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentModeLabel }}</p>
- </div>
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Deployment mode
+ </p>
+ <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentModeLabel }}</p>
+ </div>
- @if (simpleDeployment) {
- <div
- cdsCol
- [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Profile</p>
- <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentOptionTitle }}</p>
- </div>
+ @if (simpleDeployment) {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Profile
+ </p>
+ <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentOptionTitle }}</p>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Profile details</p>
- <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentOptionDescription }}</p>
- </div>
- } @else {
- <div
- cdsCol
- [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Host pattern</p>
- <p class="cds--type-label-02 cds-mt-2">{{ reviewHostPattern }}</p>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Profile details
+ </p>
+ <p class="cds--type-label-02 cds-mt-2">{{ reviewDeploymentOptionDescription }}</p>
+ </div>
+ } @else {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 4, lg: 6 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Host pattern
+ </p>
+ <p class="cds--type-label-02 cds-mt-2">{{ reviewHostPattern }}</p>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
- class="cds-mt-7">
- <h4
- class="cds--type-heading-compact-01"
- i18n>Device selections</h4>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-7"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Device selections
+ </h4>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Data devices</p>
- @if (reviewDataSelection.hasSelection) {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>{{ reviewDataSelection.count }} device(s) selected</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>Total capacity: {{ reviewDataSelection.capacity }}</p>
- @if (reviewDataSelection.filters.length > 0) {
- <div class="osd-review-section cds-pl-4 cds-mt-3">
- @for (filter of reviewDataSelection.filters; track filter.label + filter.value) {
- <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
- <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
- }
- </div>
- }
- } @else {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>None selected</p>
- }
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Data devices
+ </p>
+ @if (reviewDataSelection.hasSelection) {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ reviewDataSelection.count }} device(s) selected
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ Total capacity: {{ reviewDataSelection.capacity }}
+ </p>
+ @if (reviewDataSelection.filters.length > 0) {
+ <div class="osd-review-section cds-pl-4 cds-mt-3">
+ @for (filter of reviewDataSelection.filters; track filter.label + filter.value) {
+ <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
+ <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
+ }
+ </div>
+ }
+ } @else {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ None selected
+ </p>
+ }
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>WAL devices</p>
- @if (reviewWalSelection.hasSelection) {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>{{ reviewWalSelection.count }} device(s) selected</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>Total capacity: {{ reviewWalSelection.capacity }}</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>WAL slots: {{ reviewWalSelection.slots }}</p>
- @if (reviewWalSelection.filters.length > 0) {
- <div class="osd-review-section cds-pl-4 cds-mt-3">
- @for (filter of reviewWalSelection.filters; track filter.label + filter.value) {
- <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
- <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
- }
- </div>
- }
- } @else {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>None selected</p>
- }
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ WAL devices
+ </p>
+ @if (reviewWalSelection.hasSelection) {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ reviewWalSelection.count }} device(s) selected
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ Total capacity: {{ reviewWalSelection.capacity }}
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ WAL slots: {{ reviewWalSelection.slots }}
+ </p>
+ @if (reviewWalSelection.filters.length > 0) {
+ <div class="osd-review-section cds-pl-4 cds-mt-3">
+ @for (filter of reviewWalSelection.filters; track filter.label + filter.value) {
+ <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
+ <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
+ }
+ </div>
+ }
+ } @else {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ None selected
+ </p>
+ }
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>DB devices</p>
- @if (reviewDbSelection.hasSelection) {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>{{ reviewDbSelection.count }} device(s) selected</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>Total capacity: {{ reviewDbSelection.capacity }}</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>DB slots: {{ reviewDbSelection.slots }}</p>
- @if (reviewDbSelection.filters.length > 0) {
- <div class="osd-review-section cds-pl-4 cds-mt-3">
- @for (filter of reviewDbSelection.filters; track filter.label + filter.value) {
- <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
- <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
- }
- </div>
- }
- } @else {
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>None selected</p>
- }
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ DB devices
+ </p>
+ @if (reviewDbSelection.hasSelection) {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ reviewDbSelection.count }} device(s) selected
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ Total capacity: {{ reviewDbSelection.capacity }}
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ DB slots: {{ reviewDbSelection.slots }}
+ </p>
+ @if (reviewDbSelection.filters.length > 0) {
+ <div class="osd-review-section cds-pl-4 cds-mt-3">
+ @for (filter of reviewDbSelection.filters; track filter.label + filter.value) {
+ <p class="cds--type-label-01 cds-mb-2">{{ filter.label }}</p>
+ <p class="cds--type-label-02 cds-mt-1">{{ filter.value }}</p>
+ }
+ </div>
+ }
+ } @else {
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ None selected
+ </p>
+ }
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
- class="cds-mt-7">
- <h4
- class="cds--type-heading-compact-01"
- i18n>Device Groups</h4>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
+ class="cds-mt-7"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Device Groups
+ </h4>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Service Type</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>{{driveGroup.spec.service_type}}</p>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Service Type
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ driveGroup.spec.service_type }}
+ </p>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
- class="cds-mt-5">
- <p
- class="cds--type-label-01"
- i18n>Service ID</p>
- <p
- class="cds--type-label-02 cds-mt-2"
- i18n>{{driveGroup.spec.service_id}}</p>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
+ class="cds-mt-5"
+ >
+ <p
+ class="cds--type-label-01"
+ i18n
+ >
+ Service ID
+ </p>
+ <p
+ class="cds--type-label-02 cds-mt-2"
+ i18n
+ >
+ {{ driveGroup.spec.service_id }}
+ </p>
+ </div>
- <!-- <div
+ <!-- <div
cdsCol
[columnNumbers]="{ sm: 4, md: 4, lg: 4 }"
class="cds-mt-5">
<p class="cds--type-label-02 cds-mt-1">{{ driveGroup.spec.data_devices.rotational }}</p>
</div>
</div> -->
+ }
- }
-
- <div
+ <div
cdsCol
[columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
- class="cds-mt-7">
- <h4
- class="cds--type-heading-compact-01"
- i18n>Features</h4>
- </div>
+ class="cds-mt-7"
+ >
+ <h4
+ class="cds--type-heading-compact-01"
+ i18n
+ >
+ Features
+ </h4>
+ </div>
- <div
+ <div
cdsCol
[columnNumbers]="{ sm: 4, md: 8, lg: 12 }"
- class="cds-mt-5">
- @if (reviewEnabledFeatures.length > 0) {
- @for (feature of reviewEnabledFeatures; track feature) {
- <p class="cds--type-label-02 osd-review-item">{{ feature }}</p>
- }
- } @else {
- <p
- class="cds--type-label-02"
- i18n>No features enabled</p>
- }
- </div>
+ class="cds-mt-5"
+ >
+ @if (reviewEnabledFeatures.length > 0) {
+ @for (feature of reviewEnabledFeatures; track feature) {
+ <p class="cds--type-label-02 osd-review-item">{{ feature }}</p>
+ }
+ } @else {
+ <p
+ class="cds--type-label-02"
+ i18n
+ >
+ No features enabled
+ </p>
+ }
+ </div>
</div>
</div>
- </cd-tearsheet-step>
- </cd-tearsheet>
+ </cd-tearsheet-step>
+</cd-tearsheet>
<ng-template #osdTableTpl>
- <cd-table [data]="osds"
- (fetchData)="getOsdList($event)"
- [columns]="columns"
- selectionType="multiClick"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- [updateSelectionOnRefresh]="'never'"
- [serverSide]="true"
- [count]="count">
-
+ <cd-table
+ [data]="osds"
+ (fetchData)="getOsdList($event)"
+ [columns]="columns"
+ selectionType="multiClick"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ [updateSelectionOnRefresh]="'never'"
+ [serverSide]="true"
+ [count]="count"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permissions.osd"
- [selection]="selection"
- class="btn-group"
- id="osd-actions"
- [tableActions]="tableActions">
+ <cd-table-actions
+ [permission]="permissions.osd"
+ [selection]="selection"
+ class="btn-group"
+ id="osd-actions"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-table-actions [permission]="{read: true}"
- [selection]="selection"
- dropDownOnly="Cluster-wide configuration"
- [dropDownOnlyOffset]="{ x: 110, y: 0 }"
- [dropDownOnlyBtnColor]="'tertiary'"
- class="btn-group"
- id="cluster-wide-actions"
- [tableActions]="clusterWideActions">
+ <cd-table-actions
+ [permission]="{ read: true }"
+ [selection]="selection"
+ dropDownOnly="Cluster-wide configuration"
+ [dropDownOnlyOffset]="{ x: 110, y: 0 }"
+ [dropDownOnlyBtnColor]="'tertiary'"
+ class="btn-group"
+ id="cluster-wide-actions"
+ [tableActions]="clusterWideActions"
+ >
</cd-table-actions>
</div>
- <cd-osd-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-osd-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-osd-details>
</cd-table>
</ng-template>
@if (showTabs) {
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ >
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>OSDs List</a>
+ <a
+ ngbNavLink
+ i18n
+ >OSDs List</a
+ >
<ng-template ngbNavContent>
<ng-container *ngTemplateOutlet="osdTableTpl"></ng-container>
</ng-template>
</ng-container>
- @if (permissions.grafana.read) {
- <ng-container ngbNavItem>
- <a
- ngbNavLink
- i18n>Overall Performance</a>
- <ng-template
- ngbNavContent>
- <cd-grafana i18n-title
- title="OSD list"
- [grafanaPath]="'ceph-osds-overview?'"
- [type]="'metrics'"
- uid="lo02I1Aiz"
- grafanaStyle="three">
- </cd-grafana>
- </ng-template>
- </ng-container>
- }
+ @if (permissions.grafana.read) {
+ <ng-container ngbNavItem>
+ <a
+ ngbNavLink
+ i18n
+ >Overall Performance</a
+ >
+ <ng-template ngbNavContent>
+ <cd-grafana
+ i18n-title
+ title="OSD list"
+ [grafanaPath]="'ceph-osds-overview?'"
+ [type]="'metrics'"
+ uid="lo02I1Aiz"
+ grafanaStyle="three"
+ >
+ </cd-grafana>
+ </ng-template>
+ </ng-container>
+ }
</nav>
<div [ngbNavOutlet]="nav"></div>
<ng-container *ngTemplateOutlet="osdTableTpl"></ng-container>
}
-<ng-template #markOsdConfirmationTpl
- let-markActionDescription="markActionDescription"
- let-osdIds="osdIds">
- <ng-container i18n><strong>OSD(s) {{ osdIds | join }}</strong> will be marked
- <strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
+<ng-template
+ #markOsdConfirmationTpl
+ let-markActionDescription="markActionDescription"
+ let-osdIds="osdIds"
+>
+ <ng-container i18n
+ ><strong>OSD(s) {{ osdIds | join }}</strong> will be marked
+ <strong>{{ markActionDescription }}</strong> if you proceed.</ng-container
+ >
</ng-template>
-<ng-template #criticalConfirmationTpl
- let-safeToPerform="safeToPerform"
- let-message="message"
- let-active="active"
- let-missingStats="missingStats"
- let-storedPgs="storedPgs"
- let-actionDescription="actionDescription"
- let-osdIds="osdIds">
- <div *ngIf="!safeToPerform"
- class="danger mb-3">
+<ng-template
+ #criticalConfirmationTpl
+ let-safeToPerform="safeToPerform"
+ let-message="message"
+ let-active="active"
+ let-missingStats="missingStats"
+ let-storedPgs="storedPgs"
+ let-actionDescription="actionDescription"
+ let-osdIds="osdIds"
+>
+ <div
+ *ngIf="!safeToPerform"
+ class="danger mb-3"
+ >
<cd-alert-panel type="warning">
<span i18n>
The {selection.hasSingleSelection, select, true {OSD is} other {OSDs are}} not safe to be
{{ actionDescription }}!
</span>
- <br>
+ <br />
<ul class="mb-0 ps-4">
- <li *ngIf="active.length > 0"
- i18n>
- {selection.hasSingleSelection, select, true {} other {{{ active | join }} : }}
+ <li
+ *ngIf="active.length > 0"
+ i18n
+ >
+ {selection.hasSingleSelection, select, true {} other {{{ active | join }} :}}
Some PGs are currently mapped to
{active.length === 1, select, true {it} other {them}}.
</li>
- <li *ngIf="missingStats.length > 0"
- i18n>
- {selection.hasSingleSelection, select, true {} other {{{ missingStats | join }} : }}
+ <li
+ *ngIf="missingStats.length > 0"
+ i18n
+ >
+ {selection.hasSingleSelection, select, true {} other {{{ missingStats | join }} :}}
There are no reported stats and not all PGs are active and clean.
</li>
- <li *ngIf="storedPgs.length > 0"
- i18n>
- {selection.hasSingleSelection, select, true {OSD} other {{{ storedPgs | join }} : OSDs }}
+ <li
+ *ngIf="storedPgs.length > 0"
+ i18n
+ >
+ {selection.hasSingleSelection, select, true {OSD} other {{{ storedPgs | join }} : OSDs}}
still store some PG data and not all PGs are active and clean.
</li>
<li *ngIf="message">
</ul>
</cd-alert-panel>
</div>
- <div *ngIf="safeToPerform"
- class="danger mb-3">
+ <div
+ *ngIf="safeToPerform"
+ class="danger mb-3"
+ >
<cd-alert-panel type="info">
<span i18n>
The {selection.hasSingleSelection, select, true {OSD is} other {OSDs are}}
</span>
</cd-alert-panel>
</div>
- <ng-container i18n><strong>OSD {{ osdIds | join }}</strong> will be
- <strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
+ <ng-container i18n
+ ><strong>OSD {{ osdIds | join }}</strong> will be <strong>{{ actionDescription }}</strong> if
+ you proceed.</ng-container
+ >
</ng-template>
-<ng-template #flagsTpl
- let-row="data.row">
- <cds-tag *ngFor="let flag of row.cdClusterFlags;"
- class="tag-hdd me-1">
+<ng-template
+ #flagsTpl
+ let-row="data.row"
+>
+ <cds-tag
+ *ngFor="let flag of row.cdClusterFlags"
+ class="tag-hdd me-1"
+ >
{{ flag }}
</cds-tag>
- <cds-tag *ngFor="let flag of row.cdIndivFlags;"
- class="tag-info me-1">
- {{ flag }}
+ <cds-tag
+ *ngFor="let flag of row.cdIndivFlags"
+ class="tag-info me-1"
+ >
+ {{ flag }}
</cds-tag>
</ng-template>
-<ng-template #osdUsageTpl
- let-row="data.row">
- <cd-usage-bar [title]="'osd ' + row.osd"
- [total]="row.stats.stat_bytes"
- [used]="row.stats.stat_bytes_used"
- [warningThreshold]="osdSettings.nearfull_ratio"
- [errorThreshold]="osdSettings.full_ratio">
+<ng-template
+ #osdUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ [title]="'osd ' + row.osd"
+ [total]="row.stats.stat_bytes"
+ [used]="row.stats.stat_bytes_used"
+ [warningThreshold]="osdSettings.nearfull_ratio"
+ [errorThreshold]="osdSettings.full_ratio"
+ >
</cd-usage-bar>
</ng-template>
-<ng-template #deleteOsdExtraTpl
- let-form="form">
+<ng-template
+ #deleteOsdExtraTpl
+ let-form="form"
+>
<ng-container [formGroup]="form">
<ng-container formGroupName="child">
<div class="form-item cds-pt-3">
- <cds-checkbox id="preserve"
- formControlName="preserve"
- modal-primary-focus
- ariaLabel="preserve"
- i18n>Preserve OSD ID(s) for replacement.</cds-checkbox>
+ <cds-checkbox
+ id="preserve"
+ formControlName="preserve"
+ modal-primary-focus
+ ariaLabel="preserve"
+ i18n
+ >Preserve OSD ID(s) for replacement.</cds-checkbox
+ >
</div>
</ng-container>
</ng-container>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >{{ action | titlecase }} {{ resource | upperFirst }}</ng-container
+ >
<ng-container class="modal-content">
- <form #formDir="ngForm"
- [formGroup]="osdPgScrubForm"
- novalidate
- cdFormScope="osd">
+ <form
+ #formDir="ngForm"
+ [formGroup]="osdPgScrubForm"
+ novalidate
+ cdFormScope="osd"
+ >
<div class="modal-body osd-modal">
<!-- Basic -->
- <cd-config-option [optionNames]="basicOptions"
- [optionsForm]="osdPgScrubForm"
- [optionsFormDir]="formDir"
- [optionsFormGroupName]="'basicFormGroup'"
- #basicOptionsValues></cd-config-option>
+ <cd-config-option
+ [optionNames]="basicOptions"
+ [optionsForm]="osdPgScrubForm"
+ [optionsFormDir]="formDir"
+ [optionsFormGroupName]="'basicFormGroup'"
+ #basicOptionsValues
+ ></cd-config-option>
<!-- Advanced -->
<div class="row">
<div class="col-sm-12">
- <a class="pull-right margin-right-md"
- (click)="advancedEnabled = true"
- (keydown.enter)="advancedEnabled = true"
- *ngIf="!advancedEnabled"
- i18n
- tabindex="0">Advanced...</a>
+ <a
+ class="pull-right margin-right-md"
+ (click)="advancedEnabled = true"
+ (keydown.enter)="advancedEnabled = true"
+ *ngIf="!advancedEnabled"
+ i18n
+ tabindex="0"
+ >Advanced...</a
+ >
</div>
</div>
<div *ngIf="advancedEnabled">
- <h3 class="page-header"
- i18n>Advanced configuration options</h3>
- <cd-config-option [optionNames]="advancedOptions"
- [optionsForm]="osdPgScrubForm"
- [optionsFormDir]="formDir"
- [optionsFormGroupName]="'advancedFormGroup'"
- #advancedOptionsValues></cd-config-option>
+ <h3
+ class="page-header"
+ i18n
+ >
+ Advanced configuration options
+ </h3>
+ <cd-config-option
+ [optionNames]="advancedOptions"
+ [optionsForm]="osdPgScrubForm"
+ [optionsFormDir]="formDir"
+ [optionsFormGroupName]="'advancedFormGroup'"
+ #advancedOptionsValues
+ ></cd-config-option>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submitAction()"
- [form]="osdPgScrubForm"
- [showSubmit]="permissions.configOpt.update"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)">
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="osdPgScrubForm"
+ [showSubmit]="permissions.configOpt.update"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ >
</cd-form-button-panel>
</div>
</form>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>OSD Recovery Priority</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >OSD Recovery Priority</ng-container
+ >
<ng-container class="modal-content">
- <form #formDir="ngForm"
- [formGroup]="osdRecvSpeedForm"
- novalidate
- cdFormScope="osd">
+ <form
+ #formDir="ngForm"
+ [formGroup]="osdRecvSpeedForm"
+ novalidate
+ cdFormScope="osd"
+ >
<div class="modal-body">
<!-- Priority -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="priority"
- i18n>Priority</label>
+ <label
+ class="cd-col-form-label required"
+ for="priority"
+ i18n
+ >Priority</label
+ >
<div class="cd-col-form-input">
- <select class="form-select"
- formControlName="priority"
- id="priority"
- (change)="onPriorityChange($event.target.value)">
- <option *ngFor="let priority of priorities"
- [value]="priority.name">
+ <select
+ class="form-select"
+ formControlName="priority"
+ id="priority"
+ (change)="onPriorityChange($event.target.value)"
+ >
+ <option
+ *ngFor="let priority of priorities"
+ [value]="priority.name"
+ >
{{ priority.text }}
</option>
</select>
- <span class="invalid-feedback"
- *ngIf="osdRecvSpeedForm.showError('priority', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="osdRecvSpeedForm.showError('priority', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
- <input formControlName="customizePriority"
- class="custom-control-input"
- id="customizePriority"
- name="customizePriority"
- type="checkbox"
- (change)="onCustomizePriorityChange()">
- <label class="custom-control-label"
- for="customizePriority"
- i18n>Customize priority values</label>
+ <input
+ formControlName="customizePriority"
+ class="custom-control-input"
+ id="customizePriority"
+ name="customizePriority"
+ type="checkbox"
+ (change)="onCustomizePriorityChange()"
+ />
+ <label
+ class="custom-control-label"
+ for="customizePriority"
+ i18n
+ >Customize priority values</label
+ >
</div>
</div>
</div>
<!-- Priority values -->
- <div class="form-group row"
- *ngFor="let attr of priorityAttrs | keyvalue">
- <label class="cd-col-form-label"
- [for]="attr.key">
- <span [ngClass]="{'required': osdRecvSpeedForm.getValue('customizePriority')}">
+ <div
+ class="form-group row"
+ *ngFor="let attr of priorityAttrs | keyvalue"
+ >
+ <label
+ class="cd-col-form-label"
+ [for]="attr.key"
+ >
+ <span [ngClass]="{ required: osdRecvSpeedForm.getValue('customizePriority') }">
{{ attr.value.text }}
</span>
<cd-helper *ngIf="attr.value.desc">{{ attr.value.desc }}</cd-helper>
</label>
<div class="cd-col-form-input">
- <input class="form-control"
- type="number"
- [id]="attr.key"
- [formControlName]="attr.key"
- [readonly]="!osdRecvSpeedForm.getValue('customizePriority')">
- <span class="invalid-feedback"
- *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
- osdRecvSpeedForm.showError(attr.key, formDir, 'required')"
- i18n>This field is required!</span>
- <span class="invalid-feedback"
- *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
- osdRecvSpeedForm.showError(attr.key, formDir, 'pattern')"
- i18n>{{ attr.value.patternHelpText }}</span>
- <span class="invalid-feedback"
- *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
- osdRecvSpeedForm.showError(attr.key, formDir, 'max')"
- i18n>The entered value is too high! It must not be greater than {{ attr.value.maxValue }}.</span>
- <span class="invalid-feedback"
- *ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
- osdRecvSpeedForm.showError(attr.key, formDir, 'min')"
- i18n>The entered value is too low! It must not be lower than {{ attr.value.minValue }}.</span>
+ <input
+ class="form-control"
+ type="number"
+ [id]="attr.key"
+ [formControlName]="attr.key"
+ [readonly]="!osdRecvSpeedForm.getValue('customizePriority')"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ osdRecvSpeedForm.getValue('customizePriority') &&
+ osdRecvSpeedForm.showError(attr.key, formDir, 'required')
+ "
+ i18n
+ >This field is required!</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ osdRecvSpeedForm.getValue('customizePriority') &&
+ osdRecvSpeedForm.showError(attr.key, formDir, 'pattern')
+ "
+ i18n
+ >{{ attr.value.patternHelpText }}</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ osdRecvSpeedForm.getValue('customizePriority') &&
+ osdRecvSpeedForm.showError(attr.key, formDir, 'max')
+ "
+ i18n
+ >The entered value is too high! It must not be greater than
+ {{ attr.value.maxValue }}.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ osdRecvSpeedForm.getValue('customizePriority') &&
+ osdRecvSpeedForm.showError(attr.key, formDir, 'min')
+ "
+ i18n
+ >The entered value is too low! It must not be lower than
+ {{ attr.value.minValue }}.</span
+ >
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submitAction()"
- [form]="osdRecvSpeedForm"
- [submitText]="actionLabels.UPDATE"
- [showSubmit]="permissions.configOpt.update"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="osdRecvSpeedForm"
+ [submitText]="actionLabels.UPDATE"
+ [showSubmit]="permissions.configOpt.update"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-modal [modalRef]="activeModal">
- <ng-container class="modal-title"
- i18n>Reweight OSD: {{ osdId }}</ng-container>
+ <ng-container
+ class="modal-title"
+ i18n
+ >Reweight OSD: {{ osdId }}</ng-container
+ >
<ng-container class="modal-content">
<form [formGroup]="reweightForm">
<div class="modal-body">
<div class="row">
- <label for="weight"
- class="cd-col-form-label">Weight</label>
+ <label
+ for="weight"
+ class="cd-col-form-label"
+ >Weight</label
+ >
<div class="cd-col-form-input">
- <input id="weight"
- class="form-control"
- type="number"
- step="0.1"
- formControlName="weight"
- min="0"
- max="1"
- [value]="currentWeight">
- <span class="invalid-feedback"
- *ngIf="weight.errors">
- <span *ngIf="weight.errors?.required"
- i18n>This field is required.</span>
- <span *ngIf="weight.errors?.max || weight.errors?.min"
- i18n>The value needs to be between 0 and 1.</span>
+ <input
+ id="weight"
+ class="form-control"
+ type="number"
+ step="0.1"
+ formControlName="weight"
+ min="0"
+ max="1"
+ [value]="currentWeight"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="weight.errors"
+ >
+ <span
+ *ngIf="weight.errors?.required"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="weight.errors?.max || weight.errors?.min"
+ i18n
+ >The value needs to be between 0 and 1.</span
+ >
</span>
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="reweight()"
- [form]="reweightForm"
- [submitText]="actionLabels.REWEIGHT"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="reweight()"
+ [form]="reweightForm"
+ [submitText]="actionLabels.REWEIGHT"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-modal [modalRef]="activeModal">
- <span class="modal-title"
- i18n>OSDs {deep, select, true {Deep } other {}}Scrub</span>
+ <span
+ class="modal-title"
+ i18n
+ >OSDs {deep, select, true {Deep} other {}}Scrub</span
+ >
<ng-container class="modal-content">
- <form name="scrubForm"
- #formDir="ngForm"
- [formGroup]="scrubForm"
- novalidate>
+ <form
+ name="scrubForm"
+ #formDir="ngForm"
+ [formGroup]="scrubForm"
+ novalidate
+ >
<div class="modal-body">
- <p i18n>You are about to apply a {deep, select, true {deep } other {}}scrub to
- the OSD(s): <strong>{{ selected | join }}</strong>.</p>
+ <p i18n>
+ You are about to apply a {deep, select, true {deep} other {}}scrub to the OSD(s):
+ <strong>{{ selected | join }}</strong
+ >.
+ </p>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="scrub()"
- [form]="scrubForm"
- [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="scrub()"
+ [form]="scrubForm"
+ [submitText]="actionLabels.UPDATE"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-prometheus-tabs></cd-prometheus-tabs>
@if (!isAlertmanagerConfigured) {
- <cd-alert-panel type="info"
- i18n>To see all active Prometheus alerts, please provide
- the URL to the API of Prometheus' Alertmanager as described
- in the <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ i18n
+ >To see all active Prometheus alerts, please provide the URL to the API of Prometheus'
+ Alertmanager as described in the <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel
+ >
}
@if (isAlertmanagerConfigured) {
</cd-table-actions>
@if (expandedRow?.alert_count == 1) {
- <cd-table-key-value
- *cdTableDetail
- [renderObjects]="true"
- [hideEmpty]="true"
- [appendParentKey]="false"
- [data]="expandedRow"
- [customCss]="customCss"
- [autoReload]="false"
- [showMultiLineText]="true"
- [multilineTextKeys]="multilineTextKeys"
- >
- </cd-table-key-value>
+ <cd-table-key-value
+ *cdTableDetail
+ [renderObjects]="true"
+ [hideEmpty]="true"
+ [appendParentKey]="false"
+ [data]="expandedRow"
+ [customCss]="customCss"
+ [autoReload]="false"
+ [showMultiLineText]="true"
+ [multilineTextKeys]="multilineTextKeys"
+ >
+ </cd-table-key-value>
} @else if (expandedRow?.alert_count > 1) {
- <cd-table
- *cdTableDetail
- [data]="expandedRow?.subalerts"
- [columns]="innerColumns"
- identifier="fingerprint"
- [forceIdentifier]="true"
- columnMode="flex"
- [toolHeader]="false"
- [hasDetails]="false"
- [showMultiLineText]="true"
- [multilineTextKeys]="multilineTextKeys"
- [scrollable]="false">
- </cd-table>
+ <cd-table
+ *cdTableDetail
+ [data]="expandedRow?.subalerts"
+ [columns]="innerColumns"
+ identifier="fingerprint"
+ [forceIdentifier]="true"
+ columnMode="flex"
+ [toolHeader]="false"
+ [hasDetails]="false"
+ [showMultiLineText]="true"
+ [multilineTextKeys]="multilineTextKeys"
+ [scrollable]="false"
+ >
+ </cd-table>
}
</cd-table>
}
-<ng-template #externalLinkTpl
- let-row="data.row"
- let-value="data.value">
- <a [href]="value"
- target="_blank">
- <svg [cdsIcon]="icons.lineChart"
- [size]="icons.size16"
- >
- </svg> Source
+<ng-template
+ #externalLinkTpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <a
+ [href]="value"
+ target="_blank"
+ >
+ <svg
+ [cdsIcon]="icons.lineChart"
+ [size]="icons.size16"
+ ></svg>
+ Source
</a>
</ng-template>
<nav
class="nav nav-tabs"
ngbNav
- #nav="ngbNav">
+ #nav="ngbNav"
+>
<ng-container ngbNavItem>
- <a class="nav-link"
- routerLink="/monitoring/active-alerts"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Active Alerts
- <cds-tag *ngIf="prometheusAlertService.activeCriticalAlerts > 0"
- class="tag-danger ms-1">{{ prometheusAlertService.activeCriticalAlerts }}</cds-tag>
- <cds-tag *ngIf="prometheusAlertService.activeWarningAlerts > 0"
- class="tag-warning ms-1">{{ prometheusAlertService.activeWarningAlerts }}</cds-tag></a>
+ <a
+ class="nav-link"
+ routerLink="/monitoring/active-alerts"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Active Alerts
+ <cds-tag
+ *ngIf="prometheusAlertService.activeCriticalAlerts > 0"
+ class="tag-danger ms-1"
+ >{{ prometheusAlertService.activeCriticalAlerts }}</cds-tag
+ >
+ <cds-tag
+ *ngIf="prometheusAlertService.activeWarningAlerts > 0"
+ class="tag-warning ms-1"
+ >{{ prometheusAlertService.activeWarningAlerts }}</cds-tag
+ ></a
+ >
</ng-container>
<ng-container ngbNavItem>
- <a class="nav-link"
- routerLink="/monitoring/silences"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Silences</a>
+ <a
+ class="nav-link"
+ routerLink="/monitoring/silences"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Silences</a
+ >
</ng-container>
<ng-container ngbNavItem>
- <a class="nav-link"
- routerLink="/monitoring/alerts"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Alert Rules</a>
+ <a
+ class="nav-link"
+ routerLink="/monitoring/alerts"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Alert Rules</a
+ >
</ng-container>
</nav>
<cd-prometheus-tabs></cd-prometheus-tabs>
-<cd-alert-panel *ngIf="!isPrometheusConfigured"
- type="info"
- i18n>To see all configured Prometheus alerts, please
- provide the URL to the API of Prometheus as described in
- the <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel>
+<cd-alert-panel
+ *ngIf="!isPrometheusConfigured"
+ type="info"
+ i18n
+ >To see all configured Prometheus alerts, please provide the URL to the API of Prometheus as
+ described in the <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel
+>
-<cd-table *ngIf="isPrometheusConfigured"
- [data]="rules"
- [columns]="columns"
- [selectionType]="'single'"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ *ngIf="isPrometheusConfigured"
+ [data]="rules"
+ [columns]="columns"
+ [selectionType]="'single'"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+>
<ng-container *ngIf="expandedRow">
- <cd-table-key-value *cdTableDetail
- [data]="expandedRow"
- [renderObjects]="true"
- [hideKeys]="hideKeys">
+ <cd-table-key-value
+ *cdTableDetail
+ [data]="expandedRow"
+ [renderObjects]="true"
+ [hideKeys]="hideKeys"
+ >
</cd-table-key-value>
</ng-container>
</cd-table>
-<ng-template #matcherTpl
- let-matcher="matcher"
- let-index="index">
+<ng-template
+ #matcherTpl
+ let-matcher="matcher"
+ let-index="index"
+>
<div class="input-group my-2">
<ng-container *ngFor="let config of matcherConfig">
- <span class="input-group-text"
- *ngIf="config.attribute === 'isRegex'">
- <i *ngIf="matcher[config.attribute]"
- [ngbTooltip]="config.tooltip">~</i>
- <i *ngIf="!matcher[config.attribute]"
- ngbTooltip="Equals">=</i>
+ <span
+ class="input-group-text"
+ *ngIf="config.attribute === 'isRegex'"
+ >
+ <i
+ *ngIf="matcher[config.attribute]"
+ [ngbTooltip]="config.tooltip"
+ >~</i
+ >
+ <i
+ *ngIf="!matcher[config.attribute]"
+ ngbTooltip="Equals"
+ >=</i
+ >
</span>
<ng-container *ngIf="config.attribute !== 'isRegex'">
- <input type="text"
- id="matcher-{{config.attribute}}-{{index}}"
- class="form-control"
- [value]="matcher[config.attribute]"
- disabled
- readonly>
+ <input
+ type="text"
+ id="matcher-{{ config.attribute }}-{{ index }}"
+ class="form-control"
+ [value]="matcher[config.attribute]"
+ disabled
+ readonly
+ />
</ng-container>
</ng-container>
<!-- Matcher actions -->
- <button type="button"
- class="btn btn-light"
- id="matcher-edit-{{index}}"
- i18n-ngbTooltip
- ngbTooltip="Edit"
- (click)="showMatcherModal(index)">
+ <button
+ type="button"
+ class="btn btn-light"
+ id="matcher-edit-{{ index }}"
+ i18n-ngbTooltip
+ ngbTooltip="Edit"
+ (click)="showMatcherModal(index)"
+ >
<svg
- [cdsIcon]="icons.edit"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ [cdsIcon]="icons.edit"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</button>
- <button type="button"
- class="btn btn-light"
- id="matcher-delete-{{index}}"
- i18n-ngbTooltip
- ngbTooltip="Delete"
- (click)="deleteMatcher(index)">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <button
+ type="button"
+ class="btn btn-light"
+ id="matcher-delete-{{ index }}"
+ i18n-ngbTooltip
+ ngbTooltip="Delete"
+ (click)="deleteMatcher(index)"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</button>
</div>
<span class="help-block"></span>
</ng-template>
<div class="cd-col-form">
- <form #formDir="ngForm"
- [formGroup]="form"
- class="form"
- name="form"
- novalidate>
+ <form
+ #formDir="ngForm"
+ [formGroup]="form"
+ class="form"
+ name="form"
+ novalidate
+ >
<div class="card">
<div class="card-header">
<span i18n>{{ action | titlecase }} {{ resource | upperFirst }}</span>
- <cd-helper *ngIf="edit"
- i18n>Editing a silence will expire the old silence and recreate it as a new silence</cd-helper>
+ <cd-helper
+ *ngIf="edit"
+ i18n
+ >Editing a silence will expire the old silence and recreate it as a new silence</cd-helper
+ >
</div>
<!-- Creator -->
<div class="card-body">
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="created-by"
- i18n>Creator</label>
+ <label
+ class="cd-col-form-label required"
+ for="created-by"
+ i18n
+ >Creator</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- formControlName="createdBy"
- id="created-by"
- name="created-by"
- type="text">
- <span *ngIf="form.showError('createdBy', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required!</span>
+ <input
+ class="form-control"
+ formControlName="createdBy"
+ id="created-by"
+ name="created-by"
+ type="text"
+ />
+ <span
+ *ngIf="form.showError('createdBy', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- Comment -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="comment"
- i18n>Comment</label>
+ <label
+ class="cd-col-form-label required"
+ for="comment"
+ i18n
+ >Comment</label
+ >
<div class="cd-col-form-input">
- <textarea class="form-control"
- formControlName="comment"
- id="comment"
- name="comment"
- type="text">
+ <textarea
+ class="form-control"
+ formControlName="comment"
+ id="comment"
+ name="comment"
+ type="text"
+ >
</textarea>
- <span *ngIf="form.showError('comment', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required!</span>
+ <span
+ *ngIf="form.showError('comment', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- Start time -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="starts-at">
- <span class="required"
- i18n>Start time</span>
- <cd-helper i18n>If the start time lies in the past the creation time will be used</cd-helper>
+ <label
+ class="cd-col-form-label"
+ for="starts-at"
+ >
+ <span
+ class="required"
+ i18n
+ >Start time</span
+ >
+ <cd-helper i18n
+ >If the start time lies in the past the creation time will be used</cd-helper
+ >
</label>
<div class="cd-col-form-input">
- <input class="form-control"
- formControlName="startsAt"
- [ngbPopover]="popStart"
- triggers="manual"
- #ps="ngbPopover"
- (click)="ps.open()"
- (keypress)="ps.close()">
- <span *ngIf="form.showError('startsAt', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required!</span>
+ <input
+ class="form-control"
+ formControlName="startsAt"
+ [ngbPopover]="popStart"
+ triggers="manual"
+ #ps="ngbPopover"
+ (click)="ps.open()"
+ (keypress)="ps.close()"
+ />
+ <span
+ *ngIf="form.showError('startsAt', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- Duration -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="duration"
- i18n>Duration</label>
+ <label
+ class="cd-col-form-label required"
+ for="duration"
+ i18n
+ >Duration</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- formControlName="duration"
- id="duration"
- name="duration"
- type="text">
- <span *ngIf="form.showError('duration', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required!</span>
+ <input
+ class="form-control"
+ formControlName="duration"
+ id="duration"
+ name="duration"
+ type="text"
+ />
+ <span
+ *ngIf="form.showError('duration', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- End time -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="ends-at"
- i18n>End time</label>
+ <label
+ class="cd-col-form-label required"
+ for="ends-at"
+ i18n
+ >End time</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- formControlName="endsAt"
- [ngbPopover]="popEnd"
- triggers="manual"
- #pe="ngbPopover"
- (click)="pe.open()"
- (keypress)="pe.close()">
- <span *ngIf="form.showError('endsAt', formDir, 'required')"
- class="invalid-feedback"
- i18n>This field is required!</span>
+ <input
+ class="form-control"
+ formControlName="endsAt"
+ [ngbPopover]="popEnd"
+ triggers="manual"
+ #pe="ngbPopover"
+ (click)="pe.open()"
+ (keypress)="pe.close()"
+ />
+ <span
+ *ngIf="form.showError('endsAt', formDir, 'required')"
+ class="invalid-feedback"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- Matchers -->
<fieldset>
- <legend class="required"
- i18n>Matchers</legend>
+ <legend
+ class="required"
+ i18n
+ >
+ Matchers
+ </legend>
<div class="cd-col-form-offset">
- <h5 *ngIf="matchers.length === 0"
- [ngClass]="{'text-warning': !formDir.submitted, 'text-danger': formDir.submitted}">
+ <h5
+ *ngIf="matchers.length === 0"
+ [ngClass]="{ 'text-warning': !formDir.submitted, 'text-danger': formDir.submitted }"
+ >
<strong i18n>A silence requires at least one matcher</strong>
</h5>
- <span *ngFor="let matcher of matchers; let i=index;">
- <ng-container *ngTemplateOutlet="matcherTpl; context:{index: i, matcher: matcher}"></ng-container>
+ <span *ngFor="let matcher of matchers; let i = index">
+ <ng-container
+ *ngTemplateOutlet="matcherTpl; context: { index: i, matcher: matcher }"
+ ></ng-container>
</span>
<div class="row">
<div class="col-12">
- <button type="button"
- id="add-matcher"
- class="btn btn-light float-end my-3"
- [ngClass]="{'btn-warning': formDir.submitted && matchers.length === 0 }"
- (click)="showMatcherModal()">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- ></svg>
+ <button
+ type="button"
+ id="add-matcher"
+ class="btn btn-light float-end my-3"
+ [ngClass]="{ 'btn-warning': formDir.submitted && matchers.length === 0 }"
+ (click)="showMatcherModal()"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Add matcher</ng-container>
</button>
</div>
</div>
</div>
- <div *ngIf="matchers.length && matcherMatch"
- class="cd-col-form-offset {{matcherMatch.cssClass}}"
- id="match-state">
- <span class="text-muted {{matcherMatch.cssClass}}">
+ <div
+ *ngIf="matchers.length && matcherMatch"
+ class="cd-col-form-offset {{ matcherMatch.cssClass }}"
+ id="match-state"
+ >
+ <span class="text-muted {{ matcherMatch.cssClass }}">
{{ matcherMatch.status }}
</span>
</div>
<div class="card-footer">
<div class="text-right">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="form"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ ></cd-form-button-panel>
</div>
</div>
</div>
</div>
<ng-template #popStart>
- <cd-date-time-picker [control]="form.get('startsAt')"
- [hasSeconds]="false"></cd-date-time-picker>
+ <cd-date-time-picker
+ [control]="form.get('startsAt')"
+ [hasSeconds]="false"
+ ></cd-date-time-picker>
</ng-template>
-
<ng-template #popEnd>
- <cd-date-time-picker [control]="form.get('endsAt')"
- [hasSeconds]="false"></cd-date-time-picker>
+ <cd-date-time-picker
+ [control]="form.get('endsAt')"
+ [hasSeconds]="false"
+ ></cd-date-time-picker>
</ng-template>
<cd-prometheus-tabs></cd-prometheus-tabs>
-<cd-alert-panel *ngIf="!isAlertmanagerConfigured"
- type="info"
- i18n>To enable Silences, please provide the URL to
- the API of the Prometheus' Alertmanager as described in the
- <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel>
+<cd-alert-panel
+ *ngIf="!isAlertmanagerConfigured"
+ type="info"
+ i18n
+ >To enable Silences, please provide the URL to the API of the Prometheus' Alertmanager as
+ described in the <cd-doc section="prometheus"></cd-doc>.</cd-alert-panel
+>
-<cd-table *ngIf="isAlertmanagerConfigured"
- [data]="silences"
- [columns]="columns"
- [forceIdentifier]="true"
- [customCss]="customCss"
- [sorts]="sorts"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (fetchData)="refresh()"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ *ngIf="isAlertmanagerConfigured"
+ [data]="silences"
+ [columns]="columns"
+ [forceIdentifier]="true"
+ [customCss]="customCss"
+ [sorts]="sorts"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (fetchData)="refresh()"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
<ng-container *ngIf="expandedRow">
- <cd-table-key-value *cdTableDetail
- [renderObjects]="true"
- [hideEmpty]="true"
- [appendParentKey]="false"
- [data]="expandedRow"
- [customCss]="customCss"
- [autoReload]="false">
+ <cd-table-key-value
+ *cdTableDetail
+ [renderObjects]="true"
+ [hideEmpty]="true"
+ [appendParentKey]="false"
+ [data]="expandedRow"
+ [customCss]="customCss"
+ [autoReload]="false"
+ >
</cd-table-key-value>
</ng-container>
</cd-table>
<cd-modal [modalRef]="activeModal">
- <span class="modal-title"
- i18n>{editMode, select, true {Edit} other {Add}} Matcher</span>
+ <span
+ class="modal-title"
+ i18n
+ >{editMode, select, true {Edit} other {Add}} Matcher</span
+ >
<ng-container class="modal-content">
- <form class="form"
- #formDir="ngForm"
- [formGroup]="form"
- novalidate>
+ <form
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
<div class="modal-body">
<!-- Name -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="name"
- i18n>Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="name"
+ i18n
+ >Name</label
+ >
<div class="cd-col-form-input">
- <select class="form-select"
- id="name"
- formControlName="name"
- name="name">
- <option [ngValue]="null"
- i18n>-- Select an attribute to match against --</option>
- <option *ngFor="let attribute of nameAttributes"
- [value]="attribute">
+ <select
+ class="form-select"
+ id="name"
+ formControlName="name"
+ name="name"
+ >
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- Select an attribute to match against --
+ </option>
+ <option
+ *ngFor="let attribute of nameAttributes"
+ [value]="attribute"
+ >
{{ attribute }}
</option>
</select>
- <span class="help-block"
- *ngIf="form.showError('name', formDir, 'required')"
- i18n>This field is required!</span>
+ <span
+ class="help-block"
+ *ngIf="form.showError('name', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
<!-- Value -->
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="value"
- i18n>Value</label>
+ <label
+ class="cd-col-form-label required"
+ for="value"
+ i18n
+ >Value</label
+ >
<div class="cd-col-form-input">
- <input id="value"
- (focus)="valueFocus.next($any($event).target.value)"
- (click)="valueClick.next($any($event).target.value)"
- class="form-control"
- type="text"
- [ngbTypeahead]="search"
- formControlName="value"
- #instance="ngbTypeahead">
- <span *ngIf="form.showError('value', formDir, 'required')"
- class="help-block"
- i18n>This field is required!</span>
+ <input
+ id="value"
+ (focus)="valueFocus.next($any($event).target.value)"
+ (click)="valueClick.next($any($event).target.value)"
+ class="form-control"
+ type="text"
+ [ngbTypeahead]="search"
+ formControlName="value"
+ #instance="ngbTypeahead"
+ />
+ <span
+ *ngIf="form.showError('value', formDir, 'required')"
+ class="help-block"
+ i18n
+ >This field is required!</span
+ >
</div>
- <div *ngIf="form.getValue('value') && !form.getValue('isRegex') && matcherMatch"
- class="cd-col-form-offset {{matcherMatch.cssClass}}"
- id="match-state">
- <span class="text-muted {{matcherMatch.cssClass}}">
- {{matcherMatch.status}}
+ <div
+ *ngIf="form.getValue('value') && !form.getValue('isRegex') && matcherMatch"
+ class="cd-col-form-offset {{ matcherMatch.cssClass }}"
+ id="match-state"
+ >
+ <span class="text-muted {{ matcherMatch.cssClass }}">
+ {{ matcherMatch.status }}
</span>
</div>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- formControlName="isRegex"
- name="is-regex"
- id="is-regex">
- <label for="is-regex"
- class="custom-control-label"
- i18n>Use regular expression</label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ formControlName="isRegex"
+ name="is-regex"
+ id="is-regex"
+ />
+ <label
+ for="is-regex"
+ class="custom-control-label"
+ i18n
+ >Use regular expression</label
+ >
</div>
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="form"
- [submitText]="getMode()"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="getMode()"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-details-card>
- <ng-container
- class="details-body-content">
- <div cdsStack="horizontal"
- [gap]="6">
- <div cdsStack="vertical"
- [gap]="3">
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <ng-container class="details-body-content">
+ <div
+ cdsStack="horizontal"
+ [gap]="6"
+ >
+ <div
+ cdsStack="vertical"
+ [gap]="3"
+ >
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Certificate name
</span>
- <span class="cds--type-body-compact-01"
- [title]="certificate?.cert_name || '-'">
+ <span
+ class="cds--type-body-compact-01"
+ [title]="certificate?.cert_name || '-'"
+ >
{{ certificate?.cert_name || '-' }}
</span>
</div>
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Valid until
</span>
- <span class="cds--type-body-compact-01"
- [title]="formatDate(certificate?.expiry_date) || '-'">
+ <span
+ class="cds--type-body-compact-01"
+ [title]="formatDate(certificate?.expiry_date) || '-'"
+ >
{{ formatDate(certificate?.expiry_date) || '-' }}
</span>
</div>
</div>
- <div cdsStack="vertical"
- [gap]="3">
- <div cdsStack="horizontal"
- [gap]="1">
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="3"
+ >
+ <div
+ cdsStack="horizontal"
+ [gap]="1"
+ >
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Status
</span>
- <ng-container *ngTemplateOutlet="statusTemplate; context: { status: certificate?.status }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="statusTemplate; context: { status: certificate?.status }"
+ ></ng-container>
</div>
@if (SERVICES_SUPPORTING_CERT_EDIT.includes(serviceType)) {
- <cds-icon-button kind="ghost"
- size="sm"
- (click)="onEdit()"
- class="cds-mt-5">
- <cd-icon type="edit">
- </cd-icon>
- </cds-icon-button>
+ <cds-icon-button
+ kind="ghost"
+ size="sm"
+ (click)="onEdit()"
+ class="cds-mt-5"
+ >
+ <cd-icon type="edit"> </cd-icon>
+ </cds-icon-button>
}
-
</div>
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Days remaining
</span>
- <span class="cds--type-body-compact-01"
- [title]="certificate?.days_to_expiration ? certificate.days_to_expiration : '-'">
+ <span
+ class="cds--type-body-compact-01"
+ [title]="certificate?.days_to_expiration ? certificate.days_to_expiration : '-'"
+ >
{{ certificate?.days_to_expiration ? certificate.days_to_expiration : '-' }}
</span>
</div>
</div>
- <div cdsStack="vertical"
- [gap]="3">
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="3"
+ >
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Issuer
</span>
- <span class="cds--type-body-compact-01"
- [title]="certificate?.issuer || certificate?.signed_by || '-'">
+ <span
+ class="cds--type-body-compact-01"
+ [title]="certificate?.issuer || certificate?.signed_by || '-'"
+ >
{{ certificate?.issuer || certificate?.signed_by || '-' }}
</span>
</div>
- <div cdsStack="vertical"
- [gap]="1">
- <span class="cds--type-label-01"
- i18n>
+ <div
+ cdsStack="vertical"
+ [gap]="1"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >
Common name
</span>
- <span class="cds--type-body-compact-01"
- [title]="certificate?.common_name || '-'">
+ <span
+ class="cds--type-body-compact-01"
+ [title]="certificate?.common_name || '-'"
+ >
{{ certificate?.common_name || '-' }}
</span>
</div>
</div>
</div>
- <ng-template #statusTemplate
- let-status="status">
- <div cdsStack="horizontal"
- [gap]="2"
- class="status-row">
- <cd-icon
- [type]="statusIconMap[status] || statusIconMap['default']">
- </cd-icon>
+ <ng-template
+ #statusTemplate
+ let-status="status"
+ >
+ <div
+ cdsStack="horizontal"
+ [gap]="2"
+ class="status-row"
+ >
+ <cd-icon [type]="statusIconMap[status] || statusIconMap['default']"> </cd-icon>
<span class="cds--type-body-compact-01">{{ formatCertificateStatus(certificate) }}</span>
-
</div>
</ng-template>
-
</ng-container>
</cd-details-card>
</div>
<ng-template #serviceDetailsTpl>
-@switch (mode) {
- @case ('daemons') {
- <ng-container *ngTemplateOutlet="serviceDaemonDetailsTpl"></ng-container>
- }
- @case ('events') {
- @if (hasOrchestrator) {
- <cd-table
- #serviceTable
- [data]="services"
- [columns]="serviceColumns"
- columnMode="flex"
- (fetchData)="getServices($event)">
- </cd-table>
- }
+ @switch (mode) {
+ @case ('daemons') {
+ <ng-container *ngTemplateOutlet="serviceDaemonDetailsTpl"></ng-container>
+ }
+ @case ('events') {
+ @if (hasOrchestrator) {
+ <cd-table
+ #serviceTable
+ [data]="services"
+ [columns]="serviceColumns"
+ columnMode="flex"
+ (fetchData)="getServices($event)"
+ >
+ </cd-table>
+ }
+ }
}
-}
</ng-template>
-<ng-template #statusTpl
- let-row="data.row">
- <cds-tag *ngIf="row.status_desc"
- [class]="row | pipeFunction:getStatusClass">
+<ng-template
+ #statusTpl
+ let-row="data.row"
+>
+ <cds-tag
+ *ngIf="row.status_desc"
+ [class]="row | pipeFunction: getStatusClass"
+ >
{{ row.status_desc }}
-</cds-tag>
+ </cds-tag>
</ng-template>
-<ng-template #listTpl
- let-events="data.value">
- <ul class="list-group list-group-flush"
- *ngIf="events?.length else noEventsAvailable">
- <li class="list-group-item"
- *ngFor="let event of events; trackBy:trackByFn">
+<ng-template
+ #listTpl
+ let-events="data.value"
+>
+ <ul
+ class="list-group list-group-flush"
+ *ngIf="events?.length; else noEventsAvailable"
+ >
+ <li
+ class="list-group-item"
+ *ngFor="let event of events; trackBy: trackByFn"
+ >
<b>{{ event.created | relativeDate }} - </b>
- <cds-tag class="tag-info">{{ event.subject }}</cds-tag><br>
+ <cds-tag class="tag-info">{{ event.subject }}</cds-tag
+ ><br />
<span *ngIf="event.level === 'INFO'">
- <svg [cdsIcon]="icons.infoCircle"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <svg
+ [cdsIcon]="icons.infoCircle"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</span>
<span *ngIf="event.level === 'ERROR'">
- <svg [cdsIcon]="icons.warning"
- [size]="icons.size16"
- class="cds-warning-color"></svg>
+ <svg
+ [cdsIcon]="icons.warning"
+ [size]="icons.size16"
+ class="cds-warning-color"
+ ></svg>
</span>
{{ event.message }}
</li>
</ng-template>
<ng-template #serviceDaemonDetailsTpl>
- <cd-table *ngIf="hasOrchestrator"
- #daemonsTable
- [data]="daemons"
- selectionType="single"
- [columns]="columns"
- columnMode="flex"
- identifier="daemon_name"
- (fetchData)="getDaemons($event)"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions id="service-daemon-list-actions"
- class="table-actions"
- [selection]="selection"
- [permission]="permissions.hosts"
- [tableActions]="tableActions">
+ <cd-table
+ *ngIf="hasOrchestrator"
+ #daemonsTable
+ [data]="daemons"
+ selectionType="single"
+ [columns]="columns"
+ columnMode="flex"
+ identifier="daemon_name"
+ (fetchData)="getDaemons($event)"
+ (updateSelection)="updateSelection($event)"
+ >
+ <cd-table-actions
+ id="service-daemon-list-actions"
+ class="table-actions"
+ [selection]="selection"
+ [permission]="permissions.hosts"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
</ng-template>
-<ng-template #cpuTpl
- let-row="data.row">
- <cd-usage-bar [total]="total"
- [calculatePerc]="false"
- [used]="row.cpu_percentage"
- [isBinary]="false">
+<ng-template
+ #cpuTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ [total]="total"
+ [calculatePerc]="false"
+ [used]="row.cpu_percentage"
+ [isBinary]="false"
+ >
</cd-usage-bar>
</ng-template>
@if (service) {
<cds-tabs [cacheActive]="false">
- <cds-tab heading="Daemons"
- i18n-heading>
+ <cds-tab
+ heading="Daemons"
+ i18n-heading
+ >
<cd-service-daemon-list
[serviceName]="service?.service_name"
- mode="daemons">
+ mode="daemons"
+ >
</cd-service-daemon-list>
</cds-tab>
@if (hasCertificate) {
- <cds-tab heading="Certificate"
- i18n-heading>
+ <cds-tab
+ heading="Certificate"
+ i18n-heading
+ >
<cd-service-certificate-details
[certificate]="certificate"
[serviceName]="service?.service_name"
[serviceType]="service?.service_type"
- (editService)="onEditService($event)">
+ (editService)="onEditService($event)"
+ >
</cd-service-certificate-details>
</cds-tab>
}
- <cds-tab heading="Service Events"
- i18n-heading>
+ <cds-tab
+ heading="Service Events"
+ i18n-heading
+ >
<cd-service-daemon-list
[serviceName]="service?.service_name"
- mode="events">
+ mode="events"
+ >
</cd-service-daemon-list>
</cds-tab>
</cds-tabs>
-<cds-modal size="lg"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource }}
+ </h3>
<cd-help-text></cd-help-text>
</cds-modal-header>
- <section cdsModalContent
- hasForm="true">
- <form #frm="ngForm"
- [formGroup]="serviceForm"
- novalidate>
+ <section
+ cdsModalContent
+ hasForm="true"
+ >
+ <form
+ #frm="ngForm"
+ [formGroup]="serviceForm"
+ novalidate
+ >
@if (serviceForm.controls.service_type.value === 'rgw' && showRealmCreationForm) {
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- i18n>
- <a class="text-decoration-underline"
- tabindex="0"
- (keydown.enter)="createMultisiteSetup()"
- (click)="createMultisiteSetup()">
- Click here</a> to create a new Realm/Zonegroup/Zone
- </cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ >
+ <a
+ class="text-decoration-underline"
+ tabindex="0"
+ (keydown.enter)="createMultisiteSetup()"
+ (click)="createMultisiteSetup()"
+ >
+ Click here</a
+ >
+ to create a new Realm/Zonegroup/Zone
+ </cd-alert-panel>
}
@if (serviceForm.controls.service_type.value === 'oauth2-proxy') {
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- i18n>
- Authentication must be enabled in an active `mgmt-gateway` service to enable Single Sign-On(SSO) with
- `oauth2-proxy`
- </cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ >
+ Authentication must be enabled in an active `mgmt-gateway` service to enable Single
+ Sign-On(SSO) with `oauth2-proxy`
+ </cd-alert-panel>
}
@if (serviceForm.controls.service_type.value === 'mgmt-gateway') {
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- i18n>
- With an active mgmt-gateway service, the dashboard will continue to be served on {{currentURL}}:{{port}} and all
- other services will be accessible from {{currentURL}}:{{port}}/service_name
- </cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ >
+ With an active mgmt-gateway service, the dashboard will continue to be served on
+ {{ currentURL }}:{{ port }} and all other services will be accessible from
+ {{ currentURL }}:{{ port }}/service_name
+ </cd-alert-panel>
}
@if (serviceForm.controls.service_type.value === 'smb') {
- <cd-alert-panel type="warning"
- spacingClass="mb-3"
- i18n>
- SMB service management is intended for advanced users only.
- For most scenarios, it is recommended to use the SMB module instead.
- To manage SMB clusters and shares, please visit the <a routerLink="/cephfs/smb">SMB page</a>.
- </cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-3"
+ i18n
+ >
+ SMB service management is intended for advanced users only. For most scenarios, it is
+ recommended to use the SMB module instead. To manage SMB clusters and shares, please visit
+ the <a routerLink="/cephfs/smb">SMB page</a>.
+ </cd-alert-panel>
}
<!-- Service type -->
<div class="form-item">
- <cds-select formControlName="service_type"
- label="Type"
- cdRequiredField="Type"
- id="service_type"
- [invalid]="serviceForm.controls.service_type.invalid && serviceForm.controls.service_type.dirty"
- [invalidText]="invalidServiceTypeError"
- (change)="onServiceTypeChange($event.target.value)">
- <option i18n
- [ngValue]="null">
+ <cds-select
+ formControlName="service_type"
+ label="Type"
+ cdRequiredField="Type"
+ id="service_type"
+ [invalid]="
+ serviceForm.controls.service_type.invalid && serviceForm.controls.service_type.dirty
+ "
+ [invalidText]="invalidServiceTypeError"
+ (change)="onServiceTypeChange($event.target.value)"
+ >
+ <option
+ i18n
+ [ngValue]="null"
+ >
-- Select a service type --
</option>
@for (serviceType of serviceTypes; track serviceType) {
- <option [value]="serviceType">
- {{ serviceType }}
- </option>
+ <option [value]="serviceType">
+ {{ serviceType }}
+ </option>
}
</cds-select>
<ng-template #invalidServiceTypeError>
@if (serviceForm.showError('service_type', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
<!-- backend_service -->
@if (serviceForm.controls.service_type.value === 'ingress') {
- <div class="form-item">
- <cds-select id="backend_service"
- formControlName="backend_service"
- label="Backend service"
- cdRequiredField="Backend service"
- [invalid]="serviceForm.controls.backend_service.invalid && serviceForm.controls.backend_service.dirty"
- [invalidText]="invalidBackendServiceError"
- (change)="prePopulateId()">
- @if (services === null) {
- <option [ngValue]="null"
- i18n>Loading...</option>
- }
- @if (services !== null && services.length === 0) {
- <option [ngValue]="null"
- i18n>-- No service available --</option>
- }
- @if (services !== null && services.length > 0) {
- <option [ngValue]="null"
- i18n>-- Select an existing service --</option>
- }
- @for (service of services; track service) {
- <option [value]="service.service_name">{{ service.service_name }}</option>
- }
- </cds-select>
- <ng-template #invalidBackendServiceError>
- @if (serviceForm.showError('backend_service', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-select
+ id="backend_service"
+ formControlName="backend_service"
+ label="Backend service"
+ cdRequiredField="Backend service"
+ [invalid]="
+ serviceForm.controls.backend_service.invalid &&
+ serviceForm.controls.backend_service.dirty
+ "
+ [invalidText]="invalidBackendServiceError"
+ (change)="prePopulateId()"
+ >
+ @if (services === null) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ }
+ @if (services !== null && services.length === 0) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- No service available --
+ </option>
+ }
+ @if (services !== null && services.length > 0) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- Select an existing service --
+ </option>
+ }
+ @for (service of services; track service) {
+ <option [value]="service.service_name">{{ service.service_name }}</option>
+ }
+ </cds-select>
+ <ng-template #invalidBackendServiceError>
+ @if (serviceForm.showError('backend_service', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
}
<!-- Group Name -->
@if (serviceForm.controls.service_type.value === 'nvmeof') {
- <div class="form-item">
- <cds-text-label helperText="The name of the gateway group."
- i18n-helperText
- label="Group name"
- cdRequiredField="Group name"
- [invalid]="serviceForm.controls.group.invalid && serviceForm.controls.group.dirty"
- [invalidText]="requiredFieldGroup">
- <input cdsText
- type="text"
- id="group"
- formControlName="group"
- [invalid]="serviceForm.controls.group.invalid && serviceForm.controls.group.dirty"
- (change)="setNvmeServiceId()" />
- </cds-text-label>
- <ng-template #requiredFieldGroup>
- @if (serviceForm.showError('service_id', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ helperText="The name of the gateway group."
+ i18n-helperText
+ label="Group name"
+ cdRequiredField="Group name"
+ [invalid]="serviceForm.controls.group.invalid && serviceForm.controls.group.dirty"
+ [invalidText]="requiredFieldGroup"
+ >
+ <input
+ cdsText
+ type="text"
+ id="group"
+ formControlName="group"
+ [invalid]="serviceForm.controls.group.invalid && serviceForm.controls.group.dirty"
+ (change)="setNvmeServiceId()"
+ />
+ </cds-text-label>
+ <ng-template #requiredFieldGroup>
+ @if (serviceForm.showError('service_id', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
}
<!-- Service id -->
@if (serviceForm.controls.service_type.value !== 'snmp-gateway') {
- <div class="form-item">
- @if (isPrefixedNamedService) {
- <div class="cds-input-group">
- <div class="fit-content">
- <cds-text-label cdRequiredField="Service name"
- [disabled]="editing"
- i18n>
- <input cdsText
- type="text"
- [value]="serviceForm.controls.service_type.value + '.'"
- disabled="true">
+ <div class="form-item">
+ @if (isPrefixedNamedService) {
+ <div class="cds-input-group">
+ <div class="fit-content">
+ <cds-text-label
+ cdRequiredField="Service name"
+ [disabled]="editing"
+ i18n
+ >
+ <input
+ cdsText
+ type="text"
+ [value]="serviceForm.controls.service_type.value + '.'"
+ disabled="true"
+ />
+ </cds-text-label>
+ </div>
+ <cds-text-label
+ [invalid]="
+ serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty
+ "
+ [disabled]="editing"
+ [invalidText]="serviceIdError"
+ >
+ <!-- Invisible character to set input fields on same line -->
+ ​
+ <input
+ cdsText
+ type="text"
+ id="service_id"
+ formControlName="service_id"
+ [invalid]="
+ serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty
+ "
+ />
+ </cds-text-label>
+ </div>
+ } @else {
+ <cds-text-label
+ [invalid]="
+ serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty
+ "
+ [disabled]="editing"
+ [invalidText]="serviceIdError"
+ >
+ Service name
+ <input
+ cdsText
+ type="text"
+ id="service_id"
+ formControlName="service_id"
+ [invalid]="
+ serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty
+ "
+ />
</cds-text-label>
- </div>
- <cds-text-label [invalid]="serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty"
- [disabled]="editing"
- [invalidText]="serviceIdError">
- <!-- Invisible character to set input fields on same line -->
- ​
- <input cdsText
- type="text"
- id="service_id"
- formControlName="service_id"
- [invalid]="serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty" />
- </cds-text-label>
- </div>
- } @else {
- <cds-text-label [invalid]="serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty"
- [disabled]="editing"
- [invalidText]="serviceIdError">
- Service name
- <input cdsText
- type="text"
- id="service_id"
- formControlName="service_id"
- [invalid]="serviceForm.controls.service_id.invalid && serviceForm.controls.service_id.dirty" />
- </cds-text-label>
- }
-
- <ng-template #serviceIdError>
- @if (serviceForm.showError('service_id', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
}
- @if (serviceForm.showError('service_id', frm, 'uniqueName')) {
- <span class="invalid-feedback"
- i18n>This service id is already in use.</span>
- }
- @if (serviceForm.showError('service_id', frm, 'mdsPattern')) {
- <span class="invalid-feedback"
- i18n>MDS service id must start with a letter and contain alphanumeric characters or '.', '-', and
- '_'</span>
- }
- </ng-template>
- </div>
+
+ <ng-template #serviceIdError>
+ @if (serviceForm.showError('service_id', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('service_id', frm, 'uniqueName')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This service id is already in use.</span
+ >
+ }
+ @if (serviceForm.showError('service_id', frm, 'mdsPattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >MDS service id must start with a letter and contain alphanumeric characters or '.',
+ '-', and '_'</span
+ >
+ }
+ </ng-template>
+ </div>
}
@if (serviceForm.controls.service_type.value === 'rgw') {
- <div class="form-item">
- <cds-select formControlName="realm_name"
- label="Realm"
- [invalid]="serviceForm.controls.realm_name.invalid && serviceForm.controls.realm_name.dirty"
- [invalidText]="authModeError"
- helperText="Active-directory authentication for domain member servers and User authentication for Stand-alone servers configuration."
- i18n-helperText>
- @if (realmList.length === 0) {
- <option i18n
- selected>-- No realm available --
- </option>
- }
- @for (realm of realmList; track realm) {
- <option [value]="realm.name">
- {{ realm.name }}
- </option>
- }
- </cds-select>
- <ng-template #authModeError>
- @if (serviceForm.showError('realm_name', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-select
+ formControlName="realm_name"
+ label="Realm"
+ [invalid]="
+ serviceForm.controls.realm_name.invalid && serviceForm.controls.realm_name.dirty
+ "
+ [invalidText]="authModeError"
+ helperText="Active-directory authentication for domain member servers and User authentication for Stand-alone servers configuration."
+ i18n-helperText
+ >
+ @if (realmList.length === 0) {
+ <option
+ i18n
+ selected
+ >
+ -- No realm available --
+ </option>
+ }
+ @for (realm of realmList; track realm) {
+ <option [value]="realm.name">
+ {{ realm.name }}
+ </option>
+ }
+ </cds-select>
+ <ng-template #authModeError>
+ @if (serviceForm.showError('realm_name', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <div class="form-item">
- <cds-select id="zonegroup_name"
- formControlName="zonegroup_name"
- label="Zonegroup">
- @for (zonegroup of zonegroupList; track zonegroup) {
- <option [value]="zonegroup.name">
- {{ zonegroup.name }}
- </option>
- }
- </cds-select>
- </div>
+ <div class="form-item">
+ <cds-select
+ id="zonegroup_name"
+ formControlName="zonegroup_name"
+ label="Zonegroup"
+ >
+ @for (zonegroup of zonegroupList; track zonegroup) {
+ <option [value]="zonegroup.name">
+ {{ zonegroup.name }}
+ </option>
+ }
+ </cds-select>
+ </div>
- <div class="form-item">
- <cds-select id="zone_name"
- formControlName="zone_name"
- label="Zone">
- @for (zone of zoneList; track zone) {
- <option [value]="zone.name">
- {{ zone.name }}
- </option>
- }
- </cds-select>
- </div>
+ <div class="form-item">
+ <cds-select
+ id="zone_name"
+ formControlName="zone_name"
+ label="Zone"
+ >
+ @for (zone of zoneList; track zone) {
+ <option [value]="zone.name">
+ {{ zone.name }}
+ </option>
+ }
+ </cds-select>
+ </div>
}
<!-- unmanaged -->
<div class="form-item">
<fieldset>
- <label class="cds--label"
- for="unmanaged"
- i18n>Unmanaged</label>
- <cds-checkbox i18n-label
- id="unmanaged"
- formControlName="unmanaged">
+ <label
+ class="cds--label"
+ for="unmanaged"
+ i18n
+ >Unmanaged</label
+ >
+ <cds-checkbox
+ i18n-label
+ id="unmanaged"
+ formControlName="unmanaged"
+ >
Enable
<cd-help-text i18n>
- If Unmanaged is selected, the orchestrator will not start or stop any daemons associated with this
- service.
- Placement and all other properties will be ignored.
+ If Unmanaged is selected, the orchestrator will not start or stop any daemons
+ associated with this service. Placement and all other properties will be ignored.
</cd-help-text>
</cds-checkbox>
</fieldset>
<!-- Placement -->
@if (!serviceForm.controls.unmanaged.value) {
- <div class="form-item">
- <cds-select id="placement"
- formControlName="placement"
- label="Placement"
- (change)="onPlacementChange($event.target.value)">
- <option i18n
- value="hosts">Hosts</option>
- <option i18n
- value="label">Label</option>
- </cds-select>
- </div>
+ <div class="form-item">
+ <cds-select
+ id="placement"
+ formControlName="placement"
+ label="Placement"
+ (change)="onPlacementChange($event.target.value)"
+ >
+ <option
+ i18n
+ value="hosts"
+ >
+ Hosts
+ </option>
+ <option
+ i18n
+ value="label"
+ >
+ Label
+ </option>
+ </cds-select>
+ </div>
}
<!-- Label -->
@if (hostsAndLabels$ | async; as data) {
- @if (!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'label') {
- <div class="form-item">
- <cds-combo-box type="single"
- selectionFeedback="top-after-reopen"
- label="Label"
- cdRequiredField="Label"
- formControlName="label"
- id="label"
- [appendInline]="true"
- [items]="data.labels"
- [invalid]="serviceForm.controls.label.invalid && serviceForm.controls.label.dirty"
- [invalidText]="requiredFieldLabel">
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- <ng-template #requiredFieldLabel>
- @if (serviceForm.showError('label', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- }
- <!-- Hosts -->
- @if (!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'hosts') {
- <div class="form-item">
- <cds-combo-box type="multi"
- selectionFeedback="top-after-reopen"
- label="Hosts"
- formControlName="hosts"
- id="hosts"
- [appendInline]="true"
- [items]="data.hosts"
- (selected)="multiSelector($event)"
- i18n>
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- </div>
- }
+ @if (
+ !serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'label'
+ ) {
+ <div class="form-item">
+ <cds-combo-box
+ type="single"
+ selectionFeedback="top-after-reopen"
+ label="Label"
+ cdRequiredField="Label"
+ formControlName="label"
+ id="label"
+ [appendInline]="true"
+ [items]="data.labels"
+ [invalid]="serviceForm.controls.label.invalid && serviceForm.controls.label.dirty"
+ [invalidText]="requiredFieldLabel"
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ <ng-template #requiredFieldLabel>
+ @if (serviceForm.showError('label', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ <!-- Hosts -->
+ @if (
+ !serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'hosts'
+ ) {
+ <div class="form-item">
+ <cds-combo-box
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ label="Hosts"
+ formControlName="hosts"
+ id="hosts"
+ [appendInline]="true"
+ [items]="data.hosts"
+ (selected)="multiSelector($event)"
+ i18n
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ </div>
+ }
}
-
<!-- Count -->
- @if (!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value !== 'nvmeof') {
- <div class="form-item">
- <cds-number label="Count"
- formControlName="count"
- id="count"
- min="1"
- helperText="Number of deamons that will be deployed"
- i18n-helperText>
- </cds-number>
- </div>
+ @if (
+ !serviceForm.controls.unmanaged.value &&
+ serviceForm.controls.service_type.value !== 'nvmeof'
+ ) {
+ <div class="form-item">
+ <cds-number
+ label="Count"
+ formControlName="count"
+ id="count"
+ min="1"
+ helperText="Number of deamons that will be deployed"
+ i18n-helperText
+ >
+ </cds-number>
+ </div>
}
<!-- RGW -->
- @if (!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'rgw') {
- <!-- rgw_frontend_port -->
- <div class="form-item">
- <cds-number label="Port"
- formControlName="rgw_frontend_port"
- id="rgw_frontend_port"
- min="1"
- max="65535"
- helperText="Number of deamons that will be deployed"
- i18n-helperText
- [invalid]="serviceForm.controls.rgw_frontend_port.invalid && serviceForm.controls.rgw_frontend_port.dirty"
- [invalidText]="invalidRgwFrontendPortError">
- </cds-number>
- <ng-template #invalidRgwFrontendPortError>
- @if (serviceForm.showError('rgw_frontend_port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('rgw_frontend_port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
+ @if (
+ !serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'rgw'
+ ) {
+ <!-- rgw_frontend_port -->
+ <div class="form-item">
+ <cds-number
+ label="Port"
+ formControlName="rgw_frontend_port"
+ id="rgw_frontend_port"
+ min="1"
+ max="65535"
+ helperText="Number of deamons that will be deployed"
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.rgw_frontend_port.invalid &&
+ serviceForm.controls.rgw_frontend_port.dirty
+ "
+ [invalidText]="invalidRgwFrontendPortError"
+ >
+ </cds-number>
+ <ng-template #invalidRgwFrontendPortError>
+ @if (serviceForm.showError('rgw_frontend_port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('rgw_frontend_port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
- @if (!rgwModuleEnabled) {
- <cd-alert-panel type="warning"
- spacingClass="mb-3"
- actionName="Enable"
- (action)="enableRgwModule()"
- i18n-actionName
- i18n>
- The RGW mgr module must be enabled to configure S3 hostnames.
- Enabling the module will cause temporary manager downtime while it loads.
- </cd-alert-panel>
- }
- <div class="form-item">
- <cds-checkbox i18n-label
- formControlName="virtual_host_enabled">
- Enable virtual-host style bucket access
- <cd-help-text i18n>
- Allows bucket access via hostnames such as mybucket.s3.example.com.
- </cd-help-text>
- </cds-checkbox>
- </div>
- @if (serviceForm.controls.virtual_host_enabled.value) {
- <div class="form-item">
- <cd-text-label-list formControlName="zonegroup_hostnames"
- label="S3 hostname"
- i18n-label
- helperText="Domain names for S3 virtual-host bucket access (e.g., s3.example.com). Enables bucket URLs like bucket.s3.example.com instead of s3.example.com/bucket."
- i18n-helperText>
- </cd-text-label-list>
- </div>
- }
+ @if (!rgwModuleEnabled) {
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-3"
+ actionName="Enable"
+ (action)="enableRgwModule()"
+ i18n-actionName
+ i18n
+ >
+ The RGW mgr module must be enabled to configure S3 hostnames. Enabling the module will
+ cause temporary manager downtime while it loads.
+ </cd-alert-panel>
+ }
+ <div class="form-item">
+ <cds-checkbox
+ i18n-label
+ formControlName="virtual_host_enabled"
+ >
+ Enable virtual-host style bucket access
+ <cd-help-text i18n>
+ Allows bucket access via hostnames such as mybucket.s3.example.com.
+ </cd-help-text>
+ </cds-checkbox>
+ </div>
+ @if (serviceForm.controls.virtual_host_enabled.value) {
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="zonegroup_hostnames"
+ label="S3 hostname"
+ i18n-label
+ helperText="Domain names for S3 virtual-host bucket access (e.g., s3.example.com). Enables bucket URLs like bucket.s3.example.com instead of s3.example.com/bucket."
+ i18n-helperText
+ >
+ </cd-text-label-list>
+ </div>
+ }
}
<!-- iSCSI -->
<!-- pool -->
@if (serviceForm.controls.service_type.value === 'iscsi') {
- <div class="form-item">
- <cds-select label="Pool"
- formControlName="pool"
- cdRequiredField="Pool"
- id="pool"
- [invalid]="serviceForm.controls.pool.invalid && serviceForm.controls.pool.dirty"
- [invalidText]="invalidPoolError">
- @if (pools === null) {
- <option [ngValue]="null"
- i18n>Loading...</option>
- }
- @if (pools && pools.length === 0) {
- <option [ngValue]="null"
- i18n>-- No pools available --</option>
- }
- @if (pools && pools.length > 0) {
- <option [ngValue]="null"
- i18n>-- Select a pool --</option>
- }
- @for (pool of pools; track pool) {
- <option [value]="pool.pool_name">{{ pool.pool_name }}</option>
- }
- </cds-select>
- <ng-template #invalidPoolError>
- @if (serviceForm.showError('pool', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-select
+ label="Pool"
+ formControlName="pool"
+ cdRequiredField="Pool"
+ id="pool"
+ [invalid]="serviceForm.controls.pool.invalid && serviceForm.controls.pool.dirty"
+ [invalidText]="invalidPoolError"
+ >
+ @if (pools === null) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ Loading...
+ </option>
+ }
+ @if (pools && pools.length === 0) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- No pools available --
+ </option>
+ }
+ @if (pools && pools.length > 0) {
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a pool --
+ </option>
+ }
+ @for (pool of pools; track pool) {
+ <option [value]="pool.pool_name">{{ pool.pool_name }}</option>
+ }
+ </cds-select>
+ <ng-template #invalidPoolError>
+ @if (serviceForm.showError('pool', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
}
<!-- fields in iSCSI which are hidden when unmanaged is true -->
- @if (!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'iscsi') {
- <!-- trusted_ip_list -->
- <div class="form-item">
- <cd-text-label-list formControlName="trusted_ip_list"
- label="Trusted IPs"
- helperText="List of trusted IP addresses. Add the Ceph Manager IP addresses so the iSCSI gateways can be reached.">
- </cd-text-label-list>
- </div>
- <!-- api_port -->
- <div class="form-item">
- <cds-number label="Port"
- formControlName="api_port"
- id="api_port"
- min="1"
- max="65535"
- [invalid]="serviceForm.controls.api_port.invalid && serviceForm.controls.api_port.dirty"
- [invalidText]="invalidApiPortError">
- </cds-number>
- <ng-template #invalidApiPortError>
- @if (serviceForm.showError('api_port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('api_port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
- <!-- api_user -->
- <div class="form-item">
- <cds-text-label cdRequiredField="User"
- [invalid]="serviceForm.controls.api_user.invalid && serviceForm.controls.api_user.dirty"
- [invalidText]="invalidUser">
- <input cdsText
- type="text"
- id="api_user"
- formControlName="api_user"
- [invalid]="serviceForm.controls.api_user.invalid && serviceForm.controls.api_user.dirty" />
- </cds-text-label>
- <ng-template #invalidUser>
- @if (serviceForm.showError('api_user', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ @if (
+ !serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'iscsi'
+ ) {
+ <!-- trusted_ip_list -->
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="trusted_ip_list"
+ label="Trusted IPs"
+ helperText="List of trusted IP addresses. Add the Ceph Manager IP addresses so the iSCSI gateways can be reached."
+ >
+ </cd-text-label-list>
+ </div>
+ <!-- api_port -->
+ <div class="form-item">
+ <cds-number
+ label="Port"
+ formControlName="api_port"
+ id="api_port"
+ min="1"
+ max="65535"
+ [invalid]="serviceForm.controls.api_port.invalid && serviceForm.controls.api_port.dirty"
+ [invalidText]="invalidApiPortError"
+ >
+ </cds-number>
+ <ng-template #invalidApiPortError>
+ @if (serviceForm.showError('api_port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('api_port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- api_user -->
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="User"
+ [invalid]="serviceForm.controls.api_user.invalid && serviceForm.controls.api_user.dirty"
+ [invalidText]="invalidUser"
+ >
+ <input
+ cdsText
+ type="text"
+ id="api_user"
+ formControlName="api_user"
+ [invalid]="
+ serviceForm.controls.api_user.invalid && serviceForm.controls.api_user.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidUser>
+ @if (serviceForm.showError('api_user', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- api_password -->
- <div class="form-item">
- <cds-password-label cdRequiredField="Password"
- [invalid]="serviceForm.controls.api_password.invalid && serviceForm.controls.api_password.dirty"
- [invalidText]="invalidPassword">
- <input cdsPassword
- type="password"
- id="api_password"
- formControlName="api_password"
- [invalid]="serviceForm.controls.api_password.invalid && serviceForm.controls.api_password.dirty" />
- </cds-password-label>
- <ng-template #invalidPassword>
- @if (serviceForm.showError('api_password', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <!-- api_password -->
+ <div class="form-item">
+ <cds-password-label
+ cdRequiredField="Password"
+ [invalid]="
+ serviceForm.controls.api_password.invalid && serviceForm.controls.api_password.dirty
+ "
+ [invalidText]="invalidPassword"
+ >
+ <input
+ cdsPassword
+ type="password"
+ id="api_password"
+ formControlName="api_password"
+ [invalid]="
+ serviceForm.controls.api_password.invalid && serviceForm.controls.api_password.dirty
+ "
+ />
+ </cds-password-label>
+ <ng-template #invalidPassword>
+ @if (serviceForm.showError('api_password', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
}
<!-- smb -->
@if (serviceForm.controls.service_type.value === 'smb') {
- <div class="form-item">
- <cds-text-label cdRequiredField="Cluster id"
- helperText="A short name identifying the SMB “cluster”. In this case a cluster is simply a management unit of one or more Samba services sharing a common configuration, and may not provide actual clustering or availability mechanisms."
- i18n-helperText
- [invalid]="serviceForm.controls.cluster_id.invalid && serviceForm.controls.cluster_id.dirty"
- [invalidText]="requiredFieldClusterId">
- <input cdsText
- type="text"
- id="cluster_id"
- formControlName="cluster_id"
- placeholder="foo"
- [invalid]="serviceForm.controls.cluster_id.invalid && serviceForm.controls.cluster_id.dirty" />
- </cds-text-label>
- <ng-template #requiredFieldClusterId>
- @if (serviceForm.showError('cluster_id', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Cluster id"
+ helperText="A short name identifying the SMB “cluster”. In this case a cluster is simply a management unit of one or more Samba services sharing a common configuration, and may not provide actual clustering or availability mechanisms."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.cluster_id.invalid && serviceForm.controls.cluster_id.dirty
+ "
+ [invalidText]="requiredFieldClusterId"
+ >
+ <input
+ cdsText
+ type="text"
+ id="cluster_id"
+ formControlName="cluster_id"
+ placeholder="foo"
+ [invalid]="
+ serviceForm.controls.cluster_id.invalid && serviceForm.controls.cluster_id.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #requiredFieldClusterId>
+ @if (serviceForm.showError('cluster_id', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <div class="form-item">
- <cds-text-label cdRequiredField="Config URI"
- helperText="Configuration source that should be loaded by the samba-container as the primary configuration file."
- i18n-helperText
- [invalid]="serviceForm.controls.config_uri.invalid && serviceForm.controls.config_uri.dirty"
- [invalidText]="invalidConfigUriError">
- <input cdsText
- type="text"
- id="config_uri"
- formControlName="config_uri"
- placeholder="rados://.smb/foo/scc.toml"
- [invalid]="serviceForm.controls.config_uri.invalid && serviceForm.controls.config_uri.dirty" />
- </cds-text-label>
- <ng-template #invalidConfigUriError>
- @if (serviceForm.showError('config_uri', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('config_uri', frm, 'configUriPattern')) {
- <span class="invalid-feedback"
- i18n>The value must start with either 'http:', 'https:', 'rados:' or 'rados:mon-config-key:'</span>
- }
- </ng-template>
- </div>
- <div class="form-item">
- <fieldset>
- <label class="cds--label"
- for="features"
- i18n>Features
- <cd-help-text>
- Pre-defined terms enabling specific deployment characteristics.
- </cd-help-text>
- </label>
- @for (feature of smbFeaturesList; track feature) {
- <cds-checkbox i18n-label
- id="{{feature}}"
- name="{{feature}}"
- formControlName="{{feature}}">
- Enable
- </cds-checkbox>
- }
- </fieldset>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Config URI"
+ helperText="Configuration source that should be loaded by the samba-container as the primary configuration file."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.config_uri.invalid && serviceForm.controls.config_uri.dirty
+ "
+ [invalidText]="invalidConfigUriError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="config_uri"
+ formControlName="config_uri"
+ placeholder="rados://.smb/foo/scc.toml"
+ [invalid]="
+ serviceForm.controls.config_uri.invalid && serviceForm.controls.config_uri.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidConfigUriError>
+ @if (serviceForm.showError('config_uri', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('config_uri', frm, 'configUriPattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must start with either 'http:', 'https:', 'rados:' or
+ 'rados:mon-config-key:'</span
+ >
+ }
+ </ng-template>
+ </div>
+ <div class="form-item">
+ <fieldset>
+ <label
+ class="cds--label"
+ for="features"
+ i18n
+ >Features
+ <cd-help-text>
+ Pre-defined terms enabling specific deployment characteristics.
+ </cd-help-text>
+ </label>
+ @for (feature of smbFeaturesList; track feature) {
+ <cds-checkbox
+ i18n-label
+ id="{{ feature }}"
+ name="{{ feature }}"
+ formControlName="{{ feature }}"
+ >
+ Enable
+ </cds-checkbox>
+ }
+ </fieldset>
+ </div>
- <div class="form-item">
- <cd-text-label-list formControlName="custom_dns"
- label="Custom DNS"
- helperText="IP addresses that will be used as the DNS servers for a Samba container."
- placeholder="192.168.76.204"
- i18n-placeholder>
- </cd-text-label-list>
- </div>
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="custom_dns"
+ label="Custom DNS"
+ helperText="IP addresses that will be used as the DNS servers for a Samba container."
+ placeholder="192.168.76.204"
+ i18n-placeholder
+ >
+ </cd-text-label-list>
+ </div>
- <div class="form-item">
- <cd-text-label-list formControlName="join_sources"
- label="Join sources"
- helperText="Identify where authentication data that will be used to perform domain joins is located."
- placeholder="rados:mon-config-key:smb/config/foo/join1.json"
- i18n-placeholder>
- </cd-text-label-list>
- </div>
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="join_sources"
+ label="Join sources"
+ helperText="Identify where authentication data that will be used to perform domain joins is located."
+ placeholder="rados:mon-config-key:smb/config/foo/join1.json"
+ i18n-placeholder
+ >
+ </cd-text-label-list>
+ </div>
- <div class="form-item">
- <cd-text-label-list formControlName="user_sources"
- label="User sources"
- helperText="Pseudo-uris containing data the samba-container can use to create users. A ceph based samba container may typically use a rados uri
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="user_sources"
+ label="User sources"
+ helperText="Pseudo-uris containing data the samba-container can use to create users. A ceph based samba container may typically use a rados uri
or a mon config-key store uri "
- placeholder="rados:mon-config-key:smb/config/foo/join2.json"
- i18n-placeholder>
- </cd-text-label-list>
- </div>
+ placeholder="rados:mon-config-key:smb/config/foo/join2.json"
+ i18n-placeholder
+ >
+ </cd-text-label-list>
+ </div>
- <div class="form-item">
- <cd-text-label-list formControlName="include_ceph_users"
- label="Ceph users"
- helperText="Cephx user names that the Samba containers may use."
- placeholder="client.smb.fs.cluster.foo"
- i18n-placeholder>
- </cd-text-label-list>
- </div>
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="include_ceph_users"
+ label="Ceph users"
+ helperText="Cephx user names that the Samba containers may use."
+ placeholder="client.smb.fs.cluster.foo"
+ i18n-placeholder
+ >
+ </cd-text-label-list>
+ </div>
}
<!-- Ingress -->
@if (serviceForm.controls.service_type.value === 'ingress') {
- <!-- virtual_ip -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Virtual IP"
- helperText="The virtual IP address and subnet (in CIDR notation) where the ingress service will be available."
- i18n-helperText
- [invalid]="serviceForm.controls.virtual_ip.invalid && serviceForm.controls.virtual_ip.dirty"
- [invalidText]="requiredFieldVirtualIp">
- <input cdsText
- type="text"
- id="virtual_ip"
- formControlName="virtual_ip"
- [invalid]="serviceForm.controls.virtual_ip.invalid && serviceForm.controls.virtual_ip.dirty" />
- </cds-text-label>
- <ng-template #requiredFieldVirtualIp>
- @if (serviceForm.showError('virtual_ip', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- frontend_port -->
- <div class="form-item">
- <cds-number cdRequiredField="Frontend port"
- label="Frontend port"
- formControlName="frontend_port"
- id="frontend_port"
- min="1"
- max="65535"
- helperText="The port used to access the ingress service."
- i18n-helperText
- [invalid]="serviceForm.controls.frontend_port.invalid && serviceForm.controls.frontend_port.dirty"
- [invalidText]="invalidFrontendPortError">
- </cds-number>
- <ng-template #invalidFrontendPortError>
- @if (serviceForm.showError('frontend_port', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('frontend_port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('frontend_port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
- <!-- monitor_port -->
- <div class="form-item">
- <cds-number cdRequiredField="Monitor port"
- label="Monitor port"
- formControlName="monitor_port"
- id="monitor_port"
- min="1"
- max="65535"
- helperText="The port used by haproxy for load balancer status."
- i18n-helperText
- [invalid]="serviceForm.controls.monitor_port.invalid && serviceForm.controls.monitor_port.dirty"
- [invalidText]="invalidMonitorPortError">
- </cds-number>
- <ng-template #invalidMonitorPortError>
- @if (serviceForm.showError('monitor_port', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('monitor_port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('monitor_port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
- <!-- virtual_interface_networks -->
- @if (!serviceForm.controls.unmanaged.value) {
- <div class="form-item">
- <cd-text-label-list formControlName="virtual_interface_networks"
- label="CIDR Networks"
- helperText="A list of networks to identify which network interface to use for the virtual IP address.">
- </cd-text-label-list>
- </div>
- }
+ <!-- virtual_ip -->
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Virtual IP"
+ helperText="The virtual IP address and subnet (in CIDR notation) where the ingress service will be available."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.virtual_ip.invalid && serviceForm.controls.virtual_ip.dirty
+ "
+ [invalidText]="requiredFieldVirtualIp"
+ >
+ <input
+ cdsText
+ type="text"
+ id="virtual_ip"
+ formControlName="virtual_ip"
+ [invalid]="
+ serviceForm.controls.virtual_ip.invalid && serviceForm.controls.virtual_ip.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #requiredFieldVirtualIp>
+ @if (serviceForm.showError('virtual_ip', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- frontend_port -->
+ <div class="form-item">
+ <cds-number
+ cdRequiredField="Frontend port"
+ label="Frontend port"
+ formControlName="frontend_port"
+ id="frontend_port"
+ min="1"
+ max="65535"
+ helperText="The port used to access the ingress service."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.frontend_port.invalid && serviceForm.controls.frontend_port.dirty
+ "
+ [invalidText]="invalidFrontendPortError"
+ >
+ </cds-number>
+ <ng-template #invalidFrontendPortError>
+ @if (serviceForm.showError('frontend_port', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('frontend_port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('frontend_port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- monitor_port -->
+ <div class="form-item">
+ <cds-number
+ cdRequiredField="Monitor port"
+ label="Monitor port"
+ formControlName="monitor_port"
+ id="monitor_port"
+ min="1"
+ max="65535"
+ helperText="The port used by haproxy for load balancer status."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.monitor_port.invalid && serviceForm.controls.monitor_port.dirty
+ "
+ [invalidText]="invalidMonitorPortError"
+ >
+ </cds-number>
+ <ng-template #invalidMonitorPortError>
+ @if (serviceForm.showError('monitor_port', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('monitor_port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('monitor_port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- virtual_interface_networks -->
+ @if (!serviceForm.controls.unmanaged.value) {
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="virtual_interface_networks"
+ label="CIDR Networks"
+ helperText="A list of networks to identify which network interface to use for the virtual IP address."
+ >
+ </cd-text-label-list>
+ </div>
+ }
}
<!-- SNMP-Gateway -->
@if (serviceForm.controls.service_type.value === 'snmp-gateway') {
- <!-- snmp-version -->
- <div class="form-item">
- <cds-select formControlName="snmp_version"
- id="snmp_version"
- label="Version"
- cdRequiredField="Version"
- helperText="Active-directory authentication for domain member servers and User authentication for Stand-alone servers configuration."
- i18n-helperText
- [invalid]="serviceForm.controls.snmp_version.invalid && serviceForm.controls.snmp_version.dirty"
- [invalidText]="requiredFieldSnmpVersion"
- (change)="clearValidations()">
- <option i18n
- [ngValue]="null">-- Select SNMP version --</option>
- @for (snmpVersion of ['V2c', 'V3']; track snmpVersion) {
- <option [value]="snmpVersion">{{ snmpVersion }}</option>
- }
- </cds-select>
- <ng-template #requiredFieldSnmpVersion>
- @if (serviceForm.showError('snmp_version', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- Destination -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Destination"
- helperText="Must be of the format hostname:port."
- i18n-helperText
- [invalid]="serviceForm.controls.snmp_destination.invalid && serviceForm.controls.snmp_destination.dirty"
- [invalidText]="invalidSnmpDestinationError">
- <input cdsText
- type="text"
- id="snmp_destination"
- formControlName="snmp_destination"
- [invalid]="serviceForm.controls.snmp_destination.invalid && serviceForm.controls.snmp_destination.dirty" />
- <ng-template #invalidSnmpDestinationError>
- @if (serviceForm.showError('snmp_destination', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <!-- snmp-version -->
+ <div class="form-item">
+ <cds-select
+ formControlName="snmp_version"
+ id="snmp_version"
+ label="Version"
+ cdRequiredField="Version"
+ helperText="Active-directory authentication for domain member servers and User authentication for Stand-alone servers configuration."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.snmp_version.invalid && serviceForm.controls.snmp_version.dirty
+ "
+ [invalidText]="requiredFieldSnmpVersion"
+ (change)="clearValidations()"
+ >
+ <option
+ i18n
+ [ngValue]="null"
+ >
+ -- Select SNMP version --
+ </option>
+ @for (snmpVersion of ['V2c', 'V3']; track snmpVersion) {
+ <option [value]="snmpVersion">{{ snmpVersion }}</option>
}
- @if (serviceForm.showError('snmp_destination', frm, 'snmpDestinationPattern')) {
- <span class="invalid-feedback"
- i18n>The value does not match the pattern: <strong>hostname:port</strong></span>
+ </cds-select>
+ <ng-template #requiredFieldSnmpVersion>
+ @if (serviceForm.showError('snmp_version', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
- </cds-text-label>
- </div>
- <!-- Engine id for snmp V3 -->
- @if (serviceForm.controls.snmp_version.value === 'V3') {
- <div class="form-item">
- <cds-text-label cdRequiredField="Engine Id"
- helperText="Unique identifier for the device (in hex)."
- i18n-helperText
- [invalid]="serviceForm.controls.engine_id.invalid && serviceForm.controls.engine_id.dirty"
- [invalidText]="invalidEngineIdError">
- <input cdsText
- type="text"
- id="engine_id"
- formControlName="engine_id"
- [invalid]="serviceForm.controls.engine_id.invalid && serviceForm.controls.engine_id.dirty" />
- </cds-text-label>
- <ng-template #invalidEngineIdError>
- @if (serviceForm.showError('engine_id', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('engine_id', frm, 'snmpEngineIdPattern')) {
- <span class="invalid-feedback"
- i18n>The value does not match the pattern: <strong>Must be in hexadecimal and length must be multiple of
- 2
- with min value = 10 and max value = 64.</strong></span>
- }
- </ng-template>
- </div>
- <!-- Auth protocol for snmp V3 -->
- <div class="form-item">
- <cds-select formControlName="auth_protocol"
- id="auth_protocol"
- label="Auth protocol"
- cdRequiredField="Auth protocol"
- [invalid]="serviceForm.controls.auth_protocol.invalid && serviceForm.controls.auth_protocol.dirty"
- [invalidText]="requiredFieldAuthProtocol">
- <option i18n
- [ngValue]="null">-- Select auth protocol --</option>
- @for (authProtocol of ['SHA', 'MD5']; track authProtocol) {
- <option [value]="authProtocol">
- {{ authProtocol }}
- </option>
- }
- </cds-select>
- <ng-template #requiredFieldAuthProtocol>
- @if (serviceForm.showError('auth_protocol', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ </div>
+ <!-- Destination -->
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Destination"
+ helperText="Must be of the format hostname:port."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.snmp_destination.invalid &&
+ serviceForm.controls.snmp_destination.dirty
+ "
+ [invalidText]="invalidSnmpDestinationError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="snmp_destination"
+ formControlName="snmp_destination"
+ [invalid]="
+ serviceForm.controls.snmp_destination.invalid &&
+ serviceForm.controls.snmp_destination.dirty
+ "
+ />
+ <ng-template #invalidSnmpDestinationError>
+ @if (serviceForm.showError('snmp_destination', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('snmp_destination', frm, 'snmpDestinationPattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value does not match the pattern: <strong>hostname:port</strong></span
+ >
+ }
+ </ng-template>
+ </cds-text-label>
+ </div>
+ <!-- Engine id for snmp V3 -->
+ @if (serviceForm.controls.snmp_version.value === 'V3') {
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Engine Id"
+ helperText="Unique identifier for the device (in hex)."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.engine_id.invalid && serviceForm.controls.engine_id.dirty
+ "
+ [invalidText]="invalidEngineIdError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="engine_id"
+ formControlName="engine_id"
+ [invalid]="
+ serviceForm.controls.engine_id.invalid && serviceForm.controls.engine_id.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidEngineIdError>
+ @if (serviceForm.showError('engine_id', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('engine_id', frm, 'snmpEngineIdPattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value does not match the pattern:
+ <strong
+ >Must be in hexadecimal and length must be multiple of 2 with min value = 10 and
+ max value = 64.</strong
+ ></span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- Auth protocol for snmp V3 -->
+ <div class="form-item">
+ <cds-select
+ formControlName="auth_protocol"
+ id="auth_protocol"
+ label="Auth protocol"
+ cdRequiredField="Auth protocol"
+ [invalid]="
+ serviceForm.controls.auth_protocol.invalid &&
+ serviceForm.controls.auth_protocol.dirty
+ "
+ [invalidText]="requiredFieldAuthProtocol"
+ >
+ <option
+ i18n
+ [ngValue]="null"
+ >
+ -- Select auth protocol --
+ </option>
+ @for (authProtocol of ['SHA', 'MD5']; track authProtocol) {
+ <option [value]="authProtocol">
+ {{ authProtocol }}
+ </option>
+ }
+ </cds-select>
+ <ng-template #requiredFieldAuthProtocol>
+ @if (serviceForm.showError('auth_protocol', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- Privacy protocol for snmp V3 -->
- <div class="form-item">
- <cds-select formControlName="privacy_protocol"
- id="privacy_protocol"
- label="Privacy protocol">
- <option i18n
- [ngValue]="null">-- Select privacy protocol --</option>
- @for (privacyProtocol of ['DES', 'AES']; track privacyProtocol) {
- <option [value]="privacyProtocol">
- {{ privacyProtocol }}
- </option>
- }
- </cds-select>
- </div>
+ <!-- Privacy protocol for snmp V3 -->
+ <div class="form-item">
+ <cds-select
+ formControlName="privacy_protocol"
+ id="privacy_protocol"
+ label="Privacy protocol"
+ >
+ <option
+ i18n
+ [ngValue]="null"
+ >
+ -- Select privacy protocol --
+ </option>
+ @for (privacyProtocol of ['DES', 'AES']; track privacyProtocol) {
+ <option [value]="privacyProtocol">
+ {{ privacyProtocol }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ }
+ <!-- Credentials -->
+ @if (['V2c', 'V3'].includes(serviceForm.controls.snmp_version?.value)) {
+ <fieldset>
+ <legend i18n>Credentials</legend>
+ <!-- snmp v2c snmp_community -->
+ @if (serviceForm.controls.snmp_version.value === 'V2c') {
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="SNMP community"
+ [invalid]="
+ serviceForm.controls.snmp_community.invalid &&
+ serviceForm.controls.snmp_community.dirty
+ "
+ [invalidText]="invalidSnmpCommunityError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="snmp_community"
+ formControlName="snmp_community"
+ [invalid]="
+ serviceForm.controls.snmp_community.invalid &&
+ serviceForm.controls.snmp_community.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidSnmpCommunityError>
+ @if (serviceForm.showError('snmp_community', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ <!-- snmp v3 auth username -->
+ @if (serviceForm.controls.snmp_version.value === 'V3') {
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Username"
+ [invalid]="
+ serviceForm.controls.snmp_v3_auth_username.invalid &&
+ serviceForm.controls.snmp_v3_auth_username.dirty
+ "
+ [invalidText]="invalidSnmpV3AuthUsernameError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="snmp_v3_auth_username"
+ formControlName="snmp_v3_auth_username"
+ [invalid]="
+ serviceForm.controls.snmp_v3_auth_username.invalid &&
+ serviceForm.controls.snmp_v3_auth_username.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidSnmpV3AuthUsernameError>
+ @if (serviceForm.showError('snmp_v3_auth_username', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ <!-- snmp v3 auth password -->
+ @if (serviceForm.controls.snmp_version.value === 'V3') {
+ <div class="form-item">
+ <cds-password-label
+ cdRequiredField="Password"
+ [invalid]="
+ serviceForm.controls.snmp_v3_auth_password.invalid &&
+ serviceForm.controls.snmp_v3_auth_password.dirty
+ "
+ [invalidText]="invalidSnmpV3AuthPasswordError"
+ >
+ <input
+ cdsPassword
+ type="password"
+ id="snmp_v3_auth_password"
+ formControlName="snmp_v3_auth_password"
+ [invalid]="
+ serviceForm.controls.snmp_v3_auth_password.invalid &&
+ serviceForm.controls.snmp_v3_auth_password.dirty
+ "
+ />
+ </cds-password-label>
+ <ng-template #invalidSnmpV3AuthPasswordError>
+ @if (serviceForm.showError('snmp_v3_auth_password', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ <!-- snmp v3 priv password -->
+ @if (
+ serviceForm.controls.snmp_version.value === 'V3' &&
+ serviceForm.controls.privacy_protocol.value !== null &&
+ serviceForm.controls.privacy_protocol.value !== undefined
+ ) {
+ <div class="form-item">
+ <cds-password-label
+ cdRequiredField="Encryption"
+ [invalid]="
+ serviceForm.controls.snmp_v3_priv_password.invalid &&
+ serviceForm.controls.snmp_v3_priv_password.dirty
+ "
+ [invalidText]="invalidSnmpV3PrivPasswordError"
+ >
+ <input
+ cdsPassword
+ type="password"
+ id="snmp_v3_priv_password"
+ formControlName="snmp_v3_priv_password"
+ [invalid]="
+ serviceForm.controls.snmp_v3_priv_password.invalid &&
+ serviceForm.controls.snmp_v3_priv_password.dirty
+ "
+ />
+ </cds-password-label>
+ <ng-template #invalidSnmpV3PrivPasswordError>
+ @if (serviceForm.showError('snmp_v3_priv_password', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ </fieldset>
+ }
}
- <!-- Credentials -->
- @if (['V2c', 'V3'].includes(serviceForm.controls.snmp_version?.value)) {
- <fieldset>
- <legend i18n>Credentials</legend>
- <!-- snmp v2c snmp_community -->
- @if (serviceForm.controls.snmp_version.value === 'V2c') {
+
+ <!-- oauth2-proxy -->
+ @if (serviceForm.controls.service_type.value === 'oauth2-proxy') {
+ <!-- provider_display_name -->
<div class="form-item">
- <cds-text-label cdRequiredField="SNMP community"
- [invalid]="serviceForm.controls.snmp_community.invalid && serviceForm.controls.snmp_community.dirty"
- [invalidText]="invalidSnmpCommunityError">
- <input cdsText
- type="text"
- id="snmp_community"
- formControlName="snmp_community"
- [invalid]="serviceForm.controls.snmp_community.invalid && serviceForm.controls.snmp_community.dirty" />
+ <cds-text-label
+ cdRequiredField="Provider display name"
+ placeholder="My OIDC Provider"
+ i18n-placeholder
+ [invalid]="
+ serviceForm.controls.provider_display_name.invalid &&
+ serviceForm.controls.provider_display_name.dirty
+ "
+ [invalidText]="invalidProviderDisplayNameError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="provider_display_name"
+ formControlName="provider_display_name"
+ [invalid]="
+ serviceForm.controls.provider_display_name.invalid &&
+ serviceForm.controls.provider_display_name.dirty
+ "
+ />
</cds-text-label>
- <ng-template #invalidSnmpCommunityError>
- @if (serviceForm.showError('snmp_community', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <ng-template #invalidProviderDisplayNameError>
+ @if (serviceForm.showError('provider_display_name', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
- }
- <!-- snmp v3 auth username -->
- @if (serviceForm.controls.snmp_version.value === 'V3') {
+ <!-- client_id -->
<div class="form-item">
- <cds-text-label cdRequiredField="Username"
- [invalid]="serviceForm.controls.snmp_v3_auth_username.invalid && serviceForm.controls.snmp_v3_auth_username.dirty"
- [invalidText]="invalidSnmpV3AuthUsernameError">
- <input cdsText
- type="text"
- id="snmp_v3_auth_username"
- formControlName="snmp_v3_auth_username"
- [invalid]="serviceForm.controls.snmp_v3_auth_username.invalid && serviceForm.controls.snmp_v3_auth_username.dirty" />
+ <cds-text-label
+ cdRequiredField="Client ID"
+ placeholder="oauth2-client"
+ [invalid]="
+ serviceForm.controls.client_id.invalid && serviceForm.controls.client_id.dirty
+ "
+ [invalidText]="invalidClientIdError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="client_id"
+ formControlName="client_id"
+ [invalid]="
+ serviceForm.controls.client_id.invalid && serviceForm.controls.client_id.dirty
+ "
+ />
</cds-text-label>
- <ng-template #invalidSnmpV3AuthUsernameError>
- @if (serviceForm.showError('snmp_v3_auth_username', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <ng-template #invalidClientIdError>
+ @if (serviceForm.showError('client_id', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
- }
- <!-- snmp v3 auth password -->
- @if (serviceForm.controls.snmp_version.value === 'V3') {
- <div class="form-item">
- <cds-password-label cdRequiredField="Password"
- [invalid]="serviceForm.controls.snmp_v3_auth_password.invalid && serviceForm.controls.snmp_v3_auth_password.dirty"
- [invalidText]="invalidSnmpV3AuthPasswordError">
- <input cdsPassword
- type="password"
- id="snmp_v3_auth_password"
- formControlName="snmp_v3_auth_password"
- [invalid]="serviceForm.controls.snmp_v3_auth_password.invalid && serviceForm.controls.snmp_v3_auth_password.dirty" />
+ <!-- client_secret -->
+ <div class="form-item form-item-append">
+ <cds-password-label
+ cdRequiredField="Client secret"
+ [invalid]="
+ serviceForm.controls.client_secret.invalid && serviceForm.controls.client_secret.dirty
+ "
+ [invalidText]="invalidClientSecretError"
+ >
+ <input
+ cdsPassword
+ type="text"
+ id="client_secret"
+ formControlName="client_secret"
+ [invalid]="
+ serviceForm.controls.client_secret.invalid &&
+ serviceForm.controls.client_secret.dirty
+ "
+ />
</cds-password-label>
- <ng-template #invalidSnmpV3AuthPasswordError>
- @if (serviceForm.showError('snmp_v3_auth_password', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <cd-copy-2-clipboard-button
+ source="client_secret"
+ class="mt-4"
+ >
+ </cd-copy-2-clipboard-button>
+ <ng-template #invalidClientSecretError>
+ @if (serviceForm.showError('client_secret', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
- }
- <!-- snmp v3 priv password -->
- @if (serviceForm.controls.snmp_version.value === 'V3' && serviceForm.controls.privacy_protocol.value !== null &&
- serviceForm.controls.privacy_protocol.value !== undefined) {
+ <!-- oidc_issuer_url -->
<div class="form-item">
- <cds-password-label cdRequiredField="Encryption"
- [invalid]="serviceForm.controls.snmp_v3_priv_password.invalid && serviceForm.controls.snmp_v3_priv_password.dirty"
- [invalidText]="invalidSnmpV3PrivPasswordError">
- <input cdsPassword
- type="password"
- id="snmp_v3_priv_password"
- formControlName="snmp_v3_priv_password"
- [invalid]="serviceForm.controls.snmp_v3_priv_password.invalid && serviceForm.controls.snmp_v3_priv_password.dirty" />
- </cds-password-label>
- <ng-template #invalidSnmpV3PrivPasswordError>
- @if (serviceForm.showError('snmp_v3_priv_password', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <cds-text-label
+ cdRequiredField="OIDC issuer URL"
+ [invalid]="
+ serviceForm.controls.oidc_issuer_url.invalid &&
+ serviceForm.controls.oidc_issuer_url.dirty
+ "
+ [invalidText]="invalidOidcIssuerUrlError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="oidc_issuer_url"
+ formControlName="oidc_issuer_url"
+ [invalid]="
+ serviceForm.controls.oidc_issuer_url.invalid &&
+ serviceForm.controls.oidc_issuer_url.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidOidcIssuerUrlError>
+ @if (serviceForm.showError('oidc_issuer_url', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('oidc_issuer_url', frm, 'validUrl')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Invalid url.</span
+ >
}
</ng-template>
</div>
- }
- </fieldset>
- }
- }
-
- <!-- oauth2-proxy -->
- @if (serviceForm.controls.service_type.value === 'oauth2-proxy') {
- <!-- provider_display_name -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Provider display name"
- placeholder="My OIDC Provider"
- i18n-placeholder
- [invalid]="serviceForm.controls.provider_display_name.invalid && serviceForm.controls.provider_display_name.dirty"
- [invalidText]="invalidProviderDisplayNameError">
- <input cdsText
- type="text"
- id="provider_display_name"
- formControlName="provider_display_name"
- [invalid]="serviceForm.controls.provider_display_name.invalid && serviceForm.controls.provider_display_name.dirty" />
- </cds-text-label>
- <ng-template #invalidProviderDisplayNameError>
- @if (serviceForm.showError('provider_display_name', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- client_id -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Client ID"
- placeholder="oauth2-client"
- [invalid]="serviceForm.controls.client_id.invalid && serviceForm.controls.client_id.dirty"
- [invalidText]="invalidClientIdError">
- <input cdsText
- type="text"
- id="client_id"
- formControlName="client_id"
- [invalid]="serviceForm.controls.client_id.invalid && serviceForm.controls.client_id.dirty" />
- </cds-text-label>
- <ng-template #invalidClientIdError>
- @if (serviceForm.showError('client_id', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- client_secret -->
- <div class="form-item form-item-append">
- <cds-password-label cdRequiredField="Client secret"
- [invalid]="serviceForm.controls.client_secret.invalid && serviceForm.controls.client_secret.dirty"
- [invalidText]="invalidClientSecretError">
- <input cdsPassword
- type="text"
- id="client_secret"
- formControlName="client_secret"
- [invalid]="serviceForm.controls.client_secret.invalid && serviceForm.controls.client_secret.dirty" />
- </cds-password-label>
- <cd-copy-2-clipboard-button source="client_secret"
- class="mt-4">
- </cd-copy-2-clipboard-button>
- <ng-template #invalidClientSecretError>
- @if (serviceForm.showError('client_secret', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- oidc_issuer_url -->
- <div class="form-item">
- <cds-text-label cdRequiredField="OIDC issuer URL"
- [invalid]="serviceForm.controls.oidc_issuer_url.invalid && serviceForm.controls.oidc_issuer_url.dirty"
- [invalidText]="invalidOidcIssuerUrlError">
- <input cdsText
- type="text"
- id="oidc_issuer_url"
- formControlName="oidc_issuer_url"
- [invalid]="serviceForm.controls.oidc_issuer_url.invalid && serviceForm.controls.oidc_issuer_url.dirty" />
- </cds-text-label>
- <ng-template #invalidOidcIssuerUrlError>
- @if (serviceForm.showError('oidc_issuer_url', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('oidc_issuer_url', frm, 'validUrl')) {
- <span class="invalid-feedback"
- i18n>Invalid url.</span>
- }
- </ng-template>
- </div>
- <!-- https_address -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Https address"
- helperText="The address for HTTPS connections as [IP|Hostname]:port."
- i18n-helperText
- placeholder="0.0.0.0:4180"
- [invalid]="serviceForm.controls.https_address.invalid && serviceForm.controls.https_address.dirty"
- [invalidText]="invalidHttpsAddressError">
- <input cdsText
- type="text"
- id="https_address"
- formControlName="https_address"
- [invalid]="serviceForm.controls.https_address.invalid && serviceForm.controls.https_address.dirty" />
- </cds-text-label>
- <ng-template #invalidHttpsAddressError>
- @if (serviceForm.showError('https_address', frm, 'invalidAddress')) {
- <span class="invalid-feedback"
- i18n>Format must be [IP|Hostname]:port and the port between 0 and 65535</span>
- }
- </ng-template>
- </div>
- <!-- redirect_url -->
- <div class="form-item">
- <cds-text-label cdRequiredField="Redirect URL"
- placeholder="https://<IP|Hostname>:4180/oauth2/callback"
- helperText="The URL the oauth2-proxy service will redirect to after a successful login."
- i18n-helperText
- [invalid]="serviceForm.controls.redirect_url.invalid && serviceForm.controls.redirect_url.dirty"
- [invalidText]="invalidRedirectUrlError">
- <input cdsText
- type="text"
- id="redirect_url"
- formControlName="redirect_url"
- [invalid]="serviceForm.controls.redirect_url.invalid && serviceForm.controls.redirect_url.dirty" />
- </cds-text-label>
- <ng-template #invalidRedirectUrlError>
- @if (serviceForm.showError('redirect_url', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <!-- Scope -->
- <div class="form-item">
- <cd-text-label-list formControlName="scope"
- label="Scope"
- helperText="OAuth scope specification."
- placeholder="openid profile email">
- </cd-text-label-list>
- </div>
- <!-- Email_domains -->
- <div class="form-item">
- <cd-text-label-list formControlName="email_domains"
- label="Email domains"
- helperText="Email domains to be allowed."
- placeholder="*">
- </cd-text-label-list>
- </div>
- <!-- Allowlist_domains -->
- <div class="form-item">
- <cd-text-label-list formControlName="allowlist_domains"
- label="Allowlist domains"
- helperText="Domains to be allowed to redirect to, used for login or logout."
- placeholder="192.168.100.1:8080">
- </cd-text-label-list>
- </div>
- <!-- SSL Insecure Skip Verify -->
- <div class="form-item">
- <cds-checkbox i18n-label
- formControlName="ssl_insecure_skip_verify">
- Skip TLS verification
- <cd-help-text i18n>
- Skip TLS certificate verification for the OIDC provider. Use only in non-production environments.
- </cd-help-text>
- </cds-checkbox>
- </div>
- }
-
- @if (!serviceForm.controls.unmanaged.value && ['mgmt-gateway'].includes(serviceForm.controls.service_type.value))
- {
- <!-- port -->
- <div class="form-item">
- <cds-number label="Port"
- formControlName="port"
- id="port"
- min="1"
- max="65535"
- [invalid]="serviceForm.controls.port.invalid && serviceForm.controls.port.dirty"
- [invalidText]="invalidPortError">
- </cds-number>
- <ng-template #invalidPortError>
- @if (serviceForm.showError('port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
- <!-- enable_auth -->
- <div class="form-item">
- <fieldset>
- <label class="cds--label"
- for="pools"
- i18n>Authentication</label>
- <cds-checkbox i18n-label
- id="enable_auth"
- name="enable_auth"
- formControlName="enable_auth">
- Enable
+ <!-- https_address -->
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Https address"
+ helperText="The address for HTTPS connections as [IP|Hostname]:port."
+ i18n-helperText
+ placeholder="0.0.0.0:4180"
+ [invalid]="
+ serviceForm.controls.https_address.invalid && serviceForm.controls.https_address.dirty
+ "
+ [invalidText]="invalidHttpsAddressError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="https_address"
+ formControlName="https_address"
+ [invalid]="
+ serviceForm.controls.https_address.invalid &&
+ serviceForm.controls.https_address.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidHttpsAddressError>
+ @if (serviceForm.showError('https_address', frm, 'invalidAddress')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Format must be [IP|Hostname]:port and the port between 0 and 65535</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- redirect_url -->
+ <div class="form-item">
+ <cds-text-label
+ cdRequiredField="Redirect URL"
+ placeholder="https://<IP|Hostname>:4180/oauth2/callback"
+ helperText="The URL the oauth2-proxy service will redirect to after a successful login."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.redirect_url.invalid && serviceForm.controls.redirect_url.dirty
+ "
+ [invalidText]="invalidRedirectUrlError"
+ >
+ <input
+ cdsText
+ type="text"
+ id="redirect_url"
+ formControlName="redirect_url"
+ [invalid]="
+ serviceForm.controls.redirect_url.invalid && serviceForm.controls.redirect_url.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #invalidRedirectUrlError>
+ @if (serviceForm.showError('redirect_url', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- Scope -->
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="scope"
+ label="Scope"
+ helperText="OAuth scope specification."
+ placeholder="openid profile email"
+ >
+ </cd-text-label-list>
+ </div>
+ <!-- Email_domains -->
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="email_domains"
+ label="Email domains"
+ helperText="Email domains to be allowed."
+ placeholder="*"
+ >
+ </cd-text-label-list>
+ </div>
+ <!-- Allowlist_domains -->
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="allowlist_domains"
+ label="Allowlist domains"
+ helperText="Domains to be allowed to redirect to, used for login or logout."
+ placeholder="192.168.100.1:8080"
+ >
+ </cd-text-label-list>
+ </div>
+ <!-- SSL Insecure Skip Verify -->
+ <div class="form-item">
+ <cds-checkbox
+ i18n-label
+ formControlName="ssl_insecure_skip_verify"
+ >
+ Skip TLS verification
<cd-help-text i18n>
- Allows to enable authentication through an external Identity Provider (IdP) using Single Sign-On (SSO)
+ Skip TLS certificate verification for the OIDC provider. Use only in non-production
+ environments.
</cd-help-text>
</cds-checkbox>
- </fieldset>
- </div>
- <!-- ssl_protocols -->
- <div class="form-item">
- <cds-combo-box type="multi"
- label="SSL protocols"
- selectionFeedback="top-after-reopen"
- for="ssl_protocols"
- name="ssl_protocols"
- formControlName="ssl_protocols"
- id="ssl_protocols"
- placeholder="Select protocols..."
- [appendInline]="true"
- [items]="sslProtocolsItems"
- i18n-placeholder
- i18n>
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- </div>
- <!-- ssl_ciphers -->
- <div class="form-item">
- <cds-text-label placeholder="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
- [helperText]="cipherListLink"
- i18n-helperText>
- SSL ciphers
- <input cdsText
- type="text"
- id="ssl_ciphers"
- formControlName="ssl_ciphers" />
- @if (serviceForm.showError('ssl_ciphers', frm, 'invalidPattern')) {
- <span class="invalid-feedback"
- i18n>Invalid cipher suite. Each cipher must be separated by '-' and each cipher suite must be separated
- by
- ':'</span>
- }
- </cds-text-label>
- </div>
- }
- <!-- RGW, Ingress, iSCSI, Oauth2-proxy, NFS & mgmt-gateway -->
- @if (!serviceForm.controls.unmanaged.value && ['rgw', 'iscsi', 'ingress', 'oauth2-proxy',
- 'mgmt-gateway', 'nfs'].includes(serviceForm.controls.service_type.value)) {
- <!-- ssl -->
- @if (!['mgmt-gateway'].includes(serviceForm.controls.service_type.value)) {
- <div class="form-item">
- <cds-checkbox formControlName="ssl"
- name="security_label"
- id="ssl"
- i18n>SSL
- </cds-checkbox>
- </div>
+ </div>
}
- <!-- Certificate Management UI -->
- @if (serviceForm.controls.ssl.value && ['rgw', 'ingress', 'iscsi', 'grafana', 'oauth2-proxy', 'mgmt-gateway', 'nfs'].includes(serviceForm.controls.service_type.value)) {
- <ng-container *ngTemplateOutlet="certificateAuthorityManagement"></ng-container>
+ @if (
+ !serviceForm.controls.unmanaged.value &&
+ ['mgmt-gateway'].includes(serviceForm.controls.service_type.value)
+ ) {
+ <!-- port -->
+ <div class="form-item">
+ <cds-number
+ label="Port"
+ formControlName="port"
+ id="port"
+ min="1"
+ max="65535"
+ [invalid]="serviceForm.controls.port.invalid && serviceForm.controls.port.dirty"
+ [invalidText]="invalidPortError"
+ >
+ </cds-number>
+ <ng-template #invalidPortError>
+ @if (serviceForm.showError('port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- enable_auth -->
+ <div class="form-item">
+ <fieldset>
+ <label
+ class="cds--label"
+ for="pools"
+ i18n
+ >Authentication</label
+ >
+ <cds-checkbox
+ i18n-label
+ id="enable_auth"
+ name="enable_auth"
+ formControlName="enable_auth"
+ >
+ Enable
+ <cd-help-text i18n>
+ Allows to enable authentication through an external Identity Provider (IdP) using
+ Single Sign-On (SSO)
+ </cd-help-text>
+ </cds-checkbox>
+ </fieldset>
+ </div>
+ <!-- ssl_protocols -->
+ <div class="form-item">
+ <cds-combo-box
+ type="multi"
+ label="SSL protocols"
+ selectionFeedback="top-after-reopen"
+ for="ssl_protocols"
+ name="ssl_protocols"
+ formControlName="ssl_protocols"
+ id="ssl_protocols"
+ placeholder="Select protocols..."
+ [appendInline]="true"
+ [items]="sslProtocolsItems"
+ i18n-placeholder
+ i18n
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ </div>
+ <!-- ssl_ciphers -->
+ <div class="form-item">
+ <cds-text-label
+ placeholder="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
+ [helperText]="cipherListLink"
+ i18n-helperText
+ >
+ SSL ciphers
+ <input
+ cdsText
+ type="text"
+ id="ssl_ciphers"
+ formControlName="ssl_ciphers"
+ />
+ @if (serviceForm.showError('ssl_ciphers', frm, 'invalidPattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Invalid cipher suite. Each cipher must be separated by '-' and each cipher suite
+ must be separated by ':'</span
+ >
+ }
+ </cds-text-label>
+ </div>
}
+ <!-- RGW, Ingress, iSCSI, Oauth2-proxy, NFS & mgmt-gateway -->
+ @if (
+ !serviceForm.controls.unmanaged.value &&
+ ['rgw', 'iscsi', 'ingress', 'oauth2-proxy', 'mgmt-gateway', 'nfs'].includes(
+ serviceForm.controls.service_type.value
+ )
+ ) {
+ <!-- ssl -->
+ @if (!['mgmt-gateway'].includes(serviceForm.controls.service_type.value)) {
+ <div class="form-item">
+ <cds-checkbox
+ formControlName="ssl"
+ name="security_label"
+ id="ssl"
+ i18n
+ >SSL
+ </cds-checkbox>
+ </div>
+ }
- <!-- ssl_cert - Only show when SSL is enabled AND certificate type is external -->
- @if (showExternalSslCert) {
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'ssl_cert', title: 'Certificate Input', helperText: 'Uploaded files will populate the certificate details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a .crt file, or paste the certificate PEM content directly.', invalidTemplate: invalidSslCertError, isRequired: false }"></ng-container>
- <ng-template #invalidSslCertError>
- @if (serviceForm.showError('ssl_cert', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('ssl_cert', frm, 'pattern')) {
- <span class="invalid-feedback"
- i18n>Invalid SSL certificate.</span>
- }
- </ng-template>
- </div>
- }
- @if (showExternalSslKey) {
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'ssl_key', title: 'Private Key Input', helperText: 'Uploaded files will populate the private key details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a .key file, or paste the private key PEM content directly.', invalidTemplate: invalidSslKeyError, isRequired: false }"></ng-container>
- <ng-template #invalidSslKeyError>
- @if (serviceForm.showError('ssl_key', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('ssl_key', frm, 'pattern')) {
- <span class="invalid-feedback"
- i18n>Invalid SSL private key.</span>
- }
- </ng-template>
- </div>
- <!-- ssl_ca_cert - Only show for NFS when SSL is enabled AND certificate type is external -->
- @if (serviceForm.controls.ssl.value && serviceForm.controls.certificateType.value === CertificateType.external && serviceForm.controls.service_type.value === 'nfs') {
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'ssl_ca_cert', title: 'CA Certificate Input', helperText: 'Uploaded files will populate the CA certificate details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a CA certificate file, or paste the CA certificate PEM content directly.', invalidTemplate: invalidSslCaCertError, isRequired: false }"></ng-container>
- <ng-template #invalidSslCaCertError>
- @if (serviceForm.showError('ssl_ca_cert', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('ssl_ca_cert', frm, 'pattern')) {
- <span class="invalid-feedback"
- i18n>Invalid CA certificate.</span>
+ <!-- Certificate Management UI -->
+ @if (
+ serviceForm.controls.ssl.value &&
+ ['rgw', 'ingress', 'iscsi', 'grafana', 'oauth2-proxy', 'mgmt-gateway', 'nfs'].includes(
+ serviceForm.controls.service_type.value
+ )
+ ) {
+ <ng-container *ngTemplateOutlet="certificateAuthorityManagement"></ng-container>
+ }
+
+ <!-- ssl_cert - Only show when SSL is enabled AND certificate type is external -->
+ @if (showExternalSslCert) {
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'ssl_cert',
+ title: 'Certificate Input',
+ helperText:
+ 'Uploaded files will populate the certificate details automatically. Or paste the PEM content directly in the text area.',
+ description: 'Upload a .crt file, or paste the certificate PEM content directly.',
+ invalidTemplate: invalidSslCertError,
+ isRequired: false
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidSslCertError>
+ @if (serviceForm.showError('ssl_cert', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('ssl_cert', frm, 'pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Invalid SSL certificate.</span
+ >
+ }
+ </ng-template>
+ </div>
+ }
+ @if (showExternalSslKey) {
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'ssl_key',
+ title: 'Private Key Input',
+ helperText:
+ 'Uploaded files will populate the private key details automatically. Or paste the PEM content directly in the text area.',
+ description: 'Upload a .key file, or paste the private key PEM content directly.',
+ invalidTemplate: invalidSslKeyError,
+ isRequired: false
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidSslKeyError>
+ @if (serviceForm.showError('ssl_key', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('ssl_key', frm, 'pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Invalid SSL private key.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <!-- ssl_ca_cert - Only show for NFS when SSL is enabled AND certificate type is external -->
+ @if (
+ serviceForm.controls.ssl.value &&
+ serviceForm.controls.certificateType.value === CertificateType.external &&
+ serviceForm.controls.service_type.value === 'nfs'
+ ) {
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'ssl_ca_cert',
+ title: 'CA Certificate Input',
+ helperText:
+ 'Uploaded files will populate the CA certificate details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a CA certificate file, or paste the CA certificate PEM content directly.',
+ invalidTemplate: invalidSslCaCertError,
+ isRequired: false
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidSslCaCertError>
+ @if (serviceForm.showError('ssl_ca_cert', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('ssl_ca_cert', frm, 'pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Invalid CA certificate.</span
+ >
+ }
+ </ng-template>
+ </div>
}
- </ng-template>
- </div>
- }
- }
+ }
- <!-- RGW QAT Compression -->
- @if(serviceForm.controls.service_type.value === 'rgw') {
- <div class="form-item"
- formGroupName="qat">
- <cds-select formControlName="compression"
- name="compression"
- label="QAT compression mode"
- id="compression"
- helperText="QAT compression is optional. Choose Hardware or Software to enable compression, or select None to disable it."
- i18n-helperText>
- <option *ngFor="let option of qatCompressionOptions"
- [value]="option.value"
- i18n>{{ option.label }}</option>
- </cds-select>
- </div>
+ <!-- RGW QAT Compression -->
+ @if (serviceForm.controls.service_type.value === 'rgw') {
+ <div
+ class="form-item"
+ formGroupName="qat"
+ >
+ <cds-select
+ formControlName="compression"
+ name="compression"
+ label="QAT compression mode"
+ id="compression"
+ helperText="QAT compression is optional. Choose Hardware or Software to enable compression, or select None to disable it."
+ i18n-helperText
+ >
+ <option
+ *ngFor="let option of qatCompressionOptions"
+ [value]="option.value"
+ i18n
+ >
+ {{ option.label }}
+ </option>
+ </cds-select>
+ </div>
}
}
<!-- Grafana -->
@if (serviceForm.controls.service_type.value === 'grafana') {
- <div class="form-item">
- <cds-number label="Grafana port"
- i18n-label
- formControlName="grafana_port"
- id="grafana_port"
- min="1"
- max="65535"
- helperText="The default port used by grafana."
- i18n-helperText
- [invalid]="serviceForm.controls.grafana_port.invalid && serviceForm.controls.grafana_port.dirty"
- [invalidText]="invalidGrafanaPortError">
- </cds-number>
- <ng-template #invalidGrafanaPortError>
- @if (serviceForm.showError('grafana_port', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- @if (serviceForm.showError('grafana_port', frm, 'min')) {
- <span class="invalid-feedback"
- i18n>The value must be at least 1.</span>
- }
- @if (serviceForm.showError('grafana_port', frm, 'max')) {
- <span class="invalid-feedback"
- i18n>The value cannot exceed 65535.</span>
- }
- </ng-template>
- </div>
- <div class="form-item form-item-append">
- <cds-password-label for="grafana_admin_password">
- Grafana password
- <input cdsPassword
- type="password"
- id="grafana_admin_password"
- formControlName="grafana_admin_password" />
- </cds-password-label>
- <cd-copy-2-clipboard-button source="grafana_admin_password"
- class="mt-4">
- </cd-copy-2-clipboard-button>
- </div>
+ <div class="form-item">
+ <cds-number
+ label="Grafana port"
+ i18n-label
+ formControlName="grafana_port"
+ id="grafana_port"
+ min="1"
+ max="65535"
+ helperText="The default port used by grafana."
+ i18n-helperText
+ [invalid]="
+ serviceForm.controls.grafana_port.invalid && serviceForm.controls.grafana_port.dirty
+ "
+ [invalidText]="invalidGrafanaPortError"
+ >
+ </cds-number>
+ <ng-template #invalidGrafanaPortError>
+ @if (serviceForm.showError('grafana_port', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (serviceForm.showError('grafana_port', frm, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value must be at least 1.</span
+ >
+ }
+ @if (serviceForm.showError('grafana_port', frm, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <div class="form-item form-item-append">
+ <cds-password-label for="grafana_admin_password">
+ Grafana password
+ <input
+ cdsPassword
+ type="password"
+ id="grafana_admin_password"
+ formControlName="grafana_admin_password"
+ />
+ </cds-password-label>
+ <cd-copy-2-clipboard-button
+ source="grafana_admin_password"
+ class="mt-4"
+ >
+ </cd-copy-2-clipboard-button>
+ </div>
}
@if (serviceForm.controls.service_type.value === 'mgmt-gateway' && showMgmtGatewayMessage) {
- <cd-alert-panel type="warning"
- spacingClass="mb-3"
- i18n>
- Modifying the default settings could lead to a weaker security configuration
- </cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-3"
+ i18n
+ >
+ Modifying the default settings could lead to a weaker security configuration
+ </cd-alert-panel>
}
<!-- NVMe/TCP -->
<!-- mTLS -->
@if (serviceForm.controls.service_type.value === 'nvmeof') {
- <div class="form-item">
- <fieldset class="cds--fieldset">
- <label class="cds--label"
- for="enable_mtls"
- i18n>Encryption</label>
- <cds-checkbox i18n-label
- id="enable_mtls"
- formControlName="enable_mtls">
- Enable
- <cd-help-text i18n>
- Enables mutual TLS (mTLS) between the client and the gateway server.
- </cd-help-text>
- </cds-checkbox>
- </fieldset>
- </div>
- @if (serviceForm.controls.enable_mtls.value) {
- <ng-container *ngTemplateOutlet="certificateAuthorityManagement"></ng-container>
+ <div class="form-item">
+ <fieldset class="cds--fieldset">
+ <label
+ class="cds--label"
+ for="enable_mtls"
+ i18n
+ >Encryption</label
+ >
+ <cds-checkbox
+ i18n-label
+ id="enable_mtls"
+ formControlName="enable_mtls"
+ >
+ Enable
+ <cd-help-text i18n>
+ Enables mutual TLS (mTLS) between the client and the gateway server.
+ </cd-help-text>
+ </cds-checkbox>
+ </fieldset>
+ </div>
+ @if (serviceForm.controls.enable_mtls.value) {
+ <ng-container *ngTemplateOutlet="certificateAuthorityManagement"></ng-container>
- @if (serviceForm.controls.certificateType.value === CertificateType.external) {
- <!-- root_ca_cert -->
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'root_ca_cert', title: 'Root CA Certificate Input', helperText: 'Uploaded files will populate the Root CA certificate details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a Root CA certificate file, or paste the Root CA certificate PEM content directly.', invalidTemplate: invalidRootCaCertError, isRequired: true }"></ng-container>
- <ng-template #invalidRootCaCertError>
- @if (serviceForm.showError('root_ca_cert', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ @if (serviceForm.controls.certificateType.value === CertificateType.external) {
+ <!-- root_ca_cert -->
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'root_ca_cert',
+ title: 'Root CA Certificate Input',
+ helperText:
+ 'Uploaded files will populate the Root CA certificate details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a Root CA certificate file, or paste the Root CA certificate PEM content directly.',
+ invalidTemplate: invalidRootCaCertError,
+ isRequired: true
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidRootCaCertError>
+ @if (serviceForm.showError('root_ca_cert', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- client_cert -->
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'client_cert', title: 'Client Certificate Input', helperText: 'Uploaded files will populate the client certificate details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a client certificate file, or paste the client certificate PEM content directly.', invalidTemplate: invalidClientCertError, isRequired: true }"></ng-container>
- <ng-template #invalidClientCertError>
- @if (serviceForm.showError('client_cert', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <!-- client_cert -->
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'client_cert',
+ title: 'Client Certificate Input',
+ helperText:
+ 'Uploaded files will populate the client certificate details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a client certificate file, or paste the client certificate PEM content directly.',
+ invalidTemplate: invalidClientCertError,
+ isRequired: true
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidClientCertError>
+ @if (serviceForm.showError('client_cert', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- client_key -->
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'client_key', title: 'Client Key Input', helperText: 'Uploaded files will populate the client key details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a client key file, or paste the client key PEM content directly.', invalidTemplate: invalidClientKeyError, isRequired: true }"></ng-container>
- <ng-template #invalidClientKeyError>
- @if (serviceForm.showError('client_key', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <!-- client_key -->
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'client_key',
+ title: 'Client Key Input',
+ helperText:
+ 'Uploaded files will populate the client key details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a client key file, or paste the client key PEM content directly.',
+ invalidTemplate: invalidClientKeyError,
+ isRequired: true
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidClientKeyError>
+ @if (serviceForm.showError('client_key', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- server_cert -->
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'server_cert', title: 'Gateway Server Certificate Input', helperText: 'Uploaded files will populate the gateway server certificate details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a gateway server certificate file, or paste the certificate PEM content directly.', invalidTemplate: invalidServerCertError, isRequired: true }"></ng-container>
- <ng-template #invalidServerCertError>
- @if (serviceForm.showError('server_cert', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ <!-- server_cert -->
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'server_cert',
+ title: 'Gateway Server Certificate Input',
+ helperText:
+ 'Uploaded files will populate the gateway server certificate details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a gateway server certificate file, or paste the certificate PEM content directly.',
+ invalidTemplate: invalidServerCertError,
+ isRequired: true
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidServerCertError>
+ @if (serviceForm.showError('server_cert', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- server_key -->
- <div class="form-item">
- <ng-container *ngTemplateOutlet="fileUploaderTextarea; context: { controlName: 'server_key', title: 'Gateway Server Key Input', helperText: 'Uploaded files will populate the gateway server key details automatically. Or paste the PEM content directly in the text area.', description: 'Upload a gateway server key file, or paste the key PEM content directly.', invalidTemplate: invalidServerKeyError, isRequired: true }"></ng-container>
- <ng-template #invalidServerKeyError>
- @if (serviceForm.showError('server_key', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <!-- server_key -->
+ <div class="form-item">
+ <ng-container
+ *ngTemplateOutlet="
+ fileUploaderTextarea;
+ context: {
+ controlName: 'server_key',
+ title: 'Gateway Server Key Input',
+ helperText:
+ 'Uploaded files will populate the gateway server key details automatically. Or paste the PEM content directly in the text area.',
+ description:
+ 'Upload a gateway server key file, or paste the key PEM content directly.',
+ invalidTemplate: invalidServerKeyError,
+ isRequired: true
+ }
+ "
+ ></ng-container>
+ <ng-template #invalidServerKeyError>
+ @if (serviceForm.showError('server_key', frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
}
- </ng-template>
- </div>
- }
- }
+ }
}
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="serviceForm"
- [submitText]="(action | titlecase) + ' ' + (resource)"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="serviceForm"
+ [submitText]="(action | titlecase) + ' ' + resource"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
<ng-template #cipherListLink>
<span>
- Default cipher list used: <a href="https://ssl-config.mozilla.org/#server=nginx"
- target="_blank">https://ssl-config.mozilla.org/#server=nginx</a>
+ Default cipher list used:
+ <a
+ href="https://ssl-config.mozilla.org/#server=nginx"
+ target="_blank"
+ >https://ssl-config.mozilla.org/#server=nginx</a
+ >
</span>
</ng-template>
<ng-template #certificateAuthorityManagement>
<div [formGroup]="serviceForm">
- <!-- Current Certificate Section - Only shown in Edit mode when certificate exists -->
- @if (editing && currentCertificate?.has_certificate) {
- <div class="form-item">
- <legend class="cds--label cds--type-heading-compact-01"
- i18n>Current Certificate</legend>
- <div class="row">
- <div class="col-6">
- <legend class="cds--label"
- i18n>Certificate</legend>
- <div>{{ currentCertificate.cert_name }}</div>
- </div>
- <div class="col-6">
- <legend class="cds--label"
- i18n>Valid Until</legend>
- <div>{{ currentCertificate.expiry_date | cdDate }} • {{ currentCertificate.days_to_expiration }} <span i18n>days left</span></div>
- </div>
- </div>
- <div class="row mt-3">
- <div class="col-6">
- <legend class="cds--label"
- i18n>Status</legend>
- <div class="align-items-center">
- <cd-icon [type]="statusIconMap[currentCertificate.status] || statusIconMap['default']"></cd-icon>
- @switch (currentCertificate.status) {
- @case ('valid') { <span i18n>Valid</span> }
- @case ('expiring') { <span i18n>Expiring soon</span> }
- @case ('expired') { <span i18n>Expired</span> }
- @case ('not_configured') { <span i18n>Not configured</span> }
- @case ('invalid') { <span i18n>Invalid</span> }
- @default { {{ currentCertificate.status }} }
- }
+ <!-- Current Certificate Section - Only shown in Edit mode when certificate exists -->
+ @if (editing && currentCertificate?.has_certificate) {
+ <div class="form-item">
+ <legend
+ class="cds--label cds--type-heading-compact-01"
+ i18n
+ >
+ Current Certificate
+ </legend>
+ <div class="row">
+ <div class="col-6">
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Certificate
+ </legend>
+ <div>{{ currentCertificate.cert_name }}</div>
+ </div>
+ <div class="col-6">
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Valid Until
+ </legend>
+ <div>
+ {{ currentCertificate.expiry_date | cdDate }} •
+ {{ currentCertificate.days_to_expiration }} <span i18n>days left</span>
+ </div>
+ </div>
</div>
- </div>
- <div class="col-6">
- <legend class="cds--label"
- i18n>Issuer</legend>
- <div>
- @if (currentCertificate.signed_by === 'cephadm') {
- <span i18n>Internal (Cephadm CA)</span>
- } @else {
- {{ currentCertificate.issuer || 'External' }}
- }
+ <div class="row mt-3">
+ <div class="col-6">
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Status
+ </legend>
+ <div class="align-items-center">
+ <cd-icon
+ [type]="statusIconMap[currentCertificate.status] || statusIconMap['default']"
+ ></cd-icon>
+ @switch (currentCertificate.status) {
+ @case ('valid') {
+ <span i18n>Valid</span>
+ }
+ @case ('expiring') {
+ <span i18n>Expiring soon</span>
+ }
+ @case ('expired') {
+ <span i18n>Expired</span>
+ }
+ @case ('not_configured') {
+ <span i18n>Not configured</span>
+ }
+ @case ('invalid') {
+ <span i18n>Invalid</span>
+ }
+ @default {
+ {{ currentCertificate.status }}
+ }
+ }
+ </div>
+ </div>
+ <div class="col-6">
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Issuer
+ </legend>
+ <div>
+ @if (currentCertificate.signed_by === 'cephadm') {
+ <span i18n>Internal (Cephadm CA)</span>
+ } @else {
+ {{ currentCertificate.issuer || 'External' }}
+ }
+ </div>
+ </div>
</div>
</div>
- </div>
- </div>
- }
+ }
- <!-- Certificate Authority Selection -->
- <div class="form-item">
- <label class="cds--label cds--type-heading-compact-01"
- for="certificateType"
- i18n>Choose Certificate Authority</label>
- <cds-radio-group formControlName="certificateType"
- orientation="horizontal"
- helperText="Select how certificates will be signed for this service. Choose internal to use the cluster's CA, or external to upload certificates signed by your organization."
- i18n-helperText>
- <cds-radio [value]="CertificateType.internal"
- (change)="onCertificateTypeChange(CertificateType.internal)"
- i18n>
- Internal
- </cds-radio>
- <cds-radio [value]="CertificateType.external"
- (change)="onCertificateTypeChange(CertificateType.external)"
- i18n>
- External
- </cds-radio>
- </cds-radio-group>
- </div>
+ <!-- Certificate Authority Selection -->
+ <div class="form-item">
+ <label
+ class="cds--label cds--type-heading-compact-01"
+ for="certificateType"
+ i18n
+ >Choose Certificate Authority</label
+ >
+ <cds-radio-group
+ formControlName="certificateType"
+ orientation="horizontal"
+ helperText="Select how certificates will be signed for this service. Choose internal to use the cluster's CA, or external to upload certificates signed by your organization."
+ i18n-helperText
+ >
+ <cds-radio
+ [value]="CertificateType.internal"
+ (change)="onCertificateTypeChange(CertificateType.internal)"
+ i18n
+ >
+ Internal
+ </cds-radio>
+ <cds-radio
+ [value]="CertificateType.external"
+ (change)="onCertificateTypeChange(CertificateType.external)"
+ i18n
+ >
+ External
+ </cds-radio>
+ </cds-radio-group>
+ </div>
- @if (showCertSourceChangeWarning) {
- <cd-alert-panel type="warning"
- spacingClass="mb-3"
- i18n>
- Changing the certificate source will redeploy the service daemons to apply the new certificate configuration.
- </cd-alert-panel>
- }
+ @if (showCertSourceChangeWarning) {
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-3"
+ i18n
+ >
+ Changing the certificate source will redeploy the service daemons to apply the new
+ certificate configuration.
+ </cd-alert-panel>
+ }
- @if (serviceForm.controls.certificateType.value === CertificateType.internal) {
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- i18n>
- Certificate will be generated automatically by Cephadm CA for internal certificate type.
- </cd-alert-panel>
- <div class="form-item">
- <cd-text-label-list formControlName="custom_sans"
- label="Custom SAN Entries"
- i18n-label
- helperText="Optional list of Subject Alternative Names (hostnames, IPs, or DNS names) to include in the auto-generated certificate."
- i18n-helperText>
- </cd-text-label-list>
- </div>
- @if (serviceForm.controls.service_type.value === 'rgw'
- && serviceForm.controls.virtual_host_enabled.value) {
- <div class="form-item">
- <cds-checkbox i18n-label
- formControlName="wildcard_enabled">
- Include wildcard certificate for bucket subdomains
- <cd-help-text i18n>
- Add wildcard certificates (*.domain) to allow SSL for all bucket subdomains. Required for virtual-host style with SSL.
- </cd-help-text>
- </cds-checkbox>
- </div>
- }
- }
+ @if (serviceForm.controls.certificateType.value === CertificateType.internal) {
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ >
+ Certificate will be generated automatically by Cephadm CA for internal certificate type.
+ </cd-alert-panel>
+ <div class="form-item">
+ <cd-text-label-list
+ formControlName="custom_sans"
+ label="Custom SAN Entries"
+ i18n-label
+ helperText="Optional list of Subject Alternative Names (hostnames, IPs, or DNS names) to include in the auto-generated certificate."
+ i18n-helperText
+ >
+ </cd-text-label-list>
+ </div>
+ @if (
+ serviceForm.controls.service_type.value === 'rgw' &&
+ serviceForm.controls.virtual_host_enabled.value
+ ) {
+ <div class="form-item">
+ <cds-checkbox
+ i18n-label
+ formControlName="wildcard_enabled"
+ >
+ Include wildcard certificate for bucket subdomains
+ <cd-help-text i18n>
+ Add wildcard certificates (*.domain) to allow SSL for all bucket subdomains. Required
+ for virtual-host style with SSL.
+ </cd-help-text>
+ </cds-checkbox>
+ </div>
+ }
+ }
</div>
</ng-template>
-<ng-template #fileUploaderTextarea
- let-controlName="controlName"
- let-title="title"
- let-helperText="helperText"
- let-description="description"
- let-invalidTemplate="invalidTemplate"
- let-isRequired="isRequired">
- <cds-textarea-label [attr.cdRequiredField]="isRequired ? title : null"
- [helperText]="helperText"
- [invalid]="serviceForm.controls[controlName].invalid && serviceForm.controls[controlName].dirty"
- [invalidText]="invalidTemplate">
- <cds-file-uploader [title]="title"
- buttonText="Upload File"
- i18n-buttonText
- buttonType="tertiary"
- [multiple]="false"
- size="md"
- [description]="description"
- (filesChange)="fileUpload($event, controlName)"
- (removeFile)="clearText()"></cds-file-uploader>
- <textarea cdsTextArea
- [id]="controlName"
- [theme]="'dark'"
- placeholder="Paste certificate or private key PEM content"
- [formControl]="serviceForm.controls[controlName]"
- cols="50"
- rows="5"
- [invalid]="serviceForm.controls[controlName].invalid && serviceForm.controls[controlName].dirty">
+<ng-template
+ #fileUploaderTextarea
+ let-controlName="controlName"
+ let-title="title"
+ let-helperText="helperText"
+ let-description="description"
+ let-invalidTemplate="invalidTemplate"
+ let-isRequired="isRequired"
+>
+ <cds-textarea-label
+ [attr.cdRequiredField]="isRequired ? title : null"
+ [helperText]="helperText"
+ [invalid]="serviceForm.controls[controlName].invalid && serviceForm.controls[controlName].dirty"
+ [invalidText]="invalidTemplate"
+ >
+ <cds-file-uploader
+ [title]="title"
+ buttonText="Upload File"
+ i18n-buttonText
+ buttonType="tertiary"
+ [multiple]="false"
+ size="md"
+ [description]="description"
+ (filesChange)="fileUpload($event, controlName)"
+ (removeFile)="clearText()"
+ ></cds-file-uploader>
+ <textarea
+ cdsTextArea
+ [id]="controlName"
+ [theme]="'dark'"
+ placeholder="Paste certificate or private key PEM content"
+ [formControl]="serviceForm.controls[controlName]"
+ cols="50"
+ rows="5"
+ [invalid]="
+ serviceForm.controls[controlName].invalid && serviceForm.controls[controlName].dirty
+ "
+ >
</textarea>
</cds-textarea-label>
</ng-template>
<cd-orchestrator-doc-panel *ngIf="showDocPanel"></cd-orchestrator-doc-panel>
<ng-container *ngIf="orchStatus?.available">
- <cd-table [data]="services"
- [columns]="columns"
- identifier="service_name"
- forceIdentifier="true"
- columnMode="flex"
- selectionType="single"
- [autoReload]="5000"
- (fetchData)="getServices($event)"
- [hasDetails]="hasDetails"
- [serverSide]="true"
- [count]="count"
- updateExpandedOnRefresh="always"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permissions.hosts"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table
+ [data]="services"
+ [columns]="columns"
+ identifier="service_name"
+ forceIdentifier="true"
+ columnMode="flex"
+ selectionType="single"
+ [autoReload]="5000"
+ (fetchData)="getServices($event)"
+ [hasDetails]="hasDetails"
+ [serverSide]="true"
+ [count]="count"
+ updateExpandedOnRefresh="always"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permissions.hosts"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-service-details *cdTableDetail
- [permissions]="permissions"
- [selection]="expandedRow"
- (editService)="openModal(true, $event)">
+ <cd-service-details
+ *cdTableDetail
+ [permissions]="permissions"
+ [selection]="expandedRow"
+ (editService)="openModal(true, $event)"
+ >
</cd-service-details>
</cd-table>
</ng-container>
<router-outlet name="modal"></router-outlet>
-
-<ng-template #runningTpl
- let-value="data.value">
+<ng-template
+ #runningTpl
+ let-value="data.value"
+>
<span ngbTooltip="Service instances running out of the total number of services requested.">
{{ value.running }} / {{ value.size }}
</span>
- <svg *ngIf="value.running == 0 || value.size == 0"
- [cdsIcon]="icons.warning"
- [size]="icons.size16"
- class="cds-warning-color"></svg>
+ <svg
+ *ngIf="value.running == 0 || value.size == 0"
+ [cdsIcon]="icons.warning"
+ [size]="icons.size16"
+ class="cds-warning-color"
+ ></svg>
</ng-template>
-<ng-template #urlTpl
- let-row="data.row">
- <ng-container *ngIf="serviceUrls[row.service_type] else noUrl">
- <a *ngIf="!isMgmtGateway else mgmtGateway"
- target="_blank"
- [href]="serviceUrls[row.service_type]">
+<ng-template
+ #urlTpl
+ let-row="data.row"
+>
+ <ng-container *ngIf="serviceUrls[row.service_type]; else noUrl">
+ <a
+ *ngIf="!isMgmtGateway; else mgmtGateway"
+ target="_blank"
+ [href]="serviceUrls[row.service_type]"
+ >
{{ row.service_name }}
- <svg [cdsIcon]="icons.launch"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <svg
+ [cdsIcon]="icons.launch"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</a>
<ng-template #mgmtGateway>
- <a target="_blank"
- [href]="row.service_type">
+ <a
+ target="_blank"
+ [href]="row.service_type"
+ >
{{ row.service_name }}
- <svg [cdsIcon]="icons.launch"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <svg
+ [cdsIcon]="icons.launch"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</a>
</ng-template>
</ng-container>
- <ng-template #noUrl>{{row.service_name}}</ng-template>
+ <ng-template #noUrl>{{ row.service_name }}</ng-template>
</ng-template>
-<ng-template #certificateStatusTpl
- let-row="data.row">
-@if (row.certificate?.requires_certificate && row.certificate?.status && row.certificate?.status !== 'not_configured') {
- <span class="d-flex align-items-center gap-1">
- <cd-icon [type]="statusIconMap[row.certificate.status] || statusIconMap['default']"></cd-icon>
- {{ formatCertificateStatus(row.certificate) }}
- </span>
-} @else {
- -
-}
+<ng-template
+ #certificateStatusTpl
+ let-row="data.row"
+>
+ @if (
+ row.certificate?.requires_certificate &&
+ row.certificate?.status &&
+ row.certificate?.status !== 'not_configured'
+ ) {
+ <span class="d-flex align-items-center gap-1">
+ <cd-icon [type]="statusIconMap[row.certificate.status] || statusIconMap['default']"></cd-icon>
+ {{ formatCertificateStatus(row.certificate) }}
+ </span>
+ } @else {
+ -
+ }
</ng-template>
-<div class="cd-col-form"
- *cdFormLoading="loading">
+<div
+ class="cd-col-form"
+ *cdFormLoading="loading"
+>
<ng-container [ngSwitch]="step">
<!-- Configuration step -->
<div *ngSwitchCase="1">
- <form name="form"
- #formDir="ngForm"
- [formGroup]="configForm"
- novalidate>
+ <form
+ name="form"
+ #formDir="ngForm"
+ [formGroup]="configForm"
+ novalidate
+ >
<div class="card">
- <div class="card-header"
- i18n>Step {{ step }} of 2: Telemetry report configuration</div>
+ <div
+ class="card-header"
+ i18n
+ >
+ Step {{ step }} of 2: Telemetry report configuration
+ </div>
<div class="card-body">
- <p i18n>The telemetry module sends anonymous data about this Ceph cluster back to the Ceph developers
- to help understand how Ceph is used and what problems users may be experiencing.<br/>
- This data is visualized on <a href="https://telemetry-public.ceph.com/">public dashboards</a>
- that allow the community to quickly see summary statistics on how many clusters are reporting,
- their total capacity and OSD count, and version distribution trends.<br/><br/>
- The data being reported does <b>not</b> contain any sensitive data like pool names, object names, object contents,
- hostnames, or device serial numbers. It contains counters and statistics on how the cluster has been
- deployed, the version of Ceph, the distribution of the hosts and other parameters which help the project
- to gain a better understanding of the way Ceph is used. The data is sent secured to {{ sendToUrl }} and
- {{ sendToDeviceUrl }} (device report).</p>
+ <p i18n>
+ The telemetry module sends anonymous data about this Ceph cluster back to the Ceph
+ developers to help understand how Ceph is used and what problems users may be
+ experiencing.<br />
+ This data is visualized on
+ <a href="https://telemetry-public.ceph.com/">public dashboards</a> that allow the
+ community to quickly see summary statistics on how many clusters are reporting, their
+ total capacity and OSD count, and version distribution trends.<br /><br />
+ The data being reported does <b>not</b> contain any sensitive data like pool names,
+ object names, object contents, hostnames, or device serial numbers. It contains
+ counters and statistics on how the cluster has been deployed, the version of Ceph, the
+ distribution of the hosts and other parameters which help the project to gain a better
+ understanding of the way Ceph is used. The data is sent secured to {{ sendToUrl }} and
+ {{ sendToDeviceUrl }} (device report).
+ </p>
<div *ngIf="moduleEnabled">
The plugin is already <b>enabled</b>. Click <b>Deactivate</b> to disable it.
- <button type="button"
- class="btn btn-light"
- (click)="disableModule('The Telemetry module has been disabled successfully.')"
- i18n>Deactivate</button>
+ <button
+ type="button"
+ class="btn btn-light"
+ (click)="disableModule('The Telemetry module has been disabled successfully.')"
+ i18n
+ >
+ Deactivate
+ </button>
</div>
<legend i18n>Channels</legend>
- <p i18n>The telemetry report is broken down into several "channels", each with a different type of information that can
- be configured below.</p>
+ <p i18n>
+ The telemetry report is broken down into several "channels", each with a different
+ type of information that can be configured below.
+ </p>
<!-- Channel basic -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="channel_basic">
+ <label
+ class="cd-col-form-label"
+ for="channel_basic"
+ >
<ng-container i18n>Basic</ng-container>
<cd-helper>
<ng-container i18n>Includes basic information about the cluster:</ng-container>
<ul>
<li i18n>Capacity of the cluster</li>
- <li i18n>Number of monitors, managers, OSDs, MDSs, object gateways, or other daemons</li>
+ <li i18n>
+ Number of monitors, managers, OSDs, MDSs, object gateways, or other daemons
+ </li>
<li i18n>Software version currently being used</li>
<li i18n>Number and types of RADOS pools and CephFS file systems</li>
- <li i18n>Names of configuration options that have been changed from their default (but not their values)</li>
+ <li i18n>
+ Names of configuration options that have been changed from their default (but
+ not their values)
+ </li>
</ul>
</cd-helper>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="channel_basic"
- formControlName="channel_basic">
- <label class="custom-control-label"
- for="channel_basic"></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="channel_basic"
+ formControlName="channel_basic"
+ />
+ <label
+ class="custom-control-label"
+ for="channel_basic"
+ ></label>
</div>
</div>
</div>
<!-- Channel crash -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="channel_crash">
+ <label
+ class="cd-col-form-label"
+ for="channel_crash"
+ >
<ng-container i18n>Crash</ng-container>
<cd-helper>
<ng-container i18n>Includes information about daemon crashes:</ng-container>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="channel_crash"
- formControlName="channel_crash">
- <label class="custom-control-label"
- for="channel_crash"></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="channel_crash"
+ formControlName="channel_crash"
+ />
+ <label
+ class="custom-control-label"
+ for="channel_crash"
+ ></label>
</div>
</div>
</div>
<!-- Channel device -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="channel_device">
+ <label
+ class="cd-col-form-label"
+ for="channel_device"
+ >
<ng-container i18n>Device</ng-container>
- <cd-helper i18n-html
- html="Includes information about device metrics like anonymized SMART metrics.">
+ <cd-helper
+ i18n-html
+ html="Includes information about device metrics like anonymized SMART metrics."
+ >
</cd-helper>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="channel_device"
- formControlName="channel_device">
- <label class="custom-control-label"
- for="channel_device"></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="channel_device"
+ formControlName="channel_device"
+ />
+ <label
+ class="custom-control-label"
+ for="channel_device"
+ ></label>
</div>
</div>
</div>
<!-- Channel ident -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="channel_ident">
+ <label
+ class="cd-col-form-label"
+ for="channel_ident"
+ >
<ng-container i18n>Ident</ng-container>
<cd-helper>
- <ng-container i18n>Includes user-provided identifying information about the cluster:</ng-container>
+ <ng-container i18n
+ >Includes user-provided identifying information about the cluster:</ng-container
+ >
<ul>
<li>Cluster description</li>
<li>Contact email address</li>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="channel_ident"
- formControlName="channel_ident"
- (click)="toggleIdent()">
- <label class="custom-control-label"
- for="channel_ident"></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="channel_ident"
+ formControlName="channel_ident"
+ (click)="toggleIdent()"
+ />
+ <label
+ class="custom-control-label"
+ for="channel_ident"
+ ></label>
</div>
</div>
</div>
<!-- Channel perf -->
<div class="form-group row">
- <label class="cd-col-form-label"
- for="channel_perf">
+ <label
+ class="cd-col-form-label"
+ for="channel_perf"
+ >
<ng-container i18n>Perf</ng-container>
<cd-helper>
- <ng-container i18n>Includes various performance metrics of a cluster.</ng-container>
+ <ng-container i18n
+ >Includes various performance metrics of a cluster.</ng-container
+ >
</cd-helper>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="channel_perf"
- formControlName="channel_perf">
- <label class="custom-control-label"
- for="channel_perf"></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="channel_perf"
+ formControlName="channel_perf"
+ />
+ <label
+ class="custom-control-label"
+ for="channel_perf"
+ ></label>
</div>
</div>
</div>
<ng-container *ngIf="showContactInfo">
- <legend>
- <ng-container i18n>Contact Information</ng-container>
- <cd-helper i18n>Submitting any contact information is completely optional and disabled by default.</cd-helper>
- </legend>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="contact"
- i18n>Contact</label>
- <div class="cd-col-form-input">
- <input id="contact"
- class="form-control"
- type="text"
- formControlName="contact"
- placeholder="Example User <user@example.com>">
+ <legend>
+ <ng-container i18n>Contact Information</ng-container>
+ <cd-helper i18n
+ >Submitting any contact information is completely optional and disabled by
+ default.</cd-helper
+ >
+ </legend>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="contact"
+ i18n
+ >Contact</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ id="contact"
+ class="form-control"
+ type="text"
+ formControlName="contact"
+ placeholder="Example User <user@example.com>"
+ />
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="description"
- i18n>Description</label>
- <div class="cd-col-form-input">
- <input id="description"
- class="form-control"
- type="text"
- formControlName="description"
- placeholder="My first Ceph cluster"
- i18n-placeholder>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="description"
+ i18n
+ >Description</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ id="description"
+ class="form-control"
+ type="text"
+ formControlName="description"
+ placeholder="My first Ceph cluster"
+ i18n-placeholder
+ />
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="organization"
- i18n>Organization</label>
- <div class="cd-col-form-input">
- <input id="organization"
- class="form-control"
- type="text"
- formControlName="organization"
- placeholder="Organization name"
- i18n-placeholder>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="organization"
+ i18n
+ >Organization</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ id="organization"
+ class="form-control"
+ type="text"
+ formControlName="organization"
+ placeholder="Organization name"
+ i18n-placeholder
+ />
+ </div>
</div>
- </div>
- </ng-container>
+ </ng-container>
<legend i18n>Advanced Settings</legend>
<div class="form-group row">
- <label class="cd-col-form-label"
- for="interval">
+ <label
+ class="cd-col-form-label"
+ for="interval"
+ >
<ng-container i18n>Interval</ng-container>
- <cd-helper i18n>The module compiles and sends a new report every 24 hours by default. You can
- adjust this interval by setting a different number of hours.</cd-helper>
+ <cd-helper i18n
+ >The module compiles and sends a new report every 24 hours by default. You can
+ adjust this interval by setting a different number of hours.</cd-helper
+ >
</label>
<div class="cd-col-form-input">
- <input id="interval"
- class="form-control"
- type="number"
- formControlName="interval"
- min="8">
- <span class="invalid-feedback"
- *ngIf="configForm.showError('interval', formDir, 'min')"
- i18n>The entered value is too low! It must be greater or equal to 8.</span>
+ <input
+ id="interval"
+ class="form-control"
+ type="number"
+ formControlName="interval"
+ min="8"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('interval', formDir, 'min')"
+ i18n
+ >The entered value is too low! It must be greater or equal to 8.</span
+ >
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label"
- for="proxy">
+ <label
+ class="cd-col-form-label"
+ for="proxy"
+ >
<ng-container i18n>Proxy</ng-container>
<cd-helper>
- <p i18n>If the cluster cannot directly connect to the configured telemetry endpoint
- (default telemetry.ceph.com), you can configure a HTTP/HTTPS proxy server by e.g. adding
- https://10.0.0.1:8080</p>
- <p i18n>You can also include a user:pass if needed e.g. https://ceph:telemetry@10.0.0.1:8080</p>
+ <p i18n>
+ If the cluster cannot directly connect to the configured telemetry endpoint
+ (default telemetry.ceph.com), you can configure a HTTP/HTTPS proxy server by
+ e.g. adding https://10.0.0.1:8080
+ </p>
+ <p i18n>
+ You can also include a user:pass if needed e.g.
+ https://ceph:telemetry@10.0.0.1:8080
+ </p>
</cd-helper>
</label>
<div class="cd-col-form-input">
- <input id="proxy"
- class="form-control"
- type="text"
- formControlName="proxy"
- placeholder="https://10.0.0.1:8080">
+ <input
+ id="proxy"
+ class="form-control"
+ type="text"
+ formControlName="proxy"
+ placeholder="https://10.0.0.1:8080"
+ />
</div>
</div>
<br />
- <p i18n><b>Note:</b> By clicking 'Next' you will first see a preview of the report content before you
- can activate the automatic submission of your data.</p>
+ <p i18n>
+ <b>Note:</b> By clicking 'Next' you will first see a preview of the report content
+ before you can activate the automatic submission of your data.
+ </p>
</div>
<div class="card-footer">
<div class="button-group text-right">
- <button type="button"
- class="btn btn-light"
- (click)="next()">
+ <button
+ type="button"
+ class="btn btn-light"
+ (click)="next()"
+ >
<ng-container>{{ actionLabels.NEXT }}</ng-container>
</button>
</div>
<!-- Preview step -->
<div *ngSwitchCase="2">
- <form name="previewForm"
- #frm="ngForm"
- [formGroup]="previewForm"
- novalidate>
+ <form
+ name="previewForm"
+ #frm="ngForm"
+ [formGroup]="previewForm"
+ novalidate
+ >
<div class="card">
- <div class="card-header"
- i18n>Step {{ step }} of 2: Telemetry report preview</div>
+ <div
+ class="card-header"
+ i18n
+ >
+ Step {{ step }} of 2: Telemetry report preview
+ </div>
<div class="card-body">
<!-- Telemetry report ID -->
<div class="form-group row">
- <label i18n
- for="reportId"
- class="cd-col-form-label">Report ID
- <cd-helper i18n-html
- html="A randomized UUID to identify a particular cluster over the course of several telemetry reports.">
- </cd-helper>
+ <label
+ i18n
+ for="reportId"
+ class="cd-col-form-label"
+ >Report ID
+ <cd-helper
+ i18n-html
+ html="A randomized UUID to identify a particular cluster over the course of several telemetry reports."
+ >
+ </cd-helper>
</label>
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="reportId"
- formControlName="reportId"
- readonly>
+ <input
+ class="form-control"
+ type="text"
+ id="reportId"
+ formControlName="reportId"
+ readonly
+ />
</div>
</div>
<!-- Telemetry report -->
<div class="form-group row">
- <label i18n
- for="report"
- class="cd-col-form-label">Report preview
- <cd-helper i18n-html
- html="The actual telemetry data that will be submitted."><em>Note: Please select 'Download' to
- view the full report, including metrics from the perf channel.</em>
+ <label
+ i18n
+ for="report"
+ class="cd-col-form-label"
+ >Report preview
+ <cd-helper
+ i18n-html
+ html="The actual telemetry data that will be submitted."
+ ><em
+ >Note: Please select 'Download' to view the full report, including metrics from
+ the perf channel.</em
+ >
</cd-helper>
</label>
<div class="cd-col-form-input">
- <textarea class="form-control"
- id="report"
- formControlName="report"
- rows="15"
- readonly></textarea>
+ <textarea
+ class="form-control"
+ id="report"
+ formControlName="report"
+ rows="15"
+ readonly
+ ></textarea>
</div>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
- <div class="btn-group"
- role="group">
- <cd-download-button [objectItem]="report"
- fileName="telemetry_report">
+ <div
+ class="btn-group"
+ role="group"
+ >
+ <cd-download-button
+ [objectItem]="report"
+ fileName="telemetry_report"
+ >
</cd-download-button>
- <cd-copy-2-clipboard-button source="report">
- </cd-copy-2-clipboard-button>
+ <cd-copy-2-clipboard-button source="report"> </cd-copy-2-clipboard-button>
</div>
</div>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="licenseAgrmt"
- name="licenseAgrmt"
- formControlName="licenseAgrmt">
- <label class="custom-control-label"
- for="licenseAgrmt"
- i18n>I agree to my telemetry data being submitted under the <a href="https://cdla.io/sharing-1-0/">Community Data License Agreement - Sharing - Version 1.0</a></label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="licenseAgrmt"
+ name="licenseAgrmt"
+ formControlName="licenseAgrmt"
+ />
+ <label
+ class="custom-control-label"
+ for="licenseAgrmt"
+ i18n
+ >I agree to my telemetry data being submitted under the
+ <a href="https://cdla.io/sharing-1-0/"
+ >Community Data License Agreement - Sharing - Version 1.0</a
+ ></label
+ >
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="button-group text-right">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- (backActionEvent)="back()"
- [form]="previewForm"
- [submitText]="actionLabels.UPDATE"
- [cancelText]="actionLabels.BACK"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ (backActionEvent)="back()"
+ [form]="previewForm"
+ [submitText]="actionLabels.UPDATE"
+ [cancelText]="actionLabels.BACK"
+ ></cd-form-button-panel>
</div>
</div>
</div>
</ng-container>
<ng-container class="modal-content">
- <form name="upgradeForm"
- class="form"
- #formDir="ngForm"
- [formGroup]="upgradeForm"
- novalidate>
+ <form
+ name="upgradeForm"
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="upgradeForm"
+ novalidate
+ >
<div class="modal-body">
- <cd-alert-panel type="warning"
- spacingClass="mb-3"
- *ngIf="showImageField"
- i18n>Make sure to put the correct image. Passing an incorrect image can lead the cluster into an undesired state.</cd-alert-panel>
- <div *ngIf="versions"
- class="form-group row">
- <label class="cd-col-form-label"
- [ngClass]="{'required': !showImageField}"
- for="availableVersions"
- i18n>New Version</label>
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-3"
+ *ngIf="showImageField"
+ i18n
+ >Make sure to put the correct image. Passing an incorrect image can lead the cluster into
+ an undesired state.</cd-alert-panel
+ >
+ <div
+ *ngIf="versions"
+ class="form-group row"
+ >
+ <label
+ class="cd-col-form-label"
+ [ngClass]="{ required: !showImageField }"
+ for="availableVersions"
+ i18n
+ >New Version</label
+ >
<div class="cd-col-form-input">
- <select id="availableVersions"
- name="availableVersions"
- class="form-select"
- formControlName="availableVersions">
- <option *ngIf="versions === null"
- ngValue="null"
- i18n>Loading...</option>
- <option *ngIf="versions !== null && versions.length === 0"
- [ngValue]="null"
- i18n>-- No version available --</option>
- <option *ngIf="versions !== null && versions.length > 0"
- [ngValue]="null"
- i18n>-- Select a version --</option>
- <option *ngFor="let version of versions"
- [value]="version">{{ version }}</option>
+ <select
+ id="availableVersions"
+ name="availableVersions"
+ class="form-select"
+ formControlName="availableVersions"
+ >
+ <option
+ *ngIf="versions === null"
+ ngValue="null"
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="versions !== null && versions.length === 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- No version available --
+ </option>
+ <option
+ *ngIf="versions !== null && versions.length > 0"
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a version --
+ </option>
+ <option
+ *ngFor="let version of versions"
+ [value]="version"
+ >
+ {{ version }}
+ </option>
</select>
- <span class="invalid-feedback"
- *ngIf="upgradeForm.showError('availableVersions', formDir, 'required')"
- i18n>This field is required!</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="upgradeForm.showError('availableVersions', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
- <div *ngIf="versions"
- class="form-group row">
+ <div
+ *ngIf="versions"
+ class="form-group row"
+ >
<div class="cd-col-form-offset">
<div class="custom-control custom-checkbox">
- <input type="checkbox"
- class="custom-control-input"
- id="useImage"
- name="useImage"
- formControlName="useImage"
- (click)="useImage()">
- <label class="custom-control-label"
- for="useImage"
- i18n>Use image</label>
+ <input
+ type="checkbox"
+ class="custom-control-input"
+ id="useImage"
+ name="useImage"
+ formControlName="useImage"
+ (click)="useImage()"
+ />
+ <label
+ class="custom-control-label"
+ for="useImage"
+ i18n
+ >Use image</label
+ >
</div>
</div>
</div>
<!-- Custom image name input-->
- <div class="form-group row"
- *ngIf="showImageField || !versions">
- <label class="cd-col-form-label required"
- for="customImageName"
- i18n>Image</label>
+ <div
+ class="form-group row"
+ *ngIf="showImageField || !versions"
+ >
+ <label
+ class="cd-col-form-label required"
+ for="customImageName"
+ i18n
+ >Image</label
+ >
<div class="cd-col-form-input">
- <input type="text"
- class="form-control"
- id="customImageName"
- name="customImageName"
- formControlName="customImageName">
- <span class="invalid-feedback"
- *ngIf="upgradeForm.showError('customImageName', formDir, 'required')"
- i18n>This field is required!</span>
+ <input
+ type="text"
+ class="form-control"
+ id="customImageName"
+ name="customImageName"
+ formControlName="customImageName"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="upgradeForm.showError('customImageName', formDir, 'required')"
+ i18n
+ >This field is required!</span
+ >
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="startUpgrade()"
- [form]="upgradeForm"
- [submitText]="actionLabels.START_UPGRADE"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="startUpgrade()"
+ [form]="upgradeForm"
+ [submitText]="actionLabels.START_UPGRADE"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<div *ngIf="upgradeStatus$ | async as upgradeStatus">
<ng-container>
- <cd-progress [value]="executingTask?.progress"
- [label]="executingTask?.description"
- [status]="upgradeStatus.in_progress ? 'in-progress' : 'paused'"
- [subLabel]="upgradeStatus.which"
- [completedItems]="upgradeStatus.services_complete"
- [actionName]="'upgrading'"
- [helperText]="upgradeStatus.progress"
- [footerText]="upgradeStatus.message"
- [isPaused]="upgradeStatus.is_paused">
+ <cd-progress
+ [value]="executingTask?.progress"
+ [label]="executingTask?.description"
+ [status]="upgradeStatus.in_progress ? 'in-progress' : 'paused'"
+ [subLabel]="upgradeStatus.which"
+ [completedItems]="upgradeStatus.services_complete"
+ [actionName]="'upgrading'"
+ [helperText]="upgradeStatus.progress"
+ [footerText]="upgradeStatus.message"
+ [isPaused]="upgradeStatus.is_paused"
+ >
</cd-progress>
<div class="text-center mt-3">
- <button class="btn btn-light"
- aria-label="Go back"
- routerLink="/upgrade"
- type="button"
- i18n>Back</button>
- <button *ngIf="upgradeStatus.in_progress && !upgradeStatus.is_paused"
- (click)="pauseUpgrade()"
- class="btn btn-light m-2"
- aria-label="Pause Upgrade"
- type="button"
- i18n>Pause</button>
- <button *ngIf="upgradeStatus.in_progress && upgradeStatus.is_paused"
- (click)="resumeUpgrade()"
- class="btn btn-light m-2"
- aria-label="Resume Upgrade"
- type="button"
- i18n>Resume</button>
- <button *ngIf="upgradeStatus.in_progress"
- (click)="stopUpgradeModal()"
- class="btn btn-danger"
- aria-label="Stop Upgrade"
- type="button"
- i18n>Stop</button>
+ <button
+ class="btn btn-light"
+ aria-label="Go back"
+ routerLink="/upgrade"
+ type="button"
+ i18n
+ >
+ Back
+ </button>
+ <button
+ *ngIf="upgradeStatus.in_progress && !upgradeStatus.is_paused"
+ (click)="pauseUpgrade()"
+ class="btn btn-light m-2"
+ aria-label="Pause Upgrade"
+ type="button"
+ i18n
+ >
+ Pause
+ </button>
+ <button
+ *ngIf="upgradeStatus.in_progress && upgradeStatus.is_paused"
+ (click)="resumeUpgrade()"
+ class="btn btn-light m-2"
+ aria-label="Resume Upgrade"
+ type="button"
+ i18n
+ >
+ Resume
+ </button>
+ <button
+ *ngIf="upgradeStatus.in_progress"
+ (click)="stopUpgradeModal()"
+ class="btn btn-danger"
+ aria-label="Stop Upgrade"
+ type="button"
+ i18n
+ >
+ Stop
+ </button>
</div>
</ng-container>
</div>
-<legend class="cd-header"
- i18n>Cluster logs</legend>
- <cd-logs [showAuditLogs]="false"
- [showDaemonLogs]="false"
- [showNavLinks]="false"
- [showFilterTools]="false"
- [showDownloadCopyButton]="false"
- defaultTab="cluster-logs"
- ></cd-logs>
+<legend
+ class="cd-header"
+ i18n
+>
+ Cluster logs
+</legend>
+<cd-logs
+ [showAuditLogs]="false"
+ [showDaemonLogs]="false"
+ [showNavLinks]="false"
+ [showFilterTools]="false"
+ [showDownloadCopyButton]="false"
+ defaultTab="cluster-logs"
+></cd-logs>
-<main *cdScope="'configOpt'"
- cdsGrid
- [fullWidth]="true"
- [narrow]="true"
- class="cds-mt-5">
+<main
+ *cdScope="'configOpt'"
+ cdsGrid
+ [fullWidth]="true"
+ [narrow]="true"
+ class="cds-mt-5"
+>
<ng-container *ngIf="healthData$ | async as healthData">
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 16}">
- <cds-tile aria-label="Cluster Information"
- i18n-aria-label>
- <h4 class="cds--type-heading-03 tile-title"
- i18n>Cluster Information</h4>
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
+ <cds-tile
+ aria-label="Cluster Information"
+ i18n-aria-label
+ >
+ <h4
+ class="cds--type-heading-03 tile-title"
+ i18n
+ >
+ Cluster Information
+ </h4>
<div class="details-grid">
<!-- Current Version -->
<div class="detail-item">
- <span class="cds--type-label-01"
- i18n>Current Version</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Current Version</span
+ >
<span class="cds--type-body-compact-01">{{ version }}</span>
</div>
<!-- New Version / Upgrade Status -->
- <div class="detail-item"
- *ngIf="upgradeStatus$ | async as status"
- id="newVersionAvailable">
- <span class="cds--type-label-01"
- i18n>New Version</span>
+ <div
+ class="detail-item"
+ *ngIf="upgradeStatus$ | async as status"
+ id="newVersionAvailable"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >New Version</span
+ >
<ng-container *ngIf="status.in_progress; else upgradeStatusTpl">
- <div cdsStack
- orientation="vertical"
- gap="2">
- <span class="cds--type-body-compact-01"
- i18n
- *ngIf="status.is_paused; else inProgress">
+ <div
+ cdsStack
+ orientation="vertical"
+ gap="2"
+ >
+ <span
+ class="cds--type-body-compact-01"
+ i18n
+ *ngIf="status.is_paused; else inProgress"
+ >
<cds-inline-loading></cds-inline-loading>
- Upgrade is paused {{executingTasks?.progress}}%</span>
- <a class="cds--link"
- routerLink="/upgrade/progress"
- i18n>View Details...</a>
+ Upgrade is paused {{ executingTasks?.progress }}%</span
+ >
+ <a
+ class="cds--link"
+ routerLink="/upgrade/progress"
+ i18n
+ >View Details...</a
+ >
</div>
<ng-template #inProgress>
- <span class="cds--type-body-compact-01"
- i18n>
+ <span
+ class="cds--type-body-compact-01"
+ i18n
+ >
<cds-inline-loading></cds-inline-loading>
- Upgrading {{executingTasks?.progress}}%
+ Upgrading {{ executingTasks?.progress }}%
</span>
</ng-template>
</ng-container>
</div>
<!-- Cluster Status -->
- <div class="detail-item"
- id="clusterStatus">
- <span class="cds--type-label-01"
- i18n>Cluster Status</span>
+ <div
+ class="detail-item"
+ id="clusterStatus"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Cluster Status</span
+ >
<ng-container *ngIf="healthData.health?.status !== 'HEALTH_OK'; else healthOk">
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/overview"
- [ngStyle]="healthData.health.status | healthColor">
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/overview"
+ [ngStyle]="healthData.health.status | healthColor"
+ >
{{ healthData.health.status | healthLabel | titlecase }}
<cd-icon type="warning"></cd-icon>
</a>
</ng-container>
<ng-template #healthOk>
- <span class="cds--type-body-compact-01"
- [ngStyle]="healthData.health.status | healthColor">
+ <span
+ class="cds--type-body-compact-01"
+ [ngStyle]="healthData.health.status | healthColor"
+ >
{{ healthData.health.status | healthLabel | titlecase }}
</span>
</ng-template>
</div>
<!-- MGR Count -->
- <div class="detail-item"
- id="mgrCount">
- <span class="cds--type-label-01"
- i18n>MGR Count</span>
+ <div
+ class="detail-item"
+ id="mgrCount"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >MGR Count</span
+ >
<span class="cds--type-body-compact-01">
- <cd-icon type="success"
- *ngIf="(healthData.mgr_map | mgrSummary)?.total > 1; else warningIcon">
+ <cd-icon
+ type="success"
+ *ngIf="(healthData.mgr_map | mgrSummary)?.total > 1; else warningIcon"
+ >
</cd-icon>
{{ (healthData.mgr_map | mgrSummary)?.total }}
</span>
</div>
<!-- Cluster FSID -->
- <div class="detail-item"
- *ngIf="fsid$ | async as fsid">
- <span class="cds--type-label-01"
- i18n>Cluster FSID</span>
+ <div
+ class="detail-item"
+ *ngIf="fsid$ | async as fsid"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Cluster FSID</span
+ >
<span class="cds--type-body-compact-01">{{ fsid }}</span>
</div>
<!-- Release Image -->
<div class="detail-item">
- <span class="cds--type-label-01"
- i18n>Release Image</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Release Image</span
+ >
<ng-container *ngIf="info$ | async as info; else releaseImageError">
<span class="cds--type-body-compact-01">{{ info.image }}</span>
</ng-container>
<ng-template #releaseImageError>
- <span class="cds--type-body-compact-01"
- *ngIf="!errorMessage; else showError">
+ <span
+ class="cds--type-body-compact-01"
+ *ngIf="!errorMessage; else showError"
+ >
<cds-inline-loading></cds-inline-loading>
<span i18n>Loading...</span>
</span>
<!-- Registry -->
<div class="detail-item">
- <span class="cds--type-label-01"
- i18n>Registry</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Registry</span
+ >
<ng-container *ngIf="info$ | async as info; else registryError">
<span class="cds--type-body-compact-01">{{ info.registry }}</span>
</ng-container>
<ng-template #registryError>
- <span class="cds--type-body-compact-01"
- *ngIf="!errorMessage; else showRegistryError">
+ <span
+ class="cds--type-body-compact-01"
+ *ngIf="!errorMessage; else showRegistryError"
+ >
<cds-inline-loading></cds-inline-loading>
<span i18n>Loading...</span>
</span>
</div>
</div>
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 16}">
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
<cds-tile *ngIf="daemons$ | async as daemons">
- <h4 class="cds--type-heading-03 tile-title"
- i18n>Daemon Versions</h4>
+ <h4
+ class="cds--type-heading-03 tile-title"
+ i18n
+ >
+ Daemon Versions
+ </h4>
<div>
- <cd-table #daemonsTable
- [data]="daemons"
- selectionType="single"
- [columns]="columns"
- columnMode="flex"
- [limit]="5">
+ <cd-table
+ #daemonsTable
+ [data]="daemons"
+ selectionType="single"
+ [columns]="columns"
+ columnMode="flex"
+ [limit]="5"
+ >
</cd-table>
</div>
</cds-tile>
</div>
</div>
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 16}">
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
<cds-tile>
- <h4 class="cds--type-heading-03 tile-title"
- i18n>Cluster Logs</h4>
- <cd-logs [showAuditLogs]="false"
- [showDaemonLogs]="false"
- [showNavLinks]="false"
- [showFilterTools]="false"
- [showDownloadCopyButton]="false"
- defaultTab="cluster-logs"></cd-logs>
+ <h4
+ class="cds--type-heading-03 tile-title"
+ i18n
+ >
+ Cluster Logs
+ </h4>
+ <cd-logs
+ [showAuditLogs]="false"
+ [showDaemonLogs]="false"
+ [showNavLinks]="false"
+ [showFilterTools]="false"
+ [showDownloadCopyButton]="false"
+ defaultTab="cluster-logs"
+ ></cd-logs>
</cds-tile>
</div>
</div>
<ng-template #upgradeStatusTpl>
- <div cdsStack
- orientation="vertical"
- gap="4"
- class="cds-mt-3"
- *ngIf="info$ | async as info; else checkingForUpgradeStatus">
+ <div
+ cdsStack
+ orientation="vertical"
+ gap="4"
+ class="cds-mt-3"
+ *ngIf="info$ | async as info; else checkingForUpgradeStatus"
+ >
<ng-container *ngIf="info.versions.length > 0; else noUpgradesAvailable">
- <div [cdsTip]="(healthData.mgr_map | mgrSummary)?.total <= 1 ? 'To upgrade, you need minimum 2 mgr daemons.' : ''"
- i18n-cdsTip>
- <button cdsButton="primary"
- class="cds-mt-3"
- id="upgrade"
- aria-label="Upgrade now"
- (click)="upgradeNow(info.versions[info.versions.length - 1])"
- [disabled]="(healthData.mgr_map | mgrSummary)?.total <= 1"
- type="button"
- i18n>Upgrade to {{ info.versions[info.versions.length - 1] }}</button>
+ <div
+ [cdsTip]="
+ (healthData.mgr_map | mgrSummary)?.total <= 1
+ ? 'To upgrade, you need minimum 2 mgr daemons.'
+ : ''
+ "
+ i18n-cdsTip
+ >
+ <button
+ cdsButton="primary"
+ class="cds-mt-3"
+ id="upgrade"
+ aria-label="Upgrade now"
+ (click)="upgradeNow(info.versions[info.versions.length - 1])"
+ [disabled]="(healthData.mgr_map | mgrSummary)?.total <= 1"
+ type="button"
+ i18n
+ >
+ Upgrade to {{ info.versions[info.versions.length - 1] }}
+ </button>
</div>
- <a class="cds--link cds-mb-3"
- (click)="startUpgradeModal()"
- tabindex="0"
- (keydown.enter)="startUpgradeModal()"
- i18n>Select another version...</a>
+ <a
+ class="cds--link cds-mb-3"
+ (click)="startUpgradeModal()"
+ tabindex="0"
+ (keydown.enter)="startUpgradeModal()"
+ i18n
+ >Select another version...</a
+ >
</ng-container>
</div>
</ng-template>
</main>
<ng-template #noUpgradesAvailable>
- <span class="cds--type-body-compact-01"
- id="no-upgrades-available"
- i18n>
+ <span
+ class="cds--type-body-compact-01"
+ id="no-upgrades-available"
+ i18n
+ >
<cd-icon type="success"></cd-icon>
Cluster is up-to-date
</span>
- <a class="cds--link cds-mb-3"
- (click)="startUpgradeModal()"
- tabindex="0"
- (keydown.enter)="startUpgradeModal()"
- i18n>Upgrade using custom image...</a>
+ <a
+ class="cds--link cds-mb-3"
+ (click)="startUpgradeModal()"
+ tabindex="0"
+ (keydown.enter)="startUpgradeModal()"
+ i18n
+ >Upgrade using custom image...</a
+ >
</ng-template>
<ng-template #warningIcon>
- <cd-icon type="warning"
- title="To upgrade, you need minimum 2 mgr daemons.">
+ <cd-icon
+ type="warning"
+ title="To upgrade, you need minimum 2 mgr daemons."
+ >
</cd-icon>
</ng-template>
<ng-template #checkingForUpgradeStatus>
- <div cdsStack
- orientation="vertical"
- gap="4"
- class="cds-mt-3"
- *ngIf="!errorMessage; else upgradeStatusError">
- <button cdsButton="primary"
- class="cds-mt-3 cds-mb-5"
- id="upgrade"
- aria-label="Upgrade now"
- [disabled]="true"
- type="button"
- i18n>Checking for upgrades
+ <div
+ cdsStack
+ orientation="vertical"
+ gap="4"
+ class="cds-mt-3"
+ *ngIf="!errorMessage; else upgradeStatusError"
+ >
+ <button
+ cdsButton="primary"
+ class="cds-mt-3 cds-mb-5"
+ id="upgrade"
+ aria-label="Upgrade now"
+ [disabled]="true"
+ type="button"
+ i18n
+ >
+ Checking for upgrades
<cds-inline-loading></cds-inline-loading>
</button>
</div>
</ng-template>
<ng-template #loadingDetails>
- <div class="w-50"
- *ngIf="!errorMessage; else upgradeInfoError">
- <span class="text-info justify-content-center align-items-center"
- i18n>Fetching registry information
+ <div
+ class="w-50"
+ *ngIf="!errorMessage; else upgradeInfoError"
+ >
+ <span
+ class="text-info justify-content-center align-items-center"
+ i18n
+ >Fetching registry information
<cds-inline-loading></cds-inline-loading>
</span>
</div>
</ng-template>
<ng-template #upgradeStatusError>
- <div cdsStack
- orientation="vertical"
- gap="4"
- class="cds-mt-3 cds-mb-5">
- <span class="cds--type-body-compact-01"
- id="upgrade-status-error"
- i18n>
+ <div
+ cdsStack
+ orientation="vertical"
+ gap="4"
+ class="cds-mt-3 cds-mb-5"
+ >
+ <span
+ class="cds--type-body-compact-01"
+ id="upgrade-status-error"
+ i18n
+ >
<cd-icon type="danger"></cd-icon>
{{ errorMessage }}
</span>
- <a class="cds--link cds-mb-3"
- (click)="startUpgradeModal()"
- tabindex="0"
- (keydown.enter)="startUpgradeModal()"
- i18n>Upgrade using custom image...</a>
+ <a
+ class="cds--link cds-mb-3"
+ (click)="startUpgradeModal()"
+ tabindex="0"
+ (keydown.enter)="startUpgradeModal()"
+ i18n
+ >Upgrade using custom image...</a
+ >
</div>
</ng-template>
<ng-template #upgradeProgress>
- <div cdsStack
- orientation="vertical"
- gap="4"
- class="cds-mt-3">
- <h5 class="cds--type-heading-compact-01"
- i18n>
+ <div
+ cdsStack
+ orientation="vertical"
+ gap="4"
+ class="cds-mt-3"
+ >
+ <h5
+ class="cds--type-heading-compact-01"
+ i18n
+ >
<cds-inline-loading></cds-inline-loading>
- Upgrade in progress {{executingTasks?.progress}}%</h5>
- <a class="cds--link cds-mb-3"
- routerLink="/upgrade/progress"
- i18n>View Details...</a>
+ Upgrade in progress {{ executingTasks?.progress }}%
+ </h5>
+ <a
+ class="cds--link cds-mb-3"
+ routerLink="/upgrade/progress"
+ i18n
+ >View Details...</a
+ >
</div>
</ng-template>
<div class="row mt-2">
<div class="col-3 d-flex flex-column align-self-center">
- <br>
- <b class="chartTitle pb-2"
- i18n>{{ chartTitle }}</b>
- <div *ngFor="let data of currentChartData.dataset"
- i18n>
- <div *ngIf="data.data.length !== 0"
- class="d-inline-flex align-items-center gap-1">
- <div class="box"
- [style.background-color]="data.pointBackgroundColor">
- </div>
+ <br />
+ <b
+ class="chartTitle pb-2"
+ i18n
+ >{{ chartTitle }}</b
+ >
+ <div
+ *ngFor="let data of currentChartData.dataset"
+ i18n
+ >
+ <div
+ *ngIf="data.data.length !== 0"
+ class="d-inline-flex align-items-center gap-1"
+ >
+ <div
+ class="box"
+ [style.background-color]="data.pointBackgroundColor"
+ ></div>
<ng-container *ngIf="!chartTitle.includes(data.label)">
- <span [ngClass]="{'d-inline-block text-truncate': truncateLabel}"
- [ngStyle]="{'width': truncateLabel ? '10rem' : 'auto'}"
- [title]="data.label">{{ data.label }}</span>:
+ <span
+ [ngClass]="{ 'd-inline-block text-truncate': truncateLabel }"
+ [ngStyle]="{ width: truncateLabel ? '10rem' : 'auto' }"
+ [title]="data.label"
+ >{{ data.label }}</span
+ >:
</ng-container>
<span>{{ data?.currentData || 'N/A' }} {{ data?.currentDataUnits }}</span>
<div *ngIf="maxValue && data.currentData">
</div>
<div class="col-9 d-flex flex-column">
- <div [ngClass]="{'chart mt-3': !isMultiCluster, 'mt-3': isMultiCluster}">
- <canvas baseChart
- [datasets]="chartData.dataset"
- [options]="options"
- [type]="'line'"
- [plugins]="chartAreaBorderPlugin">
+ <div [ngClass]="{ 'chart mt-3': !isMultiCluster, 'mt-3': isMultiCluster }">
+ <canvas
+ baseChart
+ [datasets]="chartData.dataset"
+ [options]="options"
+ [type]="'line'"
+ [plugins]="chartAreaBorderPlugin"
+ >
</canvas>
</div>
</div>
<div class="chart-container d-flex align-items-center justify-content-center">
- <canvas baseChart
- #chartCanvas
- [datasets]="chartConfig.dataset"
- [type]="chartConfig.chartType"
- [options]="chartConfig.options"
- [labels]="chartConfig.labels"
- [plugins]="doughnutChartPlugins"
- class="chart-canvas">
+ <canvas
+ baseChart
+ #chartCanvas
+ [datasets]="chartConfig.dataset"
+ [type]="chartConfig.chartType"
+ [options]="chartConfig.options"
+ [labels]="chartConfig.labels"
+ [plugins]="doughnutChartPlugins"
+ class="chart-canvas"
+ >
</canvas>
- <div class="chartjs-tooltip"
- #chartTooltip>
+ <div
+ class="chartjs-tooltip"
+ #chartTooltip
+ >
<table></table>
</div>
</div>
<div class="timeSelector">
- <select id="timepicker"
- name="timepicker"
- [(ngModel)]="time"
- (ngModelChange)="emitTime()"
- class="form-select">
- <option *ngFor="let key of times"
- [ngValue]="key.value">{{ key.name }}
+ <select
+ id="timepicker"
+ name="timepicker"
+ [(ngModel)]="time"
+ (ngModelChange)="emitTime()"
+ class="form-select"
+ >
+ <option
+ *ngFor="let key of times"
+ [ngValue]="key.value"
+ >
+ {{ key.name }}
</option>
</select>
</div>
- <ng-container *ngIf="!!selection">
- <legend
- i18n
- >
- {{title | titlecase}}
- <cd-help-text>
- Lists shares for a cluster
- </cd-help-text>
+<ng-container *ngIf="!!selection">
+ <legend i18n>
+ {{ title | titlecase }}
+ <cd-help-text> Lists shares for a cluster </cd-help-text>
</legend>
<cd-nfs-list [clusterId]="selection.name"></cd-nfs-list>
- </ng-container>
+</ng-container>
- <ng-container *ngIf="orchStatus?.available && clusters$ | async as clusters">
- <cd-table [autoReload]="true"
- [data]="clusters"
- columnMode="flex"
- [columns]="columns"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (fetchData)="loadData()"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [selection]="selection"
- [permission]="permission"
- [tableActions]="tableActions"></cd-table-actions>
- <cd-nfs-cluster-details *cdTableDetail
- [selection]="expandedRow"></cd-nfs-cluster-details>
+<ng-container *ngIf="orchStatus?.available && clusters$ | async as clusters">
+ <cd-table
+ [autoReload]="true"
+ [data]="clusters"
+ columnMode="flex"
+ [columns]="columns"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (fetchData)="loadData()"
+ (updateSelection)="updateSelection($event)"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [selection]="selection"
+ [permission]="permission"
+ [tableActions]="tableActions"
+ ></cd-table-actions>
+ <cd-nfs-cluster-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ ></cd-nfs-cluster-details>
</cd-table>
- </ng-container>
+</ng-container>
- <ng-template
+<ng-template
#virtualIpTpl
let-row="data.row"
- >
+>
<span *ngIf="row.virtual_ip || row.port">
- <cds-tag size="md">
- {{ row.virtual_ip }}:{{row.port}}
- </cds-tag>
+ <cds-tag size="md"> {{ row.virtual_ip }}:{{ row.port }} </cds-tag>
</span>
- </ng-template>
+</ng-template>
- <ng-template
+<ng-template
#ipAddrTpl
let-backends="data.value"
- >
+>
<span *ngFor="let backend of backends">
- <span *ngIf="backend.ip || backend.port">
- <cds-tag size="md">
- {{ backend.ip }}:{{backend.port}}
- </cds-tag>
- </span>
+ <span *ngIf="backend.ip || backend.port">
+ <cds-tag size="md"> {{ backend.ip }}:{{ backend.port }} </cds-tag>
+ </span>
</span>
- </ng-template>
+</ng-template>
- <ng-template #hostnameTpl
- let-backends="data.value">
+<ng-template
+ #hostnameTpl
+ let-backends="data.value"
+>
<span *ngFor="let backend of backends">
<span *ngIf="backend.hostname">
- <cds-tag size="md">{{backend.hostname }}</cds-tag>
+ <cds-tag size="md">{{ backend.hostname }}</cds-tag>
</span>
</span>
- </ng-template>
+</ng-template>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="nfs-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="nfs-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [data]="data">
- </cd-table-key-value>
+ <cd-table-key-value [data]="data"> </cd-table-key-value>
</ng-template>
</ng-container>
<ng-container ngbNavItem="clients">
- <a ngbNavLink
- i18n>Clients ({{ clients.length }})</a>
+ <a
+ ngbNavLink
+ i18n
+ >Clients ({{ clients.length }})</a
+ >
<ng-template ngbNavContent>
-
- <cd-table #table
- [data]="clients"
- columnMode="flex"
- [columns]="clientsColumns"
- identifier="addresses"
- forceIdentifier="true"
- selectionType="">
+ <cd-table
+ #table
+ [data]="clients"
+ columnMode="flex"
+ [columns]="clientsColumns"
+ identifier="addresses"
+ forceIdentifier="true"
+ selectionType=""
+ >
</cd-table>
</ng-template>
</ng-container>
<div class="form-item">
- <legend class="cds--label"
- i18n>Clients</legend>
+ <legend
+ class="cds--label"
+ i18n
+ >
+ Clients
+ </legend>
- <div [formGroup]="form"
- #formDir="ngForm">
- <span *ngIf="form.get('clients').value.length === 0"
- class="no-border text-muted">
- <span class="form-text text-muted"
- i18n>Any client can access</span>
+ <div
+ [formGroup]="form"
+ #formDir="ngForm"
+ >
+ <span
+ *ngIf="form.get('clients').value.length === 0"
+ class="no-border text-muted"
+ >
+ <span
+ class="form-text text-muted"
+ i18n
+ >Any client can access</span
+ >
</span>
<ng-container formArrayName="clients">
<div *ngFor="let item of clientsFormArray.controls; let index = index; trackBy: trackByFn">
<div [formGroup]="item">
<h6>
- Client {{ (index + 1) }}
- <cds-icon-button kind="ghost"
- size="md"
- class="float-end"
- (click)="removeClient(index)"
- data-testid="remove_client"
- data-toggle="button"
- title="Remove Client">
- <svg cdsIcon="close"
- size="32"
- class="cds--btn__icon"></svg>
+ Client {{ index + 1 }}
+ <cds-icon-button
+ kind="ghost"
+ size="md"
+ class="float-end"
+ (click)="removeClient(index)"
+ data-testid="remove_client"
+ data-toggle="button"
+ title="Remove Client"
+ >
+ <svg
+ cdsIcon="close"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</h6>
<div>
<!-- Addresses -->
<div class="form-item">
- <cds-text-label for="addresses"
- i18n
- cdRequiredField="Addresses"
- [invalid]="!item.controls['addresses'].valid && (item.controls['addresses'].dirty)"
- [invalidText]="addressesError"
- i18n-invalidText>Addresses
- <input cdsText
- name="addresses"
- id="addresses"
- formControlName="addresses"
- placeholder="e.g. 192.168.0.10, 192.168.1.0/8"
- [invalid]="!item.controls['addresses'].valid && (item.controls['addresses'].dirty)">
+ <cds-text-label
+ for="addresses"
+ i18n
+ cdRequiredField="Addresses"
+ [invalid]="!item.controls['addresses'].valid && item.controls['addresses'].dirty"
+ [invalidText]="addressesError"
+ i18n-invalidText
+ >Addresses
+ <input
+ cdsText
+ name="addresses"
+ id="addresses"
+ formControlName="addresses"
+ placeholder="e.g. 192.168.0.10, 192.168.1.0/8"
+ [invalid]="!item.controls['addresses'].valid && item.controls['addresses'].dirty"
+ />
</cds-text-label>
<ng-template #addressesError>
<span class="invalid-feedback">
- <span *ngIf="showError(index, 'addresses', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ *ngIf="showError(index, 'addresses', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
<span *ngIf="showError(index, 'addresses', formDir, 'invalidAddress')">
- <ng-container i18n>Must contain one or more comma-separated valid addresses.</ng-container>
- <br>
+ <ng-container i18n
+ >Must contain one or more comma-separated valid addresses.</ng-container
+ >
+ <br />
<ng-container i18n>For example:</ng-container> 192.168.0.10, 192.168.1.0/8
</span>
</span>
<!-- Access Type-->
<div class="form-item">
- <cds-select label="Access Type"
- for="access_type"
- formControlName="access_type"
- name="access_type"
- id="access_type"
- [helperText]="accessTypeHelper"
- i18n>Access Type
+ <cds-select
+ label="Access Type"
+ for="access_type"
+ formControlName="access_type"
+ name="access_type"
+ id="access_type"
+ [helperText]="accessTypeHelper"
+ i18n
+ >Access Type
<option value="">No Access Type</option>
- <option *ngFor="let item of nfsAccessType"
- [value]="item.value">{{ item.value }}</option>
+ <option
+ *ngFor="let item of nfsAccessType"
+ [value]="item.value"
+ >
+ {{ item.value }}
+ </option>
</cds-select>
<ng-template #accessTypeHelper>
<span *ngIf="getValue(index, 'access_type')">
<!-- Squash -->
<div class="form-group row">
- <cds-select label="Squash"
- for="squash"
- formControlName="squash"
- name="squash"
- id="squash"
- [helperText]="squashHelperTpl"
- i18n>Squash
+ <cds-select
+ label="Squash"
+ for="squash"
+ formControlName="squash"
+ name="squash"
+ id="squash"
+ [helperText]="squashHelperTpl"
+ i18n
+ >Squash
<option value="">{{ getNoSquashDescr() }}</option>
- <option *ngFor="let squash of nfsSquash"
- [value]="squash">{{ squash }}</option>
+ <option
+ *ngFor="let squash of nfsSquash"
+ [value]="squash"
+ >
+ {{ squash }}
+ </option>
</cds-select>
</div>
</div>
<div cdsRow>
<div cdsCol>
- <button cdsButton="tertiary"
- type="button"
- (click)="addClient()"
- name="add_client">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addClient()"
+ name="add_client"
+ >
<ng-container i18n>Add clients</ng-container>
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
</div>
-<div cdsCol
- [columnNumbers]="{md: 4}">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="nfsForm"
- #formDir="ngForm"
- [formGroup]="nfsForm"
- novalidate>
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+ <form
+ name="nfsForm"
+ #formDir="ngForm"
+ [formGroup]="nfsForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
<!-- cluster_id -->
<div class="form-item">
- <cds-select formControlName="cluster_id"
- name="cluster_id"
- for="cluster_id"
- label="Cluster"
- cdRequiredField="Cluster"
- id="cluster_id"
- [invalid]="nfsForm.controls.cluster_id.invalid && (nfsForm.controls.cluster_id.dirty)"
- [invalidText]="clusterError"
- [skeleton]="allClusters === null"
- [helperText]="clusterHelperText"
- i18n>
- <option *ngIf="allClusters === null"
- value="">Loading...</option>
- <option *ngIf="allClusters !== null && allClusters.length === 0"
- value="">-- No cluster available --</option>
- <option *ngIf="allClusters !== null && allClusters.length > 0"
- value="">-- Select the cluster --</option>
- <option *ngFor="let cluster of allClusters"
- [value]="cluster.cluster_id">{{ cluster.cluster_id }}</option>
+ <cds-select
+ formControlName="cluster_id"
+ name="cluster_id"
+ for="cluster_id"
+ label="Cluster"
+ cdRequiredField="Cluster"
+ id="cluster_id"
+ [invalid]="nfsForm.controls.cluster_id.invalid && nfsForm.controls.cluster_id.dirty"
+ [invalidText]="clusterError"
+ [skeleton]="allClusters === null"
+ [helperText]="clusterHelperText"
+ i18n
+ >
+ <option
+ *ngIf="allClusters === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allClusters !== null && allClusters.length === 0"
+ value=""
+ >
+ -- No cluster available --
+ </option>
+ <option
+ *ngIf="allClusters !== null && allClusters.length > 0"
+ value=""
+ >
+ -- Select the cluster --
+ </option>
+ <option
+ *ngFor="let cluster of allClusters"
+ [value]="cluster.cluster_id"
+ >
+ {{ cluster.cluster_id }}
+ </option>
</cds-select>
- <cd-alert-panel *ngIf="allClusters?.length === 0"
- type="info"
- actionName="Create"
- spacingClass="mt-2"
- (action)="(router.navigate(['/services', {outlets: {modal: ['create']}}]))"
- i18n>To create a new NFS cluster, you need to create an NFS Service.
+ <cd-alert-panel
+ *ngIf="allClusters?.length === 0"
+ type="info"
+ actionName="Create"
+ spacingClass="mt-2"
+ (action)="router.navigate(['/services', { outlets: { modal: ['create'] } }])"
+ i18n
+ >To create a new NFS cluster, you need to create an NFS Service.
</cd-alert-panel>
<ng-template #clusterHelperText>
- <span i18n>
- This is the ID of an NFS Service</span>
+ <span i18n> This is the ID of an NFS Service</span>
</ng-template>
<ng-template #clusterError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('cluster_id', formDir, 'required') || allClusters?.length === 0"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ nfsForm.showError('cluster_id', formDir, 'required') || allClusters?.length === 0
+ "
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- RGW Share Type -->
- <div *ngIf="storageBackend === 'RGW' && !isEdit"
- class="form-item">
- <cds-select formControlName="rgw_export_type"
- name="rgw_export_type"
- (valueChange)="onExportTypeChange()"
- label="Type">
- <option value="bucket"
- i18n>Bucket</option>
- <option value="user"
- i18n>User</option>
+ <div
+ *ngIf="storageBackend === 'RGW' && !isEdit"
+ class="form-item"
+ >
+ <cds-select
+ formControlName="rgw_export_type"
+ name="rgw_export_type"
+ (valueChange)="onExportTypeChange()"
+ label="Type"
+ >
+ <option
+ value="bucket"
+ i18n
+ >
+ Bucket
+ </option>
+ <option
+ value="user"
+ i18n
+ >
+ User
+ </option>
</cds-select>
</div>
<!-- FSAL -->
<div formGroupName="fsal">
<!-- CephFS Volume -->
- <div class="form-item"
- *ngIf="storageBackend === 'CEPH'">
- <cds-select formControlName="fs_name"
- name="fs_name"
- for="fs_name"
- label="Volume"
- cdRequiredField="Volume"
- id="fs_name"
- (change)="volumeChangeHandler()"
- [invalid]="nfsForm.controls.fsal.controls.fs_name.invalid && (nfsForm.controls.fsal.controls.fs_name.dirty)"
- [invalidText]="fsNameError"
- [skeleton]="allFsNames === null"
- i18n>
- <option *ngIf="allFsNames === null"
- value="">Loading...</option>
- <option *ngIf="allFsNames !== null && allFsNames.length === 0"
- value="">-- No CephFS filesystem available --</option>
- <option *ngIf="allFsNames !== null && allFsNames.length > 0"
- value="">-- Select the CephFS filesystem --</option>
- <option *ngFor="let filesystem of allFsNames"
- [value]="filesystem.name">{{ filesystem.name }}</option>
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'CEPH'"
+ >
+ <cds-select
+ formControlName="fs_name"
+ name="fs_name"
+ for="fs_name"
+ label="Volume"
+ cdRequiredField="Volume"
+ id="fs_name"
+ (change)="volumeChangeHandler()"
+ [invalid]="
+ nfsForm.controls.fsal.controls.fs_name.invalid &&
+ nfsForm.controls.fsal.controls.fs_name.dirty
+ "
+ [invalidText]="fsNameError"
+ [skeleton]="allFsNames === null"
+ i18n
+ >
+ <option
+ *ngIf="allFsNames === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allFsNames !== null && allFsNames.length === 0"
+ value=""
+ >
+ -- No CephFS filesystem available --
+ </option>
+ <option
+ *ngIf="allFsNames !== null && allFsNames.length > 0"
+ value=""
+ >
+ -- Select the CephFS filesystem --
+ </option>
+ <option
+ *ngFor="let filesystem of allFsNames"
+ [value]="filesystem.name"
+ >
+ {{ filesystem.name }}
+ </option>
</cds-select>
<ng-template #fsNameError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('fs_name', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('fs_name', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- RGW User -->
- <div class="form-item"
- *ngIf="storageBackend === 'RGW' && nfsForm.getValue('rgw_export_type') === 'user'">
- <cds-select formControlName="user_id"
- name="user_id"
- for="user_id"
- label="User"
- cdRequiredField="User"
- id="user_id"
- [invalid]="nfsForm.controls.fsal.controls.user_id.invalid && (nfsForm.controls.fsal.controls.user_id.dirty)"
- [invalidText]="userIdError"
- [skeleton]="allRGWUsers === null"
- i18n>
- <option *ngIf="allRGWUsers === null"
- value="">Loading...</option>
- <option *ngIf="allRGWUsers !== null && allRGWUsers.length === 0"
- value="">-- No RGW User available --</option>
- <option *ngIf="allRGWUsers !== null && allRGWUsers.length > 0"
- value="">-- Select the RGW User --</option>
- <option *ngFor="let user of allRGWUsers"
- [value]="user.user_id">{{ user.user_id }}</option>
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'RGW' && nfsForm.getValue('rgw_export_type') === 'user'"
+ >
+ <cds-select
+ formControlName="user_id"
+ name="user_id"
+ for="user_id"
+ label="User"
+ cdRequiredField="User"
+ id="user_id"
+ [invalid]="
+ nfsForm.controls.fsal.controls.user_id.invalid &&
+ nfsForm.controls.fsal.controls.user_id.dirty
+ "
+ [invalidText]="userIdError"
+ [skeleton]="allRGWUsers === null"
+ i18n
+ >
+ <option
+ *ngIf="allRGWUsers === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allRGWUsers !== null && allRGWUsers.length === 0"
+ value=""
+ >
+ -- No RGW User available --
+ </option>
+ <option
+ *ngIf="allRGWUsers !== null && allRGWUsers.length > 0"
+ value=""
+ >
+ -- Select the RGW User --
+ </option>
+ <option
+ *ngFor="let user of allRGWUsers"
+ [value]="user.user_id"
+ >
+ {{ user.user_id }}
+ </option>
</cds-select>
<ng-template #userIdError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('user_id', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('user_id', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</div>
<!-- Security Label -->
- <div class="form-item"
- *ngIf="storageBackend === 'CEPH'">
- <cds-checkbox formControlName="security_label"
- name="security_label"
- id="security_label"
- i18n>Enable security label</cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'CEPH'"
+ >
+ <cds-checkbox
+ formControlName="security_label"
+ name="security_label"
+ id="security_label"
+ i18n
+ >Enable security label</cds-checkbox
+ >
</div>
- <div class="form-item"
- *ngIf="nfsForm.getValue('security_label')">
- <cds-text-label for="sec_label_xattr"
- [invalid]="nfsForm.controls.sec_label_xattr.invalid && (nfsForm.controls.sec_label_xattr.dirty)"
- [invalidText]="secLabelError"
- i18n>Security Label
- <input cdsText
- name="sec_label_xattr"
- id="sec_label_xattr"
- formControlName="sec_label_xattr"
- [invalid]="nfsForm.controls.sec_label_xattr.invalid && (nfsForm.controls.sec_label_xattr.dirty)">
+ <div
+ class="form-item"
+ *ngIf="nfsForm.getValue('security_label')"
+ >
+ <cds-text-label
+ for="sec_label_xattr"
+ [invalid]="
+ nfsForm.controls.sec_label_xattr.invalid && nfsForm.controls.sec_label_xattr.dirty
+ "
+ [invalidText]="secLabelError"
+ i18n
+ >Security Label
+ <input
+ cdsText
+ name="sec_label_xattr"
+ id="sec_label_xattr"
+ formControlName="sec_label_xattr"
+ [invalid]="
+ nfsForm.controls.sec_label_xattr.invalid && nfsForm.controls.sec_label_xattr.dirty
+ "
+ />
</cds-text-label>
<ng-template #secLabelError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('sec_label_xattr', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('sec_label_xattr', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
- <div class="form-item"
- *ngIf="storageBackend === 'CEPH' && nfsForm.getValue('fsal').fs_name">
- <cds-select formControlName="subvolume_group"
- name="subvolume_group"
- for="subvolume_group"
- label="Subvolume Group"
- id="subvolume_group"
- (change)="getSubVol()"
- [skeleton]="allsubvolgrps === null"
- i18n>
- <option *ngIf="allsubvolgrps === null"
- value="">Loading...</option>
- <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
- value="">-- Select the CephFS subvolume group --</option>
- <option *ngFor="let subvol_grp of allsubvolgrps"
- [value]="subvol_grp.name"
- [selected]="subvol_grp.name === nfsForm.get('subvolume_group').value">{{ subvol_grp.name }}</option>
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'CEPH' && nfsForm.getValue('fsal').fs_name"
+ >
+ <cds-select
+ formControlName="subvolume_group"
+ name="subvolume_group"
+ for="subvolume_group"
+ label="Subvolume Group"
+ id="subvolume_group"
+ (change)="getSubVol()"
+ [skeleton]="allsubvolgrps === null"
+ i18n
+ >
+ <option
+ *ngIf="allsubvolgrps === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
+ value=""
+ >
+ -- Select the CephFS subvolume group --
+ </option>
+ <option
+ *ngFor="let subvol_grp of allsubvolgrps"
+ [value]="subvol_grp.name"
+ [selected]="subvol_grp.name === nfsForm.get('subvolume_group').value"
+ >
+ {{ subvol_grp.name }}
+ </option>
<option [value]="defaultSubVolGroup">{{ defaultSubVolGroup }}</option>
</cds-select>
</div>
- <div class="form-group row"
- *ngIf="storageBackend === 'CEPH' && nfsForm.getValue('fsal').fs_name">
- <cds-select formControlName="subvolume"
- name="subvolume"
- for="subvolume"
- label="Subvolume"
- id="subvolume"
- [skeleton]="allsubvols === null"
- (change)="setSubVolPath()"
- [invalid]="nfsForm.controls.subvolume.invalid && (nfsForm.controls.subvolume.dirty)"
- [invalidText]="subvolumeError"
- i18n>
- <option *ngIf="allsubvols === null"
- value="">Loading...</option>
- <option *ngIf="allsubvols !== null && allsubvols.length === 0"
- value="">-- No CephFS subvolume available --</option>
- <option *ngIf="allsubvols !== null && allsubvols.length > 0"
- value="">-- Select the CephFS subvolume --</option>
- <option *ngFor="let subvolume of allsubvols"
- [value]="subvolume.name"
- [selected]="subvolume.name === nfsForm.get('subvolume').value">{{ subvolume.name }}</option>
- </cds-select>
- <ng-template #subvolumeError>
- <span
- *ngIf="nfsForm.getValue('subvolume_group') === defaultSubVolGroup && !nfsForm.getValue('subvolume')"
- class="invalid-feedback"
- i18n>
- This field is required.
- </span>
- </ng-template>
- </div>
+ <div
+ class="form-group row"
+ *ngIf="storageBackend === 'CEPH' && nfsForm.getValue('fsal').fs_name"
+ >
+ <cds-select
+ formControlName="subvolume"
+ name="subvolume"
+ for="subvolume"
+ label="Subvolume"
+ id="subvolume"
+ [skeleton]="allsubvols === null"
+ (change)="setSubVolPath()"
+ [invalid]="nfsForm.controls.subvolume.invalid && nfsForm.controls.subvolume.dirty"
+ [invalidText]="subvolumeError"
+ i18n
+ >
+ <option
+ *ngIf="allsubvols === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allsubvols !== null && allsubvols.length === 0"
+ value=""
+ >
+ -- No CephFS subvolume available --
+ </option>
+ <option
+ *ngIf="allsubvols !== null && allsubvols.length > 0"
+ value=""
+ >
+ -- Select the CephFS subvolume --
+ </option>
+ <option
+ *ngFor="let subvolume of allsubvols"
+ [value]="subvolume.name"
+ [selected]="subvolume.name === nfsForm.get('subvolume').value"
+ >
+ {{ subvolume.name }}
+ </option>
+ </cds-select>
+ <ng-template #subvolumeError>
+ <span
+ *ngIf="
+ nfsForm.getValue('subvolume_group') === defaultSubVolGroup &&
+ !nfsForm.getValue('subvolume')
+ "
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
+ </ng-template>
+ </div>
<!-- Path -->
- <div class="form-item"
- *ngIf="storageBackend === 'CEPH'">
- <cds-text-label for="path"
- i18n
- helperText="A path in a CephFS file system."
- cdRequiredField="Path"
- [invalid]="nfsForm.controls.path.invalid && (nfsForm.controls.path.dirty)"
- [invalidText]="pathError">Path
- <input cdsText
- type="text"
- placeholder="Path..."
- i18n-placeholder
- id="path"
- name="path"
- formControlName="path"
- [ngbTypeahead]="pathDataSource"
- [invalid]="nfsForm.controls.path.invalid && (nfsForm.controls.path.dirty)">
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'CEPH'"
+ >
+ <cds-text-label
+ for="path"
+ i18n
+ helperText="A path in a CephFS file system."
+ cdRequiredField="Path"
+ [invalid]="nfsForm.controls.path.invalid && nfsForm.controls.path.dirty"
+ [invalidText]="pathError"
+ >Path
+ <input
+ cdsText
+ type="text"
+ placeholder="Path..."
+ i18n-placeholder
+ id="path"
+ name="path"
+ formControlName="path"
+ [ngbTypeahead]="pathDataSource"
+ [invalid]="nfsForm.controls.path.invalid && nfsForm.controls.path.dirty"
+ />
</cds-text-label>
<ng-template #pathError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('path', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.get('path').hasError('isIsolatedSlash') && nfsForm.get('path').touched"
- i18n>Share on CephFS volume "<code>/</code>" not allowed.</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('path', formDir, 'pattern')"
- i18n>Path need to start with a '/' and can be followed by a word</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('path', formDir, 'pathNameNotAllowed')"
- i18n>The path does not exist in the selected volume.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('path', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.get('path').hasError('isIsolatedSlash') && nfsForm.get('path').touched"
+ i18n
+ >Share on CephFS volume "<code>/</code>" not allowed.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('path', formDir, 'pattern')"
+ i18n
+ >Path need to start with a '/' and can be followed by a word</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('path', formDir, 'pathNameNotAllowed')"
+ i18n
+ >The path does not exist in the selected volume.</span
+ >
</ng-template>
</div>
<!-- Bucket -->
- <div class="form-item"
- *ngIf="storageBackend === 'RGW' && nfsForm.getValue('rgw_export_type') === 'bucket'">
- <cds-text-label for="path"
- i18n
- cdRequiredField="Bucket"
- [invalid]="nfsForm.controls.path.invalid && (nfsForm.controls.path.dirty)"
- [invalidText]="bucketPathError">
- <input cdsText
- type="text"
- placeholder="Bucket name..."
- i18n-placeholder
- id="path"
- name="path"
- formControlName="path"
- [ngbTypeahead]="bucketDataSource"
- [invalid]="nfsForm.controls.path.invalid && (nfsForm.controls.path.dirty)">
+ <div
+ class="form-item"
+ *ngIf="storageBackend === 'RGW' && nfsForm.getValue('rgw_export_type') === 'bucket'"
+ >
+ <cds-text-label
+ for="path"
+ i18n
+ cdRequiredField="Bucket"
+ [invalid]="nfsForm.controls.path.invalid && nfsForm.controls.path.dirty"
+ [invalidText]="bucketPathError"
+ >
+ <input
+ cdsText
+ type="text"
+ placeholder="Bucket name..."
+ i18n-placeholder
+ id="path"
+ name="path"
+ formControlName="path"
+ [ngbTypeahead]="bucketDataSource"
+ [invalid]="nfsForm.controls.path.invalid && nfsForm.controls.path.dirty"
+ />
</cds-text-label>
<ng-template #bucketPathError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('path', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('path', formDir, 'bucketNameNotAllowed')"
- i18n>The bucket does not exist or is not in the default realm (if multiple realms are configured).
- To continue, <a routerLink="/rgw/bucket/create"
- class="btn-link">create a new bucket</a>.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('path', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('path', formDir, 'bucketNameNotAllowed')"
+ i18n
+ >The bucket does not exist or is not in the default realm (if multiple realms are
+ configured). To continue,
+ <a
+ routerLink="/rgw/bucket/create"
+ class="btn-link"
+ >create a new bucket</a
+ >.</span
+ >
</ng-template>
</div>
<!-- NFS Protocol -->
<div class="form-item">
- <legend class="cds--label"
- cdRequiredField="NFS Protocol"
- i18n>NFS Protocol (required)</legend>
- <cds-checkbox formControlName="protocolNfsv3"
- name="protocolNfsv3"
- id="protocolNfsv3"
- [invalid]="nfsForm.controls.protocolNfsv3.invalid && (nfsForm.controls.protocolNfsv3.dirty)"
- [invalidText]="protocolError"
- i18n>NFSv3</cds-checkbox>
- <cds-checkbox formControlName="protocolNfsv4"
- name="protocolNfsv4"
- id="protocolNfsv4"
- [invalid]="nfsForm.controls.protocolNfsv4.invalid && (nfsForm.controls.protocolNfsv4.dirty)"
- [invalidText]="protocolError"
- i18n>NFSv4</cds-checkbox>
- <ng-template #protocolError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('protocolNfsv3', formDir, 'required') ||
- nfsForm.showError('protocolNfsv4', formDir, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <legend
+ class="cds--label"
+ cdRequiredField="NFS Protocol"
+ i18n
+ >
+ NFS Protocol (required)
+ </legend>
+ <cds-checkbox
+ formControlName="protocolNfsv3"
+ name="protocolNfsv3"
+ id="protocolNfsv3"
+ [invalid]="nfsForm.controls.protocolNfsv3.invalid && nfsForm.controls.protocolNfsv3.dirty"
+ [invalidText]="protocolError"
+ i18n
+ >NFSv3</cds-checkbox
+ >
+ <cds-checkbox
+ formControlName="protocolNfsv4"
+ name="protocolNfsv4"
+ id="protocolNfsv4"
+ [invalid]="nfsForm.controls.protocolNfsv4.invalid && nfsForm.controls.protocolNfsv4.dirty"
+ [invalidText]="protocolError"
+ i18n
+ >NFSv4</cds-checkbox
+ >
+ <ng-template #protocolError>
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ nfsForm.showError('protocolNfsv3', formDir, 'required') ||
+ nfsForm.showError('protocolNfsv4', formDir, 'required')
+ "
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
<!-- Pseudo -->
- <div class="form-item"
- *ngIf="nfsForm.getValue('protocolNfsv4') || nfsForm.getValue('protocolNfsv3')">
- <cds-text-label for="pseudo"
- i18n
- [helperText]="pseudoHelper"
- cdRequiredField="Pseudo"
- [invalid]="nfsForm.controls.pseudo.invalid && (nfsForm.controls.pseudo.dirty)"
- [invalidText]="pseudoError">
- <input cdsText
- type="text"
- placeholder="Pseudo..."
- i18n-placeholder
- id="pseudo"
- name="pseudo"
- formControlName="pseudo"
- minlength="2"
- [invalid]="nfsForm.controls.pseudo.invalid && (nfsForm.controls.pseudo.dirty)">
+ <div
+ class="form-item"
+ *ngIf="nfsForm.getValue('protocolNfsv4') || nfsForm.getValue('protocolNfsv3')"
+ >
+ <cds-text-label
+ for="pseudo"
+ i18n
+ [helperText]="pseudoHelper"
+ cdRequiredField="Pseudo"
+ [invalid]="nfsForm.controls.pseudo.invalid && nfsForm.controls.pseudo.dirty"
+ [invalidText]="pseudoError"
+ >
+ <input
+ cdsText
+ type="text"
+ placeholder="Pseudo..."
+ i18n-placeholder
+ id="pseudo"
+ name="pseudo"
+ formControlName="pseudo"
+ minlength="2"
+ [invalid]="nfsForm.controls.pseudo.invalid && nfsForm.controls.pseudo.dirty"
+ />
</cds-text-label>
<ng-template #pseudoHelper>
- <span i18n>The position this share occupies in the Pseudo FS. It must be unique.</span><br/>
- <span i18n>By using different Pseudo options, the same Path may be shared multiple times.</span>
+ <span i18n>The position this share occupies in the Pseudo FS. It must be unique.</span
+ ><br />
+ <span i18n
+ >By using different Pseudo options, the same Path may be shared multiple times.</span
+ >
</ng-template>
<ng-template #pseudoError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('pseudo', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('pseudo', formDir, 'pseudoAlreadyExists')"
- i18n>The pseudo is already in use by another share.</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('pseudo', formDir, 'pattern')"
- i18n>Pseudo needs to start with a '/' and can't contain any of the following: >, <, |, &, ( or ).</span>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('pseudo', formDir, 'minlength') && nfsForm.getValue('pseudo') === '/'"
- i18n>Pseudo path should be an absolute path and it cannot be just '/'</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('pseudo', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('pseudo', formDir, 'pseudoAlreadyExists')"
+ i18n
+ >The pseudo is already in use by another share.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('pseudo', formDir, 'pattern')"
+ i18n
+ >Pseudo needs to start with a '/' and can't contain any of the following: >, <, |,
+ &, ( or ).</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ nfsForm.showError('pseudo', formDir, 'minlength') &&
+ nfsForm.getValue('pseudo') === '/'
+ "
+ i18n
+ >Pseudo path should be an absolute path and it cannot be just '/'</span
+ >
</ng-template>
</div>
<!-- Access Type -->
<div class="form-item">
- <cds-select formControlName="access_type"
- name="access_type"
- for="access_type"
- label="Access Type"
- cdRequiredField="Access Type"
- id="access_type"
- [invalid]="nfsForm.controls.access_type.invalid && (nfsForm.controls.access_type.dirty)"
- [invalidText]="accessTypeError"
- [helperText]="accessTypeHelper"
- [warn]="nfsForm.getValue('access_type') === 'RW' && storageBackend === 'RGW'"
- [warnText]="accessTypeWarning"
- [skeleton]="nfsAccessType === null"
- i18n>
- <option *ngIf="nfsAccessType === null"
- value="">Loading...</option>
- <option *ngIf="nfsAccessType !== null && nfsAccessType.length === 0"
- value="">-- No access type available --</option>
- <option *ngFor="let accessType of nfsAccessType"
- [value]="accessType.value">{{ accessType.value }}</option>
+ <cds-select
+ formControlName="access_type"
+ name="access_type"
+ for="access_type"
+ label="Access Type"
+ cdRequiredField="Access Type"
+ id="access_type"
+ [invalid]="nfsForm.controls.access_type.invalid && nfsForm.controls.access_type.dirty"
+ [invalidText]="accessTypeError"
+ [helperText]="accessTypeHelper"
+ [warn]="nfsForm.getValue('access_type') === 'RW' && storageBackend === 'RGW'"
+ [warnText]="accessTypeWarning"
+ [skeleton]="nfsAccessType === null"
+ i18n
+ >
+ <option
+ *ngIf="nfsAccessType === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="nfsAccessType !== null && nfsAccessType.length === 0"
+ value=""
+ >
+ -- No access type available --
+ </option>
+ <option
+ *ngFor="let accessType of nfsAccessType"
+ [value]="accessType.value"
+ >
+ {{ accessType.value }}
+ </option>
</cds-select>
<ng-template #accessTypeHelper>
<span *ngIf="nfsForm.getValue('access_type')">
</span>
</ng-template>
<ng-template #accessTypeWarning>
- <span *ngIf="nfsForm.getValue('access_type') === 'RW' && storageBackend === 'RGW'"
- i18n>The Object Gateway NFS backend has a number of
- limitations which will seriously affect applications writing to
- the share. Please consult the <cd-doc section="rgw-nfs"></cd-doc>
- for details before enabling write access.</span>
+ <span
+ *ngIf="nfsForm.getValue('access_type') === 'RW' && storageBackend === 'RGW'"
+ i18n
+ >The Object Gateway NFS backend has a number of limitations which will seriously affect
+ applications writing to the share. Please consult the <cd-doc
+ section="rgw-nfs"
+ ></cd-doc
+ > for details before enabling write access.</span
+ >
</ng-template>
<ng-template #accessTypeError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('access_type', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('access_type', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Squash -->
<div class="form-item">
- <cds-select formControlName="squash"
- name="squash"
- for="squash"
- label="Squash"
- cdRequiredField="Squash"
- id="squash"
- [invalid]="nfsForm.controls.squash.invalid && (nfsForm.controls.squash.dirty)"
- [invalidText]="squashError"
- [skeleton]="nfsSquash === null"
- [helperText]="squashHelper"
- i18n>
- <option *ngIf="nfsSquash === null"
- value="">Loading...</option>
- <option *ngIf="nfsSquash !== null && nfsSquash.length === 0"
- value="">-- No squash available --</option>
- <option *ngFor="let squash of nfsSquash"
- [value]="squash">{{ squash }}</option>
+ <cds-select
+ formControlName="squash"
+ name="squash"
+ for="squash"
+ label="Squash"
+ cdRequiredField="Squash"
+ id="squash"
+ [invalid]="nfsForm.controls.squash.invalid && nfsForm.controls.squash.dirty"
+ [invalidText]="squashError"
+ [skeleton]="nfsSquash === null"
+ [helperText]="squashHelper"
+ i18n
+ >
+ <option
+ *ngIf="nfsSquash === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="nfsSquash !== null && nfsSquash.length === 0"
+ value=""
+ >
+ -- No squash available --
+ </option>
+ <option
+ *ngFor="let squash of nfsSquash"
+ [value]="squash"
+ >
+ {{ squash }}
+ </option>
</cds-select>
<ng-template #squashHelper>
- <span *ngIf="nfsForm.getValue('squash') === 'root_squash'"
- i18n>Maps the root user on the NFS client to an anonymous user/group with limited privileges. This prevents a root client user from having total control over the NFS share.</span>
+ <span
+ *ngIf="nfsForm.getValue('squash') === 'root_squash'"
+ i18n
+ >Maps the root user on the NFS client to an anonymous user/group with limited
+ privileges. This prevents a root client user from having total control over the NFS
+ share.</span
+ >
- <span *ngIf="nfsForm.getValue('squash') === 'root_id_squash'"
- i18n>Maps the root user on the NFS client to an anonymous user/group with limited privileges, preventing root access but retaining non-root group privileges.</span>
+ <span
+ *ngIf="nfsForm.getValue('squash') === 'root_id_squash'"
+ i18n
+ >Maps the root user on the NFS client to an anonymous user/group with limited
+ privileges, preventing root access but retaining non-root group privileges.</span
+ >
- <span *ngIf="nfsForm.getValue('squash') === 'all_squash'"
- i18n>Maps all users on the NFS client to an anonymous user/group with limited privileges, ensuring that no user has special privileges on the NFS share.</span>
+ <span
+ *ngIf="nfsForm.getValue('squash') === 'all_squash'"
+ i18n
+ >Maps all users on the NFS client to an anonymous user/group with limited privileges,
+ ensuring that no user has special privileges on the NFS share.</span
+ >
- <span *ngIf="nfsForm.getValue('squash') === 'no_root_squash'"
- i18n>Allows the root user on the NFS client to retain full root privileges on the NFS server, which may pose security risks.</span>
+ <span
+ *ngIf="nfsForm.getValue('squash') === 'no_root_squash'"
+ i18n
+ >Allows the root user on the NFS client to retain full root privileges on the NFS
+ server, which may pose security risks.</span
+ >
</ng-template>
<ng-template #squashError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('squash', formDir,'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="nfsForm.showError('squash', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Transport Protocol -->
<div class="form-item">
- <legend class="cds--label"
- cdRequiredField="Transport Protocol"
- i18n>Transport Protocol (required)</legend>
- <cds-checkbox formControlName="transportUDP"
- name="transportUDP"
- id="transportUDP"
- [invalid]="nfsForm.controls.transportUDP.invalid && (nfsForm.controls.transportUDP.dirty)"
- [invalidText]="transportError"
- i18n>UDP</cds-checkbox>
- <cds-checkbox formControlName="transportTCP"
- name="transportTCP"
- id="transportTCP"
- [invalid]="nfsForm.controls.transportTCP.invalid && (nfsForm.controls.transportTCP.dirty)"
- [invalidText]="transportError"
- i18n>TCP</cds-checkbox>
+ <legend
+ class="cds--label"
+ cdRequiredField="Transport Protocol"
+ i18n
+ >
+ Transport Protocol (required)
+ </legend>
+ <cds-checkbox
+ formControlName="transportUDP"
+ name="transportUDP"
+ id="transportUDP"
+ [invalid]="nfsForm.controls.transportUDP.invalid && nfsForm.controls.transportUDP.dirty"
+ [invalidText]="transportError"
+ i18n
+ >UDP</cds-checkbox
+ >
+ <cds-checkbox
+ formControlName="transportTCP"
+ name="transportTCP"
+ id="transportTCP"
+ [invalid]="nfsForm.controls.transportTCP.invalid && nfsForm.controls.transportTCP.dirty"
+ [invalidText]="transportError"
+ i18n
+ >TCP</cds-checkbox
+ >
<ng-template #transportError>
- <span class="invalid-feedback"
- *ngIf="nfsForm.showError('transportUDP', formDir, 'required') ||
- nfsForm.showError('transportTCP', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ nfsForm.showError('transportUDP', formDir, 'required') ||
+ nfsForm.showError('transportTCP', formDir, 'required')
+ "
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Clients -->
- <cd-nfs-form-client [form]="nfsForm"
- [clients]="clients"
- #nfsClients>
+ <cd-nfs-form-client
+ [form]="nfsForm"
+ [clients]="clients"
+ #nfsClients
+ >
</cd-nfs-form-client>
<!-- Errors -->
- <cd-alert-panel type="error"
- *ngIf="!!storageBackendError">
- {{storageBackendError}}
+ <cd-alert-panel
+ type="error"
+ *ngIf="!!storageBackendError"
+ >
+ {{ storageBackendError }}
</cd-alert-panel>
- <cd-form-button-panel (submitActionEvent)="submitAction()"
- [form]="nfsForm"
- [disabled]="!!storageBackendError"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="nfsForm"
+ [disabled]="!!storageBackendError"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</ng-container>
</div>
-<cd-table #table
- [data]="exports"
- columnMode="flex"
- [columns]="columns"
- identifier="id"
- forceIdentifier="true"
- selectionType="single"
- [hasDetails]="false"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
+<cd-table
+ #table
+ [data]="exports"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="id"
+ forceIdentifier="true"
+ selectionType="single"
+ [hasDetails]="false"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
- <cd-table-actions class="btn-group"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
- <cd-nfs-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-nfs-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-nfs-details>
</cd-table>
-<ng-template #nfsFsal
- let-value="data.value">
- <ng-container *ngIf="value.name==='CEPH'"
- i18n>CephFS</ng-container>
- <ng-container *ngIf="value.name==='RGW'"
- i18n>Object Gateway</ng-container>
+<ng-template
+ #nfsFsal
+ let-value="data.value"
+>
+ <ng-container
+ *ngIf="value.name === 'CEPH'"
+ i18n
+ >CephFS</ng-container
+ >
+ <ng-container
+ *ngIf="value.name === 'RGW'"
+ i18n
+ >Object Gateway</ng-container
+ >
</ng-template>
-<ng-template #protocolTpl
- let-protocols="data.value">
+<ng-template
+ #protocolTpl
+ let-protocols="data.value"
+>
<span *ngFor="let protocol of protocols">
- <cds-tag size="md">NFSv{{protocol}}</cds-tag>
+ <cds-tag size="md">NFSv{{ protocol }}</cds-tag>
</span>
</ng-template>
-<ng-template #transportTpl
- let-transports="data.value">
+<ng-template
+ #transportTpl
+ let-transports="data.value"
+>
<span *ngFor="let transport of transports">
- <cds-tag size="md">{{transport}}</cds-tag>
+ <cds-tag size="md">{{ transport }}</cds-tag>
</span>
</ng-template>
-<ng-template #pathTmpl
- let-value="data.value">
- <span *ngIf="value === ''"
- i18n
- i18n-ngbTooltip
- ngbTooltip="All buckets owned by user">*</span>
+<ng-template
+ #pathTmpl
+ let-value="data.value"
+>
+ <span
+ *ngIf="value === ''"
+ i18n
+ i18n-ngbTooltip
+ ngbTooltip="All buckets owned by user"
+ >*</span
+ >
<span *ngIf="value !== ''">{{ value }}</span>
</ng-template>
<cd-productive-card class="overview-alerts-card">
-@if (vm$ | async; as vm) {
- <!-- HEADER -->
- <ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>
- System alerts
- </h2>
- <button
- cdsButton="ghost"
- size="sm"
- [routerLink]="['/monitoring/active-alerts']"
- type="button"
- i18n
- >
- View all
- </button>
- </ng-template>
- <!-- TOTAL COUNT -->
- @if (vm?.total || vm?.total === 0) {
- <div>
- <span class="cds--type-heading-07">{{ vm.total }}</span>
- <cd-icon [type]="vm.icon"></cd-icon>
- </div>
+ @if (vm$ | async; as vm) {
+ <!-- HEADER -->
+ <ng-template #header>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ System alerts
+ </h2>
+ <button
+ cdsButton="ghost"
+ size="sm"
+ [routerLink]="['/monitoring/active-alerts']"
+ type="button"
+ i18n
+ >
+ View all
+ </button>
+ </ng-template>
+ <!-- TOTAL COUNT -->
+ @if (vm?.total || vm?.total === 0) {
+ <div>
+ <span class="cds--type-heading-07">{{ vm.total }}</span>
+ <cd-icon [type]="vm.icon"></cd-icon>
+ </div>
- <small
- class="cds--type-label-01 overview-alerts-card-need-attention"
- i18n>
- {{ vm.statusText }}
- </small>
- <!-- SUB TOTAL COUNTS -->
- <div class="cds-mt-5">
- @if (vm.badges.length) {
- <div [cdsStack]="compact? 'horizontal' : 'vertical'">
- @for (b of vm.badges; track b.key; let last = $last) {
- <span
- class="overview-alerts-card-badge cds-pr-4"
- [class.cds-mr-4]="!last && compact"
- [class.border-subtle-right]="!last && compact"
- [class.overview-alerts-card-badge--compact]="!compact"
- [class.border-subtle-bottom]="!compact">
- <a
- cdsLink
- [routerLink]="['/monitoring/active-alerts']"
- [queryParams]="{ severity: b.key }">
- <cd-icon [type]="b.icon"></cd-icon>
- <span class="cds-ml-3">
- @if(compact) {
- {{ b.count }}
- } @else {
- {{b.key | upperFirst}} ({{ b.count }})
- }
- </span>
- </a>
- </span>
- }
- </div>
+ <small
+ class="cds--type-label-01 overview-alerts-card-need-attention"
+ i18n
+ >
+ {{ vm.statusText }}
+ </small>
+ <!-- SUB TOTAL COUNTS -->
+ <div class="cds-mt-5">
+ @if (vm.badges.length) {
+ <div [cdsStack]="compact ? 'horizontal' : 'vertical'">
+ @for (b of vm.badges; track b.key; let last = $last) {
+ <span
+ class="overview-alerts-card-badge cds-pr-4"
+ [class.cds-mr-4]="!last && compact"
+ [class.border-subtle-right]="!last && compact"
+ [class.overview-alerts-card-badge--compact]="!compact"
+ [class.border-subtle-bottom]="!compact"
+ >
+ <a
+ cdsLink
+ [routerLink]="['/monitoring/active-alerts']"
+ [queryParams]="{ severity: b.key }"
+ >
+ <cd-icon [type]="b.icon"></cd-icon>
+ <span class="cds-ml-3">
+ @if (compact) {
+ {{ b.count }}
+ } @else {
+ {{ b.key | upperFirst }} ({{ b.count }})
+ }
+ </span>
+ </a>
+ </span>
+ }
+ </div>
+ }
+ </div>
+ } @else {
+ <cds-skeleton-placeholder></cds-skeleton-placeholder>
+ <div class="cds-mt-3">
+ <cds-skeleton-text [lines]="1"></cds-skeleton-text>
+ </div>
+ }
}
- </div>
- }@else {
- <cds-skeleton-placeholder></cds-skeleton-placeholder>
- <div class="cds-mt-3">
- <cds-skeleton-text [lines]="1"></cds-skeleton-text>
- </div>
- }
-}
</cd-productive-card>
-@let data=(data$ | async);
-@let hwEnabled = (enabled$ | async);
-@let hwSections = (sections$ | async);
-@let telemetryEnabled = (telemetryEnabled$ | async);
-
-@let colorClass="overview-health-card-status--" + vm?.clusterHealth?.icon;
+@let data = data$ | async;
+@let hwEnabled = enabled$ | async;
+@let hwSections = sections$ | async;
+@let telemetryEnabled = telemetryEnabled$ | async;
+@let colorClass = 'overview-health-card-status--' + vm?.clusterHealth?.icon;
<cd-productive-card class="overview-health-card">
<!-- ----------------------HEALTH CARD HEADER ---------------->
- @if(vm?.fsid) {
- <ng-template #header>
- <div class="overview-health-card-header">
- <div class="cds-mb-4 cds-mr-3">
- <cd-icon type="dataCenter"></cd-icon>
+ @if (vm?.fsid) {
+ <ng-template #header>
+ <div class="overview-health-card-header">
+ <div class="cds-mb-4 cds-mr-3">
+ <cd-icon type="dataCenter"></cd-icon>
+ </div>
+ <h2
+ class="cds--type-heading-compact-02"
+ id="fsid"
+ >
+ <span class="cds-mr-2">{{ vm?.fsid }}</span>
+ </h2>
+ <cd-copy-2-clipboard-button
+ size="sm"
+ title="Copy cluster fsid"
+ i18n-title
+ source="fsid"
+ >
+ </cd-copy-2-clipboard-button>
</div>
- <h2 class="cds--type-heading-compact-02"
- id="fsid">
- <span class="cds-mr-2">{{vm?.fsid}}</span>
- </h2>
- <cd-copy-2-clipboard-button
- size="sm"
- title="Copy cluster fsid"
- i18n-title
- source="fsid">
- </cd-copy-2-clipboard-button>
- </div>
- <ng-template #telemetryDescription>
- <div class="cds--type-heading-compact-01 cds-mb-2"
- i18n>Support & diagnostics</div>
- <div cdsStack="horizontal"
- [gap]="10">
- <span i18n>Telemetry</span>
- <span>
- @if (telemetryEnabled) {
- <cd-icon type="success"></cd-icon>
- <span i18n>on</span>
- } @else {
- <cd-icon type="infoCircle"></cd-icon>
- <span i18n>off</span>
- }
- </span>
+ <ng-template #telemetryDescription>
+ <div
+ class="cds--type-heading-compact-01 cds-mb-2"
+ i18n
+ >
+ Support & diagnostics
+ </div>
+ <div
+ cdsStack="horizontal"
+ [gap]="10"
+ >
+ <span i18n>Telemetry</span>
+ <span>
+ @if (telemetryEnabled) {
+ <cd-icon type="success"></cd-icon>
+ <span i18n>on</span>
+ } @else {
+ <cd-icon type="infoCircle"></cd-icon>
+ <span i18n>off</span>
+ }
+ </span>
+ </div>
+ </ng-template>
+ <div
+ cdsStack="horizontal"
+ [gap]="2"
+ >
+ <cds-icon-button
+ type="button"
+ kind="ghost"
+ size="sm"
+ [description]="telemetryDescription"
+ >
+ <cd-icon type="cloudMonitoring"></cd-icon>
+ </cds-icon-button>
+ <cds-icon-button
+ type="button"
+ kind="ghost"
+ size="sm"
+ description="Check logs"
+ i18n-description
+ [routerLink]="['/logs']"
+ >
+ <cd-icon type="dataViewAlt"></cd-icon>
+ </cds-icon-button>
</div>
</ng-template>
- <div cdsStack="horizontal"
- [gap]="2">
- <cds-icon-button
- type="button"
- kind="ghost"
- size="sm"
- [description]="telemetryDescription">
- <cd-icon type="cloudMonitoring"></cd-icon>
- </cds-icon-button>
- <cds-icon-button
- type="button"
- kind="ghost"
- size="sm"
- description="Check logs"
- i18n-description
- [routerLink]="['/logs']">
- <cd-icon type="dataViewAlt"></cd-icon>
- </cds-icon-button>
- </div>
- </ng-template>
} @else {
- <cds-skeleton-text
- [lines]="1"
- [maxLineWidth]="400"
- [minLineWidth]="400"></cds-skeleton-text>
+ <cds-skeleton-text
+ [lines]="1"
+ [maxLineWidth]="400"
+ [minLineWidth]="400"
+ ></cds-skeleton-text>
}
<!------------------------- HEALTH CARD CLUSTER STATUS ------------------>
- @if(vm?.clusterHealth){
- <p class="cds--type-heading-05 cds-mb-0"
- [ngClass]="colorClass">
- {{vm?.clusterHealth?.title}}
- <cd-icon [type]="vm?.clusterHealth?.icon"></cd-icon>
- </p>
- <p class="cds--type-label-01 overview-health-card-secondary-text">{{vm?.clusterHealth?.message}}</p>
+ @if (vm?.clusterHealth) {
+ <p
+ class="cds--type-heading-05 cds-mb-0"
+ [ngClass]="colorClass"
+ >
+ {{ vm?.clusterHealth?.title }}
+ <cd-icon [type]="vm?.clusterHealth?.icon"></cd-icon>
+ </p>
+ <p class="cds--type-label-01 overview-health-card-secondary-text">
+ {{ vm?.clusterHealth?.message }}
+ </p>
} @else {
- <cds-skeleton-placeholder></cds-skeleton-placeholder>
+ <cds-skeleton-placeholder></cds-skeleton-placeholder>
}
- @if(data?.summary?.version) {
- <!-- CEPH VERSION -->
- <p class="cds--type-label-02">
- <span i18n>Ceph version: </span>
- <span class="cds--type-heading-compact-01">{{ data?.summary?.version | cephVersion }}</span>
- @if (data?.upgrade?.versions?.length) {
- <a [routerLink]="['/upgrade']"
- cdsLink
- [inline]="true"
- i18n>
- Upgrade available
- <cd-icon type="upgrade"></cd-icon>
- </a>
- }
- </p>
+ @if (data?.summary?.version) {
+ <!-- CEPH VERSION -->
+ <p class="cds--type-label-02">
+ <span i18n>Ceph version: </span>
+ <span class="cds--type-heading-compact-01">{{ data?.summary?.version | cephVersion }}</span
+ >
+ @if (data?.upgrade?.versions?.length) {
+ <a
+ [routerLink]="['/upgrade']"
+ cdsLink
+ [inline]="true"
+ i18n
+ >
+ Upgrade available
+ <cd-icon type="upgrade"></cd-icon>
+ </a>
+ }
+ </p>
} @else {
- <cds-skeleton-text
- [lines]="1"
- [maxLineWidth]="250"></cds-skeleton-text>
+ <cds-skeleton-text
+ [lines]="1"
+ [maxLineWidth]="250"
+ ></cds-skeleton-text>
}
<!-----------------------------------TABS -------------------------------------->
- <div cdsStack="horizontal"
- [gap]="4">
- <!-- HEALTH CHECKS -->
- @if(vm?.incidents > 0) {
- <div>
- <cd-icon
- type="incidentReporter"
- [ngClass]="colorClass"></cd-icon>
- <cds-tooltip-definition
- [highContrast]="true"
- [openOnHover]="true"
- [dropShadow]="true"
- [caret]="true"
- (click)="onViewIncidentsClick()"
- description="Click to view health incidents"
- i18n-description>
- <span
- class="cds--type-heading-compact-01"
- [ngClass]="colorClass"
- i18n>
- {{vm?.incidents}} Health incidents
- </span>
- </cds-tooltip-definition>
- <cds-tooltip
- class="cds-ml-3"
- [caret]="true"
- description="Health incidents represent Ceph health check warnings that indicate abnormal conditions requiring intervention and persist until the condition is resolved."
- i8n-description
- >
- <cd-icon type="help"></cd-icon> |
- </cds-tooltip>
- </div>
- }
- <!-- SYSTEM TAB -->
- @if(vm?.overallSystemSev) {
- <div class="overview-health-card-tab"
- [class.overview-health-card-tab-selected]="activeSection === 'system'">
- <div class="cds-mb-1"><cd-icon
- [type]="vm?.overallSystemSev"></cd-icon></div>
- <cds-tooltip-definition
- [highContrast]="true"
- [openOnHover]="true"
- [dropShadow]="true"
- class="cds-ml-2"
- [caret]="true"
- (click)="toggleSection('system')"
- data-test-id="systems-tab"
- description=""
- i18n-description>
- <span
- class="cds-mr-1"
- [class.cds--type-heading-compact-01]="activeSection === 'system'"
- i18n>
- Systems
- </span>
- </cds-tooltip-definition>
- </div>
- } @else {
- <cds-skeleton-text [lines]="1"></cds-skeleton-text>
- }
- <!-- HARDWARE TAB -->
- @if(hwEnabled && hwSections) {
- <div class="overview-health-card-tab"
- [class.overview-health-card-tab-selected]="activeSection === 'hardware'">
- <div class="cds-mb-1"><cd-icon
- [type]="vm?.overallSystemSev"></cd-icon></div>
- <cds-tooltip-definition
- [highContrast]="true"
- [openOnHover]="true"
- [dropShadow]="true"
- class="cds-ml-2"
- [caret]="true"
- (click)="toggleSection('hardware')"
- description=""
- i18n-description>
- <span
- class="cds-mr-1"
- [class.cds--type-heading-compact-01]="activeSection === 'hardware'"
- i18n>
- Hardware
- </span>
- </cds-tooltip-definition>
- </div>
- }
- <!-- RESILIENCY TAB -->
- @if(vm?.overallSystemSev) {
- <div class="overview-health-card-tab"
- [class.overview-health-card-tab-selected]="activeSection === 'resiliency'">
- <div class="cds-mb-1"><cd-icon
- [type]="vm?.resiliencyHealth?.icon"></cd-icon></div>
- <cds-tooltip-definition
- [highContrast]="true"
- [openOnHover]="true"
- [dropShadow]="true"
- class="cds-ml-2"
- [caret]="true"
- (click)="toggleSection('resiliency')"
- description=""
- i18n-description>
- <span
- class="cds-mr-1"
- [class.cds--type-heading-compact-01]="activeSection === 'resiliency'"
- i18n>
- Data resiliency
- </span>
- </cds-tooltip-definition>
- </div>
- } @else {
- <cds-skeleton-text [lines]="1"></cds-skeleton-text>
- }
+ <div
+ cdsStack="horizontal"
+ [gap]="4"
+ >
+ <!-- HEALTH CHECKS -->
+ @if (vm?.incidents > 0) {
+ <div>
+ <cd-icon
+ type="incidentReporter"
+ [ngClass]="colorClass"
+ ></cd-icon>
+ <cds-tooltip-definition
+ [highContrast]="true"
+ [openOnHover]="true"
+ [dropShadow]="true"
+ [caret]="true"
+ (click)="onViewIncidentsClick()"
+ description="Click to view health incidents"
+ i18n-description
+ >
+ <span
+ class="cds--type-heading-compact-01"
+ [ngClass]="colorClass"
+ i18n
+ >
+ {{ vm?.incidents }} Health incidents
+ </span>
+ </cds-tooltip-definition>
+ <cds-tooltip
+ class="cds-ml-3"
+ [caret]="true"
+ description="Health incidents represent Ceph health check warnings that indicate abnormal conditions requiring intervention and persist until the condition is resolved."
+ i8n-description
+ >
+ <cd-icon type="help"></cd-icon> |
+ </cds-tooltip>
+ </div>
+ }
+ <!-- SYSTEM TAB -->
+ @if (vm?.overallSystemSev) {
+ <div
+ class="overview-health-card-tab"
+ [class.overview-health-card-tab-selected]="activeSection === 'system'"
+ >
+ <div class="cds-mb-1"><cd-icon [type]="vm?.overallSystemSev"></cd-icon></div>
+ <cds-tooltip-definition
+ [highContrast]="true"
+ [openOnHover]="true"
+ [dropShadow]="true"
+ class="cds-ml-2"
+ [caret]="true"
+ (click)="toggleSection('system')"
+ data-test-id="systems-tab"
+ description=""
+ i18n-description
+ >
+ <span
+ class="cds-mr-1"
+ [class.cds--type-heading-compact-01]="activeSection === 'system'"
+ i18n
+ >
+ Systems
+ </span>
+ </cds-tooltip-definition>
+ </div>
+ } @else {
+ <cds-skeleton-text [lines]="1"></cds-skeleton-text>
+ }
+ <!-- HARDWARE TAB -->
+ @if (hwEnabled && hwSections) {
+ <div
+ class="overview-health-card-tab"
+ [class.overview-health-card-tab-selected]="activeSection === 'hardware'"
+ >
+ <div class="cds-mb-1"><cd-icon [type]="vm?.overallSystemSev"></cd-icon></div>
+ <cds-tooltip-definition
+ [highContrast]="true"
+ [openOnHover]="true"
+ [dropShadow]="true"
+ class="cds-ml-2"
+ [caret]="true"
+ (click)="toggleSection('hardware')"
+ description=""
+ i18n-description
+ >
+ <span
+ class="cds-mr-1"
+ [class.cds--type-heading-compact-01]="activeSection === 'hardware'"
+ i18n
+ >
+ Hardware
+ </span>
+ </cds-tooltip-definition>
+ </div>
+ }
+ <!-- RESILIENCY TAB -->
+ @if (vm?.overallSystemSev) {
+ <div
+ class="overview-health-card-tab"
+ [class.overview-health-card-tab-selected]="activeSection === 'resiliency'"
+ >
+ <div class="cds-mb-1"><cd-icon [type]="vm?.resiliencyHealth?.icon"></cd-icon></div>
+ <cds-tooltip-definition
+ [highContrast]="true"
+ [openOnHover]="true"
+ [dropShadow]="true"
+ class="cds-ml-2"
+ [caret]="true"
+ (click)="toggleSection('resiliency')"
+ description=""
+ i18n-description
+ >
+ <span
+ class="cds-mr-1"
+ [class.cds--type-heading-compact-01]="activeSection === 'resiliency'"
+ i18n
+ >
+ Data resiliency
+ </span>
+ </cds-tooltip-definition>
+ </div>
+ } @else {
+ <cds-skeleton-text [lines]="1"></cds-skeleton-text>
+ }
</div>
<!-- TAB CONTENT -->
- <div [ngSwitch]="activeSection">
+ <div [ngSwitch]="activeSection">
<!-- SYSTEM TAB CONTENT -->
<ng-container *ngSwitchCase="'system'">
<div class="overview-health-card-tab-content">
- <p class="overview-health-card-secondary-text cds--type-body-compact-01"
- i18n>Some cluster components are degraded and may require attention.</p>
- <div cdsStack="horizontal"
- [gap]="8">
+ <p
+ class="overview-health-card-secondary-text cds--type-body-compact-01"
+ i18n
+ >
+ Some cluster components are degraded and may require attention.
+ </p>
+ <div
+ cdsStack="horizontal"
+ [gap]="8"
+ >
@for (item of healthItems; track item.key; let isLast = $last) {
- <div class="cds-pr-8"
- [class.overview-health-card-tab-content-item]="!isLast"
- [class.border-subtle-right]="!isLast">
- <span class="overview-health-card-icon-and-text">
- <cd-icon [type]="vm?.[item.key]?.severity"></cd-icon>
- <span
- class="cds--type-body-compact-01"
- [data-test-id]="item.label">
- {{ item.label }}
+ <div
+ class="cds-pr-8"
+ [class.overview-health-card-tab-content-item]="!isLast"
+ [class.border-subtle-right]="!isLast"
+ >
+ <span class="overview-health-card-icon-and-text">
+ <cd-icon [type]="vm?.[item.key]?.severity"></cd-icon>
+ <span
+ class="cds--type-body-compact-01"
+ [data-test-id]="item.label"
+ >
+ {{ item.label }}
+ </span>
</span>
- </span>
- <p
- class="cds--type-label-01 cds-mt-3 cds-mb-0 overview-health-card-secondary-text"
- [data-test-id]="item.label+'-value'">
- {{ vm?.[item.key]?.value }}
- </p>
- </div>
+ <p
+ class="cds--type-label-01 cds-mt-3 cds-mb-0 overview-health-card-secondary-text"
+ [data-test-id]="item.label + '-value'"
+ >
+ {{ vm?.[item.key]?.value }}
+ </p>
+ </div>
}
</div>
</div>
<!-- HARDWARE TAB CONTENT -->
<ng-container *ngSwitchCase="'hardware'">
<div class="overview-health-card-tab-content">
- <p class="overview-health-card-secondary-text cds--type-body-compact-01"
- i18n>
+ <p
+ class="overview-health-card-secondary-text cds--type-body-compact-01"
+ i18n
+ >
Some cluster components are degraded and may require attention.
</p>
@if (hwEnabled && hwSections) {
<div class="overview-health-card-hardware-sections">
- @for (section of sections; track $index; let isLast = $last) {
- <div class="overview-health-card-hardware-section"
- [class.border-subtle-right]="!isLast">
- @for (row of section; track row.key) {
- <div class="overview-health-card-hardware-row">
- <span class="overview-health-card-icon-and-text">
- <cd-icon [type]="row.key"></cd-icon>
- <span class="cds--type-body-compact-01">
- {{ row.label }}
- </span>
- </span>
+ @for (section of sections; track $index; let isLast = $last) {
+ <div
+ class="overview-health-card-hardware-section"
+ [class.border-subtle-right]="!isLast"
+ >
+ @for (row of section; track row.key) {
+ <div class="overview-health-card-hardware-row">
+ <span class="overview-health-card-icon-and-text">
+ <cd-icon [type]="row.key"></cd-icon>
+ <span class="cds--type-body-compact-01">
+ {{ row.label }}
+ </span>
+ </span>
- <span class="overview-health-card-hardware-status">
- @if (row.error > 0) {
- <cd-icon type="warningAlt"></cd-icon>
- <span class="cds--type-body-compact-01">
- {{ row.error }}
- </span>
- }
- <cd-icon type="checkMarkOutline"></cd-icon>
- <span class="cds--type-body-compact-01">
- {{ row.ok }}
- </span>
- </span>
- </div>
+ <span class="overview-health-card-hardware-status">
+ @if (row.error > 0) {
+ <cd-icon type="warningAlt"></cd-icon>
+ <span class="cds--type-body-compact-01">
+ {{ row.error }}
+ </span>
+ }
+ <cd-icon type="checkMarkOutline"></cd-icon>
+ <span class="cds--type-body-compact-01">
+ {{ row.ok }}
+ </span>
+ </span>
+ </div>
+ }
+ </div>
}
- </div>
- }
</div>
} @else {
- <cds-skeleton-placeholder></cds-skeleton-placeholder>
+ <cds-skeleton-placeholder></cds-skeleton-placeholder>
}
</div>
</ng-container>
<span class="overview-health-card-icon-and-text">
<cd-icon [type]="vm?.resiliencyHealth?.icon"></cd-icon>
<span class="cds--type-body-compact-01">
- {{vm?.resiliencyHealth?.title}}
+ {{ vm?.resiliencyHealth?.title }}
</span>
</span>
<p class="overview-health-card-secondary-text cds--type-label-01">
- {{vm?.resiliencyHealth?.description}}</p>
+ {{ vm?.resiliencyHealth?.description }}
+ </p>
<button
cdsButton="tertiary"
size="sm"
type="button"
- (click)="onViewPGStatesClick()">
+ (click)="onViewPGStatesClick()"
+ >
<span
i18n
- class="cds-ml-3">See all PGs states</span>
+ class="cds-ml-3"
+ >See all PGs states</span
+ >
<cd-icon type="arrowUpRight"></cd-icon>
</button>
</div>
@if (vm?.pgs?.activeCleanChartData && vm?.pgs?.activeCleanChartOptions) {
- <div class="overview-health-card-tab-content-item-row">
- <ibm-gauge-chart
- class="overview-health-card-resiliency-chart"
- [options]="vm?.pgs?.activeCleanChartOptions"
- [data]="vm?.pgs?.activeCleanChartData"></ibm-gauge-chart>
- <div class="overview-health-card-resiliency-chart-text">
- <p
- i18n
- class="cds--type-helper-text-01 overview-health-card-secondary-text"><em>Data resiliency</em> reflects data availability and replication (% of placement groups that are active and clean).
- </p>
- @if (vm?.pgs?.activeCleanChartReason?.length) {
- <p
- class="cds--type-helper-text-01 overview-health-card-secondary-text overview-health-card-bold cds-mb-2"
- i18n>
- {{vm?.resiliencyHealth?.severity === 'progress' ? 'Data cleanup in progress' : 'What is affecting resiliency?'}}
- </p>
- @for (item of vm?.pgs?.activeCleanChartReason; track item.state; let isLast =$last) {
- @if(item.count) {
- <p
- [class.cds-mb-0]="isLast"
- class="cds-mb-2">
- <span class="cds--type-label-01 cds-mr-1">{{item?.state}}:</span>
- <span class="cds--type-label-01 overview-health-card-bold">{{item.count}} %</span>
- @if(!item?.state?.includes('Scrub') && item?.state !== 'Remapped') {
- <cd-icon type="arrowDown"></cd-icon>
+ <div class="overview-health-card-tab-content-item-row">
+ <ibm-gauge-chart
+ class="overview-health-card-resiliency-chart"
+ [options]="vm?.pgs?.activeCleanChartOptions"
+ [data]="vm?.pgs?.activeCleanChartData"
+ ></ibm-gauge-chart>
+ <div class="overview-health-card-resiliency-chart-text">
+ <p
+ i18n
+ class="cds--type-helper-text-01 overview-health-card-secondary-text"
+ >
+ <em>Data resiliency</em> reflects data availability and replication (% of placement
+ groups that are active and clean).
+ </p>
+ @if (vm?.pgs?.activeCleanChartReason?.length) {
+ <p
+ class="cds--type-helper-text-01 overview-health-card-secondary-text overview-health-card-bold cds-mb-2"
+ i18n
+ >
+ {{
+ vm?.resiliencyHealth?.severity === 'progress'
+ ? 'Data cleanup in progress'
+ : 'What is affecting resiliency?'
+ }}
+ </p>
+ @for (
+ item of vm?.pgs?.activeCleanChartReason;
+ track item.state;
+ let isLast = $last
+ ) {
+ @if (item.count) {
+ <p
+ [class.cds-mb-0]="isLast"
+ class="cds-mb-2"
+ >
+ <span class="cds--type-label-01 cds-mr-1">{{ item?.state }}:</span>
+ <span class="cds--type-label-01 overview-health-card-bold"
+ >{{ item.count }} %</span
+ >
+ @if (!item?.state?.includes('Scrub') && item?.state !== 'Remapped') {
+ <cd-icon type="arrowDown"></cd-icon>
+ }
+ </p>
+ }
+ }
}
- </p>
- }
- }
- }
+ </div>
</div>
- </div>
} @else {
- <cds-skeleton-placeholder></cds-skeleton-placeholder>
+ <cds-skeleton-placeholder></cds-skeleton-placeholder>
}
</div>
</ng-container>
<!-- OVEVRIEW -->
-@let storageCard = (storageCardVm$ | async);
-@let health = (healthCardVm$ | async);
-@let storageEmptyState = (storageEmptyState$ | async);
-@let prometheusEmptyState = (prometheusEmptyState$ | async);
-<main cdsGrid
- [fullWidth]="true"
- [narrow]="true"
- class="overview cds-mt-5">
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 11}">
+@let storageCard = storageCardVm$ | async;
+@let health = healthCardVm$ | async;
+@let storageEmptyState = storageEmptyState$ | async;
+@let prometheusEmptyState = prometheusEmptyState$ | async;
+<main
+ cdsGrid
+ [fullWidth]="true"
+ [narrow]="true"
+ class="overview cds-mt-5"
+>
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 11 }"
+ >
<cd-overview-health-card
- [vm]="health"
- (viewIncidents)="toggleHealthPanel()"
- (viewPGStates)="togglePGStatesPanel()"
- (activeSectionChange)="activeHealthTab = $event"
- ></cd-overview-health-card>
+ [vm]="health"
+ (viewIncidents)="toggleHealthPanel()"
+ (viewPGStates)="togglePGStatesPanel()"
+ (activeSectionChange)="activeHealthTab = $event"
+ ></cd-overview-health-card>
</div>
- <div cdsCol
- class="overview-pr-0"
- [columnNumbers]="{lg: 5}">
+ <div
+ cdsCol
+ class="overview-pr-0"
+ [columnNumbers]="{ lg: 5 }"
+ >
<cd-overview-alerts-card [compact]="!activeHealthTab"></cd-overview-alerts-card>
</div>
</div>
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- class="overview-pr-0"
- [columnNumbers]="{lg: 16}">
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ class="overview-pr-0"
+ [columnNumbers]="{ lg: 16 }"
+ >
<cd-overview-storage-card
[totalCapacity]="storageCard?.totalCapacity"
[usedCapacity]="storageCard?.usedCapacity"
[isBreakdownLoaded]="storageCard?.isBreakdownLoaded ?? false"
[threshold]="storageCard?.threshold"
[storageEmptyState]="storageEmptyState"
- [prometheusEmptyState]="prometheusEmptyState">
+ [prometheusEmptyState]="prometheusEmptyState"
+ >
</cd-overview-storage-card>
</div>
</div>
<div cdsRow>
- <div cdsCol
- class="overview-pr-0"
- [columnNumbers]="{ lg: 16 }">
+ <div
+ cdsCol
+ class="overview-pr-0"
+ [columnNumbers]="{ lg: 16 }"
+ >
<cd-performance-card
[prometheusEmptyState]="prometheusEmptyState"
- [storageEmptyState]="storageEmptyState"></cd-performance-card>
+ [storageEmptyState]="storageEmptyState"
+ ></cd-performance-card>
</div>
</div>
</main>
@if (isHealthPanelOpen && health?.incidents > 0) {
<cd-side-panel
- [headerText]="'Health incidents ('+ health?.incidents +')'"
+ [headerText]="'Health incidents (' + health?.incidents + ')'"
[expanded]="isHealthPanelOpen"
size="md"
- (closed)="toggleHealthPanel()">
- <div panel-header-description
- class="cds--type-body-01">
- <span i18n>Health incidents are Ceph health checks warnings indicating conditions that require attention and remain until resolved.</span>
+ (closed)="toggleHealthPanel()"
+ >
+ <div
+ panel-header-description
+ class="cds--type-body-01"
+ >
+ <span i18n
+ >Health incidents are Ceph health checks warnings indicating conditions that require
+ attention and remain until resolved.</span
+ >
</div>
<div class="panel-content">
@for (check of health?.checks; track check.name) {
- <div>
- <div class="overview-check-header">
- <cd-icon [type]="check?.icon"></cd-icon>
- <span class="cds--type-body-compact-01 overview-check-name">
- {{ check?.name }}
- </span>
+ <div>
+ <div class="overview-check-header">
+ <cd-icon [type]="check?.icon"></cd-icon>
+ <span class="cds--type-body-compact-01 overview-check-name">
+ {{ check?.name }}
+ </span>
+ </div>
+ <p class="cds--type-body-compact-01 overview-check-description">
+ {{ check?.description }}
+ </p>
</div>
- <p class="cds--type-body-compact-01 overview-check-description">{{ check?.description }}</p>
- </div>
}
</div>
</cd-side-panel>
}
@if (isPGStatePanelOpen) {
<cd-side-panel
- [headerText]="'Placement groups ('+ health?.pgs?.total +')'"
+ [headerText]="'Placement groups (' + health?.pgs?.total + ')'"
[expanded]="isPGStatePanelOpen"
size="md"
- (closed)="togglePGStatesPanel()">
- <div panel-header-description
- class="cds--type-body-01">
+ (closed)="togglePGStatesPanel()"
+ >
+ <div
+ panel-header-description
+ class="cds--type-body-01"
+ >
<span i18n>
- Placement groups are how Ceph groups and distributes data across storage devices to manage replication, recovery, and performance.
+ Placement groups are how Ceph groups and distributes data across storage devices to manage
+ replication, recovery, and performance.
</span>
</div>
<div class="panel-content">
<div
class="overview-pg-side-panel-rw cds-mb-4"
cdsStack="horizontal"
- gap="4">
- @for (data of health?.pgs?.io; track $index ; let isLast = $last) {
- <div
- class="overview-pg-side-panel-rw-item"
- [class.overview-pg-side-panel-rw-item--border]="!isLast">
- <p class="cds--type-label-01 cds-mb-2">{{data.label}}</p>
- <p class="cds--type-heading-03 cds-mb-0">{{data.value | dimlessBinary }} / s</p>
- </div>
+ gap="4"
+ >
+ @for (data of health?.pgs?.io; track $index; let isLast = $last) {
+ <div
+ class="overview-pg-side-panel-rw-item"
+ [class.overview-pg-side-panel-rw-item--border]="!isLast"
+ >
+ <p class="cds--type-label-01 cds-mb-2">{{ data.label }}</p>
+ <p class="cds--type-heading-03 cds-mb-0">{{ data.value | dimlessBinary }} / s</p>
+ </div>
}
</div>
<cd-table
- [data]="health?.pgs?.states"
- [columns]="pgTableColumns"
- size="xs">
+ [data]="health?.pgs?.states"
+ [columns]="pgTableColumns"
+ size="xs"
+ >
</cd-table>
</div>
</cd-side-panel>
<cd-productive-card class="overview-storage-card">
<!-- STORAGE CARD HEADER -->
<ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>Storage overview</h2>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Storage overview
+ </h2>
</ng-template>
<!-- CAPACITY USAGE TEXT -->
- @if(!storageEmptyState) {
- <div class="overview-storage-card-usage-text">
- @if( usedRaw !== null && totalRaw !== null && usedRawUnit && totalRawUnit) {
- <h5>
- <span
- class="cds--type-heading-05"
- i18n>{{usedRaw}} </span>
- <span
- class="cds--type-body-02"
- i18n>{{usedRawUnit}} of {{totalRaw}} {{totalRawUnit}} used</span>
- <cds-tooltip
- class="cds-ml-3 cds-mr-3"
- [caret]="true"
- description="Shows raw used and total capacity. Raw capacity includes all physical storage before replication or overhead."
- i18n-description
- >
- <cd-icon type="help"></cd-icon>
- </cds-tooltip>
- @if(threshold === 'high') {
- <cds-tag size="md">
- <div cdsTagIcon>
- <cd-icon
- type="warningAltFilled"
- useDefault="true"></cd-icon>
- </div>
- <span i18n>High storage usage</span>
- </cds-tag>
- }
- @else if(threshold === 'critical') {
- <cds-tag
- type="red"
- size="md">
- <div cdsTagIcon>
- <cd-icon
- type="warningAltFilled"
- useDefault="true"></cd-icon>
- </div>
- <span i18n>Capacity critically low</span>
- </cds-tag>
- }
- </h5>
- }
- @else {
- <cds-skeleton-text
- [lines]="1"
- [minLineWidth]="400"
- [maxLineWidth]="400">
- </cds-skeleton-text>
- }
- </div>
- }
- @else {
+ @if (!storageEmptyState) {
+ <div class="overview-storage-card-usage-text">
+ @if (usedRaw !== null && totalRaw !== null && usedRawUnit && totalRawUnit) {
+ <h5>
+ <span
+ class="cds--type-heading-05"
+ i18n
+ >{{ usedRaw }} </span
+ >
+ <span
+ class="cds--type-body-02"
+ i18n
+ >{{ usedRawUnit }} of {{ totalRaw }} {{ totalRawUnit }} used</span
+ >
+ <cds-tooltip
+ class="cds-ml-3 cds-mr-3"
+ [caret]="true"
+ description="Shows raw used and total capacity. Raw capacity includes all physical storage before replication or overhead."
+ i18n-description
+ >
+ <cd-icon type="help"></cd-icon>
+ </cds-tooltip>
+ @if (threshold === 'high') {
+ <cds-tag size="md">
+ <div cdsTagIcon>
+ <cd-icon
+ type="warningAltFilled"
+ useDefault="true"
+ ></cd-icon>
+ </div>
+ <span i18n>High storage usage</span>
+ </cds-tag>
+ } @else if (threshold === 'critical') {
+ <cds-tag
+ type="red"
+ size="md"
+ >
+ <div cdsTagIcon>
+ <cd-icon
+ type="warningAltFilled"
+ useDefault="true"
+ ></cd-icon>
+ </div>
+ <span i18n>Capacity critically low</span>
+ </cds-tag>
+ }
+ </h5>
+ } @else {
+ <cds-skeleton-text
+ [lines]="1"
+ [minLineWidth]="400"
+ [maxLineWidth]="400"
+ >
+ </cds-skeleton-text>
+ }
+ </div>
+ } @else {
<cd-empty-state
text="You can view capacity usage and related metrics here once you add storage."
title="Storage is not configured yet"
i18n-title
- i18n-text>
+ i18n-text
+ >
<button
cdsButton="primary"
i18n
size="sm"
[routerLink]="['/add-storage']"
type="button"
- >
+ >
Add storage
<cd-icon
type="add"
- class="cds--btn__icon"></cd-icon>
+ class="cds--btn__icon"
+ ></cd-icon>
</button>
</cd-empty-state>
}
<!-- CAPACITY BREAKDOWN CHART -->
@if (!prometheusEmptyState && !storageEmptyState) {
- @if(isBreakdownLoaded) {
- <ibm-meter-chart
- [options]="options"
- [data]="breakdownData"
- class="overview-storage-card-chart"></ibm-meter-chart>
- } @else {
- <cds-skeleton-text
- [lines]="1"
- [minLineWidth]="1200"
- [maxLineWidth]="1200">
- </cds-skeleton-text>
-}
- <!-- DATA CONSUMPTION TREND -->
- @if(consumptionTrendData.length) {
- <div cdsRow
- class="align-items-center cds-ml-2 cds-mt-6">
- <div cdsCol
- [columnNumbers]="{ lg: 14, md: 10, sm: 16 }">
- <cd-area-chart chartTitle="Consumption trend"
- [chartKey]="'Consumption trend'"
- [dataUnit]="'B'"
- [legendEnabled]="false"
- [rawData]="consumptionTrendData"
- [subHeading]="'Shows last 7 days of storage consumption trends based on recent usage'"
- [height]="'200px'"
- [decimals]="2"
- [chartType]="'area'">
- </cd-area-chart>
- </div>
- <div cdsCol
- [columnNumbers]="{ lg: 2, md: 8, sm: 8 }">
- <div cdsStack="vertical"
- gap="4">
- <div cdsStack="vertical"
- gap="1">
- <span class="cds--type-heading-03">{{ estimatedTimeUntilFull }}</span>
- <div class="consumption-stats-wrapper">
- <cds-tooltip-definition
- [autoAlign]="true"
- [highContrast]="true"
- [openOnHover]="false"
- [dropShadow]="true"
- [caret]="true"
- description="Based on recent average consumption. Actual time until full may vary based on changes in consumption patterns."
- i18n-description
- i18n>
- Estimated time until full
- </cds-tooltip-definition>
- </div>
+ @if (isBreakdownLoaded) {
+ <ibm-meter-chart
+ [options]="options"
+ [data]="breakdownData"
+ class="overview-storage-card-chart"
+ ></ibm-meter-chart>
+ } @else {
+ <cds-skeleton-text
+ [lines]="1"
+ [minLineWidth]="1200"
+ [maxLineWidth]="1200"
+ >
+ </cds-skeleton-text>
+ }
+ <!-- DATA CONSUMPTION TREND -->
+ @if (consumptionTrendData.length) {
+ <div
+ cdsRow
+ class="align-items-center cds-ml-2 cds-mt-6"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 14, md: 10, sm: 16 }"
+ >
+ <cd-area-chart
+ chartTitle="Consumption trend"
+ [chartKey]="'Consumption trend'"
+ [dataUnit]="'B'"
+ [legendEnabled]="false"
+ [rawData]="consumptionTrendData"
+ [subHeading]="'Shows last 7 days of storage consumption trends based on recent usage'"
+ [height]="'200px'"
+ [decimals]="2"
+ [chartType]="'area'"
+ >
+ </cd-area-chart>
</div>
- <div cdsStack="vertical"
- gap="1">
- <span class="cds--type-heading-03">{{ averageDailyConsumption }}</span>
- <div class="consumption-stats-wrapper">
- <cds-tooltip-definition
- [autoAlign]="true"
- [highContrast]="true"
- [openOnHover]="false"
- [dropShadow]="true"
- [caret]="true"
- description="Based on the average daily consumption over the last 7 days"
- i18n-description
- i18n>
- Average consumption
- </cds-tooltip-definition>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 2, md: 8, sm: 8 }"
+ >
+ <div
+ cdsStack="vertical"
+ gap="4"
+ >
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <span class="cds--type-heading-03">{{ estimatedTimeUntilFull }}</span>
+ <div class="consumption-stats-wrapper">
+ <cds-tooltip-definition
+ [autoAlign]="true"
+ [highContrast]="true"
+ [openOnHover]="false"
+ [dropShadow]="true"
+ [caret]="true"
+ description="Based on recent average consumption. Actual time until full may vary based on changes in consumption patterns."
+ i18n-description
+ i18n
+ >
+ Estimated time until full
+ </cds-tooltip-definition>
+ </div>
+ </div>
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
+ <span class="cds--type-heading-03">{{ averageDailyConsumption }}</span>
+ <div class="consumption-stats-wrapper">
+ <cds-tooltip-definition
+ [autoAlign]="true"
+ [highContrast]="true"
+ [openOnHover]="false"
+ [dropShadow]="true"
+ [caret]="true"
+ description="Based on the average daily consumption over the last 7 days"
+ i18n-description
+ i18n
+ >
+ Average consumption
+ </cds-tooltip-definition>
+ </div>
+ </div>
</div>
</div>
</div>
- </div>
- </div>
+ }
}
-}
</cd-productive-card>
<legend>{{ serviceType }}.{{ serviceId }}</legend>
-<cd-table-performance-counter [serviceType]="serviceType"
- [serviceId]="serviceId">
+<cd-table-performance-counter
+ [serviceType]="serviceType"
+ [serviceId]="serviceId"
+>
</cd-table-performance-counter>
-<cd-table *ngIf="counters; else warning"
- [data]="counters"
- [columns]="columns"
- columnMode="flex"
- [autoSave]="false"
- (fetchData)="getCounters($event)">
- <ng-template #valueTpl
- let-row="data.row">
+<cd-table
+ *ngIf="counters; else warning"
+ [data]="counters"
+ [columns]="columns"
+ columnMode="flex"
+ [autoSave]="false"
+ (fetchData)="getCounters($event)"
+>
+ <ng-template
+ #valueTpl
+ let-row="data.row"
+ >
{{ row.value | dimless }} {{ row.unit }}
</ng-template>
</cd-table>
<ng-template #warning>
- <cd-alert-panel type="warning"
- i18n>Performance counters not available</cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ i18n
+ >Performance counters not available</cd-alert-panel
+ >
</ng-template>
[hasScrollingContent]="false"
(overlaySelected)="closeModal()"
>
- <cds-modal-header
- (closeSelect)="closeModal()"
- >
+ <cds-modal-header (closeSelect)="closeModal()">
<h3
cdsModalHeaderHeading
i18n
</h3>
</cds-modal-header>
- <ng-container
- class="modal-content"
- >
+ <ng-container class="modal-content">
<form
[formGroup]="form"
novalidate
cdsModalContent
class="modal-wrapper"
>
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-text-label
[invalid]="!form.controls.name.valid && form.controls.name.dirty"
[invalidText]="nameError"
/>
</cds-text-label>
- <ng-template
- #nameError
- >
+ <ng-template #nameError>
@if (form.showError('name', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
@if (form.showError('name', formDir, 'pattern')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The name can only consist of alphanumeric characters, dashes and underscores.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The name can only consist of alphanumeric characters, dashes and underscores.
+ </span>
}
@if (form.showError('name', formDir, 'uniqueName')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The chosen erasure code profile name is already in use.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The chosen erasure code profile name is already in use.
+ </span>
}
</ng-template>
</div>
<!-- Root -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-dropdown
label="Root"
id="root"
[invalidText]="rootError"
i18n
>
- <cds-dropdown-list
- [items]="buckets"
- >
- </cds-dropdown-list>
+ <cds-dropdown-list [items]="buckets"> </cds-dropdown-list>
</cds-dropdown>
- <ng-template
- #rootError
- >
+ <ng-template #rootError>
@if (form.showError('root', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
</ng-template>
</div>
<!-- Failure Domain -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-select
label="Failure domain type"
id="failure_domain"
i18n
>
@if (!failureDomains) {
- <option
- value=""
- >
- Loading...
- </option>
+ <option value="">Loading...</option>
}
@for (domain of failureDomainKeys; track domain) {
- <option
- [value]="domain"
- >
- {{ domain }} ( {{failureDomains[domain].length}} )
- </option>
+ <option [value]="domain">{{ domain }} ( {{ failureDomains[domain].length }} )</option>
}
</cds-select>
- <ng-template
- #failureDomainError
- >
+ <ng-template #failureDomainError>
<span
class="invalid-feedback"
i18n
</div>
<!-- Class -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-select
label="Device class"
id="device_class"
[helperText]="tooltips.device_class"
i18n
>
- <option
- value=""
- >
- All devices
- </option>
+ <option value="">All devices</option>
@for (deviceClass of devices; track deviceClass) {
- <option
- [value]="deviceClass"
- >
- {{ deviceClass }}
- </option>
+ <option [value]="deviceClass">
+ {{ deviceClass }}
+ </option>
}
</cds-select>
- <ng-template
- #deviceClassError
- >
+ <ng-template #deviceClassError>
<span
class="invalid-feedback"
i18n
[hasScrollingContent]="true"
(overlaySelected)="closeModal()"
>
- <cds-modal-header
- (closeSelect)="closeModal()"
- >
+ <cds-modal-header (closeSelect)="closeModal()">
<h3
cdsModalHeaderHeading
i18n
novalidate
>
<!-- Name -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-text-label
[invalid]="!form.controls.name.valid && form.controls.name.dirty"
[invalidText]="nameError"
placeholder="Add issue title"
/>
</cds-text-label>
- <ng-template
- #nameError
- >
+ <ng-template #nameError>
@if (form.showError('name', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
@if (form.showError('name', formDir, 'pattern')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The name can only consist of alphanumeric characters, dashes and underscores.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The name can only consist of alphanumeric characters, dashes and underscores.
+ </span>
}
@if (form.showError('name', formDir, 'uniqueName')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The chosen erasure code profile name is already in use.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The chosen erasure code profile name is already in use.
+ </span>
}
</ng-template>
</div>
<!-- Plugin -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-select
[label]="pluginLabelTpl"
id="plugin"
i18n
>
@if (!plugins) {
- <option
- value=""
- >
- Loading...
- </option>
+ <option value="">Loading...</option>
}
@for (plugin of plugins; track plugin) {
- <option
- [value]="plugin"
- [selected]="plugin === PLUGIN.ISA"
- >
- @if(plugin === PLUGIN.JERASURE) {
- {{ plugin | upperFirst }}
- } @else {
- {{ plugin | uppercase }}
- }
- </option>
+ <option
+ [value]="plugin"
+ [selected]="plugin === PLUGIN.ISA"
+ >
+ @if (plugin === PLUGIN.JERASURE) {
+ {{ plugin | upperFirst }}
+ } @else {
+ {{ plugin | uppercase }}
+ }
+ </option>
}
</cds-select>
- <ng-template
- #pluginError
- >
+ <ng-template #pluginError>
<span
class="invalid-feedback"
i18n
</span>
</ng-template>
- <ng-template
- #pluginLabelTpl
- >
+ <ng-template #pluginLabelTpl>
Plugin
- <cd-helper
- [html]="tooltips.plugins[plugin].description"
- >
- </cd-helper>
+ <cd-helper [html]="tooltips.plugins[plugin].description"> </cd-helper>
</ng-template>
</div>
<!-- Data Chunk k -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-number
id="k"
label="Data chunks (k)"
i18n
>
</cds-number>
- <ng-template
- #dataChunkError
- >
+ <ng-template #dataChunkError>
@if (form.showError('k', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
@if (form.showError('k', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Must be equal to or greater than 2.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Must be equal to or greater than 2.
+ </span>
}
- @if (form.showError('k', formDir, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Osd) {
- <span
- class="invalid-feedback"
- i18n
- >
- Chunks (k+m) have exceeded the available OSDs of {{deviceCount}}.
- </span>
+ @if (
+ form.showError('k', formDir, 'max') &&
+ form.getValue('crushFailureDomain') === CrushFailureDomains.Osd
+ ) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Chunks (k+m) have exceeded the available OSDs of {{ deviceCount }}.
+ </span>
}
- @if (form.showError('k', formDir, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Host) {
- <span
- class="invalid-feedback"
- i18n
- >
- Chunks (k+m+1) have exceeded the available hosts of {{deviceCount}}.
- </span>
+ @if (
+ form.showError('k', formDir, 'max') &&
+ form.getValue('crushFailureDomain') === CrushFailureDomains.Host
+ ) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Chunks (k+m+1) have exceeded the available hosts of {{ deviceCount }}.
+ </span>
}
@if (form.showError('k', formDir, 'unequal')) {
- <span
- class="invalid-feedback"
- i18n
- >
- For an equal distribution k has to be a multiple of (k+m)/l.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ For an equal distribution k has to be a multiple of (k+m)/l.
+ </span>
}
@if (form.showError('k', formDir, 'kLowerM')) {
- <span
- class="invalid-feedback"
- i18n
- >
- K has to be equal to or greater than m in order to recover data correctly through c.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ K has to be equal to or greater than m in order to recover data correctly through c.
+ </span>
}
@if (plugin === 'lrc') {
- <span
- class="form-text text-muted"
- i18n
- >
- Distribution factor: {{lrcMultiK}}
- </span>
+ <span
+ class="form-text text-muted"
+ i18n
+ >
+ Distribution factor: {{ lrcMultiK }}
+ </span>
}
</ng-template>
</div>
<!-- Coding chunks (m) -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-number
id="m"
label="Coding chunks (m)"
</cds-number>
<ng-template #codeChunkError>
@if (form.showError('m', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
@if (form.showError('m', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Must be equal to or greater than 1.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Must be equal to or greater than 1.
+ </span>
}
- @if (form.showError('m', formDir, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Osd) {
- <span
- class="invalid-feedback"
- i18n
- >
- Chunks (k+m) have exceeded the available OSDs of {{deviceCount}}.
- </span>
+ @if (
+ form.showError('m', formDir, 'max') &&
+ form.getValue('crushFailureDomain') === CrushFailureDomains.Osd
+ ) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Chunks (k+m) have exceeded the available OSDs of {{ deviceCount }}.
+ </span>
}
- @if (form.showError('m', formDir, 'max') && form.getValue('crushFailureDomain') === CrushFailureDomains.Host) {
- <span
- class="invalid-feedback"
- i18n
- >
- Chunks (k+m+1) have exceeded the available hosts of {{deviceCount}}.
- </span>
+ @if (
+ form.showError('m', formDir, 'max') &&
+ form.getValue('crushFailureDomain') === CrushFailureDomains.Host
+ ) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Chunks (k+m+1) have exceeded the available hosts of {{ deviceCount }}.
+ </span>
}
</ng-template>
</div>
<!-- Durability estimator (c) -->
@if (plugin === 'shec') {
- <div
- class="form-item"
- >
- <cds-number
- id="c"
- label="Durability estimator (c)"
- [helperText]="tooltips.c"
- min="1"
- [invalid]="!form.controls.c.valid && form.controls.c.dirty"
- [invalidText]="durabilityError"
- formControlName="c"
- i18n
- >
- </cds-number>
- <ng-template
- #durabilityError
- >
- @if (form.showError('c', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Must be equal to or greater than 1.
- </span>
- }
- @if (form.showError('c', formDir, 'cGreaterM')) {
- <span
- class="invalid-feedback"
- i18n
- >
- C has to be equal to or lower than m as m defines the amount of chunks that can be used.
- </span>
- }
- </ng-template>
- </div>
- }
-
- <!--Helper chunks (d)-->
- @if (plugin === PLUGIN.CLAY) {
- <div
- cdsRow
- class="form-item form-item-append"
- >
- <div
- cdsCol
- [columnNumbers]="{ lg: 15 }"
- >
+ <div class="form-item">
<cds-number
- id="d"
- [label]="labelTpl"
- [helperText]="dCalc ? dCalcTooltip : dHelper"
- [invalid]="form.controls.d.invalid && form.controls.d.dirty"
- [invalidText]="dError"
- formControlName="d"
+ id="c"
+ label="Durability estimator (c)"
+ [helperText]="tooltips.c"
+ min="1"
+ [invalid]="!form.controls.c.valid && form.controls.c.dirty"
+ [invalidText]="durabilityError"
+ formControlName="c"
i18n
>
</cds-number>
+ <ng-template #durabilityError>
+ @if (form.showError('c', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Must be equal to or greater than 1.
+ </span>
+ }
+ @if (form.showError('c', formDir, 'cGreaterM')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ C has to be equal to or lower than m as m defines the amount of chunks that can be
+ used.
+ </span>
+ }
+ </ng-template>
</div>
+ }
+ <!--Helper chunks (d)-->
+ @if (plugin === PLUGIN.CLAY) {
<div
- cdsCol
- [columnNumbers]="{ lg: 1 }"
- class="item-action-btn"
- >
- @if(dCalc) {
- <cds-icon-button
- data-testid="d-calc-btn"
- kind="primary"
- size="sm"
- (click)="toggleDCalc()"
- >
- <svg
- cdsIcon="unlocked"
- size="16"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- } @else {
- <cds-icon-button
- data-testid="d-calc-btn"
- kind="primary"
- size="sm"
- (click)="toggleDCalc()"
- >
- <svg
- cdsIcon="locked"
- size="16"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- }
- </div>
- <ng-template
- #dHelper
- >
- <span>
- @if (!dCalc && (getDMin() < getDMax())) {
- <p
- class="form-text text-muted"
+ cdsRow
+ class="form-item form-item-append"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 15 }"
+ >
+ <cds-number
+ id="d"
+ [label]="labelTpl"
+ [helperText]="dCalc ? dCalcTooltip : dHelper"
+ [invalid]="form.controls.d.invalid && form.controls.d.dirty"
+ [invalidText]="dError"
+ formControlName="d"
i18n
>
- D can be set from {{getDMin()}} to {{getDMax()}}
- </p>
+ </cds-number>
+ </div>
+
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
+ >
+ @if (dCalc) {
+ <cds-icon-button
+ data-testid="d-calc-btn"
+ kind="primary"
+ size="sm"
+ (click)="toggleDCalc()"
+ >
+ <svg
+ cdsIcon="unlocked"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ } @else {
+ <cds-icon-button
+ data-testid="d-calc-btn"
+ kind="primary"
+ size="sm"
+ (click)="toggleDCalc()"
+ >
+ <svg
+ cdsIcon="locked"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
}
- @if (!dCalc && getDMin() === getDMax()) {
- <p
- class="form-text text-muted"
- i18n
- >
- D can only be set to {{getDMax()}}
- </p>
+ </div>
+ <ng-template #dHelper>
+ <span>
+ @if (!dCalc && getDMin() < getDMax()) {
+ <p
+ class="form-text text-muted"
+ i18n
+ >
+ D can be set from {{ getDMin() }} to {{ getDMax() }}
+ </p>
+ }
+ @if (!dCalc && getDMin() === getDMax()) {
+ <p
+ class="form-text text-muted"
+ i18n
+ >
+ D can only be set to {{ getDMax() }}
+ </p>
+ }
+ </span>
+ </ng-template>
+ <ng-template #dCalcTooltip>
+ <span i18n> D is automatically updated on k and m changes </span>
+ </ng-template>
+ <ng-template #dError>
+ @if (form.showError('d', formDir, 'dMin')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ D has to be greater than k ( {{ getDMin() }} ).
+ </span>
}
- </span>
- </ng-template>
- <ng-template
- #dCalcTooltip
- >
- <span
- i18n
- >
- D is automatically updated on k and m changes
- </span>
- </ng-template>
- <ng-template
- #dError
- >
- @if (form.showError('d', formDir, 'dMin')) {
- <span
- class="invalid-feedback"
- i18n
- >
- D has to be greater than k ( {{getDMin()}} ).
- </span>
- }
- @if (form.showError('d', formDir, 'dMax')) {
- <span
- class="invalid-feedback"
- i18n
- >
- D has to be lower than k + m ( {{getDMax()}} ).
- </span>
- }
- </ng-template>
+ @if (form.showError('d', formDir, 'dMax')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ D has to be lower than k + m ( {{ getDMax() }} ).
+ </span>
+ }
+ </ng-template>
- <ng-template
- #labelTpl
- >
- Helper chunks (d)
- <cd-helper
- [html]="tooltips.plugins.clay.d"
- >
- </cd-helper>
- </ng-template>
- </div>
+ <ng-template #labelTpl>
+ Helper chunks (d)
+ <cd-helper [html]="tooltips.plugins.clay.d"> </cd-helper>
+ </ng-template>
+ </div>
}
<!-- Locality (l) -->
@if (plugin === PLUGIN.LRC) {
- <div
- cdsrow
- class="form-item form-item-append"
- >
- <cds-number
- id="l"
- [label]="localityLabelTpl"
- [helperText]="lHelper"
- [invalid]="form.controls.l.invalid && (form.controls.l.dirty || form.controls.l.touched)"
- [invalidText]="lError"
- formControlName="l"
- min="1"
- placeholder="Coding chunks..."
- i18n
- i18n-helperText
- >
- </cds-number>
-
- <ng-template
- #lHelper
- >
- <span>
- Locality groups: {{lrcGroups}}
- </span>
- </ng-template>
-
- <ng-template
- #lError
+ <div
+ cdsrow
+ class="form-item form-item-append"
>
- @if (form.showError('l', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
- }
- @if (form.showError('l', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Must be equal to or greater than 1.
- </span>
- }
- @if (form.showError('l', formDir, 'unequal')) {
- <span
- class="invalid-feedback"
+ <cds-number
+ id="l"
+ [label]="localityLabelTpl"
+ [helperText]="lHelper"
+ [invalid]="
+ form.controls.l.invalid && (form.controls.l.dirty || form.controls.l.touched)
+ "
+ [invalidText]="lError"
+ formControlName="l"
+ min="1"
+ placeholder="Coding chunks..."
i18n
+ i18n-helperText
>
- Can't split up chunks (k+m) correctly with the current locality.
- </span>
- }
- </ng-template>
+ </cds-number>
- <ng-template
- #localityLabelTpl
- >
- Locality (l)
- <cd-helper
- [html]="tooltips.plugins.lrc.l"
- >
- </cd-helper>
- </ng-template>
- </div>
+ <ng-template #lHelper>
+ <span> Locality groups: {{ lrcGroups }} </span>
+ </ng-template>
+
+ <ng-template #lError>
+ @if (form.showError('l', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
+ }
+ @if (form.showError('l', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Must be equal to or greater than 1.
+ </span>
+ }
+ @if (form.showError('l', formDir, 'unequal')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Can't split up chunks (k+m) correctly with the current locality.
+ </span>
+ }
+ </ng-template>
+
+ <ng-template #localityLabelTpl>
+ Locality (l)
+ <cd-helper [html]="tooltips.plugins.lrc.l"> </cd-helper>
+ </ng-template>
+ </div>
}
<!-- Crush failure domain-->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-select
label="Crush failure domain"
id="crushFailureDomain"
[helperText]="tooltips.crushFailureDomain"
i18n
>
- @if (!failureDomains) {
- <option
- value=""
- >
- Loading...
- </option>
- }
- @for (domain of failureDomainKeys; track domain) {
- <option
- [value]="domain"
- [selected]="domain.toLowerCase() === CrushFailureDomains.Host"
- >
- {{ domain }} ( {{failureDomains[domain].length}} )
- </option>
- }
+ @if (!failureDomains) {
+ <option value="">Loading...</option>
+ }
+ @for (domain of failureDomainKeys; track domain) {
+ <option
+ [value]="domain"
+ [selected]="domain.toLowerCase() === CrushFailureDomains.Host"
+ >
+ {{ domain }} ( {{ failureDomains[domain].length }} )
+ </option>
+ }
</cds-select>
</div>
i18n
>
</cds-number>
- <ng-template
- #crushNumFailureDomainsError
- >
+ <ng-template #crushNumFailureDomainsError>
<ng-container
- *ngTemplateOutlet="crushFailureDomainValidationErrors; context: {
- control: form.get('crushNumFailureDomains'),
- requiredText: 'This field is required when crush osds per failure domain is set!',
- showMaxFailureDomains: true
- }"
+ *ngTemplateOutlet="
+ crushFailureDomainValidationErrors;
+ context: {
+ control: form.get('crushNumFailureDomains'),
+ requiredText: 'This field is required when crush osds per failure domain is set!',
+ showMaxFailureDomains: true
+ }
+ "
>
</ng-container>
</ng-template>
i18n
>
</cds-number>
- <ng-template
- #crushOsdsPerFailureDomainError
- >
+ <ng-template #crushOsdsPerFailureDomainError>
<ng-container
- *ngTemplateOutlet="crushFailureDomainValidationErrors; context: {
- control: form.get('crushOsdsPerFailureDomain'),
- requiredText: 'This field is required when crush num failure domain is set!',
- showMaxFailureDomains: false
- }"
+ *ngTemplateOutlet="
+ crushFailureDomainValidationErrors;
+ context: {
+ control: form.get('crushOsdsPerFailureDomain'),
+ requiredText: 'This field is required when crush num failure domain is set!',
+ showMaxFailureDomains: false
+ }
+ "
>
</ng-container>
</ng-template>
let-showMaxFailureDomains="showMaxFailureDomains"
>
@if (control?.errors) {
- @if (control.hasError('required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- {{ requiredText }}
- </span>
- }
- @if (showMaxFailureDomains && control.hasError('maxFailureDomains')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The number of failure domains ({{ form.controls.crushNumFailureDomains.value }}) cannot exceed the available count ({{ failureDomains[form.controls.crushFailureDomain.value]?.length || 0 }}) for the selected failure domain type ({{ form.controls.crushFailureDomain.value }}).
- </span>
- }
- @if (control.hasError('pattern')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Enter a valid positive number
- </span>
- }
+ @if (control.hasError('required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ {{ requiredText }}
+ </span>
+ }
+ @if (showMaxFailureDomains && control.hasError('maxFailureDomains')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The number of failure domains ({{ form.controls.crushNumFailureDomains.value }})
+ cannot exceed the available count ({{
+ failureDomains[form.controls.crushFailureDomain.value]?.length || 0
+ }}) for the selected failure domain type ({{
+ form.controls.crushFailureDomain.value
+ }}).
+ </span>
+ }
+ @if (control.hasError('pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Enter a valid positive number
+ </span>
+ }
}
</ng-template>
<!-- Crush locality -->
@if (plugin === PLUGIN.LRC) {
- <div
- class="form-item"
- >
- <cds-select
- label="Crush Locality"
- id="crushLocality"
- [helperText]="tooltips.plugins.lrc.crushLocality"
- formControlName="crushLocality"
- i18n
- >
- @if (!failureDomains) {
- <option
- value=""
- >
- Loading...
- </option>
- }
- @if (failureDomainKeys.length > 0) {
- <option
- value=""
- >
- None
- </option>
- }
- @for (domain of failureDomainKeys; track domain) {
- <option
- [value]="domain"
+ <div class="form-item">
+ <cds-select
+ label="Crush Locality"
+ id="crushLocality"
+ [helperText]="tooltips.plugins.lrc.crushLocality"
+ formControlName="crushLocality"
+ i18n
>
- {{ domain }} ( {{failureDomains[domain].length}} )
- </option>
- }
- </cds-select>
- </div>
+ @if (!failureDomains) {
+ <option value="">Loading...</option>
+ }
+ @if (failureDomainKeys.length > 0) {
+ <option value="">None</option>
+ }
+ @for (domain of failureDomainKeys; track domain) {
+ <option [value]="domain">{{ domain }} ( {{ failureDomains[domain].length }} )</option>
+ }
+ </cds-select>
+ </div>
}
<!-- Scalar mds -->
@if (PLUGIN.CLAY === plugin) {
- <div
- class="form-item"
- >
- <cds-select
- label="Scalar mds"
- id="scalar_mds"
- formControlName="scalar_mds"
- [helperText]="tooltips.plugins.clay.scalar_mds"
- i18n
- >
- @for (plugin of [PLUGIN.JERASURE, PLUGIN.ISA, PLUGIN.SHEC]; track plugin) {
- <option
- [value]="plugin"
+ <div class="form-item">
+ <cds-select
+ label="Scalar mds"
+ id="scalar_mds"
+ formControlName="scalar_mds"
+ [helperText]="tooltips.plugins.clay.scalar_mds"
+ i18n
>
- {{ plugin }}
- </option>
- }
- </cds-select>
- </div>
+ @for (plugin of [PLUGIN.JERASURE, PLUGIN.ISA, PLUGIN.SHEC]; track plugin) {
+ <option [value]="plugin">
+ {{ plugin }}
+ </option>
+ }
+ </cds-select>
+ </div>
}
<!-- Technique -->
@if ([PLUGIN.JERASURE, PLUGIN.ISA, PLUGIN.CLAY].includes(plugin)) {
- <div
- class="form-item"
- >
- <cds-select
- label="Technique"
- id="technique"
- formControlName="technique"
- [helperText]="tooltips.plugins[plugin]?.technique"
- i18n
- >
- @for (technique of techniques; track technique) {
- <option
- [value]="technique"
+ <div class="form-item">
+ <cds-select
+ label="Technique"
+ id="technique"
+ formControlName="technique"
+ [helperText]="tooltips.plugins[plugin]?.technique"
+ i18n
>
- {{ technique }}
- </option>
- }
- </cds-select>
- </div>
+ @for (technique of techniques; track technique) {
+ <option [value]="technique">
+ {{ technique }}
+ </option>
+ }
+ </cds-select>
+ </div>
}
<!-- Packetsize -->
@if (plugin === PLUGIN.JERASURE) {
- <div
- cdsrow
- class="form-item"
- >
- <cds-number
- id="packetSize"
- label="Packetsize"
- [helperText]="tooltips.plugins.jerasure.packetSize"
- [invalid]="form.controls.packetSize.invalid && form.controls.packetSize.dirty"
- [invalidText]="packetSizeError"
- formControlName="packetSize"
- min="1"
- i18n
- >
- </cds-number>
- <ng-template
- #packetSizeError
+ <div
+ cdsrow
+ class="form-item"
>
- @if (form.showError('packetSize', formDir, 'min')) {
- <span
- class="invalid-feedback"
+ <cds-number
+ id="packetSize"
+ label="Packetsize"
+ [helperText]="tooltips.plugins.jerasure.packetSize"
+ [invalid]="form.controls.packetSize.invalid && form.controls.packetSize.dirty"
+ [invalidText]="packetSizeError"
+ formControlName="packetSize"
+ min="1"
i18n
>
- Must be equal to or greater than 1.
- </span>
- }
- </ng-template>
- </div>
+ </cds-number>
+ <ng-template #packetSizeError>
+ @if (form.showError('packetSize', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Must be equal to or greater than 1.
+ </span>
+ }
+ </ng-template>
+ </div>
}
<!-- Crush root -->
@if ([PLUGIN.JERASURE, PLUGIN.ISA, PLUGIN.CLAY].includes(plugin)) {
- <div
- class="form-item"
- >
- <cds-dropdown
- label="Crush root"
- id="crushRoot"
- formControlName="crushRoot"
- [placeholder]="'Select crush root...'"
- [helperText]="tooltips.crushRoot"
- i18n-label
- >
- <cds-dropdown-list
- [items]="buckets"
- >
- </cds-dropdown-list>
- </cds-dropdown>
- </div>
+ <div class="form-item">
+ <cds-dropdown
+ label="Crush root"
+ id="crushRoot"
+ formControlName="crushRoot"
+ [placeholder]="'Select crush root...'"
+ [helperText]="tooltips.crushRoot"
+ i18n-label
+ >
+ <cds-dropdown-list [items]="buckets"> </cds-dropdown-list>
+ </cds-dropdown>
+ </div>
}
<!-- Crush device class -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-select
[label]="crushDeviceClassLabelTpl"
id="crushDeviceClass"
i18n
i18n-helperText
>
- <option
- value=""
- >
- All devices
- </option>
+ <option value="">All devices</option>
@for (deviceClass of devices; track deviceClass) {
- <option
- [value]="deviceClass"
- >
- {{ deviceClass }}
- </option>
+ <option [value]="deviceClass">
+ {{ deviceClass }}
+ </option>
}
</cds-select>
i18n
>
Crush device class
- <cd-helper
- [html]="tooltips.crushDeviceClass"
- >
- </cd-helper>
+ <cd-helper [html]="tooltips.crushDeviceClass"> </cd-helper>
</ng-template>
</div>
<!-- Directory -->
- <div
- class="form-item"
- >
- <cds-text-label
- [helperText]="tooltips.directory"
- >
+ <div class="form-item">
+ <cds-text-label [helperText]="tooltips.directory">
Directory
<input
cdsText
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="pool-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="pool-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [renderObjects]="true"
- [data]="poolDetails"
- [autoReload]="false">
+ <cd-table-key-value
+ [renderObjects]="true"
+ [data]="poolDetails"
+ [autoReload]="false"
+ >
</cd-table-key-value>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="performance-details"
- *ngIf="permissions.grafana.read">
- <a ngbNavLink
- i18n>Performance Details</a>
+ <ng-container
+ ngbNavItem="performance-details"
+ *ngIf="permissions.grafana.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Performance Details</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Pool details"
- grafanaPath="ceph-pool-details?var-pool_name={{selection.pool_name}}"
- [type]="'metrics'"
- uid="-xyV8KCiz"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="Pool details"
+ grafanaPath="ceph-pool-details?var-pool_name={{ selection.pool_name }}"
+ [type]="'metrics'"
+ uid="-xyV8KCiz"
+ grafanaStyle="three"
+ >
</cd-grafana>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="configuration"
- *ngIf="selection.type === 'replicated'">
- <a ngbNavLink
- i18n>Configuration</a>
+ <ng-container
+ ngbNavItem="configuration"
+ *ngIf="selection.type === 'replicated'"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Configuration</a
+ >
<ng-template ngbNavContent>
<cd-rbd-configuration-table [data]="selectedPoolConfiguration"></cd-rbd-configuration-table>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="cache-tiers-details"
- *ngIf="selection['tiers']?.length > 0">
- <a ngbNavLink
- i18n>Cache Tiers Details</a>
+ <ng-container
+ ngbNavItem="cache-tiers-details"
+ *ngIf="selection['tiers']?.length > 0"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Cache Tiers Details</a
+ >
<ng-template ngbNavContent>
- <cd-table [data]="cacheTiers"
- [columns]="cacheTierColumns"
- [autoSave]="false"
- columnMode="flex">
+ <cd-table
+ [data]="cacheTiers"
+ [columns]="cacheTierColumns"
+ [autoSave]="false"
+ columnMode="flex"
+ >
</cd-table>
</ng-template>
</ng-container>
cdsCol
[columnNumbers]="{ md: 4 }"
>
- <ng-container
- *cdFormLoading="loading"
- >
+ <ng-container *cdFormLoading="loading">
<form
name="form"
[formGroup]="form"
class="form-header"
>
{{ action | titlecase }} {{ resource | upperFirst }}
- @if (isStretchMode) {
- <cd-help-text>
- Stretch cluster is enabled. Only replicated pool type is supported in Stretch mode.
- </cd-help-text>
- }
+ @if (isStretchMode) {
+ <cd-help-text>
+ Stretch cluster is enabled. Only replicated pool type is supported in Stretch mode.
+ </cd-help-text>
+ }
</div>
<!-- Name -->
<div
class="form-item"
cdsRow
>
- <div
- cdsCol
- >
+ <div cdsCol>
<cds-text-label
labelInputID="name"
i18n
</cds-text-label>
<ng-template #nameError>
@if (form.showError('name', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
@if (form.showError('name', formDir, 'uniqueName')) {
- <span
- class="invalid-feedback"
- i18n
- >
- The chosen Ceph pool name is already in use.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The chosen Ceph pool name is already in use.
+ </span>
}
@if (form.showError('name', formDir, 'rbdPool')) {
- <span
- class="invalid-feedback"
- i18n
- >
- It's not possible to create an RBD pool with '/' in the name. Please change the name
- or remove 'rbd' from the applications list.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ It's not possible to create an RBD pool with '/' in the name. Please change the name
+ or remove 'rbd' from the applications list.
+ </span>
}
@if (form.showError('name', formDir, 'pattern')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Pool name can only contain letters, numbers, '.', '-', '_' or '/'.
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Pool name can only contain letters, numbers, '.', '-', '_' or '/'.
+ </span>
}
</ng-template>
</div>
class="form-item"
cdsRow
>
- <div
- cdsCol
- >
+ <div cdsCol>
<legend
class="cds--label"
i18n
Pool type
</legend>
@if (isStretchMode) {
- <cds-tooltip
- description="In stretch mode, only replicated pool type is supported."
- placement="right"
- [highContrast]="true"
- [caret]="true"
- >
+ <cds-tooltip
+ description="In stretch mode, only replicated pool type is supported."
+ placement="right"
+ [highContrast]="true"
+ [caret]="true"
+ >
+ <cds-radio-group
+ formControlName="poolType"
+ cdRequiredField="Pool type"
+ data-testid="pool-type-select"
+ >
+ @for (poolType of data.poolTypes; track poolType) {
+ <cds-radio
+ [value]="poolType"
+ [id]="poolType"
+ [disabled]="isStretchMode && !editing && poolType === 'erasure'"
+ (change)="data.erasureInfo = false; data.crushInfo = false"
+ i18n
+ >
+ {{ poolType | upperFirst }}
+ </cds-radio>
+ }
+ </cds-radio-group>
+ </cds-tooltip>
+ } @else {
<cds-radio-group
formControlName="poolType"
cdRequiredField="Pool type"
data-testid="pool-type-select"
>
@for (poolType of data.poolTypes; track poolType) {
- <cds-radio
- [value]="poolType"
- [id]="poolType"
- [disabled]="isStretchMode && !editing && poolType === 'erasure'"
- (change)="data.erasureInfo = false; data.crushInfo = false;"
- i18n
- >
- {{ poolType | upperFirst }}
- </cds-radio>
+ <cds-radio
+ [value]="poolType"
+ [id]="poolType"
+ [disabled]="isStretchMode && !editing && poolType === 'erasure'"
+ (change)="data.erasureInfo = false; data.crushInfo = false"
+ i18n
+ >
+ {{ poolType | upperFirst }}
+ </cds-radio>
}
</cds-radio-group>
- </cds-tooltip>
- } @else {
- <cds-radio-group
- formControlName="poolType"
- cdRequiredField="Pool type"
- data-testid="pool-type-select"
- >
- @for (poolType of data.poolTypes; track poolType) {
- <cds-radio
- [value]="poolType"
- [id]="poolType"
- [disabled]="isStretchMode && !editing && poolType === 'erasure'"
- (change)="data.erasureInfo = false; data.crushInfo = false;"
- i18n
- >
- {{ poolType | upperFirst }}
- </cds-radio>
- }
- </cds-radio-group>
}
@if (form.showError('poolType', formDir, 'required')) {
- <span
- class="cds--form-requirement invalid-feedback"
- i18n
- >
- This field is required!
- </span>
+ <span
+ class="cds--form-requirement invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
}
</div>
</div>
@if (isReplicated || isErasure) {
- <div>
- <!-- PG Autoscale Mode -->
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
- >
- <cds-select
- formControlName="pgAutoscaleMode"
- [helperText]="poolService.formTooltips.pgAutoscaleModes[form.getValue('pgAutoscaleMode')]"
- label="PG Autoscale"
- i18n-label
- id="pgAutoscaleMode"
- >
- @for (mode of pgAutoscaleModes; track mode) {
- <option [value]="mode">
- {{ mode }}
- </option>
- }
- </cds-select>
- </div>
- </div>
- <!-- Pg number -->
- @if (form.getValue('pgAutoscaleMode') !== 'on') {
- <div
- class="form-item"
- cdsRow
- >
+ <div>
+ <!-- PG Autoscale Mode -->
<div
- cdsCol
+ class="form-item"
+ cdsRow
>
- <cds-number
- label="Placement groups"
- cdRequiredField="Placement groups"
- [helperText]="calculationHelp"
- min="1"
- [invalid]="form.controls.pgNum.invalid && form.controls.pgNum.dirty"
- [invalidText]="pgNumError"
- formControlName="pgNum"
- data-testid="pgNum"
- (handleFocus)="externalPgChange = false"
- (blur)="alignPgs()"
- i18n
- >
- </cds-number>
- <ng-template #pgNumError>
- @if (form.showError('pgNum', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
- >
- This field is required!
- </span>
- }
- @if (form.showError('pgNum', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- At least one placement group is needed!
- </span>
- }
- @if (form.showError('pgNum', formDir, 'pgMax')) {
- <span
- class="invalid-feedback"
- i18n
+ <div cdsCol>
+ <cds-select
+ formControlName="pgAutoscaleMode"
+ [helperText]="
+ poolService.formTooltips.pgAutoscaleModes[form.getValue('pgAutoscaleMode')]
+ "
+ label="PG Autoscale"
+ i18n-label
+ id="pgAutoscaleMode"
>
- The specified PG is out of range. A value from {{ getMinPgs() }} to {{ getMaxPgs() }} is allowed.
- </span>
- }
- </ng-template>
- <ng-template #calculationHelp>
- <span>
- @if (externalPgChange) {
- <span i18n>The current PGs settings were calculated for you, you should make sure the values suit your needs before submit. </span>
+ @for (mode of pgAutoscaleModes; track mode) {
+ <option [value]="mode">
+ {{ mode }}
+ </option>
}
- <cd-doc
- section="pgs"
- docText="Calculation help"
- i18n-docText
- >
- </cd-doc>
- </span>
- </ng-template>
+ </cds-select>
+ </div>
</div>
- </div>
- }
- <!-- Replica Size -->
- @if (isReplicated) {
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
- >
- <cds-number
- label="Replicated size"
- cdRequiredField="Replicated size"
- [invalid]="form.controls.size.invalid && form.controls.size.dirty"
- [helperText]="sizeWarning"
- [invalidText]="sizeError"
- formControlName="size"
- data-testid="size"
- [max]="getMaxSize()"
- [min]="getMinSize()"
- (handleFocus)="externalPgChange = false"
- (input)="alignPgs()"
- i18n
- i18n-helperText
+ <!-- Pg number -->
+ @if (form.getValue('pgAutoscaleMode') !== 'on') {
+ <div
+ class="form-item"
+ cdsRow
>
- </cds-number>
- <ng-template #sizeError>
- @if (form.showError('size', formDir)) {
- <span
- class="invalid-feedback"
- i18n
- >
- Invalid input. Replicated size must be between {{ getMinSize() }} and
- {{ getMaxSize() }}.
- </span>
- }
- </ng-template>
- <ng-template #sizeWarning>
- @if (isStretchMode) {
- <span i18n>
- The replicated size value is predefined for stretch cluster
- </span>
- }
- @if (form.getValue('size') === 1) {
- <span
- class="text-warning-dark"
- i18n
- >
- A size of 1 will not create a replication of the object. The 'Replicated size'
- includes the object itself.
- </span>
- }
- </ng-template>
- </div>
- </div>
- }
- <!-- Flags -->
- @if (info?.is_all_bluestore && isErasure) {
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
- >
- <cds-checkbox
- id="ec-overwrites"
- formControlName="ecOverwrites"
+ <div cdsCol>
+ <cds-number
+ label="Placement groups"
+ cdRequiredField="Placement groups"
+ [helperText]="calculationHelp"
+ min="1"
+ [invalid]="form.controls.pgNum.invalid && form.controls.pgNum.dirty"
+ [invalidText]="pgNumError"
+ formControlName="pgNum"
+ data-testid="pgNum"
+ (handleFocus)="externalPgChange = false"
+ (blur)="alignPgs()"
+ i18n
+ >
+ </cds-number>
+ <ng-template #pgNumError>
+ @if (form.showError('pgNum', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
+ }
+ @if (form.showError('pgNum', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ At least one placement group is needed!
+ </span>
+ }
+ @if (form.showError('pgNum', formDir, 'pgMax')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The specified PG is out of range. A value from {{ getMinPgs() }} to
+ {{ getMaxPgs() }} is allowed.
+ </span>
+ }
+ </ng-template>
+ <ng-template #calculationHelp>
+ <span>
+ @if (externalPgChange) {
+ <span i18n
+ >The current PGs settings were calculated for you, you should make sure the
+ values suit your needs before submit.
+ </span>
+ }
+ <cd-doc
+ section="pgs"
+ docText="Calculation help"
+ i18n-docText
+ >
+ </cd-doc>
+ </span>
+ </ng-template>
+ </div>
+ </div>
+ }
+ <!-- Replica Size -->
+ @if (isReplicated) {
+ <div
+ class="form-item"
+ cdsRow
>
- <ng-container i18n>
- Flags
- </ng-container>
- <cd-help-text i18n>
- EC Overwrites
- </cd-help-text>
- </cds-checkbox>
- </div>
+ <div cdsCol>
+ <cds-number
+ label="Replicated size"
+ cdRequiredField="Replicated size"
+ [invalid]="form.controls.size.invalid && form.controls.size.dirty"
+ [helperText]="sizeWarning"
+ [invalidText]="sizeError"
+ formControlName="size"
+ data-testid="size"
+ [max]="getMaxSize()"
+ [min]="getMinSize()"
+ (handleFocus)="externalPgChange = false"
+ (input)="alignPgs()"
+ i18n
+ i18n-helperText
+ >
+ </cds-number>
+ <ng-template #sizeError>
+ @if (form.showError('size', formDir)) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Invalid input. Replicated size must be between {{ getMinSize() }} and
+ {{ getMaxSize() }}.
+ </span>
+ }
+ </ng-template>
+ <ng-template #sizeWarning>
+ @if (isStretchMode) {
+ <span i18n> The replicated size value is predefined for stretch cluster </span>
+ }
+ @if (form.getValue('size') === 1) {
+ <span
+ class="text-warning-dark"
+ i18n
+ >
+ A size of 1 will not create a replication of the object. The 'Replicated size'
+ includes the object itself.
+ </span>
+ }
+ </ng-template>
+ </div>
+ </div>
+ }
+ <!-- Flags -->
+ @if (info?.is_all_bluestore && isErasure) {
+ <div
+ class="form-item"
+ cdsRow
+ >
+ <div cdsCol>
+ <cds-checkbox
+ id="ec-overwrites"
+ formControlName="ecOverwrites"
+ >
+ <ng-container i18n> Flags </ng-container>
+ <cd-help-text i18n> EC Overwrites </cd-help-text>
+ </cds-checkbox>
+ </div>
+ </div>
+ }
</div>
- }
- </div>
}
<!-- Applications -->
- <div
- class="form-item"
- >
+ <div class="form-item">
<cds-combo-box
type="multi"
selectionFeedback="top-after-reopen"
[appendInline]="true"
[items]="data.applications.available"
(selected)="appSelection($event)"
- [invalid]="data.applications.selected.length === 0 && (formDir?.submitted || isFormSubmitted)"
+ [invalid]="
+ data.applications.selected.length === 0 && (formDir?.submitted || isFormSubmitted)
+ "
[invalidText]="applicationsError"
[helperText]="helperText"
cdRequiredField="Applications"
(updatedItems)="data.applications.available = $event"
i18n-placeholder
>
- <cds-dropdown-list>
- </cds-dropdown-list>
+ <cds-dropdown-list> </cds-dropdown-list>
</cds-combo-box>
<ng-template #applicationsError>
<span
</span>
</ng-template>
<ng-template #helperText>
- <span i18n>
- Pools need to be associated with an application before use
- </span>
+ <span i18n> Pools need to be associated with an application before use </span>
</ng-template>
</div>
<!-- Mirroring -->
- @if ((permissions?.rbdMirroring?.create || (editing && permissions?.rbdMirroring?.update)) && data.applications.selected.includes('rbd')) {
- <div
- class="form-item"
- cdsRow
- >
+ @if (
+ (permissions?.rbdMirroring?.create || (editing && permissions?.rbdMirroring?.update)) &&
+ data.applications.selected.includes('rbd')
+ ) {
<div
- cdsCol
+ class="form-item"
+ cdsRow
>
- <cds-checkbox
- id="rbdMirroring"
- formControlName="rbdMirroring"
- data-testid="rbd-mirroring-check"
- i18n-label
- >
- Mirroring
- <cd-help-text i18n>
- Check this option to enable Pool based mirroring on a Block(RBD) pool.
- </cd-help-text>
- </cds-checkbox>
+ <div cdsCol>
+ <cds-checkbox
+ id="rbdMirroring"
+ formControlName="rbdMirroring"
+ data-testid="rbd-mirroring-check"
+ i18n-label
+ >
+ Mirroring
+ <cd-help-text i18n>
+ Check this option to enable Pool based mirroring on a Block(RBD) pool.
+ </cd-help-text>
+ </cds-checkbox>
+ </div>
</div>
- </div>
}
<!-- CRUSH -->
@if (isErasure || isReplicated) {
- <div>
- <legend class="cd-header"
- i18n>
- CRUSH
- </legend>
- <!-- Erasure Profile select -->
- @if (isErasure) {
- <div
- cdsRow
- class="form-item form-item-append"
- >
- <div
- cdsCol
- [columnNumbers]="{ lg: 13 }"
+ <div>
+ <legend
+ class="cd-header"
+ i18n
>
- <cds-select
- formControlName="erasureProfile"
- label="Erasure code profile"
- i18n-label
- [helperText]="'Policy used for compression algorithm'"
- id="erasureProfile"
- i18n-helperText
+ CRUSH
+ </legend>
+ <!-- Erasure Profile select -->
+ @if (isErasure) {
+ <div
+ cdsRow
+ class="form-item form-item-append"
>
- @if (!ecProfiles) {
- <option
- value=""
- i18n
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 13 }"
>
- Loading...
- </option>
- }
- @if (ecProfiles && ecProfiles.length === 0) {
- <option
- [value]="null"
- i18n
+ <cds-select
+ formControlName="erasureProfile"
+ label="Erasure code profile"
+ i18n-label
+ [helperText]="'Policy used for compression algorithm'"
+ id="erasureProfile"
+ i18n-helperText
+ >
+ @if (!ecProfiles) {
+ <option
+ value=""
+ i18n
+ >
+ Loading...
+ </option>
+ }
+ @if (ecProfiles && ecProfiles.length === 0) {
+ <option
+ [value]="null"
+ i18n
+ >
+ -- No erasure code profile available --
+ </option>
+ }
+ @for (ecp of ecProfiles; track ecp.name) {
+ <option [value]="ecp.name">
+ {{ ecp.name }}
+ </option>
+ }
+ </cds-select>
+ </div>
+
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
>
- -- No erasure code profile available --
- </option>
- }
- @for (ecp of ecProfiles; track ecp.name) {
- <option [value]="ecp.name">
- {{ ecp.name }}
- </option>
+ <cds-icon-button
+ kind="ghost"
+ size="md"
+ data-testid="ecp-info-button"
+ (click)="data.erasureInfo = !data.erasureInfo"
+ >
+ <svg
+ cdsIcon="help"
+ size="20"
+ class="cds--btn__icon-help"
+ ></svg>
+ </cds-icon-button>
+ </div>
+ @if (!editing) {
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
+ >
+ <cds-icon-button
+ kind="primary"
+ size="md"
+ (click)="addErasureCodeProfile()"
+ >
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
+ >
+ @if (ecpUsage || ecProfiles?.length === 1) {
+ <cds-tooltip
+ [description]="
+ ecpUsage
+ ? 'This profile can\'t be deleted as it is in use.'
+ : 'At least one erasure code profile must exist.'
+ "
+ i18n-description
+ [highContrast]="true"
+ [caret]="true"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ [disabled]="true"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </cds-tooltip>
+ } @else {
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ (click)="deleteErasureCodeProfile()"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ }
+ </div>
}
- </cds-select>
- </div>
+ </div>
+ }
<div
- cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn"
+ class="form-item"
+ cdsRow
>
- <cds-icon-button
- kind="ghost"
- size="md"
- data-testid="ecp-info-button"
- (click)="data.erasureInfo = !data.erasureInfo"
- >
- <svg
- cdsIcon="help"
- size="20"
- class="cds--btn__icon-help"
- >
- </svg>
- </cds-icon-button>
+ <div cdsCol>
+ @if (data.erasureInfo) {
+ <span
+ class="form-text text-muted"
+ id="ecp-info-block"
+ >
+ <cds-tabs
+ [type]="'contained'"
+ [followFocus]="true"
+ [isNavigation]="false"
+ [cacheActive]="true"
+ >
+ <cds-tab
+ heading="Profile"
+ i18n-heading
+ [tabContent]="profilTpl"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Used by pools"
+ i18n-heading
+ [tabContent]="usedPoolTpl"
+ >
+ </cds-tab>
+ </cds-tabs>
+ <ng-template #profilTpl>
+ <cd-table-key-value
+ [renderObjects]="true"
+ [hideKeys]="['name']"
+ [data]="selectedEcp"
+ [autoReload]="false"
+ >
+ </cd-table-key-value>
+ </ng-template>
+ <ng-template #usedPoolTpl>
+ <ng-template #ecpIsNotUsed>
+ <span i18n> Profile is not in use. </span>
+ </ng-template>
+ @if (ecpUsage) {
+ <ul>
+ @for (pool of ecpUsage; track pool) {
+ <li>
+ {{ pool }}
+ </li>
+ }
+ </ul>
+ } @else {
+ <ng-container *ngTemplateOutlet="ecpIsNotUsed"></ng-container>
+ }
+ </ng-template>
+ </span>
+ }
+ </div>
</div>
- @if (!editing) {
- <div
- cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn"
- >
- <cds-icon-button
- kind="primary"
- size="md"
- (click)="addErasureCodeProfile()"
- >
- <svg
- cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- </div>
- <div
- cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn "
- >
- @if (ecpUsage || ecProfiles?.length === 1) {
- <cds-tooltip
- [description]="ecpUsage ? 'This profile can\'t be deleted as it is in use.' : 'At least one erasure code profile must exist.'"
- i18n-description
- [highContrast]="true"
- [caret]="true"
- >
- <cds-icon-button
- kind="danger"
- size="md"
- [disabled]="true"
- >
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- </cds-tooltip>
- } @else {
- <cds-icon-button
- kind="danger"
- size="md"
- (click)="deleteErasureCodeProfile()"
- >
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- }
- </div>
- }
- </div>
- }
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
- >
- @if (data.erasureInfo) {
- <span
- class="form-text text-muted"
- id="ecp-info-block"
+ <!-- Crush ruleset selection -->
+ @if (isErasure && !editing) {
+ <div
+ cdsRow
+ class="form-item"
>
- <cds-tabs
- [type]="'contained'"
- [followFocus]="true"
- [isNavigation]="false"
- [cacheActive]="true"
- >
- <cds-tab
- heading="Profile"
- i18n-heading
- [tabContent]="profilTpl"
- >
- </cds-tab>
- <cds-tab
- heading="Used by pools"
- i18n-heading
- [tabContent]="usedPoolTpl"
- >
- </cds-tab>
- </cds-tabs>
- <ng-template #profilTpl>
- <cd-table-key-value
- [renderObjects]="true"
- [hideKeys]="['name']"
- [data]="selectedEcp"
- [autoReload]="false"
+ <div cdsCol>
+ <cds-label
+ for="crushRule"
+ i18n
>
- </cd-table-key-value>
- </ng-template>
- <ng-template #usedPoolTpl>
- <ng-template #ecpIsNotUsed>
- <span i18n>
- Profile is not in use.
- </span>
- </ng-template>
- @if (ecpUsage) {
- <ul>
- @for (pool of ecpUsage; track pool) {
- <li>
- {{ pool }}
- </li>
+ Crush ruleset
+ </cds-label>
+ <div class="cd-col-form-input">
+ @if (!msrCrush) {
+ <span
+ class="form-text text-muted"
+ i18n
+ >
+ A new crush ruleset will be implicitly created.
+ </span>
+ } @else {
+ <span
+ class="form-text text-muted"
+ i18n
+ >
+ A new crush MSR ruleset will be implicitly created. When
+ crush-osds-per-failure-domain or crush-num-failure-domains is specified
+ </span>
}
- </ul>
- } @else {
- <ng-container *ngTemplateOutlet="ecpIsNotUsed"></ng-container>
- }
- </ng-template>
- </span>
- }
- </div>
- </div>
+ </div>
+ </div>
+ </div>
+ }
- <!-- Crush ruleset selection -->
- @if (isErasure && !editing) {
- <div
- cdsRow
- class="form-item"
- >
- <div
- cdsCol
- >
- <cds-label
- for="crushRule"
- i18n
+ <!-- isReplicated -->
+ @if (isReplicated || editing) {
+ <div
+ cdsRow
+ fullWidth="true"
+ class="form-item form-item-append"
>
- Crush ruleset
- </cds-label>
- <div class="cd-col-form-input">
- @if (!msrCrush) {
- <span
- class="form-text text-muted"
- i18n
- >
- A new crush ruleset will be implicitly created.
- </span>
+ <ng-template #noRules>
+ <span class="form-text text-muted">
+ <span i18n> There are no rules. </span>
+
+ </span>
+ </ng-template>
+ @if (current.rules.length > 0) {
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 13 }"
+ >
+ <cds-select
+ cdValidate
+ #crushRuleRef="cdValidate"
+ formControlName="crushRule"
+ label="Crush ruleset"
+ i18n-label
+ id="crushRule"
+ [invalid]="crushRuleRef.isInvalid"
+ [invalidText]="crushRuleError"
+ >
+ @for (rule of current.rules; track rule.rule_name) {
+ <option [value]="rule.rule_name">
+ {{ rule.rule_name }}
+ </option>
+ }
+ </cds-select>
+ <ng-template #crushRuleError>
+ @if (form.showError('crushRule', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required!
+ </span>
+ }
+ </ng-template>
+ </div>
} @else {
- <span
- class="form-text text-muted"
- i18n
- >
- A new crush MSR ruleset will be implicitly created. When
- crush-osds-per-failure-domain or crush-num-failure-domains is specified
- </span>
+ <div cdsCol>
+ <ng-container *ngTemplateOutlet="noRules"></ng-container>
+ </div>
}
- </div>
- </div>
- </div>
- }
- <!-- isReplicated -->
- @if (isReplicated || editing) {
- <div
- cdsRow
- fullWidth="true"
- class="form-item form-item-append"
- >
- <ng-template #noRules>
- <span
- class="form-text text-muted"
- >
- <span
- i18n
- >
- There are no rules.
- </span>
-
- </span>
- </ng-template>
- @if (current.rules.length > 0) {
- <div
- cdsCol
- [columnNumbers]="{ lg: 13 }"
- >
- <cds-select
- cdValidate
- #crushRuleRef="cdValidate"
- formControlName="crushRule"
- label="Crush ruleset"
- i18n-label
- id="crushRule"
- [invalid]="crushRuleRef.isInvalid"
- [invalidText]="crushRuleError"
- >
- @for (rule of current.rules; track rule.rule_name) {
- <option [value]="rule.rule_name">
- {{ rule.rule_name }}
- </option>
- }
- </cds-select>
- <ng-template #crushRuleError>
- @if (form.showError('crushRule', formDir, 'required')) {
- <span
- class="invalid-feedback"
- i18n
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
>
- This field is required!
- </span>
- }
- </ng-template>
- </div>
- } @else {
- <div cdsCol>
- <ng-container *ngTemplateOutlet="noRules"></ng-container>
- </div>
- }
-
- <div cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn">
- <cds-tooltip
- description="Placement and
+ <cds-tooltip
+ description="Placement and
replication strategies or distribution policies that allow to
specify how CRUSH places data replicas."
- [highContrast]="true"
- [caret]="true"
- >
- <cds-icon-button
- kind="ghost"
- size="md"
- data-testid="crush-info-button"
- (click)="data.crushInfo = !data.crushInfo"
- >
- <svg
- cdsIcon="help"
- size="20"
- class="cds--btn__icon-help"
+ [highContrast]="true"
+ [caret]="true"
>
- </svg>
- </cds-icon-button>
- </cds-tooltip>
- </div>
- @if (isReplicated && !editing) {
- <div
- cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn"
- >
- <cds-icon-button
- kind="primary"
- size="md"
- (click)="addCrushRule()"
- >
- <svg
- cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- </div>
- }
- @if (!editing) {
- <div
- cdsCol
- [columnNumbers]="{ lg: 1}"
- class="item-action-btn "
- >
- @if (crushUsage || current?.rules?.length === 1) {
- <cds-tooltip
- [description]="crushUsage ? 'This rule can\'t be deleted as it is in use.' : 'At least one crush rule must exist.'"
- i18n-description
- [highContrast]="true"
- [caret]="true"
- >
- <cds-icon-button
- kind="danger"
- size="md"
- [disabled]="true"
- >
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"
+ <cds-icon-button
+ kind="ghost"
+ size="md"
+ data-testid="crush-info-button"
+ (click)="data.crushInfo = !data.crushInfo"
+ >
+ <svg
+ cdsIcon="help"
+ size="20"
+ class="cds--btn__icon-help"
+ ></svg>
+ </cds-icon-button>
+ </cds-tooltip>
+ </div>
+ @if (isReplicated && !editing) {
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
>
- </svg>
- </cds-icon-button>
- </cds-tooltip>
- } @else {
- <cds-icon-button
- kind="danger"
- size="md"
- (click)="deleteCrushRule()"
- >
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"
- >
- </svg>
- </cds-icon-button>
- }
- </div>
+ <cds-icon-button
+ kind="primary"
+ size="md"
+ (click)="addCrushRule()"
+ >
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
+ }
+ @if (!editing) {
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn"
+ >
+ @if (crushUsage || current?.rules?.length === 1) {
+ <cds-tooltip
+ [description]="
+ crushUsage
+ ? 'This rule can\'t be deleted as it is in use.'
+ : 'At least one crush rule must exist.'
+ "
+ i18n-description
+ [highContrast]="true"
+ [caret]="true"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ [disabled]="true"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </cds-tooltip>
+ } @else {
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ (click)="deleteCrushRule()"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ }
+ </div>
+ }
+ </div>
}
- </div>
- }
- <div
- class="form-item"
- cdsRow
- >
<div
- cdsCol
+ class="form-item"
+ cdsRow
>
- @if (data.crushInfo && form.getValue('crushRule')) {
- <span
- class="form-text text-muted"
- id="crush-info-block"
- >
- <cds-tabs
- [type]="'contained'"
- [followFocus]="true"
- [isNavigation]="false"
- [cacheActive]="true"
- >
- <cds-tab
- heading="Crush rule"
- i18n-heading
- [tabContent]="crushRuleTpl"
- >
- </cds-tab>
- <cds-tab
- heading="Crush steps"
- i18n-heading
- [tabContent]="crushStepsTpl"
- >
- </cds-tab>
- <cds-tab
- heading="Used by pools"
- i18n-heading
- [tabContent]="usedPoolTpl"
- >
- </cds-tab>
- </cds-tabs>
- <ng-template #crushRuleTpl>
- <cd-table-key-value
- [renderObjects]="false"
- [hideKeys]="['steps', 'type', 'rule_name']"
- [data]="this.selectedCrushRule"
- [autoReload]="false"
+ <div cdsCol>
+ @if (data.crushInfo && form.getValue('crushRule')) {
+ <span
+ class="form-text text-muted"
+ id="crush-info-block"
>
- </cd-table-key-value>
- </ng-template>
- <ng-template #crushStepsTpl>
- <ol>
- @for (step of this.selectedCrushRule?.steps; track $index) {
- <li>
- {{ describeCrushStep(step) }}
- </li>
- }
- </ol>
- </ng-template>
- <ng-template #usedPoolTpl>
- <ng-template #ruleIsNotUsed>
- <span i18n>
- Rule is not in use.
- </span>
- </ng-template>
- @if (crushUsage) {
- <ul>
- @for (pool of crushUsage; track pool) {
- <li>
- {{ pool }}
- </li>
- }
- </ul>
- } @else {
- <ng-container *ngTemplateOutlet="ruleIsNotUsed"></ng-container>
- }
- </ng-template>
- </span>
- }
+ <cds-tabs
+ [type]="'contained'"
+ [followFocus]="true"
+ [isNavigation]="false"
+ [cacheActive]="true"
+ >
+ <cds-tab
+ heading="Crush rule"
+ i18n-heading
+ [tabContent]="crushRuleTpl"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Crush steps"
+ i18n-heading
+ [tabContent]="crushStepsTpl"
+ >
+ </cds-tab>
+ <cds-tab
+ heading="Used by pools"
+ i18n-heading
+ [tabContent]="usedPoolTpl"
+ >
+ </cds-tab>
+ </cds-tabs>
+ <ng-template #crushRuleTpl>
+ <cd-table-key-value
+ [renderObjects]="false"
+ [hideKeys]="['steps', 'type', 'rule_name']"
+ [data]="this.selectedCrushRule"
+ [autoReload]="false"
+ >
+ </cd-table-key-value>
+ </ng-template>
+ <ng-template #crushStepsTpl>
+ <ol>
+ @for (step of this.selectedCrushRule?.steps; track $index) {
+ <li>
+ {{ describeCrushStep(step) }}
+ </li>
+ }
+ </ol>
+ </ng-template>
+ <ng-template #usedPoolTpl>
+ <ng-template #ruleIsNotUsed>
+ <span i18n> Rule is not in use. </span>
+ </ng-template>
+ @if (crushUsage) {
+ <ul>
+ @for (pool of crushUsage; track pool) {
+ <li>
+ {{ pool }}
+ </li>
+ }
+ </ul>
+ } @else {
+ <ng-container *ngTemplateOutlet="ruleIsNotUsed"></ng-container>
+ }
+ </ng-template>
+ </span>
+ }
+ </div>
</div>
</div>
- </div>
}
<!-- Compression -->
@if (info?.is_all_bluestore) {
- <div formGroupName="compression">
- <legend class="cd-header"
- i18n>
- Compression
- </legend>
- <!-- Compression Mode -->
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
+ <div formGroupName="compression">
+ <legend
+ class="cd-header"
+ i18n
>
- <cds-select
- formControlName="mode"
- label="Mode"
- i18n-label
- [helperText]="compressionModeHelperText"
- id="mode"
- >
- @for (mode of info.compression_modes; track mode) {
- <option [value]="mode">
- {{ mode }}
- </option>
- }
- </cds-select>
- <ng-template #compressionModeHelperText>
- <span>Policy used for compression algorithm. </span>
- {{ poolService.formTooltips.compressionModes[form.controls.compression.controls.mode.value] }}
- </ng-template>
- </div>
- </div>
- @if (hasCompressionEnabled()) {
- <div>
- <!-- Compression algorithm selection -->
+ Compression
+ </legend>
+ <!-- Compression Mode -->
<div
class="form-item"
cdsRow
>
- <div
- cdsCol
- >
+ <div cdsCol>
<cds-select
- formControlName="algorithm"
- label="Algorithm"
+ formControlName="mode"
+ label="Mode"
i18n-label
- [helperText]="'Compression algorithm used'"
- id="algorithm"
+ [helperText]="compressionModeHelperText"
+ id="mode"
>
- @if (!info.compression_algorithms) {
- <option
- value=""
- i18n
- >
- Loading...
- </option>
- }
- @if (info.compression_algorithms && info.compression_algorithms.length === 0) {
- <option
- i18n
- value=""
- >
- -- No erasure compression algorithm available --
- </option>
- }
- @for (algorithm of info.compression_algorithms; track algorithm) {
- <option [value]="algorithm">
- {{ algorithm }}
- </option>
+ @for (mode of info.compression_modes; track mode) {
+ <option [value]="mode">
+ {{ mode }}
+ </option>
}
</cds-select>
- </div>
- </div>
- <!-- Compression min blob size -->
- <div
- cdsRow
- class="form-item form-item-append"
- >
- <div
- cdsCol
- >
- <cds-number
- label="Minimum blob size"
- [helperText]="'Chunks smaller than Minimum blob size are never compressed'"
- [invalid]="
- form.controls.compression.controls.minBlobSize.invalid &&
- form.controls.compression.controls.minBlobSize.dirty
- "
- [invalidText]="minBlobSizeError"
- formControlName="minBlobSize"
- min="0"
- i18n
- i18n-helperText
- >
- </cds-number>
- <ng-template #minBlobSizeError>
- @if (form.showError('minBlobSize', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Value should be greater than or equal to 0
- </span>
- }
- @if (form.showError('minBlobSize', formDir, 'maximum')) {
- <span class="invalid-feedback"
- i18n>Value should be less than the maximum blob size
- </span>
- }
+ <ng-template #compressionModeHelperText>
+ <span>Policy used for compression algorithm. </span>
+ {{
+ poolService.formTooltips.compressionModes[
+ form.controls.compression.controls.mode.value
+ ]
+ }}
</ng-template>
</div>
- <div
- cdsCol
- >
- <cds-select
- formControlName="minBlobSizeUnit"
- label="Unit"
- i18n-label
- id="minBlobSizeUnit"
- >
- @for (minBlobSizeUnit of blobUnits; track minBlobSizeUnit) {
- <option
- [value]="minBlobSizeUnit"
- i18n
- >
- {{ minBlobSizeUnit }}
- </option>
- }
- </cds-select>
- </div>
</div>
- <!-- Compression max blob size -->
- <div
- cdsRow
- class="form-item form-item-append"
- >
- <div
- cdsCol
- >
- <cds-number
- label="Maximum blob size"
- [helperText]="'Chunks larger than Maximum Blob Size are broken into smaller blobs of size mentioned before being compressed.'"
- [invalid]="
- form.controls.compression.controls.maxBlobSize.invalid &&
- form.controls.compression.controls.maxBlobSize.dirty
- "
- [invalidText]="maxBlobSizeError"
- formControlName="maxBlobSize"
- min="0"
- i18n
- i18n-helperText
+ @if (hasCompressionEnabled()) {
+ <div>
+ <!-- Compression algorithm selection -->
+ <div
+ class="form-item"
+ cdsRow
>
- </cds-number>
- <ng-template #maxBlobSizeError>
- @if (form.showError('maxBlobSize', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Value should be greater than or equal to 0
- </span>
- }
- @if (form.showError('maxBlobSize', formDir, 'minimum')) {
- <span class="invalid-feedback"
- i18n>
- Value should be greater than the minimum blob size
- </span>
- }
- </ng-template>
- </div>
- <div
- cdsCol
- >
- <cds-select
- formControlName="maxBlobSizeUnit"
- label="Unit"
- i18n-label
- id="maxBlobSizeUnit"
+ <div cdsCol>
+ <cds-select
+ formControlName="algorithm"
+ label="Algorithm"
+ i18n-label
+ [helperText]="'Compression algorithm used'"
+ id="algorithm"
+ >
+ @if (!info.compression_algorithms) {
+ <option
+ value=""
+ i18n
+ >
+ Loading...
+ </option>
+ }
+ @if (info.compression_algorithms && info.compression_algorithms.length === 0) {
+ <option
+ i18n
+ value=""
+ >
+ -- No erasure compression algorithm available --
+ </option>
+ }
+ @for (algorithm of info.compression_algorithms; track algorithm) {
+ <option [value]="algorithm">
+ {{ algorithm }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ </div>
+ <!-- Compression min blob size -->
+ <div
+ cdsRow
+ class="form-item form-item-append"
>
- @for (maxBlobSizeUnit of blobUnits; track maxBlobSizeUnit) {
- <option
- [value]="maxBlobSizeUnit"
- i18n
- >
- {{ maxBlobSizeUnit }}
- </option>
- }
- </cds-select>
- </div>
- </div>
- <!-- Compression ratio -->
- <div
- class="form-item"
- cdsRow
- >
- <div
- cdsCol
- >
- <cds-number
- label="Ratio"
- [helperText]="'The ratio of the size of the data chunk after compression relative to the original size must be at least this small in order to store the compressed version'"
- [invalid]="
- form.controls.compression.controls.ratio.invalid &&
- form.controls.compression.controls.ratio.dirty
- "
- [invalidText]="ratioError"
- formControlName="ratio"
- min="0"
- max="1"
- step="0.1"
- i18n-placeholder
- i18n-helperText
+ <div cdsCol>
+ <cds-number
+ label="Minimum blob size"
+ [helperText]="'Chunks smaller than Minimum blob size are never compressed'"
+ [invalid]="
+ form.controls.compression.controls.minBlobSize.invalid &&
+ form.controls.compression.controls.minBlobSize.dirty
+ "
+ [invalidText]="minBlobSizeError"
+ formControlName="minBlobSize"
+ min="0"
+ i18n
+ i18n-helperText
+ >
+ </cds-number>
+ <ng-template #minBlobSizeError>
+ @if (form.showError('minBlobSize', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Value should be greater than or equal to 0
+ </span>
+ }
+ @if (form.showError('minBlobSize', formDir, 'maximum')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Value should be less than the maximum blob size
+ </span>
+ }
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <cds-select
+ formControlName="minBlobSizeUnit"
+ label="Unit"
+ i18n-label
+ id="minBlobSizeUnit"
+ >
+ @for (minBlobSizeUnit of blobUnits; track minBlobSizeUnit) {
+ <option
+ [value]="minBlobSizeUnit"
+ i18n
+ >
+ {{ minBlobSizeUnit }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ </div>
+ <!-- Compression max blob size -->
+ <div
+ cdsRow
+ class="form-item form-item-append"
>
- </cds-number>
- <ng-template #ratioError>
- @if (form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')) {
- <span
- class="invalid-feedback"
- i18n
- >
- Value should be between 0.0 and 1.0
- </span>
- }
- </ng-template>
+ <div cdsCol>
+ <cds-number
+ label="Maximum blob size"
+ [helperText]="'Chunks larger than Maximum Blob Size are broken into smaller blobs of size mentioned before being compressed.'"
+ [invalid]="
+ form.controls.compression.controls.maxBlobSize.invalid &&
+ form.controls.compression.controls.maxBlobSize.dirty
+ "
+ [invalidText]="maxBlobSizeError"
+ formControlName="maxBlobSize"
+ min="0"
+ i18n
+ i18n-helperText
+ >
+ </cds-number>
+ <ng-template #maxBlobSizeError>
+ @if (form.showError('maxBlobSize', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Value should be greater than or equal to 0
+ </span>
+ }
+ @if (form.showError('maxBlobSize', formDir, 'minimum')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Value should be greater than the minimum blob size
+ </span>
+ }
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <cds-select
+ formControlName="maxBlobSizeUnit"
+ label="Unit"
+ i18n-label
+ id="maxBlobSizeUnit"
+ >
+ @for (maxBlobSizeUnit of blobUnits; track maxBlobSizeUnit) {
+ <option
+ [value]="maxBlobSizeUnit"
+ i18n
+ >
+ {{ maxBlobSizeUnit }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ </div>
+ <!-- Compression ratio -->
+ <div
+ class="form-item"
+ cdsRow
+ >
+ <div cdsCol>
+ <cds-number
+ label="Ratio"
+ [helperText]="'The ratio of the size of the data chunk after compression relative to the original size must be at least this small in order to store the compressed version'"
+ [invalid]="
+ form.controls.compression.controls.ratio.invalid &&
+ form.controls.compression.controls.ratio.dirty
+ "
+ [invalidText]="ratioError"
+ formControlName="ratio"
+ min="0"
+ max="1"
+ step="0.1"
+ i18n-placeholder
+ i18n-helperText
+ >
+ </cds-number>
+ <ng-template #ratioError>
+ @if (
+ form.showError('ratio', formDir, 'min') ||
+ form.showError('ratio', formDir, 'max')
+ ) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Value should be between 0.0 and 1.0
+ </span>
+ }
+ </ng-template>
+ </div>
+ </div>
</div>
- </div>
+ }
</div>
- }
- </div>
}
<!-- Quotas -->
<div>
- <legend class="cd-header"
- i18n>
+ <legend
+ class="cd-header"
+ i18n
+ >
Quotas
</legend>
<!-- Max Bytes -->
cdsRow
class="form-item form-item-append"
>
- <div
- cdsCol
- >
+ <div cdsCol>
<cds-number
label="Max bytes"
[helperText]="maxObjectsHelpText"
</cds-number>
<ng-template #maxBytesError>
@if (form.showError('max_bytes', formDir, 'min')) {
- <span
- class="invalid-feedback"
- i18n
- >The value should be greater or equal to 0
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value should be greater or equal to 0
+ </span>
}
</ng-template>
</div>
- <div
- cdsCol
- >
+ <div cdsCol>
<cds-select
formControlName="maxBytesUnit"
label="Unit"
id="maxBytesUnit"
>
@for (maxBytesUnit of maxBytesUnits; track maxBytesUnit) {
- <option
- [value]="maxBytesUnit"
- i18n
- >
- {{ maxBytesUnit }}
- </option>
+ <option
+ [value]="maxBytesUnit"
+ i18n
+ >
+ {{ maxBytesUnit }}
+ </option>
}
</cds-select>
</div>
cdsRow
class="form-item"
>
- <div
- cdsCol
- >
+ <div cdsCol>
<cds-number
label="Max objects"
[helperText]="maxObjectsHelpText"
>
</cds-number>
<ng-template #maxObjectsHelpText>
- <span i18n>
- Leave it blank or specify 0 to disable this quota.
- </span>
+ <span i18n> Leave it blank or specify 0 to disable this quota. </span>
<br />
- <span i18n>
- A valid quota should be greater than 0.
- </span>
+ <span i18n> A valid quota should be greater than 0. </span>
</ng-template>
<ng-template #maxObjectsError>
@if (form.showError('max_objects', formDir, 'min')) {
- <span class="invalid-feedback"
- i18n>The value should be greater or equal to 0
- </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The value should be greater or equal to 0
+ </span>
}
</ng-template>
</div>
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+<nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+>
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>Pools List</a>
+ <a
+ ngbNavLink
+ i18n
+ >Pools List</a
+ >
<ng-template ngbNavContent>
- <cd-table #table
- id="pool-list"
- [data]="pools"
- [columns]="columns"
- selectionType="single"
- [hasDetails]="true"
- [status]="tableStatus"
- [autoReload]="-1"
- (fetchData)="taskListService.fetch()"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions id="pool-list-actions"
- class="table-actions"
- [permission]="permissions.pool"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table
+ #table
+ id="pool-list"
+ [data]="pools"
+ [columns]="columns"
+ selectionType="single"
+ [hasDetails]="true"
+ [status]="tableStatus"
+ [autoReload]="-1"
+ (fetchData)="taskListService.fetch()"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ >
+ <cd-table-actions
+ id="pool-list-actions"
+ class="table-actions"
+ [permission]="permissions.pool"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-pool-details *cdTableDetail
- id="pool-list-details"
- [selection]="expandedRow"
- [permissions]="permissions"
- [cacheTiers]="cacheTiers">
+ <cd-pool-details
+ *cdTableDetail
+ id="pool-list-details"
+ [selection]="expandedRow"
+ [permissions]="permissions"
+ [cacheTiers]="cacheTiers"
+ >
</cd-pool-details>
</cd-table>
</ng-template>
</ng-container>
- <ng-container ngbNavItem
- *cdScope="'grafana'">
- <a ngbNavLink
- i18n>Overall Performance</a>
+ <ng-container
+ ngbNavItem
+ *cdScope="'grafana'"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Overall Performance</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Ceph pools overview"
- [grafanaPath]="'ceph-pools-overview?'"
- [type]="'metrics'"
- uid="z99hzWtmk"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="Ceph pools overview"
+ [grafanaPath]="'ceph-pools-overview?'"
+ [type]="'metrics'"
+ uid="z99hzWtmk"
+ grafanaStyle="three"
+ >
</cd-grafana>
</ng-template>
</ng-container>
<div [ngbNavOutlet]="nav"></div>
-<ng-template #poolUsageTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.stats?.avail_raw?.latest"
- [total]="row.stats.bytes_used.latest + row.stats.avail_raw.latest"
- [used]="row.stats.bytes_used.latest"
- [title]="row.pool_name"
- decimals="2">
+<ng-template
+ #poolUsageTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.stats?.avail_raw?.latest"
+ [total]="row.stats.bytes_used.latest + row.stats.avail_raw.latest"
+ [used]="row.stats.bytes_used.latest"
+ [title]="row.pool_name"
+ decimals="2"
+ >
</cd-usage-bar>
</ng-template>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
-
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ getMode() }} Tag</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ getMode() }} Tag
+ </h3>
</cds-modal-header>
- <form class="form"
- #formDir="ngForm"
- [formGroup]="form">
+ <form
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ >
<div cdsModalContent>
<!-- Key -->
<div class="form-item">
- <cds-text-label label="Key"
- for="key"
- cdRequiredField="Key"
- [invalid]="form.controls.key.invalid && form.controls.key.dirty"
- [invalidText]="keyError">Key
- <input cdsText
- type="text"
- id="key"
- name="key"
- formControlName="key"
- [invalid]="form.controls.key.invalid && form.controls.key.dirty"
- [autofocus]="true"
- modal-primary-focus>
+ <cds-text-label
+ label="Key"
+ for="key"
+ cdRequiredField="Key"
+ [invalid]="form.controls.key.invalid && form.controls.key.dirty"
+ [invalidText]="keyError"
+ >Key
+ <input
+ cdsText
+ type="text"
+ id="key"
+ name="key"
+ formControlName="key"
+ [invalid]="form.controls.key.invalid && form.controls.key.dirty"
+ [autofocus]="true"
+ modal-primary-focus
+ />
</cds-text-label>
<ng-template #keyError>
- <span class="invalid-feedback"
- *ngIf="form.showError('key', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="form.showError('key', formDir, 'unique')"
- i18n>This key must be unique.</span>
- <span class="invalid-feedback"
- *ngIf="form.showError('key', formDir, 'maxLength')"
- i18n>Length of the key must be maximum of 128 characters</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('key', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('key', formDir, 'unique')"
+ i18n
+ >This key must be unique.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('key', formDir, 'maxLength')"
+ i18n
+ >Length of the key must be maximum of 128 characters</span
+ >
</ng-template>
</div>
<!-- Value -->
<div class="form-item">
- <cds-text-label label="Value"
- for="value"
- cdRequiredField="Value"
- [invalid]="form.controls.value.invalid && form.controls.value.dirty"
- [invalidText]="valueError">Value
- <input cdsText
- type="text"
- id="value"
- name="value"
- formControlName="value"
- [invalid]="form.controls.value.invalid && form.controls.value.dirty">
+ <cds-text-label
+ label="Value"
+ for="value"
+ cdRequiredField="Value"
+ [invalid]="form.controls.value.invalid && form.controls.value.dirty"
+ [invalidText]="valueError"
+ >Value
+ <input
+ cdsText
+ type="text"
+ id="value"
+ name="value"
+ formControlName="value"
+ [invalid]="form.controls.value.invalid && form.controls.value.dirty"
+ />
</cds-text-label>
<ng-template #valueError>
- <span class="invalid-feedback"
- *ngIf="form.showError('value', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="form.showError('value', formDir, 'maxLength')"
- i18n>Length of the value must be a maximum of 128 characters</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('value', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="form.showError('value', formDir, 'maxLength')"
+ i18n
+ >Length of the value must be a maximum of 128 characters</span
+ >
</ng-template>
</div>
-
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="form"
- [submitText]="getMode()"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="getMode()"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</cds-modal>
-<cds-modal size="sm"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Create Realm/Zonegroup/Zone</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Create Realm/Zonegroup/Zone
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
<form
novalidate
>
<div cdsModalContent>
- <cd-alert-panel type="info"
- spacingClass="mt-3"
- i18n>The realm/zonegroup/zone created will be set as default and master.
+ <cd-alert-panel
+ type="info"
+ spacingClass="mt-3"
+ i18n
+ >The realm/zonegroup/zone created will be set as default and master.
</cd-alert-panel>
<div class="form-item">
<cds-text-label
labelInputID="realmName"
- [invalid]="createMultisiteEntitiesForm.controls.realmName.invalid &&
- createMultisiteEntitiesForm.controls.realmName.dirty"
+ [invalid]="
+ createMultisiteEntitiesForm.controls.realmName.invalid &&
+ createMultisiteEntitiesForm.controls.realmName.dirty
+ "
[invalidText]="realmNameError"
i18n
>Realm Name
formControlName="realmName"
[invalid]="
createMultisiteEntitiesForm.controls.realmName.invalid &&
- createMultisiteEntitiesForm.controls.realmName.dirty"
+ createMultisiteEntitiesForm.controls.realmName.dirty
+ "
[autofocus]="true"
modal-primary-focus
/>
<div class="form-item">
<cds-text-label
labelInputID="zonegroupName"
- [invalid]="createMultisiteEntitiesForm.controls.zonegroupName.invalid &&
- createMultisiteEntitiesForm.controls.zonegroupName.dirty"
+ [invalid]="
+ createMultisiteEntitiesForm.controls.zonegroupName.invalid &&
+ createMultisiteEntitiesForm.controls.zonegroupName.dirty
+ "
[invalidText]="zoneGroupNameError"
i18n
>Zonegroup Name
id="zonegroupName"
name="zonegroupName"
formControlName="zonegroupName"
- [invalid]="createMultisiteEntitiesForm.controls.zonegroupName.invalid &&
- createMultisiteEntitiesForm.controls.zonegroupName.dirty"
+ [invalid]="
+ createMultisiteEntitiesForm.controls.zonegroupName.invalid &&
+ createMultisiteEntitiesForm.controls.zonegroupName.dirty
+ "
/>
</cds-text-label>
<ng-template #zoneGroupNameError>
<div class="form-item">
<cds-text-label
labelInputID="zoneName"
- [invalid]="createMultisiteEntitiesForm.controls.zoneName.invalid &&
- createMultisiteEntitiesForm.controls.zoneName.dirty"
+ [invalid]="
+ createMultisiteEntitiesForm.controls.zoneName.invalid &&
+ createMultisiteEntitiesForm.controls.zoneName.dirty
+ "
[invalidText]="zoneNameError"
i18n
>Zone Name
id="zoneName"
name="zoneName"
formControlName="zoneName"
- [invalid]="createMultisiteEntitiesForm.controls.zoneName.invalid &&
- createMultisiteEntitiesForm.controls.zoneName.dirty"
+ [invalid]="
+ createMultisiteEntitiesForm.controls.zoneName.invalid &&
+ createMultisiteEntitiesForm.controls.zoneName.dirty
+ "
/>
</cds-text-label>
<ng-template #zoneNameError>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Delete zone</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Delete zone
+ </h3>
</cds-modal-header>
<ng-container>
<section cdsModalContent>
- <form [formGroup]="zoneForm"
- novalidate>
- <legend class="cds--label-description"
- i18n>
+ <form
+ [formGroup]="zoneForm"
+ novalidate
+ >
+ <legend
+ class="cds--label-description"
+ i18n
+ >
This will delete your <strong>{{ zone?.name }}</strong> Zone.
</legend>
@if (includedPools.size) {
- <legend class="cds--label-description"
- i18n>
- Do you want to delete the associated pools with the
- <strong>{{ zone?.name }}</strong> Zone?
- </legend>
- <legend class="cds--label-description"
- i18n>
- This will delete the following pools and any data stored in these pools:
- </legend>
+ <legend
+ class="cds--label-description"
+ i18n
+ >
+ Do you want to delete the associated pools with the
+ <strong>{{ zone?.name }}</strong> Zone?
+ </legend>
+ <legend
+ class="cds--label-description"
+ i18n
+ >
+ This will delete the following pools and any data stored in these pools:
+ </legend>
- <div class="scroll-list">
- @for (pool of includedPools; track pool) {
- <div>
- <strong>{{ pool }}</strong>
+ <div class="scroll-list">
+ @for (pool of includedPools; track pool) {
+ <div>
+ <strong>{{ pool }}</strong>
+ </div>
+ }
</div>
- }
- </div>
- <div class="form-item">
- <cds-checkbox id="deletePools"
- formControlName="deletePools"
- (checkedChange)="showDangerText()"
- i18n>Yes, I want to delete the pools.
- </cds-checkbox>
- </div>
+ <div class="form-item">
+ <cds-checkbox
+ id="deletePools"
+ formControlName="deletePools"
+ (checkedChange)="showDangerText()"
+ i18n
+ >Yes, I want to delete the pools.
+ </cds-checkbox>
+ </div>
- @if (displayText) {
- <cd-alert-panel type="danger"
- i18n>
- This will delete all the data in the pools!
- </cd-alert-panel>
- }
+ @if (displayText) {
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
+ This will delete all the data in the pools!
+ </cd-alert-panel>
+ }
}
</form>
</section>
</ng-container>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="zoneForm"
- [submitText]="actionLabels.DELETE"
- [modalForm]="true">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="zoneForm"
+ [submitText]="actionLabels.DELETE"
+ [modalForm]="true"
+ >
</cd-form-button-panel>
</cds-modal>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Delete zonegroup</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Delete zonegroup
+ </h3>
</cds-modal-header>
<ng-container>
<section cdsModalContent>
- <form name="zonegroupForm"
- [formGroup]="zonegroupForm"
- novalidate>
- <legend class="cds--label-description"
- i18n>
+ <form
+ name="zonegroupForm"
+ [formGroup]="zonegroupForm"
+ novalidate
+ >
+ <legend
+ class="cds--label-description"
+ i18n
+ >
This will delete your <strong>{{ zonegroup?.name }}</strong> Zonegroup.
</legend>
- @if (zonesList.length > 0) {
- <ng-container>
- <legend class="cds--label-description"
- i18n>
- Do you want to delete the associated zones and pools with the <strong>{{zonegroup?.name}}</strong> Zonegroup?
- </legend>
+ @if (zonesList.length > 0) {
+ <ng-container>
+ <legend
+ class="cds--label-description"
+ i18n
+ >
+ Do you want to delete the associated zones and pools with the
+ <strong>{{ zonegroup?.name }}</strong> Zonegroup?
+ </legend>
- @if (includedPools.size > 0) {
- <ng-container>
- <legend class="cds--label-description"
- i18n>
- This will delete the following:
- </legend>
- </ng-container>
- }
+ @if (includedPools.size > 0) {
+ <ng-container>
+ <legend
+ class="cds--label-description"
+ i18n
+ >
+ This will delete the following:
+ </legend>
+ </ng-container>
+ }
- <div><strong>Zones:</strong></div>
- <div class="scroll-list">
- @for (zone of zonesList; track zone) {
- <div><strong>{{zone}}</strong></div>
- }
- </div>
- @if (includedPools.size > 0) {
- <ng-container>
- <div><strong>Pools:</strong></div>
- <div class="scroll-list">
- @for (pool of includedPools; track pool) {
- <div><strong>{{ pool }}</strong></div>
+ <div><strong>Zones:</strong></div>
+ <div class="scroll-list">
+ @for (zone of zonesList; track zone) {
+ <div>
+ <strong>{{ zone }}</strong>
+ </div>
}
- </div>
- </ng-container>
- }
-
- <div class="form-item">
- <cds-checkbox id="deletePools"
- formControlName="deletePools"
- (checkedChange)="showDangerText()">
+ </div>
@if (includedPools.size > 0) {
- <span i18n>Yes, I want to delete the zones and their pools.</span>
- } @else {
- <span i18n>Yes, I want to delete the zones.</span>
+ <ng-container>
+ <div><strong>Pools:</strong></div>
+ <div class="scroll-list">
+ @for (pool of includedPools; track pool) {
+ <div>
+ <strong>{{ pool }}</strong>
+ </div>
+ }
+ </div>
+ </ng-container>
}
- </cds-checkbox>
- </div>
- @if (displayText) {
- <cd-alert-panel type="danger"
- i18n>
- This will delete all the data in the pools!
- </cd-alert-panel>
+ <div class="form-item">
+ <cds-checkbox
+ id="deletePools"
+ formControlName="deletePools"
+ (checkedChange)="showDangerText()"
+ >
+ @if (includedPools.size > 0) {
+ <span i18n>Yes, I want to delete the zones and their pools.</span>
+ } @else {
+ <span i18n>Yes, I want to delete the zones.</span>
+ }
+ </cds-checkbox>
+ </div>
+
+ @if (displayText) {
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
+ This will delete all the data in the pools!
+ </cd-alert-panel>
+ }
+ </ng-container>
}
- </ng-container>
- }
</form>
</section>
</ng-container>
-<cds-modal size="md" [open]="open" [hasScrollingContent]="false" (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
@if (isEdit) {
- <h4 cdsModalHeaderLabel class="cds--type-label-01" i18n>Role</h4>
- <h3 cdsModalHeaderHeading i18n>Edit session duration</h3>
- <p class="cds--modal-header__description cds--type-body-01 cds-mt-3" i18n>
+ <h4
+ cdsModalHeaderLabel
+ class="cds--type-label-01"
+ i18n
+ >
+ Role
+ </h4>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Edit session duration
+ </h3>
+ <p
+ class="cds--modal-header__description cds--type-body-01 cds-mt-3"
+ i18n
+ >
Update the maximum session duration for this role.
</p>
} @else {
- <h4 cdsModalHeaderLabel class="cds--type-label-01" i18n>User account</h4>
- <h3 cdsModalHeaderHeading i18n>Create role</h3>
- <p class="cds--modal-header__description cds--type-body-01 cds-mt-3" i18n>
+ <h4
+ cdsModalHeaderLabel
+ class="cds--type-label-01"
+ i18n
+ >
+ User account
+ </h4>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Create role
+ </h3>
+ <p
+ class="cds--modal-header__description cds--type-body-01 cds-mt-3"
+ i18n
+ >
Role grants temporary permissions to trusted users, applications, or services.
</p>
}
</cds-modal-header>
- <form class="form" #formDir="ngForm" [formGroup]="form">
+ <form
+ class="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ >
<div cdsModalContent>
@if (!isEdit) {
- <!-- Account -->
- <div class="form-item">
- <label class="cds--label cds--type-label-01" i18n>Account</label>
- <p class="cds--type-body-01">{{ accountName }}</p>
- </div>
+ <!-- Account -->
+ <div class="form-item">
+ <legend
+ class="cds--label cds--type-label-01"
+ i18n
+ >
+ Account
+ </legend>
+ <p class="cds--type-body-01">{{ accountName }}</p>
+ </div>
- <!-- Role Name -->
- <div class="form-item">
- <cds-text-label
- label="Role name"
- for="role_name"
- [invalid]="roleName.isInvalid"
- [invalidText]="roleNameError"
- helperText="Unique name used to identify this role within the account."
- i18n-helperText
- >Role name
- <input
- cdsText
- cdValidate
- #roleName="cdValidate"
- type="text"
- id="role_name"
- name="role_name"
- formControlName="role_name"
- placeholder="Enter a role name (e.g. BackupServiceRole)"
+ <!-- Role Name -->
+ <div class="form-item">
+ <cds-text-label
+ label="Role name"
+ for="role_name"
[invalid]="roleName.isInvalid"
- [autofocus]="true"
- modal-primary-focus
- />
- </cds-text-label>
- <ng-template #roleNameError>
- @if (form.showError('role_name', formDir, 'required')) {
- <span class="invalid-feedback" i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ [invalidText]="roleNameError"
+ helperText="Unique name used to identify this role within the account."
+ i18n-helperText
+ >Role name
+ <input
+ cdsText
+ cdValidate
+ #roleName="cdValidate"
+ type="text"
+ id="role_name"
+ name="role_name"
+ formControlName="role_name"
+ placeholder="Enter a role name (e.g. BackupServiceRole)"
+ [invalid]="roleName.isInvalid"
+ [autofocus]="true"
+ modal-primary-focus
+ />
+ </cds-text-label>
+ <ng-template #roleNameError>
+ @if (form.showError('role_name', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- Role (Edit only) -->
+ <!-- Role (Edit only) -->
} @else {
- <div class="form-item">
- <label class="cds--label cds--type-label-01" i18n>Role</label>
- <p class="cds--type-body-01">
- <cds-tooltip-definition
- align="right"
- [description]="accountTooltip"
- [openOnHover]="true"
- [caret]="true"
- [highContrast]="true"
- [dropShadow]="true"
- [autoAlign]="true"
+ <div class="form-item">
+ <legend
+ class="cds--label cds--type-label-01"
+ i18n
>
- {{ form.getValue('role_name') }}
- </cds-tooltip-definition>
- </p>
- <ng-template #accountTooltip>
- <div>
- User account:<br />
- <strong>{{ accountName }}</strong>
- </div>
- </ng-template>
- </div>
+ Role
+ </legend>
+ <p class="cds--type-body-01">
+ <cds-tooltip-definition
+ align="right"
+ [description]="accountTooltip"
+ [openOnHover]="true"
+ [caret]="true"
+ [highContrast]="true"
+ [dropShadow]="true"
+ [autoAlign]="true"
+ >
+ {{ form.getValue('role_name') }}
+ </cds-tooltip-definition>
+ </p>
+ <ng-template #accountTooltip>
+ <div>
+ User account:<br />
+ <strong>{{ accountName }}</strong>
+ </div>
+ </ng-template>
+ </div>
}
<!-- Path & Assume Role Policy Document (Create only) -->
@if (!isEdit) {
- <!-- Path -->
- <div class="form-item">
- <cds-text-label
- label="Role path"
- for="role_path"
- [invalid]="rolePath.isInvalid"
- [invalidText]="pathError"
- helperText='Specifies the hierarchy or namespace for the role. Use "/" for the root path.'
- i18n-helperText
- >Role path
- <input
- cdsText
- cdValidate
- #rolePath="cdValidate"
- type="text"
- id="role_path"
- name="role_path"
- formControlName="role_path"
- placeholder="Enter path (/applications/)"
+ <!-- Path -->
+ <div class="form-item">
+ <cds-text-label
+ label="Role path"
+ for="role_path"
[invalid]="rolePath.isInvalid"
- />
- </cds-text-label>
- <ng-template #pathError>
- @if (form.showError('role_path', formDir, 'required')) {
- <span class="invalid-feedback" i18n>This field is required.</span>
- }
- </ng-template>
- </div>
+ [invalidText]="pathError"
+ helperText='Specifies the hierarchy or namespace for the role. Use "/" for the root path.'
+ i18n-helperText
+ >Role path
+ <input
+ cdsText
+ cdValidate
+ #rolePath="cdValidate"
+ type="text"
+ id="role_path"
+ name="role_path"
+ formControlName="role_path"
+ placeholder="Enter path (/applications/)"
+ [invalid]="rolePath.isInvalid"
+ [invalidText]="pathError"
+ />Path
+ <input
+ cdsText
+ cdValidate
+ #rolePath="cdValidate"
+ type="text"
+ id="role_path"
+ name="role_path"
+ formControlName="role_path"
+ placeholder="Placeholder text"
+ [invalid]="rolePath.isInvalid"
+ />
+ </cds-text-label>
+ <ng-template #pathError>
+ @if (form.showError('role_path', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
- <!-- Assume Role Policy Document -->
- <div class="form-item">
- <cds-textarea-label
- labelInputID="role_assume_policy_doc"
- [invalid]="policyDoc.isInvalid"
- [invalidText]="policyError"
- helperText="Defines which principals can assume this role. Enter a valid JSON policy document."
- i18n-helperText
- >Trust policy
- <textarea
- cdsTextArea
- cdValidate
- #policyDoc="cdValidate"
- id="role_assume_policy_doc"
- name="role_assume_policy_doc"
- formControlName="role_assume_policy_doc"
- placeholder="Enter a JSON trust policy document"
- rows="8"
- cols="200"
+ <!-- Assume Role Policy Document -->
+ <div class="form-item">
+ <cds-textarea-label
+ labelInputID="role_assume_policy_doc"
[invalid]="policyDoc.isInvalid"
[invalidText]="policyError"
- ></textarea>
- </cds-textarea-label>
- <ng-template #policyError>
- @if (form.showError('role_assume_policy_doc', formDir, 'required')) {
- <span class="invalid-feedback" i18n>This field is required.</span>
- } @if (form.showError('role_assume_policy_doc', formDir, 'json')) {
- <span class="invalid-feedback" i18n>Must be a valid JSON.</span>
- }
- </ng-template>
- </div>
+ helperText="Defines which principals can assume this role. Enter a valid JSON policy document."
+ i18n-helperText
+ >Trust policy
+ <textarea
+ cdsTextArea
+ cdValidate
+ #policyDoc="cdValidate"
+ id="role_assume_policy_doc"
+ name="role_assume_policy_doc"
+ formControlName="role_assume_policy_doc"
+ placeholder="Enter a JSON trust policy document"
+ rows="8"
+ cols="200"
+ [invalid]="policyDoc.isInvalid"
+ [invalidText]="policyError"
+ cdRequiredField="Trust Policy"
+ >
+Trust policy
+ <textarea
+ cdsTextArea
+ cdValidate
+ #policyDoc="cdValidate"
+ id="role_assume_policy_doc"
+ name="role_assume_policy_doc"
+ formControlName="role_assume_policy_doc"
+ placeholder="Placeholder text"
+ rows="8"
+ cols="200"
+ [invalid]="policyDoc.isInvalid"
+ [invalidText]="policyError"
+ ></textarea>
+ </cds-textarea-label>
+ <ng-template #policyError>
+ @if (form.showError('role_assume_policy_doc', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (form.showError('role_assume_policy_doc', formDir, 'json')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Must be a valid JSON.</span
+ >
+ }
+ </ng-template>
+ </div>
}
<!-- Maximum Session Duration (Edit only) -->
@if (isEdit) {
- <div class="form-item">
- <cds-number
- label="Maximum session duration (hours)"
- cdValidate
- #maxSessionDuration="cdValidate"
- [invalid]="maxSessionDuration.isInvalid"
- [invalidText]="durationError"
- formControlName="max_session_duration"
- min="1"
- max="12"
- i18n-label
- >
- </cds-number>
- <ng-template #durationError>
- @if (form.showError('max_session_duration', formDir, 'required')) {
- <span class="invalid-feedback" i18n>This field is required.</span>
- } @if (form.showError('max_session_duration', formDir, 'min')) {
- <span class="invalid-feedback" i18n>Minimum value is 1 hour.</span>
- } @if (form.showError('max_session_duration', formDir, 'max')) {
- <span class="invalid-feedback" i18n>Maximum value is 12 hours.</span>
- }
- </ng-template>
- </div>
+ <div class="form-item">
+ <cds-number
+ label="Maximum session duration (hours)"
+ cdValidate
+ #maxSessionDuration="cdValidate"
+ [invalid]="maxSessionDuration.isInvalid"
+ [invalidText]="durationError"
+ formControlName="max_session_duration"
+ min="1"
+ max="12"
+ i18n-label
+ >
+ </cds-number>
+ <ng-template #durationError>
+ @if (form.showError('max_session_duration', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ @if (form.showError('max_session_duration', formDir, 'min')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Minimum value is 1 hour.</span
+ >
+ }
+ @if (form.showError('max_session_duration', formDir, 'max')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >Maximum value is 12 hours.</span
+ >
+ }
+ </ng-template>
+ </div>
}
</div>
-<cd-table #table
- [autoReload]="true"
- [data]="data$ | async"
- [columns]="columns"
- selectionType="single"
- columnMode="flex"
- (updateSelection)="updateSelection($event)"
- identifier="RoleName">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [autoReload]="true"
+ [data]="data$ | async"
+ [columns]="columns"
+ selectionType="single"
+ columnMode="flex"
+ (updateSelection)="updateSelection($event)"
+ identifier="RoleName"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="rgw-bucket-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="rgw-bucket-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
-
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="rgw-bucket-details">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-details"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Versioning</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Versioning
+ </td>
<td class="w-75">{{ selection.versioning }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Encryption</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Encryption
+ </td>
<td>{{ selection.encryption }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Replication</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Replication
+ </td>
<td>{{ replicationStatus }}</td>
</tr>
<tr>
- <td i18n
- class="bold">MFA Delete</td>
+ <td
+ i18n
+ class="bold"
+ >
+ MFA Delete
+ </td>
<td>{{ selection.mfa_delete }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Index type</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Index type
+ </td>
<td>{{ selection.index_type }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Placement rule</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Placement rule
+ </td>
<td>{{ selection.placement_rule }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Last modification time</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Last modification time
+ </td>
<td>{{ selection.mtime | cdDate }}</td>
</tr>
</tbody>
<!-- Bucket quota -->
<div>
<legend i18n>Bucket quota</legend>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="rgw-bucket-quota-details">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-quota-details"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Enabled</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Enabled
+ </td>
<td class="w-75">{{ selection.bucket_quota.enabled | booleanText }}</td>
</tr>
<ng-container *ngIf="selection.bucket_quota.enabled">
<tr>
- <td i18n
- class="bold">Maximum size</td>
- <td *ngIf="selection.bucket_quota.max_size <= -1"
- i18n>Unlimited</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum size
+ </td>
+ <td
+ *ngIf="selection.bucket_quota.max_size <= -1"
+ i18n
+ >
+ Unlimited
+ </td>
<td *ngIf="selection.bucket_quota.max_size > -1">
{{ selection.bucket_quota.max_size | dimless }}
</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum objects</td>
- <td *ngIf="selection.bucket_quota.max_objects <= -1"
- i18n>Unlimited</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum objects
+ </td>
+ <td
+ *ngIf="selection.bucket_quota.max_objects <= -1"
+ i18n
+ >
+ Unlimited
+ </td>
<td *ngIf="selection.bucket_quota.max_objects > -1">
{{ selection.bucket_quota.max_objects }}
</td>
<!-- Locking -->
<legend i18n>Locking</legend>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="rgw-bucket-locking-details">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-locking-details"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Enabled</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Enabled
+ </td>
<td class="w-75">{{ selection.lock_enabled | booleanText }}</td>
</tr>
<ng-container *ngIf="selection.lock_enabled">
<tr>
- <td i18n
- class="bold">Mode</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Mode
+ </td>
<td>{{ selection.lock_mode }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Days</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Days
+ </td>
<td>{{ selection.lock_retention_period_days }}</td>
</tr>
</ng-container>
<!-- Tags -->
<ng-container *ngIf="(selection.tagset | keyvalue)?.length">
<legend i18n>Tags</legend>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr *ngFor="let tag of selection.tagset | keyvalue">
- <td i18n
- class="bold w-25">{{tag.key}}</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ {{ tag.key }}
+ </td>
<td class="w-75">{{ tag.value }}</td>
</tr>
</tbody>
</table>
</ng-container>
-
<!-- Bucket Rate Limit -->
<ng-container *ngIf="!!bucketRateLimit">
- <cd-rgw-rate-limit-details [rateLimitConfig]="bucketRateLimit"
- [type]="'bucket'"></cd-rgw-rate-limit-details>
+ <cd-rgw-rate-limit-details
+ [rateLimitConfig]="bucketRateLimit"
+ [type]="'bucket'"
+ ></cd-rgw-rate-limit-details>
</ng-container>
</ng-template>
</ng-container>
<ng-container ngbNavItem="permissions">
- <a ngbNavLink
- i18n>Policies</a>
+ <a
+ ngbNavLink
+ i18n
+ >Policies</a
+ >
<ng-template ngbNavContent>
<div>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Bucket policy</td>
- <td><pre>{{ selection.bucket_policy | json}}</pre></td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Bucket policy
+ </td>
+ <td>
+ <pre>{{ selection.bucket_policy | json }}</pre>
+ </td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Lifecycle
- <div *ngIf="(selection.lifecycle | json) !== '{}'"
- class="input-group">
- <button type="button"
- class="btn btn-light"
- [ngClass]="{'active': lifecycleFormat === 'json'}"
- (click)="updateLifecycleFormatTo('json')">
- JSON
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Lifecycle
+ <div
+ *ngIf="(selection.lifecycle | json) !== '{}'"
+ class="input-group"
+ >
+ <button
+ type="button"
+ class="btn btn-light"
+ [ngClass]="{ active: lifecycleFormat === 'json' }"
+ (click)="updateLifecycleFormatTo('json')"
+ >
+ JSON
</button>
- <button type="button"
- class="btn btn-light"
- [ngClass]="{'active': lifecycleFormat === 'xml'}"
- (click)="updateLifecycleFormatTo('xml')">
- XML
+ <button
+ type="button"
+ class="btn btn-light"
+ [ngClass]="{ active: lifecycleFormat === 'xml' }"
+ (click)="updateLifecycleFormatTo('xml')"
+ >
+ XML
</button>
</div>
</td>
<td>
- <cds-code-snippet display="multi"
- *ngIf="lifecycleFormat === 'json'">
- {{selection.lifecycle | json}}
+ <cds-code-snippet
+ display="multi"
+ *ngIf="lifecycleFormat === 'json'"
+ >
+ {{ selection.lifecycle | json }}
</cds-code-snippet>
- <cds-code-snippet display="multi"
- *ngIf="lifecycleFormat === 'xml'">
- {{ (selection.lifecycle | xml:{'Rules':'Rule'}) || '-'}}
+ <cds-code-snippet
+ display="multi"
+ *ngIf="lifecycleFormat === 'xml'"
+ >
+ {{ (selection.lifecycle | xml: { Rules: 'Rule' }) || '-' }}
</cds-code-snippet>
</td>
</tr>
<tr *ngIf="selection.lifecycle_progress?.length > 0">
- <td i18n
- class="bold w-25">
+ <td
+ i18n
+ class="bold w-25"
+ >
Lifecycle progress
</td>
<td>
- <cds-tooltip [description]="lifecycleProgressMap.get(lifecycleProgress.status)?.description"
- [align]="'top'">
- <cds-tag size="md"
- [type]="lifecycleProgressMap.get(lifecycleProgress.status)?.color">
+ <cds-tooltip
+ [description]="lifecycleProgressMap.get(lifecycleProgress.status)?.description"
+ [align]="'top'"
+ >
+ <cds-tag
+ size="md"
+ [type]="lifecycleProgressMap.get(lifecycleProgress.status)?.color"
+ >
{{ lifecycleProgress.status }}
</cds-tag>
</cds-tooltip>
- <div *ngIf="lifecycleProgress?.status !== 'UNINITIAL'"
- class="spacing-left">{{lifecycleProgress?.started}}</div>
+ <div
+ *ngIf="lifecycleProgress?.status !== 'UNINITIAL'"
+ class="spacing-left"
+ >
+ {{ lifecycleProgress?.started }}
+ </div>
</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Replication policy</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Replication policy
+ </td>
<td>
- @if(hasSyncPolicyOnly) {
- Sync policy configured. View on
- <a routerLink="/rgw/multisite/sync-policy"
- i18n>Sync-policy page.</a>
- } @else {
- <pre>{{ replicationData?.policy | json}}</pre>
- }
+ @if (hasSyncPolicyOnly) {
+ Sync policy configured. View on
+ <a
+ routerLink="/rgw/multisite/sync-policy"
+ i18n
+ >Sync-policy page.</a
+ >
+ } @else {
+ <pre>{{ replicationData?.policy | json }}</pre>
+ }
</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">ACL</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ ACL
+ </td>
<td>
<table class="table">
<thead>
<tbody>
<tr i18n>
<td>Bucket Owner</td>
- <td>{{ aclPermissions.Owner || '-'}}</td>
+ <td>{{ aclPermissions.Owner || '-' }}</td>
</tr>
<tr i18n>
<td>Everyone</td>
- <td>{{ aclPermissions.AllUsers || '-'}}</td>
+ <td>{{ aclPermissions.AllUsers || '-' }}</td>
</tr>
<tr i18n>
<td>Authenticated users group</td>
- <td>{{ aclPermissions.AuthenticatedUsers || '-'}}</td>
+ <td>{{ aclPermissions.AuthenticatedUsers || '-' }}</td>
</tr>
</tbody>
</table>
</ng-container>
<ng-container ngbNavItem="tiering">
- <a ngbNavLink
- i18n>Tiering</a>
+ <a
+ ngbNavLink
+ i18n
+ >Tiering</a
+ >
<ng-template ngbNavContent>
- <cd-rgw-bucket-lifecycle-list [bucket]="selection"
- (updateBucketDetails)="updateBucketDetails(extractLifecycleDetails.bind(this))"></cd-rgw-bucket-lifecycle-list>
+ <cd-rgw-bucket-lifecycle-list
+ [bucket]="selection"
+ (updateBucketDetails)="updateBucketDetails(extractLifecycleDetails.bind(this))"
+ ></cd-rgw-bucket-lifecycle-list>
</ng-template>
</ng-container>
<ng-container ngbNavItem="notification">
- <a ngbNavLink
- i18n>Notification</a>
+ <a
+ ngbNavLink
+ i18n
+ >Notification</a
+ >
<ng-template ngbNavContent>
<cd-rgw-bucket-notification-list [bucket]="selection"></cd-rgw-bucket-notification-list>
</ng-template>
-<div cdsCol
- [columnNumbers]="{md: 4}"
- *cdFormLoading="loading">
- <form name="bucketForm"
- #frm="ngForm"
- [formGroup]="bucketForm"
- novalidate>
-
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ *cdFormLoading="loading"
+>
+ <form
+ name="bucketForm"
+ #frm="ngForm"
+ [formGroup]="bucketForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
<!-- Id -->
- <div class="form-item"
- *ngIf="editing">
- <cds-text-label for="id"
- i18n>Id
- <input cdsText
- id="id"
- name="id"
- formControlName="id"
- readonly>
+ <div
+ class="form-item"
+ *ngIf="editing"
+ >
+ <cds-text-label
+ for="id"
+ i18n
+ >Id
+ <input
+ cdsText
+ id="id"
+ name="id"
+ formControlName="id"
+ readonly
+ />
</cds-text-label>
</div>
<!-- Name -->
<div class="form-item">
- <cds-text-label for="bid"
- cdRequiredField="Name"
- [invalid]="!bucketForm.controls.bid.valid && bucketForm.controls.bid.dirty"
- [invalidText]="nameError"
- i18n>Name
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="bid"
- name="bid"
- formControlName="bid"
- [readonly]="editing"
- [autofocus]="!editing"
- [invalid]="!bucketForm.controls.bid.valid && bucketForm.controls.bid.dirty">
+ <cds-text-label
+ for="bid"
+ cdRequiredField="Name"
+ [invalid]="!bucketForm.controls.bid.valid && bucketForm.controls.bid.dirty"
+ [invalidText]="nameError"
+ i18n
+ >Name
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="bid"
+ name="bid"
+ formControlName="bid"
+ [readonly]="editing"
+ [autofocus]="!editing"
+ [invalid]="!bucketForm.controls.bid.valid && bucketForm.controls.bid.dirty"
+ />
</cds-text-label>
<ng-template #nameError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'bucketNameInvalid')"
- i18n>Bucket names can only contain lowercase letters, numbers, periods and hyphens.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'bucketNameNotAllowed')"
- i18n>The chosen name is already in use.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'containsUpperCase')"
- i18n>Bucket names must not contain uppercase characters or underscores.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'lowerCaseOrNumber')"
- i18n>Each label must start and end with a lowercase letter or a number.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'ipAddress')"
- i18n>Bucket names cannot be formatted as IP address.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'onlyLowerCaseAndNumbers')"
- i18n>Bucket labels cannot be empty and can only contain lowercase letters, numbers and hyphens.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bid', frm, 'shouldBeInRange')"
- i18n>Bucket names must be 3 to 63 characters long.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'bucketNameInvalid')"
+ i18n
+ >Bucket names can only contain lowercase letters, numbers, periods and hyphens.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'bucketNameNotAllowed')"
+ i18n
+ >The chosen name is already in use.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'containsUpperCase')"
+ i18n
+ >Bucket names must not contain uppercase characters or underscores.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'lowerCaseOrNumber')"
+ i18n
+ >Each label must start and end with a lowercase letter or a number.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'ipAddress')"
+ i18n
+ >Bucket names cannot be formatted as IP address.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'onlyLowerCaseAndNumbers')"
+ i18n
+ >Bucket labels cannot be empty and can only contain lowercase letters, numbers and
+ hyphens.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bid', frm, 'shouldBeInRange')"
+ i18n
+ >Bucket names must be 3 to 63 characters long.</span
+ >
</ng-template>
</div>
<!-- Accounts -->
- @if(accounts.length && accountUsers.length > 0){
+ @if (accounts.length && accountUsers.length > 0) {
<div class="form-item">
- <cds-checkbox formControlName="isAccountOwner"
- i18n>Select account user
+ <cds-checkbox
+ formControlName="isAccountOwner"
+ i18n
+ >Select account user
</cds-checkbox>
</div>
}
@if (bucketForm.get('isAccountOwner').value) {
<!-- Account user -->
<div class="form-item">
- <cds-select label="Account user"
- id="acc_user"
- formControlName="accountUser"
- [invalidText]="accountUserError"
- [invalid]="!bucketForm.controls.accountUser.valid && bucketForm.controls.accountUser.dirty"
- cdRequiredField="Account user"
- i18n>Account user
- <option *ngIf="accountusers === null"
- [ngValue]="null">Loading...</option>
- <option *ngIf="accountusers !== null"
- value="">-- Select a user --</option>
- <option *ngFor="let user of accountUsers"
- [value]="user.uid">{{ user.uid }}</option>
+ <cds-select
+ label="Account user"
+ id="acc_user"
+ formControlName="accountUser"
+ [invalidText]="accountUserError"
+ [invalid]="
+ !bucketForm.controls.accountUser.valid && bucketForm.controls.accountUser.dirty
+ "
+ cdRequiredField="Account user"
+ i18n
+ >Account user
+ <option
+ *ngIf="accountusers === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="accountusers !== null"
+ value=""
+ >
+ -- Select a user --
+ </option>
+ <option
+ *ngFor="let user of accountUsers"
+ [value]="user.uid"
+ >
+ {{ user.uid }}
+ </option>
</cds-select>
<ng-template #accountUserError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('accountUser', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('accountUser', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
<cd-alert-panel
type="info"
*ngIf="bucketForm.get('accountUser').disabled"
- i18n>
- The bucket is owned by an account. UI does not support changing
- the ownership of bucket owned by an account.
+ i18n
+ >
+ The bucket is owned by an account. UI does not support changing the ownership of bucket
+ owned by an account.
</cd-alert-panel>
</div>
} @else {
<!-- Owner -->
<div class="form-item">
- <cds-select label="Owner"
- formControlName="owner"
- id="owner"
- [invalidText]="ownerError"
- [invalid]="!bucketForm.controls.owner.valid && bucketForm.controls.owner.dirty"
- cdRequiredField="Owner"
- i18n>Owner
- <option *ngIf="owners === null"
- [ngValue]="null">Loading...</option>
- <option *ngIf="owners !== null"
- value="">-- Select a user --</option>
- <option *ngFor="let owner of owners"
- [value]="owner.uid">{{ owner.uid }}</option>
+ <cds-select
+ label="Owner"
+ formControlName="owner"
+ id="owner"
+ [invalidText]="ownerError"
+ [invalid]="!bucketForm.controls.owner.valid && bucketForm.controls.owner.dirty"
+ cdRequiredField="Owner"
+ i18n
+ >Owner
+ <option
+ *ngIf="owners === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="owners !== null"
+ value=""
+ >
+ -- Select a user --
+ </option>
+ <option
+ *ngFor="let owner of owners"
+ [value]="owner.uid"
+ >
+ {{ owner.uid }}
+ </option>
</cds-select>
<ng-template #ownerError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('owner', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('owner', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
}
<!-- Versioning -->
<fieldset *ngIf="editing">
<div class="form-item">
- <legend class="cd-header"
- i18n>Versioning</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Versioning
+ </legend>
- <cds-checkbox name="versioning"
- formControlName="versioning"
- id="versioning"
- (checkedChange)="setMfaDeleteValidators()"
- i18n>Enabled
+ <cds-checkbox
+ name="versioning"
+ formControlName="versioning"
+ id="versioning"
+ (checkedChange)="setMfaDeleteValidators()"
+ i18n
+ >Enabled
<cd-help-text>
<span>Enables versioning for the objects in the bucket.</span>
</cd-help-text>
<fieldset *ngIf="editing">
<!-- MFA Delete -->
<div class="form-item">
- <legend class="cd-header"
- i18n>Multi-Factor Authentication</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Multi-Factor Authentication
+ </legend>
- <cds-checkbox name="mfa-delete"
- formControlName="mfa-delete"
- id="mfa-delete"
- (checkedChange)="setMfaDeleteValidators()"
- helperText="Enables MFA (multi-factor authentication) Delete, which requires additional authentication for changing the bucket versioning state."
- i18n-helperText
- i18n>Delete enabled
+ <cds-checkbox
+ name="mfa-delete"
+ formControlName="mfa-delete"
+ id="mfa-delete"
+ (checkedChange)="setMfaDeleteValidators()"
+ helperText="Enables MFA (multi-factor authentication) Delete, which requires additional authentication for changing the bucket versioning state."
+ i18n-helperText
+ i18n
+ >Delete enabled
</cds-checkbox>
</div>
- <div *ngIf="areMfaCredentialsRequired()"
- class="form-item">
- <cds-text-label for="mfa-token-serial"
- cdRequiredField="MFA Serial Number"
- [invalid]="!bucketForm.controls['mfa-token-serial'].valid && bucketForm.controls['mfa-token-serial'].dirty"
- [invalidText]="mfaSerialError"
- i18n>Token Serial Number
- <input cdsText
- id="mfa-token-serial"
- name="mfa-token-serial"
- formControlName="mfa-token-serial"
- [invalid]="!bucketForm.controls['mfa-token-serial'].valid && bucketForm.controls['mfa-token-serial'].dirty">
+ <div
+ *ngIf="areMfaCredentialsRequired()"
+ class="form-item"
+ >
+ <cds-text-label
+ for="mfa-token-serial"
+ cdRequiredField="MFA Serial Number"
+ [invalid]="
+ !bucketForm.controls['mfa-token-serial'].valid &&
+ bucketForm.controls['mfa-token-serial'].dirty
+ "
+ [invalidText]="mfaSerialError"
+ i18n
+ >Token Serial Number
+ <input
+ cdsText
+ id="mfa-token-serial"
+ name="mfa-token-serial"
+ formControlName="mfa-token-serial"
+ [invalid]="
+ !bucketForm.controls['mfa-token-serial'].valid &&
+ bucketForm.controls['mfa-token-serial'].dirty
+ "
+ />
</cds-text-label>
<ng-template #mfaSerialError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('mfa-token-serial', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('mfa-token-serial', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
- <div *ngIf="areMfaCredentialsRequired()"
- class="form-item">
- <cds-text-label for="mfa-token-pin"
- cdRequiredField="MFA Token PIN"
- [invalid]="!bucketForm.controls['mfa-token-pin'].valid && (bucketForm.controls['mfa-token-pin'].dirty)"
- [invalidText]="mfaPinError"
- i18n>Token PIN
- <input cdsText
- id="mfa-token-pin"
- name="mfa-token-pin"
- formControlName="mfa-token-pin"
- [invalid]="!bucketForm.controls['mfa-token-pin'].valid && (bucketForm.controls['mfa-token-pin'].dirty)">
+ <div
+ *ngIf="areMfaCredentialsRequired()"
+ class="form-item"
+ >
+ <cds-text-label
+ for="mfa-token-pin"
+ cdRequiredField="MFA Token PIN"
+ [invalid]="
+ !bucketForm.controls['mfa-token-pin'].valid &&
+ bucketForm.controls['mfa-token-pin'].dirty
+ "
+ [invalidText]="mfaPinError"
+ i18n
+ >Token PIN
+ <input
+ cdsText
+ id="mfa-token-pin"
+ name="mfa-token-pin"
+ formControlName="mfa-token-pin"
+ [invalid]="
+ !bucketForm.controls['mfa-token-pin'].valid &&
+ bucketForm.controls['mfa-token-pin'].dirty
+ "
+ />
</cds-text-label>
<ng-template #mfaPinError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('mfa-token-pin', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('mfa-token-pin', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</fieldset>
<!-- Object Locking -->
<fieldset *ngIf="!editing || (editing && bucketForm.getValue('lock_enabled'))">
<div class="form-item">
- <legend class="cd-header"
- i18n>
+ <legend
+ class="cd-header"
+ i18n
+ >
Object Locking
<cd-help-text>
- Store objects using a write-once-read-many (WORM) model to prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely.
- Object Locking works only in versioned buckets.
+ Store objects using a write-once-read-many (WORM) model to prevent objects from being
+ deleted or overwritten for a fixed amount of time or indefinitely. Object Locking works
+ only in versioned buckets.
</cd-help-text>
</legend>
<!-- Object Locking enable -->
- <cds-checkbox name="lock_enabled"
- formControlName="lock_enabled"
- id="lock_enabled"
- [disabled]="editing"
- i18n>Enable
+ <cds-checkbox
+ name="lock_enabled"
+ formControlName="lock_enabled"
+ id="lock_enabled"
+ [disabled]="editing"
+ i18n
+ >Enable
<cd-help-text>
- <span>Enables locking for the objects in the bucket. Locking can only be enabled while creating a bucket.</span>
+ <span
+ >Enables locking for the objects in the bucket. Locking can only be enabled while
+ creating a bucket.</span
+ >
</cd-help-text>
</cds-checkbox>
</div>
<!-- Object Locking mode -->
- <div *ngIf="bucketForm.getValue('lock_enabled')"
- class="form-item">
- <cds-select label="Mode"
- for="lock_mode"
- formControlName="lock_mode"
- name="lock_mode"
- [helperText]="lockModeHelper"
- id="lock_mode"
- i18n>
+ <div
+ *ngIf="bucketForm.getValue('lock_enabled')"
+ class="form-item"
+ >
+ <cds-select
+ label="Mode"
+ for="lock_mode"
+ formControlName="lock_mode"
+ name="lock_mode"
+ [helperText]="lockModeHelper"
+ id="lock_mode"
+ i18n
+ >
<option value="COMPLIANCE">Compliance</option>
<option value="GOVERNANCE">Governance</option>
</cds-select>
<ng-template #lockModeHelper>
- <span *ngIf="bucketForm.getValue('lock_mode') === 'COMPLIANCE'"
- i18n>
- In COMPLIANCE an object version cannot be overwritten or deleted for the duration of the period.
+ <span
+ *ngIf="bucketForm.getValue('lock_mode') === 'COMPLIANCE'"
+ i18n
+ >
+ In COMPLIANCE an object version cannot be overwritten or deleted for the duration of the
+ period.
</span>
- <span *ngIf="bucketForm.getValue('lock_mode') === 'GOVERNANCE'"
- i18n>
- In GOVERNANCE mode, users cannot overwrite or delete an object version or alter its lock settings unless they have special permissions.
+ <span
+ *ngIf="bucketForm.getValue('lock_mode') === 'GOVERNANCE'"
+ i18n
+ >
+ In GOVERNANCE mode, users cannot overwrite or delete an object version or alter its lock
+ settings unless they have special permissions.
</span>
</ng-template>
</div>
<!-- Retention period (days) -->
- <div *ngIf="bucketForm.getValue('lock_enabled')"
- class="form-item">
- <cds-number name="lock_retention_period_days"
- formControlName="lock_retention_period_days"
- id="lock_retention_period_days"
- min="1"
- label="Retention period (days)"
- helperText="The number of days that you want to specify for the default retention period that will be applied to new objects placed in this bucket."
- [invalid]="bucketForm.controls.lock_retention_period_days.invalid && (bucketForm.controls.lock_retention_period_days.dirty)"
- [invalidText]="retentionPeriodError"
- i18n-helperText
- i18n-label
- i18n></cds-number>
+ <div
+ *ngIf="bucketForm.getValue('lock_enabled')"
+ class="form-item"
+ >
+ <cds-number
+ name="lock_retention_period_days"
+ formControlName="lock_retention_period_days"
+ id="lock_retention_period_days"
+ min="1"
+ label="Retention period (days)"
+ helperText="The number of days that you want to specify for the default retention period that will be applied to new objects placed in this bucket."
+ [invalid]="
+ bucketForm.controls.lock_retention_period_days.invalid &&
+ bucketForm.controls.lock_retention_period_days.dirty
+ "
+ [invalidText]="retentionPeriodError"
+ i18n-helperText
+ i18n-label
+ i18n
+ ></cds-number>
<ng-template #retentionPeriodError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('lock_retention_period_days', frm, 'pattern')"
- i18n>The entered value must be a positive integer.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('lock_retention_period_days', frm, 'lockDays')"
- i18n>Retention Days must be a positive integer.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('lock_retention_period_days', frm, 'pattern')"
+ i18n
+ >The entered value must be a positive integer.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('lock_retention_period_days', frm, 'lockDays')"
+ i18n
+ >Retention Days must be a positive integer.</span
+ >
</ng-template>
</div>
<!-- Alerts -->
type="info"
*ngIf="bucketForm.getValue('lock_enabled')"
class="me-1"
- i18n-title>
- Bucket Versioning can't be disabled when Object Locking is enabled.
+ i18n-title
+ >
+ Bucket Versioning can't be disabled when Object Locking is enabled.
</cd-alert-panel>
<cd-alert-panel
type="warning"
- *ngIf="bucketForm.getValue('lock_enabled')">
- Enabling Object Locking will allow the configuration of GOVERNANCE or COMPLIANCE modes, which will help ensure that an object version cannot be overwritten or deleted for the specified period.
+ *ngIf="bucketForm.getValue('lock_enabled')"
+ >
+ Enabling Object Locking will allow the configuration of GOVERNANCE or COMPLIANCE modes,
+ which will help ensure that an object version cannot be overwritten or deleted for the
+ specified period.
</cd-alert-panel>
</fieldset>
<!-- Encryption -->
<fieldset>
<div class="form-item">
- <legend class="cd-header"
- i18n>Encryption</legend>
- <cds-checkbox name="encryption_enabled"
- formControlName="encryption_enabled"
- id="encryption_enabled"
- [disabled]="!kmsConfigured && !s3Configured"
- i18n>Enable
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Encryption
+ </legend>
+ <cds-checkbox
+ name="encryption_enabled"
+ formControlName="encryption_enabled"
+ id="encryption_enabled"
+ [disabled]="!kmsConfigured && !s3Configured"
+ i18n
+ >Enable
<cd-help-text aria-label="encryption helper">
- <span>Enables encryption for the objects in the bucket.
- To enable encryption on a bucket you need to set the configuration values for SSE-S3 or SSE-KMS.
- To set the configuration values <a href="#/rgw/configuration"
- i18n-aria-label="click here">Click here</a></span>
+ <span
+ >Enables encryption for the objects in the bucket. To enable encryption on a bucket
+ you need to set the configuration values for SSE-S3 or SSE-KMS. To set the
+ configuration values
+ <a
+ href="#/rgw/configuration"
+ i18n-aria-label="click here"
+ >Click here</a
+ ></span
+ >
</cd-help-text>
</cds-checkbox>
</div>
<div *ngIf="bucketForm.getValue('encryption_enabled')">
<div class="form-item">
<cds-radio-group formControlName="encryption_type">
- <cds-radio value="AES256"
- [disabled]="!s3Configured">SSE-S3</cds-radio>
- <cds-radio value="aws:kms"
- [disabled]="!kmsConfigured">Connect to an external key management service</cds-radio>
+ <cds-radio
+ value="AES256"
+ [disabled]="!s3Configured"
+ >SSE-S3</cds-radio
+ >
+ <cds-radio
+ value="aws:kms"
+ [disabled]="!kmsConfigured"
+ >Connect to an external key management service</cds-radio
+ >
</cds-radio-group>
</div>
<div *ngIf="bucketForm.getValue('encryption_type') === 'aws:kms'">
<div class="form-item">
- <cds-select label="KMS Provider"
- for="kms_provider"
- formControlName="kms_provider"
- name="kms_provider"
- id="kms_provider"
- [invalidText]="kmsProviderError"
- [invalid]="!bucketForm.controls.kms_provider.valid && (bucketForm.controls.kms_provider.dirty)"
- cdRequiredField="KMS Provider"
- i18n>KMS Provider
- <option *ngIf="kmsProviders === null"
- [ngValue]="null">Loading...</option>
- <option *ngIf="kmsProviders !== null"
- [ngValue]="null">-- Select a provider --</option>
- <option *ngFor="let provider of kmsProviders"
- [value]="provider">{{ provider }}</option>
+ <cds-select
+ label="KMS Provider"
+ for="kms_provider"
+ formControlName="kms_provider"
+ name="kms_provider"
+ id="kms_provider"
+ [invalidText]="kmsProviderError"
+ [invalid]="
+ !bucketForm.controls.kms_provider.valid && bucketForm.controls.kms_provider.dirty
+ "
+ cdRequiredField="KMS Provider"
+ i18n
+ >KMS Provider
+ <option
+ *ngIf="kmsProviders === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="kmsProviders !== null"
+ [ngValue]="null"
+ >
+ -- Select a provider --
+ </option>
+ <option
+ *ngFor="let provider of kmsProviders"
+ [value]="provider"
+ >
+ {{ provider }}
+ </option>
</cds-select>
<ng-template #kmsProviderError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('kms_provider', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('kms_provider', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<div class="form-item">
- <cds-text-label for="keyId"
- cdRequiredField="Key Id"
- [invalid]="!bucketForm.controls.keyId.valid && (bucketForm.controls.keyId.dirty)"
- [invalidText]="keyIdError"
- i18n>Key Id
- <input cdsText
- id="keyId"
- name="keyId"
- formControlName="keyId"
- [invalid]="!bucketForm.controls.keyId.valid && (bucketForm.controls.keyId.dirty)">
+ <cds-text-label
+ for="keyId"
+ cdRequiredField="Key Id"
+ [invalid]="!bucketForm.controls.keyId.valid && bucketForm.controls.keyId.dirty"
+ [invalidText]="keyIdError"
+ i18n
+ >Key Id
+ <input
+ cdsText
+ id="keyId"
+ name="keyId"
+ formControlName="keyId"
+ [invalid]="!bucketForm.controls.keyId.valid && bucketForm.controls.keyId.dirty"
+ />
</cds-text-label>
<ng-template #keyIdError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('keyId', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('keyId', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</div>
<!-- Replication -->
<fieldset>
<div class="form-item">
- <legend class="cd-header"
- i18n>Replication</legend>
- <ng-container *ngIf="{status: multisiteStatus$ | async, isDefaultZg: isDefaultZoneGroup$ | async} as multisiteStatus; else loadingTpl">
- <cds-checkbox name="replication"
- formControlName="replication"
- id="replication"
- [disabled]="!multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available"
- [title]="!multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available ? 'Please enable the multisite configuration' : ''"
- i18n-title
- i18n-helperText
- i18n>Enable
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Replication
+ </legend>
+ <ng-container
+ *ngIf="
+ {
+ status: multisiteStatus$ | async,
+ isDefaultZg: isDefaultZoneGroup$ | async
+ } as multisiteStatus;
+ else loadingTpl
+ "
+ >
+ <cds-checkbox
+ name="replication"
+ formControlName="replication"
+ id="replication"
+ [disabled]="!multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available"
+ [title]="
+ !multisiteStatus.isDefaultZg && !multisiteStatus?.status?.available
+ ? 'Please enable the multisite configuration'
+ : ''
+ "
+ i18n-title
+ i18n-helperText
+ i18n
+ >Enable
<cd-help-text>Enables replication for the objects in the bucket.</cd-help-text>
</cds-checkbox>
- <cd-alert-panel type="info"
- class="me-1"
- id="replication-info"
- spacingClass="mt-1"
- *ngIf="!editing"
- i18n>
- A bi-directional sync policy group will be created by the dashboard along with flows and pipes.
- The pipe id will then be used for applying the replication policy to the bucket.
+ <cd-alert-panel
+ type="info"
+ class="me-1"
+ id="replication-info"
+ spacingClass="mt-1"
+ *ngIf="!editing"
+ i18n
+ >
+ A bi-directional sync policy group will be created by the dashboard along with flows and
+ pipes. The pipe id will then be used for applying the replication policy to the bucket.
</cd-alert-panel>
</ng-container>
</div>
<!-- Tags -->
<fieldset>
- <legend class="cd-header"
- i18n>Tags
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Tags
<cd-help-text>Tagging provides a way to categorize storage</cd-help-text>
</legend>
- <span *ngFor="let tag of tags; let i=index;">
- <ng-container *ngTemplateOutlet="tagTpl; context:{index: i, tag: tag}"></ng-container>
+ <span *ngFor="let tag of tags; let i = index">
+ <ng-container *ngTemplateOutlet="tagTpl; context: { index: i, tag: tag }"></ng-container>
</span>
<div cdsRow>
<div cdsCol>
- <cds-tooltip [description]="tags.length > 19 ? 'Maximum of 20 tags reached' : ''"
- [highContrast]="true"
- [caret]="true">
- <button cdsButton="tertiary"
- id="add-tag"
- [disabled]="tags.length > 19"
- (click)="showTagModal()"
- type="button">
+ <cds-tooltip
+ [description]="tags.length > 19 ? 'Maximum of 20 tags reached' : ''"
+ [highContrast]="true"
+ [caret]="true"
+ >
+ <button
+ cdsButton="tertiary"
+ id="add-tag"
+ [disabled]="tags.length > 19"
+ (click)="showTagModal()"
+ type="button"
+ >
<ng-container i18n>Add tag</ng-container>
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-tooltip>
</div>
<!-- Policies -->
<fieldset>
<div class="form-item">
- <legend class="cd-header"
- i18n>Policies
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Policies
</legend>
<!-- Bucket policy -->
- <cds-textarea-label for="id"
- [invalid]="!bucketForm.controls.bucket_policy.valid && (bucketForm.controls.bucket_policy.dirty)"
- [invalidText]="bucketPolicyError"
- helperText="Define access permissions for this bucket using an S3-compatible JSON policy. This controls who can access the bucket and what actions they can perform."
- i18n-helperText
- i18n>Bucket Policy
- <textarea cdsTextArea
- class="textarea-field"
- id="bucket_policy"
- formControlName="bucket_policy"
- (change)="textAreaOnChange('bucket_policy')"
- cols="200"
- #bucketPolicyTextArea></textarea>
+ <cds-textarea-label
+ for="id"
+ [invalid]="
+ !bucketForm.controls.bucket_policy.valid && bucketForm.controls.bucket_policy.dirty
+ "
+ [invalidText]="bucketPolicyError"
+ helperText="Define access permissions for this bucket using an S3-compatible JSON policy. This controls who can access the bucket and what actions they can perform."
+ i18n-helperText
+ i18n
+ >Bucket Policy
+ <textarea
+ cdsTextArea
+ class="textarea-field"
+ id="bucket_policy"
+ formControlName="bucket_policy"
+ (change)="textAreaOnChange('bucket_policy')"
+ cols="200"
+ #bucketPolicyTextArea
+ ></textarea>
</cds-textarea-label>
<ng-template #bucketPolicyError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('bucket_policy', frm, 'invalidJson')"
- i18n>Invalid json text.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('bucket_policy', frm, 'invalidJson')"
+ i18n
+ >Invalid json text.</span
+ >
</ng-template>
<div cdsRow>
<div cdsCol>
<cds-button-set class="mt-1">
- <button cdsButton="tertiary"
- id="example-generator-button"
- (click)="openUrl('https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html?icmpid=docs_amazons3_console')"
- type="button"
- i18n>Policy examples
- <svg [cdsIcon]="icons.launch"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <button
+ cdsButton="tertiary"
+ id="example-generator-button"
+ (click)="
+ openUrl(
+ 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html?icmpid=docs_amazons3_console'
+ )
+ "
+ type="button"
+ i18n
+ >
+ Policy examples
+ <svg
+ [cdsIcon]="icons.launch"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
- <button cdsButton="tertiary"
- id="example-generator-button"
- (click)="openUrl('https://awspolicygen.s3.amazonaws.com/policygen.html')"
- type="button"
- i18n>Policy generator
- <svg [cdsIcon]="icons.launch"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <button
+ cdsButton="tertiary"
+ id="example-generator-button"
+ (click)="openUrl('https://awspolicygen.s3.amazonaws.com/policygen.html')"
+ type="button"
+ i18n
+ >
+ Policy generator
+ <svg
+ [cdsIcon]="icons.launch"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
<div cdsCol>
<cds-button-set class="float-end mt-1">
- <button cdsButton="tertiary"
- id="clear-bucket-policy"
- (click)="clearTextArea('bucket_policy', '{}')"
- type="button"
- i18n>Clear
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <button
+ cdsButton="tertiary"
+ id="clear-bucket-policy"
+ (click)="clearTextArea('bucket_policy', '{}')"
+ type="button"
+ i18n
+ >
+ Clear
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
</div>
<!-- Lifecycle -->
- <div *ngIf="editing"
- class="form-item">
- <cds-textarea-label for="id"
- [invalid]="!bucketForm.controls.lifecycle.valid && bucketForm.controls.lifecycle.dirty"
- [invalidText]="lifecycleError"
- i18n>Lifecycle
- <textarea cdsTextArea
- class="textarea-field"
- id="lifecycle"
- formControlName="lifecycle"
- (change)="textAreaOnChange('lifecycle')"
- cols="200"
- #lifecycleTextArea></textarea>
+ <div
+ *ngIf="editing"
+ class="form-item"
+ >
+ <cds-textarea-label
+ for="id"
+ [invalid]="!bucketForm.controls.lifecycle.valid && bucketForm.controls.lifecycle.dirty"
+ [invalidText]="lifecycleError"
+ i18n
+ >Lifecycle
+ <textarea
+ cdsTextArea
+ class="textarea-field"
+ id="lifecycle"
+ formControlName="lifecycle"
+ (change)="textAreaOnChange('lifecycle')"
+ cols="200"
+ #lifecycleTextArea
+ ></textarea>
<cd-help-text>JSON or XML formatted document</cd-help-text>
</cds-textarea-label>
<ng-template #lifecycleError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('lifecycle', frm, 'invalidJson')"
- i18n>Invalid json text.</span>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('lifecycle', frm, 'invalidXml')"
- i18n>Invalid xml text.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('lifecycle', frm, 'invalidJson')"
+ i18n
+ >Invalid json text.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('lifecycle', frm, 'invalidXml')"
+ i18n
+ >Invalid xml text.</span
+ >
</ng-template>
<div cdsRow>
<div cdsCol>
<cds-button-set class="mt-1">
- <button cdsButton="tertiary"
- id="lifecycle-examples-button"
- (click)="openUrl('https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-lifecycle.html#examples')"
- type="button"
- i18n>Policy examples
- <svg [cdsIcon]="icons.launch"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <button
+ cdsButton="tertiary"
+ id="lifecycle-examples-button"
+ (click)="
+ openUrl(
+ 'https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-lifecycle.html#examples'
+ )
+ "
+ type="button"
+ i18n
+ >
+ Policy examples
+ <svg
+ [cdsIcon]="icons.launch"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
<div cdsCol>
<cds-button-set class="float-end mt-1">
- <button cdsButton="tertiary"
- id="clear-lifecycle"
- (click)="clearTextArea('lifecycle', '{}')"
- type="button"
- i18n>Clear
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <button
+ cdsButton="tertiary"
+ id="clear-lifecycle"
+ (click)="clearTextArea('lifecycle', '{}')"
+ type="button"
+ i18n
+ >
+ Clear
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
</div>
<div class="form-item">
-
<!-- ACL -->
- <cds-text-label i18n>ACL
- <cd-help-text>Any changes to the ACL will overwrite previous one.
- You can choose any of the available options to modify the spcified user group.</cd-help-text>
+ <cds-text-label i18n
+ >ACL
+ <cd-help-text
+ >Any changes to the ACL will overwrite previous one. You can choose any of the available
+ options to modify the spcified user group.</cd-help-text
+ >
</cds-text-label>
- <div cdsRow
- class="form-item-append">
+ <div
+ cdsRow
+ class="form-item-append"
+ >
<div cdsCol>
- <cds-select id="grantee"
- name="grantee"
- label="Grantee"
- formControlName="grantee"
- helperText="Select a grantee (user group) to modify it's permisions"
- [invalid]="!bucketForm.controls.grantee.valid && (bucketForm.controls.grantee.dirty)"
- [invalidText]="granteeError"
- (valueChange)="onSelectionFilter()"
- i18n>Grantee
- <option *ngFor="let item of grantees"
- [value]="item">{{ item }}</option>
+ <cds-select
+ id="grantee"
+ name="grantee"
+ label="Grantee"
+ formControlName="grantee"
+ helperText="Select a grantee (user group) to modify it's permisions"
+ [invalid]="!bucketForm.controls.grantee.valid && bucketForm.controls.grantee.dirty"
+ [invalidText]="granteeError"
+ (valueChange)="onSelectionFilter()"
+ i18n
+ >Grantee
+ <option
+ *ngFor="let item of grantees"
+ [value]="item"
+ >
+ {{ item }}
+ </option>
</cds-select>
<ng-template #granteeError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('grantee', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('grantee', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<div cdsCol>
- <cds-select id="aclPermission"
- name="aclPermission"
- [invalid]="!bucketForm.controls.aclPermission.valid && (bucketForm.controls.aclPermission.dirty)"
- [invalidText]="aclPermissionError"
- label="Permissions"
- helperText="Select the permision to give to the selected grantee. Regardless, the owner of the bucket will always have FULL CONTROL access"
- formControlName="aclPermission">
- <option *ngFor="let permission of aclPermissions"
- [value]="permission"
- i18n>{{ permission }}</option>
+ <cds-select
+ id="aclPermission"
+ name="aclPermission"
+ [invalid]="
+ !bucketForm.controls.aclPermission.valid && bucketForm.controls.aclPermission.dirty
+ "
+ [invalidText]="aclPermissionError"
+ label="Permissions"
+ helperText="Select the permision to give to the selected grantee. Regardless, the owner of the bucket will always have FULL CONTROL access"
+ formControlName="aclPermission"
+ >
+ <option
+ *ngFor="let permission of aclPermissions"
+ [value]="permission"
+ i18n
+ >
+ {{ permission }}
+ </option>
</cds-select>
<ng-template #aclPermissionError>
- <span class="invalid-feedback"
- *ngIf="bucketForm.showError('aclPermission', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="bucketForm.showError('aclPermission', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</div>
<!--Advanced-->
<cd-form-advanced-fieldset>
<!-- Placement target -->
- <div class="form-item"
- *ngIf="!editing">
- <cds-select label="Placement target"
- for="placement-target"
- formControlName="placement-target"
- name="placement-target"
- id="placement-target"
- helperText="When creating a bucket, a placement target can be provided as part of the LocationConstraint to override the default placement targets from the user and zonegroup."
- i18n-helperText
- i18n>Placement target
- <option *ngIf="placementTargets === null"
- [ngValue]="null">Loading...</option>
- <option *ngIf="placementTargets !== null"
- [ngValue]="null">-- Select a placement target --</option>
- <option *ngFor="let placementTarget of placementTargets"
- [value]="placementTarget.name">{{ placementTarget.description }}</option>
+ <div
+ class="form-item"
+ *ngIf="!editing"
+ >
+ <cds-select
+ label="Placement target"
+ for="placement-target"
+ formControlName="placement-target"
+ name="placement-target"
+ id="placement-target"
+ helperText="When creating a bucket, a placement target can be provided as part of the LocationConstraint to override the default placement targets from the user and zonegroup."
+ i18n-helperText
+ i18n
+ >Placement target
+ <option
+ *ngIf="placementTargets === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="placementTargets !== null"
+ [ngValue]="null"
+ >
+ -- Select a placement target --
+ </option>
+ <option
+ *ngFor="let placementTarget of placementTargets"
+ [value]="placementTarget.name"
+ >
+ {{ placementTarget.description }}
+ </option>
</cds-select>
</div>
<!-- Bucket Rate Limit -->
- <cd-rgw-rate-limit [type]="'bucket'"
- [isEditing]="editing"
- [allowBid]="bucketForm.getValue('bid')"
- (rateLimitFormGroup)="rateLimitFormInit($event)">
+ <cd-rgw-rate-limit
+ [type]="'bucket'"
+ [isEditing]="editing"
+ [allowBid]="bucketForm.getValue('bid')"
+ (rateLimitFormGroup)="rateLimitFormInit($event)"
+ >
</cd-rgw-rate-limit>
</cd-form-advanced-fieldset>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="bucketForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="bucketForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</div>
-<ng-template #tagTpl
- let-tag="tag"
- let-index="index">
+<ng-template
+ #tagTpl
+ let-tag="tag"
+ let-index="index"
+>
<div class="form-item form-item-append">
<ng-container *ngFor="let config of tagConfig">
- <input type="text"
- id="tag-{{config.attribute}}-{{index}}"
- cdsText
- [ngbTooltip]="config.attribute"
- [value]="tag[config.attribute]"
- readonly>
+ <input
+ type="text"
+ id="tag-{{ config.attribute }}-{{ index }}"
+ cdsText
+ [ngbTooltip]="config.attribute"
+ [value]="tag[config.attribute]"
+ readonly
+ />
</ng-container>
<!-- Tag actions -->
- <cds-icon-button kind="tertiary"
- size="md"
- (click)="showTagModal(index)">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size16"
- class="cds-info-color cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="tertiary"
+ size="md"
+ (click)="showTagModal(index)"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size16"
+ class="cds-info-color cds--btn__icon"
+ ></svg>
</cds-icon-button>
- <cds-icon-button kind="danger"
- size="md"
- (click)="deleteTag(index)">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size16"
- class="cds-info-color cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ (click)="deleteTag(index)"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size16"
+ class="cds-info-color cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
</ng-template>
<ng-template #loadingTpl>
<cd-loading-panel i18n>Checking multi-site status...</cd-loading-panel>
</ng-template>
-
<legend i18n>
Tiering Configuration
<cd-help-text>
- Configure a bucket tiering rule to automatically transition objects between storage classes after a specified number of days. Define the scope of the rule by applying it globally or to objects with specific prefixes and tags.
+ Configure a bucket tiering rule to automatically transition objects between storage classes
+ after a specified number of days. Define the scope of the rule by applying it globally or to
+ objects with specific prefixes and tags.
</cd-help-text>
</legend>
-<cd-table #table
- [data]="filteredLifecycleRules$ | async"
- [columns]="columns"
- columnMode="flex"
- selectionType="multiClick"
- (updateSelection)="updateSelection($event)"
- identifier="ID"
- (fetchData)="loadLifecyclePolicies($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [data]="filteredLifecycleRules$ | async"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="multiClick"
+ (updateSelection)="updateSelection($event)"
+ identifier="ID"
+ (fetchData)="loadLifecyclePolicies($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
-<cd-table #table
- [autoReload]="false"
- [data]="buckets"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- identifier="bid"
- (fetchData)="getBucketList($event)"
- [status]="tableStatus">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [autoReload]="false"
+ [data]="buckets"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ identifier="bid"
+ (fetchData)="getBucketList($event)"
+ [status]="tableStatus"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-rgw-bucket-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-rgw-bucket-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rgw-bucket-details>
</cd-table>
-<ng-template #bucketSizeTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.bucket_quota.max_size > 0 && row.bucket_quota.enabled; else noSizeQuota"
- [total]="row.bucket_quota.max_size"
- [used]="row.bucket_size">
+<ng-template
+ #bucketSizeTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.bucket_quota.max_size > 0 && row.bucket_quota.enabled; else noSizeQuota"
+ [total]="row.bucket_quota.max_size"
+ [used]="row.bucket_size"
+ >
</cd-usage-bar>
- <ng-template #noSizeQuota
- i18n>No Limit</ng-template>
+ <ng-template
+ #noSizeQuota
+ i18n
+ >No Limit</ng-template
+ >
</ng-template>
-<ng-template #bucketObjectTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.bucket_quota.max_objects > 0 && row.bucket_quota.enabled; else noObjectQuota"
- [total]="row.bucket_quota.max_objects"
- [used]="row.num_objects"
- [isBinary]="false">
+<ng-template
+ #bucketObjectTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.bucket_quota.max_objects > 0 && row.bucket_quota.enabled; else noObjectQuota"
+ [total]="row.bucket_quota.max_objects"
+ [used]="row.num_objects"
+ [isBinary]="false"
+ >
</cd-usage-bar>
- <ng-template #noObjectQuota
- i18n>No Limit</ng-template>
+ <ng-template
+ #noObjectQuota
+ i18n
+ >No Limit</ng-template
+ >
</ng-template>
<ng-template #deleteTpl>
- <cd-alert-panel type="danger"
- i18n>
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
Buckets might still have underlying data depending on your bucket configuration
</cd-alert-panel>
</ng-template>
- <fieldset>
- <legend i18n
- class="cd-header">
+<fieldset>
+ <legend
+ i18n
+ class="cd-header"
+ >
Notification Configuration
<cd-help-text>
- Configure bucket notification to trigger alerts for specific events, such as object creation or transitions, based on prefixes or tags.
+ Configure bucket notification to trigger alerts for specific events, such as object creation
+ or transitions, based on prefixes or tags.
</cd-help-text>
</legend>
- </fieldset>
- <ng-container *ngIf="notification$ | async as notification">
- <cd-table #table
- [data]="notification"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- identifier="Id"
- [autoReload]="true"
- (updateSelection)="updateSelection($event)"
- (fetchData)="fetchData()">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
- </cd-table-actions>
+</fieldset>
+<ng-container *ngIf="notification$ | async as notification">
+ <cd-table
+ #table
+ [data]="notification"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ identifier="Id"
+ [autoReload]="true"
+ (updateSelection)="updateSelection($event)"
+ (fetchData)="fetchData()"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
</cd-table>
- </ng-container>
- <ng-template #filterTpl
- let-config="data.value">
- <ng-container *ngIf="config">
- <ng-container *ngFor="let item of config | keyvalue">
- <ng-container *ngIf="item.value?.FilterRule?.length">
- <div class="cds--label">
- {{ item.key }}:
- </div>
- <div [cdsStack]="'horizontal'"
- *ngFor="let rule of item.value.FilterRule">
- <cds-tag size="sm"
- class="tag-background-gray">{{ rule.Name }}: {{ rule.Value }}</cds-tag>
- </div>
- <br>
- </ng-container>
+</ng-container>
+<ng-template
+ #filterTpl
+ let-config="data.value"
+>
+ <ng-container *ngIf="config">
+ <ng-container *ngFor="let item of config | keyvalue">
+ <ng-container *ngIf="item.value?.FilterRule?.length">
+ <div class="cds--label">{{ item.key }}:</div>
+ <div
+ [cdsStack]="'horizontal'"
+ *ngFor="let rule of item.value.FilterRule"
+ >
+ <cds-tag
+ size="sm"
+ class="tag-background-gray"
+ >{{ rule.Name }}: {{ rule.Value }}</cds-tag
+ >
+ </div>
+ <br />
</ng-container>
</ng-container>
- </ng-template>
- <ng-template #eventTpl
- let-events="data.value">
+ </ng-container>
+</ng-template>
+<ng-template
+ #eventTpl
+ let-events="data.value"
+>
<ng-container *ngIf="events && events.length">
- <cds-tag *ngFor="let event of events"
- size="sm"
- class="tag-background-primary">
+ <cds-tag
+ *ngFor="let event of events"
+ size="sm"
+ class="tag-background-primary"
+ >
{{ event }}
</cds-tag>
</ng-container>
</ng-template>
-
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
- <cds-modal-header (closeSelect)="closeModal()"
- i18n>{{editing ? 'Edit' : 'Create'}} Tiering configuration
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
+ <cds-modal-header
+ (closeSelect)="closeModal()"
+ i18n
+ >{{ editing ? 'Edit' : 'Create' }} Tiering configuration
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
-<ng-container *cdFormLoading="loading">
- <section cdsModalContent>
- <cd-alert-panel
- *ngIf="(snapScheduleModuleStatus$ | async) === false"
- type="info"
- spacingClass="mb-3"
- i18n
- class="align-items-center"
- actionName="Enable"
- (action)="enableSnapshotSchedule()"
->
- In order to access the snapshot scheduler feature, the snap_scheduler module must be enabled
- </cd-alert-panel>
- <cd-alert-panel *ngIf="storageClassList?.length === 0 &&
- isStorageClassFetched"
- type="info"
- spacingClass="mb-3"
- class="align-items-center"
- actionName="Create"
- i18n
- (action)="goToCreateStorageClass()">
- No storage class found. Consider creating it first to proceed.
- </cd-alert-panel>
- <form name="tieringForm"
- #formDir="ngForm"
- [formGroup]="tieringForm"
- novalidate>
- <div class="form-item">
- <cds-text-label
- labelInputID="rule_name"
- [invalid]="!tieringForm.controls.name.valid && tieringForm.controls.name.dirty"
- [invalidText]="ruleNameError"
- [helperText]="ruleHelper"
- i18n
- >Rule Name
- <input
- cdsText
- type="text"
- id="rule_name"
- maxlength="255"
- formControlName="name"
- />
- </cds-text-label>
- <ng-template #ruleHelper>
- <span i18n>Unique identifier for the rule. The value cannot be longer than 255 characters.
- </span>
- </ng-template>
- <ng-template #ruleNameError>
- <span *ngIf="tieringForm.showError('name', formDir, 'required')"
- class="invalid-feedback">
- <ng-container i18n>This field is required.</ng-container>
- </span>
- <span *ngIf="tieringForm.showError('name', formDir, 'duplicate')"
- class="invalid-feedback">
- <ng-container i18n>Please enter a unique name.</ng-container>
- </span>
- </ng-template>
- </div>
- <div class="form-item">
- <cds-select id="storageClass"
- formControlName="storageClass"
- label="Storage Class"
- [helperText]="storageClassHelper">
- <option *ngIf="storageClassList === null"
- value="">Loading...</option>
- <option *ngIf="storageClassList !== null && storageClassList.length === 0"
- value="">-- No storage class available --</option>
- <option *ngIf="storageClassList !== null && storageClassList.length > 0"
- value="">-- Select the storage class --</option>
- <option *ngFor="let tier of storageClassList"
- [value]="tier.storage_class">
- {{ tier.storage_class }}
- </option>
- </cds-select>
- <ng-template #storageClassHelper>
- <span i18n>The storage class to which you want the object to transition.
- </span>
- </ng-template>
- </div>
- <legend class="cds--label">Choose a configuration scope</legend>
- <div class="form-item">
- <cds-radio-group
- formControlName="hasPrefix"
+ <ng-container *cdFormLoading="loading">
+ <section cdsModalContent>
+ <cd-alert-panel
+ *ngIf="(snapScheduleModuleStatus$ | async) === false"
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ class="align-items-center"
+ actionName="Enable"
+ (action)="enableSnapshotSchedule()"
+ >
+ In order to access the snapshot scheduler feature, the snap_scheduler module must be enabled
+ </cd-alert-panel>
+ <cd-alert-panel
+ *ngIf="storageClassList?.length === 0 && isStorageClassFetched"
+ type="info"
+ spacingClass="mb-3"
+ class="align-items-center"
+ actionName="Create"
+ i18n
+ (action)="goToCreateStorageClass()"
+ >
+ No storage class found. Consider creating it first to proceed.
+ </cd-alert-panel>
+ <form
+ name="tieringForm"
+ #formDir="ngForm"
+ [formGroup]="tieringForm"
+ novalidate
+ >
+ <div class="form-item">
+ <cds-text-label
+ labelInputID="rule_name"
+ [invalid]="!tieringForm.controls.name.valid && tieringForm.controls.name.dirty"
+ [invalidText]="ruleNameError"
+ [helperText]="ruleHelper"
+ i18n
+ >Rule Name
+ <input
+ cdsText
+ type="text"
+ id="rule_name"
+ maxlength="255"
+ formControlName="name"
+ />
+ </cds-text-label>
+ <ng-template #ruleHelper>
+ <span i18n
+ >Unique identifier for the rule. The value cannot be longer than 255 characters.
+ </span>
+ </ng-template>
+ <ng-template #ruleNameError>
+ <span
+ *ngIf="tieringForm.showError('name', formDir, 'required')"
+ class="invalid-feedback"
+ >
+ <ng-container i18n>This field is required.</ng-container>
+ </span>
+ <span
+ *ngIf="tieringForm.showError('name', formDir, 'duplicate')"
+ class="invalid-feedback"
+ >
+ <ng-container i18n>Please enter a unique name.</ng-container>
+ </span>
+ </ng-template>
+ </div>
+ <div class="form-item">
+ <cds-select
+ id="storageClass"
+ formControlName="storageClass"
+ label="Storage Class"
+ [helperText]="storageClassHelper"
+ >
+ <option
+ *ngIf="storageClassList === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="storageClassList !== null && storageClassList.length === 0"
+ value=""
+ >
+ -- No storage class available --
+ </option>
+ <option
+ *ngIf="storageClassList !== null && storageClassList.length > 0"
+ value=""
+ >
+ -- Select the storage class --
+ </option>
+ <option
+ *ngFor="let tier of storageClassList"
+ [value]="tier.storage_class"
+ >
+ {{ tier.storage_class }}
+ </option>
+ </cds-select>
+ <ng-template #storageClassHelper>
+ <span i18n>The storage class to which you want the object to transition. </span>
+ </ng-template>
+ </div>
+ <legend class="cds--label">Choose a configuration scope</legend>
+ <div class="form-item">
+ <cds-radio-group formControlName="hasPrefix">
+ <cds-radio
+ [value]="false"
+ i18n
+ >
+ {{ 'Apply to all objects in the bucket' }}
+ </cds-radio>
+ <cds-radio
+ [value]="true"
+ i18n
+ >
+ {{ 'Limit the scope of this rule to selected filter criteria' }}
+ </cds-radio>
+ </cds-radio-group>
+ </div>
+ <div
+ class="form-item"
+ *ngIf="tieringForm.controls.hasPrefix.value"
>
- <cds-radio [value]="false"
- i18n>
- {{ 'Apply to all objects in the bucket' }}
- </cds-radio>
- <cds-radio [value]="true"
- i18n>
- {{ 'Limit the scope of this rule to selected filter criteria' }}
- </cds-radio>
- </cds-radio-group>
- </div>
- <div class="form-item"
- *ngIf="tieringForm.controls.hasPrefix.value">
- <cds-text-label labelInputID="prefix"
- [invalid]="!tieringForm.controls.prefix.valid && tieringForm.controls.prefix.dirty"
- [invalidText]="prefixError"
- [helperText]="prefixHelper"
- i18n>Prefix
- <input cdsText
- type="text"
- id="prefix"
- formControlName="prefix"/>
- </cds-text-label>
- <ng-template #prefixHelper>
- <span i18n>
- Prefix identifying one or more objects to which the rule applies
- </span>
- </ng-template>
- <ng-template #prefixError>
- <span *ngIf="tieringForm.showError('prefix', formDir, 'required')"
- class="invalid-feedback">
- <ng-container i18n>This field is required.</ng-container>
- </span>
- </ng-template>
- </div>
+ <cds-text-label
+ labelInputID="prefix"
+ [invalid]="!tieringForm.controls.prefix.valid && tieringForm.controls.prefix.dirty"
+ [invalidText]="prefixError"
+ [helperText]="prefixHelper"
+ i18n
+ >Prefix
+ <input
+ cdsText
+ type="text"
+ id="prefix"
+ formControlName="prefix"
+ />
+ </cds-text-label>
+ <ng-template #prefixHelper>
+ <span i18n> Prefix identifying one or more objects to which the rule applies </span>
+ </ng-template>
+ <ng-template #prefixError>
+ <span
+ *ngIf="tieringForm.showError('prefix', formDir, 'required')"
+ class="invalid-feedback"
+ >
+ <ng-container i18n>This field is required.</ng-container>
+ </span>
+ </ng-template>
+ </div>
- <!-- tags -->
- <div class="form-item"
- *ngIf="tieringForm.controls.hasPrefix.value">
- <div class="form-group-header">Tags</div>
- <div class="cds-mb-4">All the tags must exist in the object's tag set for the rule to apply.</div>
- <ng-container formArrayName="tags"
- *ngFor="let tags of tags.controls; index as i">
- <ng-container [formGroupName]="i">
- <div cdsRow
- class="form-item form-item-append">
- <div cdsCol>
- <cds-text-label labelInputID="Key"
- [invalid]="!tieringForm.controls['tags'].controls[i].controls['Key'].valid && tieringForm.controls['tags'].controls[i].controls['Key'].dirty"
- [invalidText]="tagKeyError"
- i18n>Name of the object key
- <input cdsText
- type="text"
- placeholder="Enter name of the object key"
- formControlName="Key"
- i18n-placeholder
- [invalid]="tieringForm.controls['tags'].controls[i].controls['Key'].invalid && tieringForm.controls['tags'].controls[i].controls['Key'].dirty"/>
- </cds-text-label>
- <ng-template #tagKeyError>
- <ng-container i18n>This field is required.</ng-container>
- </ng-template>
- </div>
- <div cdsCol>
- <cds-text-label labelInputID="Value"
- [invalid]="!tieringForm.controls['tags'].controls[i].controls['Value'].valid && tieringForm.controls['tags'].controls[i].controls['Value'].dirty"
- [invalidText]="tagValueError"
- i18n>Value of the tag
- <input cdsText
- type="text"
- placeholder="Enter value of the tag"
- formControlName="Value"
- i18n-placeholder
- [invalid]="tieringForm.controls['tags'].controls[i].controls['Value'].invalid && tieringForm.controls['tags'].controls[i].controls['Value'].dirty"/>
- </cds-text-label>
- <ng-template #tagValueError>
- <ng-container i18n>This field is required.</ng-container>
- </ng-template>
- </div>
- <div cdsCol
- [columnNumbers]="{ lg: 2, md: 2 }"
- class="item-action-btn">
- <cds-icon-button kind="tertiary"
- size="sm"
- (click)="removeTags(i)">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
- </cds-icon-button>
+ <!-- tags -->
+ <div
+ class="form-item"
+ *ngIf="tieringForm.controls.hasPrefix.value"
+ >
+ <div class="form-group-header">Tags</div>
+ <div class="cds-mb-4">
+ All the tags must exist in the object's tag set for the rule to apply.
+ </div>
+ <ng-container
+ formArrayName="tags"
+ *ngFor="let tags of tags.controls; index as i"
+ >
+ <ng-container [formGroupName]="i">
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="Key"
+ [invalid]="
+ !tieringForm.controls['tags'].controls[i].controls['Key'].valid &&
+ tieringForm.controls['tags'].controls[i].controls['Key'].dirty
+ "
+ [invalidText]="tagKeyError"
+ i18n
+ >Name of the object key
+ <input
+ cdsText
+ type="text"
+ placeholder="Enter name of the object key"
+ formControlName="Key"
+ i18n-placeholder
+ [invalid]="
+ tieringForm.controls['tags'].controls[i].controls['Key'].invalid &&
+ tieringForm.controls['tags'].controls[i].controls['Key'].dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #tagKeyError>
+ <ng-container i18n>This field is required.</ng-container>
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="Value"
+ [invalid]="
+ !tieringForm.controls['tags'].controls[i].controls['Value'].valid &&
+ tieringForm.controls['tags'].controls[i].controls['Value'].dirty
+ "
+ [invalidText]="tagValueError"
+ i18n
+ >Value of the tag
+ <input
+ cdsText
+ type="text"
+ placeholder="Enter value of the tag"
+ formControlName="Value"
+ i18n-placeholder
+ [invalid]="
+ tieringForm.controls['tags'].controls[i].controls['Value'].invalid &&
+ tieringForm.controls['tags'].controls[i].controls['Value'].dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #tagValueError>
+ <ng-container i18n>This field is required.</ng-container>
+ </ng-template>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 2, md: 2 }"
+ class="item-action-btn"
+ >
+ <cds-icon-button
+ kind="tertiary"
+ size="sm"
+ (click)="removeTags(i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
</div>
- </div>
+ </ng-container>
</ng-container>
- </ng-container>
- <div class="form-item">
- <button cdsButton="tertiary"
- type="button"
- (click)="addTags()"
- i18n>Add tags
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- icon></svg>
- </button>
+ <div class="form-item">
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addTags()"
+ i18n
+ >
+ Add tags
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
+ </button>
+ </div>
</div>
- </div>
- <legend class="cds--label">Status</legend>
- <div class="form-item">
- <cds-radio-group
- formControlName="status">
- <cds-radio [value]="'Enabled'"
- i18n>Enabled </cds-radio>
- <cds-radio [value]="'Disabled'"
- i18n>Disabled </cds-radio>
- </cds-radio-group>
- </div>
- <div>
- <cds-number formControlName="days"
- label="Number of days"
- [min]="1"
- [invalid]="!tieringForm.controls.days.valid && tieringForm.controls.days.dirty"
- [invalidText]="daysError"
- [helperText]="daysHelper"></cds-number>
- <ng-template #daysHelper>
- <span i18n>Select the number of days to transition the objects to the specified storage class. The value must be a positive integer.
- </span>
- </ng-template>
- <ng-template #daysError>
- <span *ngIf="tieringForm.showError('days', formDir, 'required')"
- i18n>This field is required.</span>
- <span *ngIf="tieringForm.showError('days', formDir, 'pattern')"
- i18n>Enter a valid positive number</span>
- </ng-template>
- </div>
- </form>
- </section>
-</ng-container>
+ <legend class="cds--label">Status</legend>
+ <div class="form-item">
+ <cds-radio-group formControlName="status">
+ <cds-radio
+ [value]="'Enabled'"
+ i18n
+ >Enabled
+ </cds-radio>
+ <cds-radio
+ [value]="'Disabled'"
+ i18n
+ >Disabled
+ </cds-radio>
+ </cds-radio-group>
+ </div>
+ <div>
+ <cds-number
+ formControlName="days"
+ label="Number of days"
+ [min]="1"
+ [invalid]="!tieringForm.controls.days.valid && tieringForm.controls.days.dirty"
+ [invalidText]="daysError"
+ [helperText]="daysHelper"
+ ></cds-number>
+ <ng-template #daysHelper>
+ <span i18n
+ >Select the number of days to transition the objects to the specified storage class.
+ The value must be a positive integer.
+ </span>
+ </ng-template>
+ <ng-template #daysError>
+ <span
+ *ngIf="tieringForm.showError('days', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="tieringForm.showError('days', formDir, 'pattern')"
+ i18n
+ >Enter a valid positive number</span
+ >
+ </ng-template>
+ </div>
+ </form>
+ </section>
+ </ng-container>
<cd-form-button-panel
(submitActionEvent)="submitTieringConfig()"
[form]="tieringForm"
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- id="tabset-config-details"
- class="nav-tabs"
- cdStatefulTab="config-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ id="tabset-config-details"
+ class="nav-tabs"
+ cdStatefulTab="config-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [data]="transformedData">
- </cd-table-key-value>
+ <cd-table-key-value [data]="transformedData"> </cd-table-key-value>
</ng-template>
</ng-container>
</nav>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">{{ action | titlecase }} RGW Encryption Configurations</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >{{ action | titlecase }} RGW Encryption Configurations</ng-container
+ >
<ng-container class="modal-content">
- <form name="configForm"
- #frm="ngForm"
- [formGroup]="configForm">
- <div class="modal-body">
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="encryptionType"
- i18n>Encryption Type</label>
- <div class="col-md-auto custom-checkbox form-check-inline ms-3">
- <input class="form-check-input"
- formControlName="encryptionType"
- id="s3Enabled"
- type="radio"
- (change)="checkKmsProviders()"
- [attr.disabled]="editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_S3 ? true : null"
- [value]="ENCRYPTION_TYPE.SSE_S3">
- <label class="custom-check-label"
- [ngClass]="{'text-muted': editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_S3}"
- for="s3Enabled"
- i18n>SSE-S3</label>
- </div>
-
- <div class="col-md-auto custom-checkbox form-check-inline">
- <input class="form-check-input"
- formControlName="encryptionType"
- id="kmsEnabled"
- (change)="checkKmsProviders()"
- [value]="ENCRYPTION_TYPE.SSE_KMS"
- [attr.disabled]="editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_KMS ? true : null"
- type="radio">
- <label class="custom-check-label"
- [ngClass]="{'text-muted': editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_KMS}"
- for="kmsEnabled"
- i18n>SSE-KMS</label>
- </div>
- </div>
-
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
+ <form
+ name="configForm"
+ #frm="ngForm"
+ [formGroup]="configForm"
+ >
+ <div class="modal-body">
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="kms_provider"
- i18n>Key management service provider</label>
- <div class="cd-col-form-input">
- <select id="kms_provider"
- class="form-select"
- (change)="setKmsProvider()"
- formControlName="kms_provider">
- <option *ngIf="kmsProviders !== null && kmsProviders.length === 0"
- ngValue="null"
- i18n>-- No kms providers available --</option>
- <option *ngIf="kmsProviders !== null && kmsProviders.length > 0"
- ngValue=""
- i18n>-- Select a provider --</option>
- <option *ngFor="let provider of kmsProviders"
- [value]="provider">{{ provider }}</option>
- </select>
- <cd-help-text>
- <span i18n>Where the encryption keys are stored.
- </span>
- </cd-help-text>
- <span class="invalid-feedback"
- *ngIf="configForm.showError('kms_provider', frm, 'required')"
- i18n>This field is required.</span>
+ <label
+ class="cd-col-form-label required"
+ for="encryptionType"
+ i18n
+ >Encryption Type</label
+ >
+ <div class="col-md-auto custom-checkbox form-check-inline ms-3">
+ <input
+ class="form-check-input"
+ formControlName="encryptionType"
+ id="s3Enabled"
+ type="radio"
+ (change)="checkKmsProviders()"
+ [attr.disabled]="
+ editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_S3
+ ? true
+ : null
+ "
+ [value]="ENCRYPTION_TYPE.SSE_S3"
+ />
+ <label
+ class="custom-check-label"
+ [ngClass]="{
+ 'text-muted':
+ editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_S3
+ }"
+ for="s3Enabled"
+ i18n
+ >SSE-S3</label
+ >
+ </div>
+
+ <div class="col-md-auto custom-checkbox form-check-inline">
+ <input
+ class="form-check-input"
+ formControlName="encryptionType"
+ id="kmsEnabled"
+ (change)="checkKmsProviders()"
+ [value]="ENCRYPTION_TYPE.SSE_KMS"
+ [attr.disabled]="
+ editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_KMS
+ ? true
+ : null
+ "
+ type="radio"
+ />
+ <label
+ class="custom-check-label"
+ [ngClass]="{
+ 'text-muted':
+ editing && configForm.getValue('encryptionType') !== ENCRYPTION_TYPE.SSE_KMS
+ }"
+ for="kmsEnabled"
+ i18n
+ >SSE-KMS</label
+ >
</div>
</div>
- </div>
- <div *ngIf="kmsProviders.length !== 0 && configForm.getValue('kms_provider') !== ''">
- <div *ngIf="(configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="auth"
- i18n>Authentication Method</label>
+ <label
+ class="cd-col-form-label required"
+ for="kms_provider"
+ i18n
+ >Key management service provider</label
+ >
<div class="cd-col-form-input">
- <select class="form-select"
- id="auth"
- formControlName="auth">
- <option *ngFor="let auth of authMethods"
- [value]="auth">{{ auth }}</option>
+ <select
+ id="kms_provider"
+ class="form-select"
+ (change)="setKmsProvider()"
+ formControlName="kms_provider"
+ >
+ <option
+ *ngIf="kmsProviders !== null && kmsProviders.length === 0"
+ ngValue="null"
+ i18n
+ >
+ -- No kms providers available --
+ </option>
+ <option
+ *ngIf="kmsProviders !== null && kmsProviders.length > 0"
+ ngValue=""
+ i18n
+ >
+ -- Select a provider --
+ </option>
+ <option
+ *ngFor="let provider of kmsProviders"
+ [value]="provider"
+ >
+ {{ provider }}
+ </option>
</select>
<cd-help-text>
- <span i18n>Type of authentication method to be used with Vault
- </span>
+ <span i18n>Where the encryption keys are stored. </span>
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="configForm.showError('auth', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('kms_provider', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
</div>
</div>
- <div *ngIf="(configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="secret_engine"
- i18n>Secret Engine</label>
- <div class="cd-col-form-input">
- <select class="form-select"
- id="secret_engine"
- formControlName="secret_engine">
- <option *ngFor="let secret_engine of secretEngines"
- [value]="secret_engine">{{ secret_engine }}</option>
- </select>
- <cd-help-text>
- <span i18n>Vault Secret Engine to be used to retrieve encryption keys.
- </span>
- </cd-help-text>
- <span class="invalid-feedback"
- *ngIf="configForm.showError('secret_engine', frm, 'required')"
- i18n>This field is required.</span>
+ <div *ngIf="kmsProviders.length !== 0 && configForm.getValue('kms_provider') !== ''">
+ <div
+ *ngIf="
+ (configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="auth"
+ i18n
+ >Authentication Method</label
+ >
+ <div class="cd-col-form-input">
+ <select
+ class="form-select"
+ id="auth"
+ formControlName="auth"
+ >
+ <option
+ *ngFor="let auth of authMethods"
+ [value]="auth"
+ >
+ {{ auth }}
+ </option>
+ </select>
+ <cd-help-text>
+ <span i18n>Type of authentication method to be used with Vault </span>
+ </cd-help-text>
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('auth', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
</div>
- </div>
- <div *ngIf="(configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="secret_path"
- i18n>Secret Path
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="secret_path"
- formControlName="secret_path"
- placeholder="/v1/secret/data">
+ <div
+ *ngIf="
+ (configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="secret_engine"
+ i18n
+ >Secret Engine</label
+ >
+ <div class="cd-col-form-input">
+ <select
+ class="form-select"
+ id="secret_engine"
+ formControlName="secret_engine"
+ >
+ <option
+ *ngFor="let secret_engine of secretEngines"
+ [value]="secret_engine"
+ >
+ {{ secret_engine }}
+ </option>
+ </select>
<cd-help-text>
- <span i18n>Vault secret URL prefix, which can be used to restrict access to a particular subset of the Vault secret space.
+ <span i18n>Vault Secret Engine to be used to retrieve encryption keys. </span>
+ </cd-help-text>
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('secret_engine', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
+ </div>
+ </div>
+
+ <div
+ *ngIf="
+ (configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="secret_path"
+ i18n
+ >Secret Path
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ id="secret_path"
+ formControlName="secret_path"
+ placeholder="/v1/secret/data"
+ />
+ <cd-help-text>
+ <span i18n
+ >Vault secret URL prefix, which can be used to restrict access to a particular
+ subset of the Vault secret space.
</span>
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="configForm.showError('secret_path', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('secret_path', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
</div>
- </div>
- <div *ngIf="(configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') == KMS_PROVIDER.VAULT) || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="namespace"
- i18n>Namespace
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- id="namespace"
- type="text"
- placeholder="tenant1"
- formControlName="namespace">
- <cd-help-text>
- <span i18n>Vault Namespace to be used to select your tenant.
- </span>
- </cd-help-text>
+ <div
+ *ngIf="
+ (configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') == KMS_PROVIDER.VAULT) ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="namespace"
+ i18n
+ >Namespace
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ id="namespace"
+ type="text"
+ placeholder="tenant1"
+ formControlName="namespace"
+ />
+ <cd-help-text>
+ <span i18n>Vault Namespace to be used to select your tenant. </span>
+ </cd-help-text>
+ </div>
</div>
</div>
- </div>
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="addr">
- <span i18n
- *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT">Vault Address
- </span>
- <span i18n
- *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP">KMIP Address
- </span>
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- id="addr"
- formControlName="addr"
- placeholder="http://127.0.0.1:8000"
- i18n>
- <cd-help-text >
- <span *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT"
- i18n>Vault server base address.
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="addr"
+ >
+ <span
+ i18n
+ *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT"
+ >Vault Address
+ </span>
+ <span
+ i18n
+ *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP"
+ >KMIP Address
+ </span>
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ id="addr"
+ formControlName="addr"
+ placeholder="http://127.0.0.1:8000"
+ i18n
+ />
+ <cd-help-text>
+ <span
+ *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT"
+ i18n
+ >Vault server base address.
</span>
- <span *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP"
- i18n>Kmip server base address.
+ <span
+ *ngIf="configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP"
+ i18n
+ >Kmip server base address.
</span>
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="configForm.showError('addr', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="configForm.showError('addr', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
</div>
- </div>
- <div *ngIf="(configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT)|| configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div *ngIf="configForm.getValue('auth') === 'token'"
- class="form-group row">
- <label class="cd-col-form-label required"
- for="token">
- <span i18n>Token</span>
- <cd-helper i18n>
- The token authentication method expects a Vault token to be present in a plaintext file.
- </cd-helper>
- </label>
- <div class="cd-col-form-input">
- <input type="file"
- id="token"
- formControlName="token"
- (change)="fileUpload($event.target.files, 'token')">
- <cd-help-text>
- <span i18n>If authentication method is 'token', provide a path to the token file.
- </span>
- </cd-help-text>
- <span class="invalid-feedback"
+ <div
+ *ngIf="
+ (configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') === KMS_PROVIDER.VAULT) ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div
+ *ngIf="configForm.getValue('auth') === 'token'"
+ class="form-group row"
+ >
+ <label
+ class="cd-col-form-label required"
+ for="token"
+ >
+ <span i18n>Token</span>
+ <cd-helper i18n>
+ The token authentication method expects a Vault token to be present in a plaintext
+ file.
+ </cd-helper>
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ type="file"
+ id="token"
+ formControlName="token"
+ (change)="fileUpload($event.target.files, 'token')"
+ />
+ <cd-help-text>
+ <span i18n
+ >If authentication method is 'token', provide a path to the token file.
+ </span>
+ </cd-help-text>
+ <span
+ class="invalid-feedback"
*ngIf="configForm.showError('token', frm, 'required')"
- i18n>This field is required.</span>
- </div>
+ i18n
+ >This field is required.</span
+ >
+ </div>
+ </div>
</div>
- </div>
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS && configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="kms_key_template"
- i18n>KMS Key Template
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- id="kms_key_template"
- placeholder="$keyid"
- formControlName="kms_key_template">
- <cd-help-text>
- <span i18n>sse-kms; kmip key names
- </span>
- </cd-help-text>
- </div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="s3_key_template"
- i18n>S3 Key Template
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- id="s3_key_template"
- placeholder="$keyid"
- formControlName="s3_key_template">
- <cd-help-text>
- <span i18n>sse-s3; kmip key template
- </span>
- </cd-help-text>
- </div>
- </div>
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS &&
+ configForm.getValue('kms_provider') === KMS_PROVIDER.KMIP
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="kms_key_template"
+ i18n
+ >KMS Key Template
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ id="kms_key_template"
+ placeholder="$keyid"
+ formControlName="kms_key_template"
+ />
+ <cd-help-text>
+ <span i18n>sse-kms; kmip key names </span>
+ </cd-help-text>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="s3_key_template"
+ i18n
+ >S3 Key Template
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ id="s3_key_template"
+ placeholder="$keyid"
+ formControlName="s3_key_template"
+ />
+ <cd-help-text>
+ <span i18n>sse-s3; kmip key template </span>
+ </cd-help-text>
+ </div>
+ </div>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="username"
- i18n>Username
- </label>
- <div class="cd-col-form-input">
- <input id="username"
- class="form-control"
- [attr.disabled]="configForm.getValue('kms_provider') !== KMS_PROVIDER.KMIP ? true : null"
- formControlName="username">
- <cd-help-text>
- <span i18n>When authenticating via username
- </span>
- </cd-help-text>
- </div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="password"
- i18n>Password
- </label>
- <div class="cd-col-form-input">
- <input id="password"
- class="form-control"
- type="password"
- [attr.disabled]="configForm.getValue('kms_provider') != KMS_PROVIDER.KMIP"
- formControlName="password">
- <cd-help-text>
- <span i18n>optional w/ username
- </span>
- </cd-help-text>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="username"
+ i18n
+ >Username
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ id="username"
+ class="form-control"
+ [attr.disabled]="
+ configForm.getValue('kms_provider') !== KMS_PROVIDER.KMIP ? true : null
+ "
+ formControlName="username"
+ />
+ <cd-help-text>
+ <span i18n>When authenticating via username </span>
+ </cd-help-text>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="password"
+ i18n
+ >Password
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ id="password"
+ class="form-control"
+ type="password"
+ [attr.disabled]="configForm.getValue('kms_provider') != KMS_PROVIDER.KMIP"
+ formControlName="password"
+ />
+ <cd-help-text>
+ <span i18n>optional w/ username </span>
+ </cd-help-text>
+ </div>
+ </div>
</div>
- </div>
- </div>
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="ssl_cert">
- <span i18n>CA Certificate Path</span>
- <cd-helper i18n>The SSL certificate in PEM format. Please provide file path to the RGW host.</cd-helper>
- </label>
- <div class="cd-col-form-input">
- <input type="text"
- id="ssl_cert"
- class="form-control"
- formControlName="ssl_cert"
- placeholder="/path/to/ca_cert.pem">
- <cd-help-text>
- <span i18n>
- Path for custom ca certificate for accessing server
- </span>
- </cd-help-text>
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="ssl_cert"
+ >
+ <span i18n>CA Certificate Path</span>
+ <cd-helper i18n
+ >The SSL certificate in PEM format. Please provide file path to the RGW
+ host.</cd-helper
+ >
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ id="ssl_cert"
+ class="form-control"
+ formControlName="ssl_cert"
+ placeholder="/path/to/ca_cert.pem"
+ />
+ <cd-help-text>
+ <span i18n> Path for custom ca certificate for accessing server </span>
+ </cd-help-text>
+ </div>
</div>
</div>
- </div>
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="client_cert">
- <span i18n>Client Certificate Path</span>
- <cd-helper i18n>The Client certificate in PEM format. Please provide file path to the RGW host.</cd-helper>
- </label>
- <div class="cd-col-form-input">
- <input type="text"
- id="client_cert"
- class="form-control"
- formControlName="client_cert"
- placeholder="/path/to/client_cert.pem">
- <cd-help-text>
- <span i18n>
- Path for custom client certificate for accessing server
- </span>
- </cd-help-text>
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="client_cert"
+ >
+ <span i18n>Client Certificate Path</span>
+ <cd-helper i18n
+ >The Client certificate in PEM format. Please provide file path to the RGW
+ host.</cd-helper
+ >
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ id="client_cert"
+ class="form-control"
+ formControlName="client_cert"
+ placeholder="/path/to/client_cert.pem"
+ />
+ <cd-help-text>
+ <span i18n> Path for custom client certificate for accessing server </span>
+ </cd-help-text>
+ </div>
</div>
</div>
- </div>
- <div *ngIf="configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS || configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="client_key">
- <span i18n>Client Private Key Path</span>
- <cd-helper i18n>The Client Private Key in PEM format. Please provide file path to the RGW host.</cd-helper>
- </label>
- <div class="cd-col-form-input">
- <input type="text"
- id="client_key"
- formControlName="client_key"
- placeholder="/path/to/client_key.pem"
- class="form-control">
- <cd-help-text>
- <span i18n>
- Path for private key required for client cert
- </span>
- </cd-help-text>
+ <div
+ *ngIf="
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_KMS ||
+ configForm.getValue('encryptionType') === ENCRYPTION_TYPE.SSE_S3
+ "
+ >
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="client_key"
+ >
+ <span i18n>Client Private Key Path</span>
+ <cd-helper i18n
+ >The Client Private Key in PEM format. Please provide file path to the RGW
+ host.</cd-helper
+ >
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ id="client_key"
+ formControlName="client_key"
+ placeholder="/path/to/client_key.pem"
+ class="form-control"
+ />
+ <cd-help-text>
+ <span i18n> Path for private key required for client cert </span>
+ </cd-help-text>
+ </div>
</div>
</div>
</div>
</div>
- </div>
- <div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [submitText]="actionLabels.SUBMIT"
- [form]="configForm"></cd-form-button-panel>
- </div>
+ <div class="modal-footer">
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [submitText]="actionLabels.SUBMIT"
+ [form]="configForm"
+ ></cd-form-button-panel>
+ </div>
</form>
</ng-container>
</cd-modal>
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+<nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+>
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>Server-side Encryption</a>
+ <a
+ ngbNavLink
+ i18n
+ >Server-side Encryption</a
+ >
<ng-template ngbNavContent>
- <cd-table #table
- [data]="encryptionConfigValues"
- [columns]="columns"
- (fetchData)="fetchData()"
- identifier="unique_id"
- [forceIdentifier]="true"
- [hasDetails]="true"
- (updateSelection)="updateSelection($event)"
- (setExpandedRow)="setExpandedRow($event)"
- columnMode="flex"
- selectionType="single">
- <cd-table-actions class="table-actions"
- [permission]="permissions.configOpt"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table
+ #table
+ [data]="encryptionConfigValues"
+ [columns]="columns"
+ (fetchData)="fetchData()"
+ identifier="unique_id"
+ [forceIdentifier]="true"
+ [hasDetails]="true"
+ (updateSelection)="updateSelection($event)"
+ (setExpandedRow)="setExpandedRow($event)"
+ columnMode="flex"
+ selectionType="single"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permissions.configOpt"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-rgw-config-details *cdTableDetail
- [selection]="expandedRow"
- [excludeProps]="excludeProps">
+ <cd-rgw-config-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ [excludeProps]="excludeProps"
+ >
</cd-rgw-config-details>
</cd-table>
</ng-template>
<ng-container *ngIf="selection">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- cdStatefulTab="rgw-daemon-details">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ cdStatefulTab="rgw-daemon-details"
+ >
<ng-container ngbNavItem="details">
- <a ngbNavLink
- i18n>Details</a>
+ <a
+ ngbNavLink
+ i18n
+ >Details</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value [data]="metadata"
- (fetchData)="getMetaData()">
+ <cd-table-key-value
+ [data]="metadata"
+ (fetchData)="getMetaData()"
+ >
</cd-table-key-value>
</ng-template>
</ng-container>
<ng-container ngbNavItem="performance-counters">
- <a ngbNavLink
- i18n>Performance Counters</a>
+ <a
+ ngbNavLink
+ i18n
+ >Performance Counters</a
+ >
<ng-template ngbNavContent>
- <cd-table-performance-counter serviceType="rgw"
- [serviceId]="serviceMapId">
+ <cd-table-performance-counter
+ serviceType="rgw"
+ [serviceId]="serviceMapId"
+ >
</cd-table-performance-counter>
</ng-template>
</ng-container>
- <ng-container ngbNavItem="performance-details"
- *ngIf="grafanaPermission.read">
- <a ngbNavLink
- i18n>Performance Details</a>
+ <ng-container
+ ngbNavItem="performance-details"
+ *ngIf="grafanaPermission.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Performance Details</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="RGW instance details"
- [grafanaPath]="'ceph-object-instance-details?var-rgw_servers=rgw.' + serviceId"
- [type]="'metrics'"
- uid="x5ARzZtmk"
- grafanaStyle="one">
+ <cd-grafana
+ i18n-title
+ title="RGW instance details"
+ [grafanaPath]="'ceph-object-instance-details?var-rgw_servers=rgw.' + serviceId"
+ [type]="'metrics'"
+ uid="x5ARzZtmk"
+ grafanaStyle="one"
+ >
</cd-grafana>
</ng-template>
</ng-container>
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
+<nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+>
<ng-container ngbNavItem>
- <a ngbNavLink
- i18n>Gateways List</a>
+ <a
+ ngbNavLink
+ i18n
+ >Gateways List</a
+ >
<ng-template ngbNavContent>
- <cd-table [data]="daemons"
- [columns]="columns"
- columnMode="flex"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (fetchData)="getDaemonList($event)">
- <cd-rgw-daemon-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-table
+ [data]="daemons"
+ [columns]="columns"
+ columnMode="flex"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (fetchData)="getDaemonList($event)"
+ >
+ <cd-rgw-daemon-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rgw-daemon-details>
</cd-table>
</ng-template>
</ng-container>
- <ng-container ngbNavItem
- *ngIf="grafanaPermission.read">
- <a ngbNavLink
- i18n>Overall Performance</a>
+ <ng-container
+ ngbNavItem
+ *ngIf="grafanaPermission.read"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Overall Performance</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="RGW overview"
- [grafanaPath]="'ceph-object-overview?'"
- [type]="'metrics'"
- uid="WAkugZpiz"
- grafanaStyle="three">
+ <cd-grafana
+ i18n-title
+ title="RGW overview"
+ [grafanaPath]="'ceph-object-overview?'"
+ [type]="'metrics'"
+ uid="WAkugZpiz"
+ grafanaStyle="three"
+ >
</cd-grafana>
</ng-template>
</ng-container>
- <ng-container ngbNavItem
- *ngIf="grafanaPermission.read && isMultiSite">
- <a ngbNavLink
- i18n>Sync Performance</a>
+ <ng-container
+ ngbNavItem
+ *ngIf="grafanaPermission.read && isMultiSite"
+ >
+ <a
+ ngbNavLink
+ i18n
+ >Sync Performance</a
+ >
<ng-template ngbNavContent>
- <cd-grafana i18n-title
- title="Radosgw sync overview"
- [grafanaPath]="'ceph-object-sync-overview?'"
- [type]="'metrics'"
- uid="rgw-sync-overview"
- grafanaStyle="two">
+ <cd-grafana
+ i18n-title
+ title="Radosgw sync overview"
+ [grafanaPath]="'ceph-object-sync-overview?'"
+ [type]="'metrics'"
+ uid="rgw-sync-overview"
+ grafanaStyle="two"
+ >
</cd-grafana>
</ng-template>
</ng-container>
<cd-rgw-multisite-tabs></cd-rgw-multisite-tabs>
<div>
<!-- Show the alert only when the user has the permission to configure -->
- <cd-alert-panel *ngIf="permissions.configOpt.create && !rgwModuleStatus"
- type="info"
- spacingClass="mb-3"
- i18n
- class="align-items-center"
- actionName="Enable"
- (action)="enableRgwModule()">
- In order to access the import/export feature, the rgw module must be enabled.
+ <cd-alert-panel
+ *ngIf="permissions.configOpt.create && !rgwModuleStatus"
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ class="align-items-center"
+ actionName="Enable"
+ (action)="enableRgwModule()"
+ >
+ In order to access the import/export feature, the rgw module must be enabled.
</cd-alert-panel>
- <cd-alert-panel *ngIf="restartGatewayMessage"
- type="warning"
- spacingClass="mb-3"
- i18n>Please restart all Ceph Object Gateway instances in all zones to ensure consistent multisite configuration updates.
- <a class="text-decoration-underline"
- routerLink="/services">
- Cluster->Services</a>
+ <cd-alert-panel
+ *ngIf="restartGatewayMessage"
+ type="warning"
+ spacingClass="mb-3"
+ i18n
+ >Please restart all Ceph Object Gateway instances in all zones to ensure consistent multisite
+ configuration updates.
+ <a
+ class="text-decoration-underline"
+ routerLink="/services"
+ >
+ Cluster->Services</a
+ >
</cd-alert-panel>
- <div [cdsStack]="'horizontal'"
- [gap]="4">
- <cd-table-actions class="btn-group"
- [permission]="permissions.rgw"
- [selection]="selection"
- [tableActions]="multisiteReplicationActions">
+ <div
+ [cdsStack]="'horizontal'"
+ [gap]="4"
+ >
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permissions.rgw"
+ [selection]="selection"
+ [tableActions]="multisiteReplicationActions"
+ >
</cd-table-actions>
- <cd-table-actions *ngIf="showMigrateAndReplicationActions"
- class="btn-group"
- [permission]="permissions.rgw"
- [selection]="selection"
- [tableActions]="migrateTableAction">
+ <cd-table-actions
+ *ngIf="showMigrateAndReplicationActions"
+ class="btn-group"
+ [permission]="permissions.rgw"
+ [selection]="selection"
+ [tableActions]="migrateTableAction"
+ >
</cd-table-actions>
- <cd-table-actions class="btn-group multisite-actions"
- [permission]="permissions.rgw"
- [selection]="selection"
- [tableActions]="createTableActions"
- dropDownOnly="Actions"
- [dropDownOnlyBtnColor]="'tertiary'"
- [dropDownOnlyOffset]="{ x: 45, y: 0 }">
+ <cd-table-actions
+ class="btn-group multisite-actions"
+ [permission]="permissions.rgw"
+ [selection]="selection"
+ [tableActions]="createTableActions"
+ dropDownOnly="Actions"
+ [dropDownOnlyBtnColor]="'tertiary'"
+ [dropDownOnlyOffset]="{ x: 45, y: 0 }"
+ >
</cd-table-actions>
</div>
</div>
<div class="card">
- <div class="card-header"
- data-testid="rgw-multisite-details-header"
- i18n>Topology Viewer</div>
+ <div
+ class="card-header"
+ data-testid="rgw-multisite-details-header"
+ i18n
+ >
+ Topology Viewer
+ </div>
<div class="row">
<div class="col-sm-6 col-lg-6 tree-container">
- <cds-loading *ngIf="loadingIndicator"
- [isActive]="true"
- [overlay]="false"
- size="sm"></cds-loading>
- <cds-tree-view #tree
- [isMultiSelect]="false"
- (select)="onNodeSelected($event)">
- <ng-template #nodeTemplateRef
- let-node="node"
- let-depth="depth">
- <cds-tree-node [node]="node"
- [depth]="depth">
+ <cds-loading
+ *ngIf="loadingIndicator"
+ [isActive]="true"
+ [overlay]="false"
+ size="sm"
+ ></cds-loading>
+ <cds-tree-view
+ #tree
+ [isMultiSelect]="false"
+ (select)="onNodeSelected($event)"
+ >
+ <ng-template
+ #nodeTemplateRef
+ let-node="node"
+ let-depth="depth"
+ >
+ <cds-tree-node
+ [node]="node"
+ [depth]="depth"
+ >
<ng-container *ngIf="node?.children && node?.children?.length">
- <ng-container *ngFor="let child of node.children; let i = index;">
- <ng-container *ngTemplateOutlet="nodeTemplateRef; context: { node: child, depth: depth + 1 };">
+ <ng-container *ngFor="let child of node.children; let i = index">
+ <ng-container
+ *ngTemplateOutlet="nodeTemplateRef; context: { node: child, depth: depth + 1 }"
+ >
</ng-container>
</ng-container>
</ng-container>
</cds-tree-node>
</ng-template>
- <ng-template #treeNodeTemplate
- let-node>
+ <ng-template
+ #treeNodeTemplate
+ let-node
+ >
<div class="w-100 d-flex justify-content-between align-items-center pe-1">
<div>
- <span *ngIf="node?.data?.name"
- class="me-3">
- <span *ngIf="(node?.data?.show_warning)">
- <svg [cdsIcon]="icons.danger"
- [size]="icons.size16"
- [title]="node?.data?.warning_message"
- class="cds-danger-color"></svg>
+ <span
+ *ngIf="node?.data?.name"
+ class="me-3"
+ >
+ <span *ngIf="node?.data?.show_warning">
+ <svg
+ [cdsIcon]="icons.danger"
+ [size]="icons.size16"
+ [title]="node?.data?.warning_message"
+ class="cds-danger-color"
+ ></svg>
</span>
- <svg *ngIf="node?.data?.icon === 'scales'"
- [cdsIcon]="icons.reweight"
- [size]="icons.size20"
- ></svg>
- <svg *ngIf="node?.data?.icon === 'cube'"
- [cdsIcon]="icons.deploy"
- [size]="icons.size20"
- ></svg>
- <svg *ngIf="node?.data?.icon === 'web-services--cluster'"
- [cdsIcon]="icons.clusterIcon"
- [size]="icons.size20"
- ></svg>
+ <svg
+ *ngIf="node?.data?.icon === 'scales'"
+ [cdsIcon]="icons.reweight"
+ [size]="icons.size20"
+ ></svg>
+ <svg
+ *ngIf="node?.data?.icon === 'cube'"
+ [cdsIcon]="icons.deploy"
+ [size]="icons.size20"
+ ></svg>
+ <svg
+ *ngIf="node?.data?.icon === 'web-services--cluster'"
+ [cdsIcon]="icons.clusterIcon"
+ [size]="icons.size20"
+ ></svg>
{{ node?.data?.name }}
</span>
- <cds-tag class="tag-success me-2"
- *ngIf="node?.data?.is_default">
- default
+ <cds-tag
+ class="tag-success me-2"
+ *ngIf="node?.data?.is_default"
+ >
+ default
+ </cds-tag>
+ <cds-tag
+ class="tag-warning me-2"
+ *ngIf="node?.data?.is_master"
+ >
+ master
</cds-tag>
- <cds-tag class="tag-warning me-2"
- *ngIf="node?.data?.is_master"> master </cds-tag>
- <cds-tag class="tag-warning me-2"
- *ngIf="node?.data?.secondary_zone">
- secondary-zone
+ <cds-tag
+ class="tag-warning me-2"
+ *ngIf="node?.data?.secondary_zone"
+ >
+ secondary-zone
</cds-tag>
- <cds-tag class="tag-info me-2"
- *ngIf="node?.data?.tier_type === 'archive'">
- archive
+ <cds-tag
+ class="tag-info me-2"
+ *ngIf="node?.data?.tier_type === 'archive'"
+ >
+ archive
</cds-tag>
</div>
- <div class="btn-group align-inline-btns"
- [ngStyle]="{'visibility': activeNodeId === node?.data?.id ? 'visible' : 'hidden'}"
- role="group">
- <div [title]="editTitle"
- i18n-title>
- <button type="button"
- class="btn btn-light dropdown-toggle-split ms-1"
- (click)="openModal(node, true)"
- [disabled]="getDisable() || node?.data?.secondary_zone">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <div
+ class="btn-group align-inline-btns"
+ [ngStyle]="{ visibility: activeNodeId === node?.data?.id ? 'visible' : 'hidden' }"
+ role="group"
+ >
+ <div
+ [title]="editTitle"
+ i18n-title
+ >
+ <button
+ type="button"
+ class="btn btn-light dropdown-toggle-split ms-1"
+ (click)="openModal(node, true)"
+ [disabled]="getDisable() || node?.data?.secondary_zone"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</button>
</div>
<ng-container *ngIf="isDeleteDisabled(node) as nodeDeleteData">
- <div [title]="nodeDeleteData.deleteTitle"
- i18n-title>
- <button type="button"
- class="btn btn-light ms-1"
- [disabled]="nodeDeleteData.isDisabled || node?.data?.secondary_zone"
- (click)="delete(node)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size16"
- class="cds-info-color"></svg>
+ <div
+ [title]="nodeDeleteData.deleteTitle"
+ i18n-title
+ >
+ <button
+ type="button"
+ class="btn btn-light ms-1"
+ [disabled]="nodeDeleteData.isDisabled || node?.data?.secondary_zone"
+ (click)="delete(node)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
</button>
</div>
</ng-container>
</div>
</ng-template>
<ng-container *ngFor="let node of nodes">
- <ng-container *ngTemplateOutlet="nodeTemplateRef; context: { node: node, depth: 0 };">
+ <ng-container *ngTemplateOutlet="nodeTemplateRef; context: { node: node, depth: 0 }">
</ng-container>
</ng-container>
</cds-tree-view>
</div>
- <div class="col-sm-6 col-lg-6 metadata"
- *ngIf="metadata">
+ <div
+ class="col-sm-6 col-lg-6 metadata"
+ *ngIf="metadata"
+ >
<legend>{{ metadataTitle }}</legend>
<div>
- <cd-table-key-value [data]="metadata">
- </cd-table-key-value>
+ <cd-table-key-value [data]="metadata"> </cd-table-key-value>
</div>
</div>
</div>
(closeSelect)="closeModal()"
i18n
>
- Export multi-site realm token
+ Export multi-site realm token
</cds-modal-header>
<div cdsModalContent>
<ng-container *cdFormLoading="loading">
<div class="form-item">
@if (!tokenValid) {
- <cd-alert-panel
- type="warning"
- i18n
- >
- @for (realminfo of realms; track realminfo) {
- <div>
- <b>{{ realminfo.realm }}</b> - {{ realminfo.token }}
- </div>
- }
- </cd-alert-panel>
+ <cd-alert-panel
+ type="warning"
+ i18n
+ >
+ @for (realminfo of realms; track realminfo) {
+ <div>
+ <b>{{ realminfo.realm }}</b> - {{ realminfo.token }}
+ </div>
+ }
+ </cd-alert-panel>
}
</div>
@for (realminfo of realms; track realminfo) {
- <div>
- <div class="form-item">
- <cds-text-label
- labelInputID="realmName"
- i18n
- >
- Realm Name
- <input
- cdsText
- readonly
- type="text"
- id="realmName"
- [value]="realminfo.realm"
- modal-primary-focus
- [autofocus]="true"
- />
- </cds-text-label>
- </div>
+ <div>
+ <div class="form-item">
+ <cds-text-label
+ labelInputID="realmName"
+ i18n
+ >
+ Realm Name
+ <input
+ cdsText
+ readonly
+ type="text"
+ id="realmName"
+ [value]="realminfo.realm"
+ modal-primary-focus
+ [autofocus]="true"
+ />
+ </cds-text-label>
+ </div>
- <div class="form-item form-item-append">
- <cds-text-label
- labelInputID="realmToken"
- i18n
- >
- Token
- <input
- cdsText
- readonly
- type="text"
- id="realmToken"
- [value]="realminfo.token"
- />
- </cds-text-label>
- <cd-copy-2-clipboard-button
- class="clipboard"
- [source]="realminfo.token"
- [byId]="false"
- size="md"
- >
- </cd-copy-2-clipboard-button>
+ <div class="form-item form-item-append">
+ <cds-text-label
+ labelInputID="realmToken"
+ i18n
+ >
+ Token
+ <input
+ cdsText
+ readonly
+ type="text"
+ id="realmToken"
+ [value]="realminfo.token"
+ />
+ </cds-text-label>
+ <cd-copy-2-clipboard-button
+ class="clipboard"
+ [source]="realminfo.token"
+ [byId]="false"
+ size="md"
+ >
+ </cd-copy-2-clipboard-button>
+ </div>
</div>
- </div>
}
</ng-container>
</form>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">Import Multi-site Token</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >Import Multi-site Token</ng-container
+ >
<ng-container class="modal-content">
- <form name="importTokenForm"
- #frm="ngForm"
- [formGroup]="importTokenForm">
- <div class="modal-body">
- <cd-alert-panel type="info"
- spacingClass="mb-3">
- <ul>
- <li>This feature allows you to configure a connection between your primary and secondary Ceph clusters for data replication. By importing a token, you establish a link between the clusters, enabling data synchronization.</li>
- <li>To obtain the token, generate it from your primary Ceph cluster. This token includes encoded information about the primary cluster's endpoint, access key, and secret key.</li>
- <li>The secondary zone represents the destination cluster where your data will be replicated.</li>
- </ul>
- </cd-alert-panel>
- <legend i18n>Zone Details</legend>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="realmToken"
- i18n>Token
- </label>
- <div class="cd-col-form-input">
- <input id="realmToken"
- name="realmToken"
- class="form-control"
- type="text"
- formControlName="realmToken">
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('realmToken', frm, 'required')"
- i18n>This field is required.</span>
- </div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zoneName"
- i18n>Secondary 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="importTokenForm.showError('zoneName', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('zoneName', frm, 'uniqueName')"
- i18n>The chosen zone name is already in use.</span>
+ <form
+ name="importTokenForm"
+ #frm="ngForm"
+ [formGroup]="importTokenForm"
+ >
+ <div class="modal-body">
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ >
+ <ul>
+ <li>
+ This feature allows you to configure a connection between your primary and secondary
+ Ceph clusters for data replication. By importing a token, you establish a link between
+ the clusters, enabling data synchronization.
+ </li>
+ <li>
+ To obtain the token, generate it from your primary Ceph cluster. This token includes
+ encoded information about the primary cluster's endpoint, access key, and secret key.
+ </li>
+ <li>
+ The secondary zone represents the destination cluster where your data will be
+ replicated.
+ </li>
+ </ul>
+ </cd-alert-panel>
+ <legend i18n>Zone Details</legend>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="realmToken"
+ i18n
+ >Token
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ id="realmToken"
+ name="realmToken"
+ class="form-control"
+ type="text"
+ formControlName="realmToken"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('realmToken', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <div class="cd-col-form-offset">
- <div class="custom-control custom-checkbox">
- <input class="custom-control-input"
- id="archive_zone"
- type="checkbox"
- formControlName="archive_zone">
- <label class="custom-control-label cds-ml-2"
- for="archive_zone"
- i18n>Archive</label>
- <cd-helper i18n>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zoneName"
+ i18n
+ >Secondary 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
- >Enable archival storage to keep all object versions and protect data from deletion or corruption.</span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('zoneName', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('zoneName', frm, 'uniqueName')"
+ i18n
+ >The chosen zone name is already in use.</span
>
- </cd-helper>
</div>
</div>
- </div>
- <legend i18n>Service Details</legend>
- <div class="form-group row">
- <div class="cd-col-form-offset">
- <div class="custom-control custom-checkbox">
- <input class="custom-control-input"
- id="unmanaged"
- type="checkbox"
- formControlName="unmanaged">
- <label class="custom-control-label cds-ml-2"
- for="unmanaged"
- i18n>Unmanaged</label>
- <cd-helper i18n>If set to true, the orchestrator will not start nor stop any daemon associated with this service.
- Placement and all other properties will be ignored.</cd-helper>
+ <div class="form-group row">
+ <div class="cd-col-form-offset">
+ <div class="custom-control custom-checkbox">
+ <input
+ class="custom-control-input"
+ id="archive_zone"
+ type="checkbox"
+ formControlName="archive_zone"
+ />
+ <label
+ class="custom-control-label cds-ml-2"
+ for="archive_zone"
+ i18n
+ >Archive</label
+ >
+ <cd-helper i18n>
+ <span
+ >Enable archival storage to keep all object versions and protect data from
+ deletion or corruption.</span
+ >
+ </cd-helper>
+ </div>
</div>
</div>
- </div>
-
- <!-- Placement -->
- <div *ngIf="!importTokenForm.controls.unmanaged.value"
- class="form-group row">
- <label class="cd-col-form-label"
- for="placement"
- i18n>Placement</label>
- <div class="cd-col-form-input">
- <select id="placement"
- class="form-select"
- formControlName="placement">
- <option i18n
- value="hosts">Hosts</option>
- <option i18n
- value="label">Label</option>
- </select>
+ <legend i18n>Service Details</legend>
+ <div class="form-group row">
+ <div class="cd-col-form-offset">
+ <div class="custom-control custom-checkbox">
+ <input
+ class="custom-control-input"
+ id="unmanaged"
+ type="checkbox"
+ formControlName="unmanaged"
+ />
+ <label
+ class="custom-control-label cds-ml-2"
+ for="unmanaged"
+ i18n
+ >Unmanaged</label
+ >
+ <cd-helper i18n
+ >If set to true, the orchestrator will not start nor stop any daemon associated with
+ this service. Placement and all other properties will be ignored.</cd-helper
+ >
+ </div>
+ </div>
</div>
- </div>
- <!-- Label -->
- <div *ngIf="!importTokenForm.controls.unmanaged.value && importTokenForm.controls.placement.value === 'label'"
- class="form-group row">
- <label i18n
- class="cd-col-form-label"
- for="label">Label</label>
- <div class="cd-col-form-input">
- <input id="label"
- class="form-control"
- type="text"
- formControlName="label"
- [ngbTypeahead]="searchLabels"
- (focus)="labelFocus.next($any($event).target.value)"
- (click)="labelClick.next($any($event).target.value)">
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('label', frm, 'required')"
- i18n>This field is required.</span>
+ <!-- Placement -->
+ <div
+ *ngIf="!importTokenForm.controls.unmanaged.value"
+ class="form-group row"
+ >
+ <label
+ class="cd-col-form-label"
+ for="placement"
+ i18n
+ >Placement</label
+ >
+ <div class="cd-col-form-input">
+ <select
+ id="placement"
+ class="form-select"
+ formControlName="placement"
+ >
+ <option
+ i18n
+ value="hosts"
+ >
+ Hosts
+ </option>
+ <option
+ i18n
+ value="label"
+ >
+ Label
+ </option>
+ </select>
+ </div>
</div>
- </div>
- <!-- Hosts -->
- <div *ngIf="!importTokenForm.controls.unmanaged.value && importTokenForm.controls.placement.value === 'hosts'"
- class="form-group row">
- <label class="cd-col-form-label"
- for="hosts"
- i18n>Hosts</label>
- <div class="cd-col-form-input">
- <cd-select-badges id="hosts"
- [data]="importTokenForm.controls.hosts.value"
- [options]="hosts.options"
- [messages]="hosts.messages">
- </cd-select-badges>
+ <!-- Label -->
+ <div
+ *ngIf="
+ !importTokenForm.controls.unmanaged.value &&
+ importTokenForm.controls.placement.value === 'label'
+ "
+ class="form-group row"
+ >
+ <label
+ i18n
+ class="cd-col-form-label"
+ for="label"
+ >Label</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ id="label"
+ class="form-control"
+ type="text"
+ formControlName="label"
+ [ngbTypeahead]="searchLabels"
+ (focus)="labelFocus.next($any($event).target.value)"
+ (click)="labelClick.next($any($event).target.value)"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('label', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
- </div>
- <!-- count -->
- <div *ngIf="!importTokenForm.controls.unmanaged.value"
- class="form-group row">
- <label class="cd-col-form-label"
- for="count">
- <span i18n>Count</span>
- <cd-helper i18n>Only that number of daemons will be created.</cd-helper>
- </label>
- <div class="cd-col-form-input">
- <input id="count"
- class="form-control"
- type="number"
- formControlName="count"
- min="1">
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('count', frm, 'min')"
- i18n>The value must be at least 1.</span>
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('count', frm, 'pattern')"
- i18n>The entered value needs to be a number.</span>
+ <!-- Hosts -->
+ <div
+ *ngIf="
+ !importTokenForm.controls.unmanaged.value &&
+ importTokenForm.controls.placement.value === 'hosts'
+ "
+ class="form-group row"
+ >
+ <label
+ class="cd-col-form-label"
+ for="hosts"
+ i18n
+ >Hosts</label
+ >
+ <div class="cd-col-form-input">
+ <cd-select-badges
+ id="hosts"
+ [data]="importTokenForm.controls.hosts.value"
+ [options]="hosts.options"
+ [messages]="hosts.messages"
+ >
+ </cd-select-badges>
+ </div>
</div>
- </div>
- <!-- RGW -->
- <ng-container *ngIf="!importTokenForm.controls.unmanaged.value">
- <!-- rgw_frontend_port -->
- <div class="form-group row">
- <label i18n
- class="cd-col-form-label"
- for="rgw_frontend_port">Port</label>
+ <!-- count -->
+ <div
+ *ngIf="!importTokenForm.controls.unmanaged.value"
+ class="form-group row"
+ >
+ <label
+ class="cd-col-form-label"
+ for="count"
+ >
+ <span i18n>Count</span>
+ <cd-helper i18n>Only that number of daemons will be created.</cd-helper>
+ </label>
<div class="cd-col-form-input">
- <input id="rgw_frontend_port"
- class="form-control"
- type="number"
- formControlName="rgw_frontend_port"
- min="1"
- max="65535">
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'pattern')"
- i18n>The entered value needs to be a number.</span>
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'min')"
- i18n>The value must be at least 1.</span>
- <span class="invalid-feedback"
- *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'max')"
- i18n>The value cannot exceed 65535.</span>
+ <input
+ id="count"
+ class="form-control"
+ type="number"
+ formControlName="count"
+ min="1"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('count', frm, 'min')"
+ i18n
+ >The value must be at least 1.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('count', frm, 'pattern')"
+ i18n
+ >The entered value needs to be a number.</span
+ >
</div>
</div>
- </ng-container>
- </div>
- <div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [submitText]="actionLabels.IMPORT"
- [form]="importTokenForm"></cd-form-button-panel>
- </div>
+
+ <!-- RGW -->
+ <ng-container *ngIf="!importTokenForm.controls.unmanaged.value">
+ <!-- rgw_frontend_port -->
+ <div class="form-group row">
+ <label
+ i18n
+ class="cd-col-form-label"
+ for="rgw_frontend_port"
+ >Port</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ id="rgw_frontend_port"
+ class="form-control"
+ type="number"
+ formControlName="rgw_frontend_port"
+ min="1"
+ max="65535"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'pattern')"
+ i18n
+ >The entered value needs to be a number.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'min')"
+ i18n
+ >The value must be at least 1.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="importTokenForm.showError('rgw_frontend_port', frm, 'max')"
+ i18n
+ >The value cannot exceed 65535.</span
+ >
+ </div>
+ </div>
+ </ng-container>
+ </div>
+ <div class="modal-footer">
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [submitText]="actionLabels.IMPORT"
+ [form]="importTokenForm"
+ ></cd-form-button-panel>
+ </div>
</form>
</ng-container>
</cd-modal>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">Migrate Single Site to Multi-site
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >Migrate Single Site to Multi-site
<cd-helper>
- <span>Migrate from a single-site deployment with a default zonegroup and zone to a multi-site system</span>
+ <span
+ >Migrate from a single-site deployment with a default zonegroup and zone to a multi-site
+ system</span
+ >
</cd-helper>
</ng-container>
<ng-container class="modal-content">
- <form name="multisiteMigrateForm"
- #formDir="ngForm"
- [formGroup]="multisiteMigrateForm"
- novalidate>
- <div class="modal-body">
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="realmName"
- i18n>Realm Name</label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="Realm name..."
- id="realmName"
- name="realmName"
- formControlName="realmName">
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('realmName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('realmName', formDir, 'uniqueName')"
- i18n>The chosen realm name is already in use.</span>
+ <form
+ name="multisiteMigrateForm"
+ #formDir="ngForm"
+ [formGroup]="multisiteMigrateForm"
+ novalidate
+ >
+ <div class="modal-body">
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="realmName"
+ i18n
+ >Realm Name</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="Realm name..."
+ id="realmName"
+ name="realmName"
+ formControlName="realmName"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('realmName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('realmName', formDir, 'uniqueName')"
+ i18n
+ >The chosen realm name is already in use.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroupName"
- i18n>Rename default zonegroup</label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="Zonegroup name..."
- id="zonegroupName"
- name="zonegroupName"
- formControlName="zonegroupName">
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zonegroupName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zonegroupName', formDir, 'uniqueName')"
- i18n>The chosen zonegroup name is already in use.</span>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zonegroupName"
+ i18n
+ >Rename default zonegroup</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="Zonegroup name..."
+ id="zonegroupName"
+ name="zonegroupName"
+ formControlName="zonegroupName"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zonegroupName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zonegroupName', formDir, 'uniqueName')"
+ i18n
+ >The chosen zonegroup name is already in use.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroup_endpoints"
- i18n>Zonegroup Endpoints
- </label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="http://ceph-node-00.com:80"
- id="zonegroup_endpoints"
- name="zonegroup_endpoints"
- formControlName="zonegroup_endpoints">
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zonegroup_endpoints', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zonegroup_endpoints', formDir, 'invalidURL')"
- i18n>Please enter a valid URL.</span>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zonegroup_endpoints"
+ i18n
+ >Zonegroup Endpoints
+ </label>
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="http://ceph-node-00.com:80"
+ id="zonegroup_endpoints"
+ name="zonegroup_endpoints"
+ formControlName="zonegroup_endpoints"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zonegroup_endpoints', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zonegroup_endpoints', formDir, 'invalidURL')"
+ i18n
+ >Please enter a valid URL.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zoneName"
- i18n>Rename default zone</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="multisiteMigrateForm.showError('zoneName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zoneName', formDir, 'uniqueName')"
- i18n>The chosen zone name is already in use.</span>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zoneName"
+ i18n
+ >Rename default zone</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="multisiteMigrateForm.showError('zoneName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zoneName', formDir, 'uniqueName')"
+ i18n
+ >The chosen zone name is already in use.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zone_endpoints"
- i18n>Zone 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="multisiteMigrateForm.showError('zone_endpoints', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('zone_endpoints', formDir, 'invalidURL')"
- i18n>Please enter a valid URL.</span>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zone_endpoints"
+ i18n
+ >Zone 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="multisiteMigrateForm.showError('zone_endpoints', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('zone_endpoints', formDir, 'invalidURL')"
+ i18n
+ >Please enter a valid URL.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="username"
- i18n>Username</label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="username"
- id="username"
- name="username"
- formControlName="username">
- <cd-help-text>
- <span i18n>Specify the username for the system user. This user will be created automatically as part of the process.</span>
- </cd-help-text>
- <span class="invalid-feedback"
- *ngIf="multisiteMigrateForm.showError('username', formDir, 'required')"
- i18n>This field is required.</span>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="username"
+ i18n
+ >Username</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="username"
+ id="username"
+ name="username"
+ formControlName="username"
+ />
+ <cd-help-text>
+ <span i18n
+ >Specify the username for the system user. This user will be created automatically
+ as part of the process.</span
+ >
+ </cd-help-text>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteMigrateForm.showError('username', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </div>
</div>
</div>
- </div>
- <div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [submitText]="actionLabels.MIGRATE + ' ' + 'to Multi-site'"
- [form]="multisiteMigrateForm"></cd-form-button-panel>
- </div>
+ <div class="modal-footer">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [submitText]="actionLabels.MIGRATE + ' ' + 'to Multi-site'"
+ [form]="multisiteMigrateForm"
+ ></cd-form-button-panel>
+ </div>
</form>
</ng-container>
</cd-modal>
-<cds-modal size="sm"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<div cdsModalContent>
- <form name="multisiteRealmForm"
- #formDir="ngForm"
- [formGroup]="multisiteRealmForm"
- novalidate>
+ <form
+ name="multisiteRealmForm"
+ #formDir="ngForm"
+ [formGroup]="multisiteRealmForm"
+ novalidate
+ >
<div class="form-item">
<cds-text-label
labelInputID="realmName"
-<cds-modal size="sm"
- [open]="open">
+<cds-modal
+ size="sm"
+ [open]="open"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ groupType }} flow</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ groupType }} flow
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
- <form name="flowForm"
- #frm="ngForm"
- [formGroup]="currentFormGroupContext"
- novalidate>
+ <form
+ name="flowForm"
+ #frm="ngForm"
+ [formGroup]="currentFormGroupContext"
+ novalidate
+ >
<div cdsModalContent>
<!-- Flow Name-->
<div class="form-item">
- <cds-text-label for="flow_id"
- [invalid]="!currentFormGroupContext.controls.flow_id.valid && currentFormGroupContext.controls.flow_id.dirty"
- [invalidText]="flowIdError">
+ <cds-text-label
+ for="flow_id"
+ [invalid]="
+ !currentFormGroupContext.controls.flow_id.valid &&
+ currentFormGroupContext.controls.flow_id.dirty
+ "
+ [invalidText]="flowIdError"
+ >
<ng-container i18n>Name</ng-container>
- <input cdsText
- type="text"
- id="flow_id"
- formControlName="flow_id"
- autofocus
- [invalid]="!currentFormGroupContext.controls.flow_id.valid && currentFormGroupContext.controls.flow_id.dirty">
+ <input
+ cdsText
+ type="text"
+ id="flow_id"
+ formControlName="flow_id"
+ autofocus
+ [invalid]="
+ !currentFormGroupContext.controls.flow_id.valid &&
+ currentFormGroupContext.controls.flow_id.dirty
+ "
+ />
</cds-text-label>
<ng-template #flowIdError>
- @if (currentFormGroupContext.showError('flow_id', formDir, 'required')) {
- <span class="invalid-feedback">
- <ng-container i18n> This field is required. </ng-container>
- </span>
- }
+ @if (currentFormGroupContext.showError('flow_id', formDir, 'required')) {
+ <span class="invalid-feedback">
+ <ng-container i18n> This field is required. </ng-container>
+ </span>
+ }
</ng-template>
</div>
<!-- Bucket Name-->
@if (currentFormGroupContext.controls.bucket_name.value) {
- <div class="form-item">
- <cds-text-label for="bucket_name"
- cdOptionalField="Bucket name">
- <ng-container i18n>Bucket name</ng-container>
- <input cdsText
- type="text"
- id="bucket_name"
- formControlName="bucket_name"
- [readOnly]="true">
- </cds-text-label>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ for="bucket_name"
+ cdOptionalField="Bucket name"
+ >
+ <ng-container i18n>Bucket name</ng-container>
+ <input
+ cdsText
+ type="text"
+ id="bucket_name"
+ formControlName="bucket_name"
+ [readOnly]="true"
+ />
+ </cds-text-label>
+ </div>
}
<!-- Symmetrical flow zones -->
@if (groupType == flowType.symmetrical) {
<div class="form-item">
- <cds-combo-box label="Zones"
- type="multi"
- selectionFeedback="top-after-reopen"
- for="zones"
- formControlName="zones"
- [helperText]="'Flow need to be associated with atleast one zone'"
- i18n-helperText
- [appendInline]="true"
- [items]="zones"
- itemValueKey="content"
- id="zones"
- cdDynamicInputCombobox
- [invalid]="currentFormGroupContext.controls?.zones?.invalid && currentFormGroupContext.controls?.zones?.dirty"
- [invalidText]="'Zone selection is required!'"
- i18n>
+ <cds-combo-box
+ label="Zones"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ for="zones"
+ formControlName="zones"
+ [helperText]="'Flow need to be associated with atleast one zone'"
+ i18n-helperText
+ [appendInline]="true"
+ [items]="zones"
+ itemValueKey="content"
+ id="zones"
+ cdDynamicInputCombobox
+ [invalid]="
+ currentFormGroupContext.controls?.zones?.invalid &&
+ currentFormGroupContext.controls?.zones?.dirty
+ "
+ [invalidText]="'Zone selection is required!'"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</div>
} @else {
<div class="form-item">
- <ng-container *ngTemplateOutlet="sourceAndDestZone;context: { formControl: 'source_zone', zones: zones, name: 'Source zone' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ sourceAndDestZone;
+ context: { formControl: 'source_zone', zones: zones, name: 'Source zone' }
+ "
+ ></ng-container>
</div>
<div class="form-item">
- <ng-container *ngTemplateOutlet="sourceAndDestZone;context: { formControl: 'destination_zone', zones: zones, name: 'Destination zone' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ sourceAndDestZone;
+ context: { formControl: 'destination_zone', zones: zones, name: 'Destination zone' }
+ "
+ ></ng-container>
</div>
}
<!-- Directional flow zones -->
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="currentFormGroupContext"
- [modalForm]="true"
- [submitText]="(action | titlecase)"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="currentFormGroupContext"
+ [modalForm]="true"
+ [submitText]="action | titlecase"
+ ></cd-form-button-panel>
</form>
</cds-modal>
-<ng-template #sourceAndDestZone
- let-name="name"
- let-zones="zones"
- let-formControl="formControl"
- [formGroup]="currentFormGroupContext">
- <cds-select [label]="name"
- [formControlName]="formControl"
- [id]="formControl"
- [invalid]="currentFormGroupContext.controls[formControl].invalid && (currentFormGroupContext.controls[formControl].dirty)"
- [invalidText]="zoneError"
- i18n>
+<ng-template
+ #sourceAndDestZone
+ let-name="name"
+ let-zones="zones"
+ let-formControl="formControl"
+ [formGroup]="currentFormGroupContext"
+>
+ <cds-select
+ [label]="name"
+ [formControlName]="formControl"
+ [id]="formControl"
+ [invalid]="
+ currentFormGroupContext.controls[formControl].invalid &&
+ currentFormGroupContext.controls[formControl].dirty
+ "
+ [invalidText]="zoneError"
+ i18n
+ >
@if (zones.length == 0) {
- <option [ngValue]="null">Loading...</option>
+ <option [ngValue]="null">Loading...</option>
}
@if (zones.length > 0) {
- <option [ngValue]="null">-- Select {{name}} --</option>
+ <option [ngValue]="null">-- Select {{ name }} --</option>
}
@for (zone of zones; track zone) {
- <option [value]="zone.name">{{ zone.name }}</option>
+ <option [value]="zone.name">{{ zone.name }}</option>
}
</cds-select>
<ng-template #zoneError>
- @if (currentFormGroupContext.showError(formControl, frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
+ @if (currentFormGroupContext.showError(formControl, frm, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
</ng-template>
</ng-template>
-<cds-modal [open]="open"
- size="md">
+<cds-modal
+ [open]="open"
+ size="md"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} pipe</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} pipe
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
- <form name="pipeForm"
- #frm="ngForm"
- [formGroup]="pipeForm"
- novalidate>
+ <form
+ name="pipeForm"
+ #frm="ngForm"
+ [formGroup]="pipeForm"
+ novalidate
+ >
<div cdsModalContent>
<!-- Pipe Name -->
<div class="form-item">
- <cds-text-label for="pipe_id"
- [invalid]="!pipeForm.controls.pipe_id.valid && pipeForm.controls.pipe_id.dirty"
- [invalidText]="pipeIdError">
+ <cds-text-label
+ for="pipe_id"
+ [invalid]="!pipeForm.controls.pipe_id.valid && pipeForm.controls.pipe_id.dirty"
+ [invalidText]="pipeIdError"
+ >
<ng-container i18n>Name</ng-container>
- <input cdsText
- type="text"
- id="pipe_id"
- formControlName="pipe_id"
- autofocus
- [invalid]="!pipeForm.controls.pipe_id.valid && pipeForm.controls.pipe_id.dirty"
- [readonly]="editing">
+ <input
+ cdsText
+ type="text"
+ id="pipe_id"
+ formControlName="pipe_id"
+ autofocus
+ [invalid]="!pipeForm.controls.pipe_id.valid && pipeForm.controls.pipe_id.dirty"
+ [readonly]="editing"
+ />
</cds-text-label>
<ng-template #pipeIdError>
@if (pipeForm.showError('pipe_id', formDir, 'required')) {
- <span class="invalid-feedback">
- <ng-container i18n> This field is required. </ng-container>
- </span>
+ <span class="invalid-feedback">
+ <ng-container i18n> This field is required. </ng-container>
+ </span>
}
</ng-template>
</div>
<!-- Source and Destination Zones -->
<div class="form-item">
- <ng-container *ngTemplateOutlet="zoneMultiSelect;context: { formControl: 'source_zones', zone: sourceZones, name: 'Source zone' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ zoneMultiSelect;
+ context: { formControl: 'source_zones', zone: sourceZones, name: 'Source zone' }
+ "
+ ></ng-container>
</div>
<div class="form-item">
- <ng-container *ngTemplateOutlet="zoneMultiSelect;context: { formControl: 'destination_zones', zone: destZones, name: 'Destination zone' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ zoneMultiSelect;
+ context: { formControl: 'destination_zones', zone: destZones, name: 'Destination zone' }
+ "
+ ></ng-container>
</div>
<!-- Bucket Name -->
@if (pipeForm.controls.bucket_name.value) {
- <div class="form-item">
- <cds-text-label for="bucket_name"
- cdOptionalField="Bucket name">
- <ng-container i18n>Bucket name</ng-container>
- <input cdsText
- type="text"
- id="bucket_name"
- formControlName="bucket_name"
- autofocus
- [readonly]="true">
- </cds-text-label>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ for="bucket_name"
+ cdOptionalField="Bucket name"
+ >
+ <ng-container i18n>Bucket name</ng-container>
+ <input
+ cdsText
+ type="text"
+ id="bucket_name"
+ formControlName="bucket_name"
+ autofocus
+ [readonly]="true"
+ />
+ </cds-text-label>
+ </div>
}
<!-- Source Bucket -->
<div class="form-item">
- <cds-text-label for="source_bucket"
- [helperText]="allBucketSelectedHelpText"
- i18n-helperText
- cdOptionalField="Source bucket">
+ <cds-text-label
+ for="source_bucket"
+ [helperText]="allBucketSelectedHelpText"
+ i18n-helperText
+ cdOptionalField="Source bucket"
+ >
<ng-container i18n>Source bucket</ng-container>
- <input cdsText
- type="text"
- id="source_bucket"
- formControlName="source_bucket">
+ <input
+ cdsText
+ type="text"
+ id="source_bucket"
+ formControlName="source_bucket"
+ />
</cds-text-label>
</div>
<!-- Destination Bucket -->
<div class="form-item">
- <cds-text-label for="destination_bucket"
- [helperText]="allBucketSelectedHelpText"
- i18n-helperText
- cdOptionalField="Destination bucket">
+ <cds-text-label
+ for="destination_bucket"
+ [helperText]="allBucketSelectedHelpText"
+ i18n-helperText
+ cdOptionalField="Destination bucket"
+ >
<ng-container i18n>Destination bucket</ng-container>
- <input cdsText
- type="text"
- id="destination_bucket"
- formControlName="destination_bucket">
+ <input
+ cdsText
+ type="text"
+ id="destination_bucket"
+ formControlName="destination_bucket"
+ />
</cds-text-label>
</div>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="pipeForm"
- [modalForm]="true"
- [submitText]="(action | titlecase) + ' ' + 'Pipe'">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="pipeForm"
+ [modalForm]="true"
+ [submitText]="(action | titlecase) + ' ' + 'Pipe'"
+ >
</cd-form-button-panel>
</form>
</cds-modal>
-<ng-template #zoneMultiSelect
- let-name="name"
- let-zone="zone"
- let-formControl="formControl"
- [formGroup]="pipeForm">
- <cds-combo-box [label]="name"
- type="multi"
- selectionFeedback="top-after-reopen"
- [for]="formControl"
- [formControlName]="formControl"
- [helperText]="'Pipe need to be associated with atleast one zone'"
- i18n-helperText
- [items]="zone"
- itemValueKey="content"
- [id]="formControl"
- [invalid]="pipeForm.controls[formControl].invalid && pipeForm.controls[formControl].dirty"
- [invalidText]="'Zone selection is required!'"
- i18n>
+<ng-template
+ #zoneMultiSelect
+ let-name="name"
+ let-zone="zone"
+ let-formControl="formControl"
+ [formGroup]="pipeForm"
+>
+ <cds-combo-box
+ [label]="name"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ [for]="formControl"
+ [formControlName]="formControl"
+ [helperText]="'Pipe need to be associated with atleast one zone'"
+ i18n-helperText
+ [items]="zone"
+ itemValueKey="content"
+ [id]="formControl"
+ [invalid]="pipeForm.controls[formControl].invalid && pipeForm.controls[formControl].dirty"
+ [invalidText]="'Zone selection is required!'"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</ng-template>
ngbNav
#nav="ngbNav"
class="nav-tabs"
- cdStatefulTab="sync-policy-details">
+ cdStatefulTab="sync-policy-details"
+ >
<ng-container ngbNavItem="flow">
<a
ngbNavLink
- i18n>Flow</a>
+ i18n
+ >Flow</a
+ >
<ng-template ngbNavContent>
<legend>
Symmetrical
[maxLimit]="25"
[toolHeader]="true"
(updateSelection)="updateSelection($event, flowType.symmetrical)"
- (fetchData)="loadData($event)">
+ (fetchData)="loadData($event)"
+ >
<div class="table-actions">
<cd-table-actions
[permission]="permission"
[selection]="symFlowSelection"
class="btn-group"
- [tableActions]="symFlowTableActions" >
+ [tableActions]="symFlowTableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
<legend>
Directional
<cd-help-text>
- It can define directional data flow, in which the data moves in one way, from one zone to another.
+ It can define directional data flow, in which the data moves in one way, from one zone
+ to another.
</cd-help-text>
</legend>
<cd-table
[maxLimit]="25"
[toolHeader]="true"
(updateSelection)="updateSelection($event, flowType.directional)"
- (fetchData)="loadData($event)">
+ (fetchData)="loadData($event)"
+ >
<div class="table-actions">
<cd-table-actions
[permission]="permission"
[selection]="dirFlowSelection"
class="btn-group"
- [tableActions]="dirFlowTableActions">
+ [tableActions]="dirFlowTableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
</ng-template>
</ng-container>
<ng-container ngbNavItem="pipe">
- <a ngbNavLink
- i18n>Pipe</a>
+ <a
+ ngbNavLink
+ i18n
+ >Pipe</a
+ >
<ng-template ngbNavContent>
<legend i18n>
Pipe
<cd-help-text>
- A pipe defines the actual buckets that can use these data flows, and the properties that are associated with it.
+ A pipe defines the actual buckets that can use these data flows, and the properties that
+ are associated with it.
</cd-help-text>
</legend>
<cd-table
[serverSide]="false"
[toolHeader]="true"
(updateSelection)="pipeSelection = $event"
- (fetchData)="loadData($event)">
+ (fetchData)="loadData($event)"
+ >
<div class="table-actions">
<cd-table-actions
[permission]="permission"
[selection]="pipeSelection"
class="btn-group"
- [tableActions]="pipeTableActions">
+ [tableActions]="pipeTableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
}
<ng-template #deleteTpl>
- <cd-alert-panel type="danger"
- i18n>
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
Deleting {{ resourceType | upperFirst }} may disrupt data synchronization
</cd-alert-panel>
</ng-template>
-<cds-modal size="sm"
- [open]="open">
+<cds-modal
+ size="sm"
+ [open]="open"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource }}
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
- <form #frm="ngForm"
- [formGroup]="syncPolicyForm"
- *cdFormLoading="loading"
- novalidate>
+ <form
+ #frm="ngForm"
+ [formGroup]="syncPolicyForm"
+ *cdFormLoading="loading"
+ novalidate
+ >
<div cdsModalContent>
<!-- Group Id -->
<div class="form-item">
- <cds-text-label for="group_id"
- [invalid]="!syncPolicyForm.controls.group_id.valid && syncPolicyForm.controls.group_id.dirty"
- [invalidText]="groupIdError">
+ <cds-text-label
+ for="group_id"
+ [invalid]="
+ !syncPolicyForm.controls.group_id.valid && syncPolicyForm.controls.group_id.dirty
+ "
+ [invalidText]="groupIdError"
+ >
<ng-container i18n>Group name</ng-container>
- <input cdsText
- type="text"
- id="group_id"
- formControlName="group_id"
- autofocus
- [invalid]="!syncPolicyForm.controls.group_id.valid && syncPolicyForm.controls.group_id.dirty"
- [readonly]="editing"/>
+ <input
+ cdsText
+ type="text"
+ id="group_id"
+ formControlName="group_id"
+ autofocus
+ [invalid]="
+ !syncPolicyForm.controls.group_id.valid && syncPolicyForm.controls.group_id.dirty
+ "
+ [readonly]="editing"
+ />
</cds-text-label>
<ng-template #groupIdError>
@if (syncPolicyForm.showError('group_id', frm, 'required')) {
- <span class="invalid-feedback">
- <ng-container i18n> This field is required. </ng-container>
- </span>
+ <span class="invalid-feedback">
+ <ng-container i18n> This field is required. </ng-container>
+ </span>
}
</ng-template>
</div>
<!-- Status -->
<div class="form-item">
- <cds-select label="Status"
- for="status"
- formControlName="status"
- id="status"
- [invalid]="syncPolicyForm.controls['status'].invalid && (syncPolicyForm.controls['status'].dirty)"
- [invalidText]="statusError"
- i18n>
+ <cds-select
+ label="Status"
+ for="status"
+ formControlName="status"
+ id="status"
+ [invalid]="
+ syncPolicyForm.controls['status'].invalid && syncPolicyForm.controls['status'].dirty
+ "
+ [invalidText]="statusError"
+ i18n
+ >
<ng-container>Status</ng-container>
- <option value="{{syncPolicyStatus.ENABLED}}">{{syncPolicyStatus.ENABLED | upperFirst }}</option>
- <option value="{{syncPolicyStatus.ALLOWED}}">{{syncPolicyStatus.ALLOWED | upperFirst }}</option>
- <option value="{{syncPolicyStatus.FORBIDDEN}}">{{syncPolicyStatus.FORBIDDEN | upperFirst }}</option>
+ <option value="{{ syncPolicyStatus.ENABLED }}">
+ {{ syncPolicyStatus.ENABLED | upperFirst }}
+ </option>
+ <option value="{{ syncPolicyStatus.ALLOWED }}">
+ {{ syncPolicyStatus.ALLOWED | upperFirst }}
+ </option>
+ <option value="{{ syncPolicyStatus.FORBIDDEN }}">
+ {{ syncPolicyStatus.FORBIDDEN | upperFirst }}
+ </option>
</cds-select>
<ng-template #statusError>
@if (syncPolicyForm.showError('status', frm, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
<!-- Bucket Name -->
<div class="form-item">
- <cds-text-label for="bucket_name"
- [invalid]="!syncPolicyForm.controls.bucket_name.valid && syncPolicyForm.controls.bucket_name.dirty"
- [invalidText]="bucketNameError"
- cdOptionalField="Bucket name">
+ <cds-text-label
+ for="bucket_name"
+ [invalid]="
+ !syncPolicyForm.controls.bucket_name.valid &&
+ syncPolicyForm.controls.bucket_name.dirty
+ "
+ [invalidText]="bucketNameError"
+ cdOptionalField="Bucket name"
+ >
<ng-container i18n>Bucket name</ng-container>
- <input cdsText
- type="text"
- id="bucket_name"
- formControlName="bucket_name"
- [invalid]="!syncPolicyForm.controls.bucket_name.valid && syncPolicyForm.controls.bucket_name.dirty"
- [readonly]="editing"/>
+ <input
+ cdsText
+ type="text"
+ id="bucket_name"
+ formControlName="bucket_name"
+ [invalid]="
+ !syncPolicyForm.controls.bucket_name.valid &&
+ syncPolicyForm.controls.bucket_name.dirty
+ "
+ [readonly]="editing"
+ />
</cds-text-label>
<ng-template #bucketNameError>
@if (syncPolicyForm.showError('bucket_name', frm, 'bucketNameNotAllowed')) {
- <span class="invalid-feedback"
- i18n>The bucket with chosen name does not exist.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The bucket with chosen name does not exist.</span
+ >
}
</ng-template>
</div>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="syncPolicyForm"
- [modalForm]="true"
- [submitText]="(action | titlecase)"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="syncPolicyForm"
+ [modalForm]="true"
+ [submitText]="action | titlecase"
+ ></cd-form-button-panel>
</form>
</ng-container>
</cds-modal>
Multisite Sync Policy
<cd-help-text>
Multisite bucket-granularity sync policy provides fine grained control of data movement between
- buckets in different zones. Leveraging the bucket-granularity sync policy is possible for buckets to diverge,
- and a bucket can pull data from other buckets (ones that don’t share its name or its ID) in different zone.
+ buckets in different zones. Leveraging the bucket-granularity sync policy is possible for
+ buckets to diverge, and a bucket can pull data from other buckets (ones that don’t share its
+ name or its ID) in different zone.
</cd-help-text>
</legend>
<cd-table
[toolHeader]="true"
(setExpandedRow)="setExpandedRow($event)"
(fetchData)="getPolicyList($event)"
- (updateSelection)="updateSelection($event)">
+ (updateSelection)="updateSelection($event)"
+>
<div class="table-actions">
<cd-table-actions
[permission]="permission"
[selection]="selection"
class="btn-group"
- [tableActions]="tableActions">
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
<cd-rgw-multisite-sync-policy-details
*cdTableDetail
[expandedRow]="expandedRow"
- [permission]="permission">
+ [permission]="permission"
+ >
</cd-rgw-multisite-sync-policy-details>
</cd-table>
<ng-template #deleteTpl>
- <cd-alert-panel type="danger"
- i18n>
+ <cd-alert-panel
+ type="danger"
+ i18n
+ >
Are you sure you want to delete these policy groups?
</cd-alert-panel>
</ng-template>
-<router-outlet name="modal"
- (deactivate)="getPolicyList()"></router-outlet>
+<router-outlet
+ name="modal"
+ (deactivate)="getPolicyList()"
+></router-outlet>
<ul class="nav nav-tabs">
<li class="nav-item">
- <a class="nav-link"
- routerLink="/rgw/multisite/configuration"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- i18n>Configuration</a>
+ <a
+ class="nav-link"
+ routerLink="/rgw/multisite/configuration"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n
+ >Configuration</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="//rgw/multisite/sync-policy"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- i18n>Sync Policy</a>
+ <a
+ class="nav-link"
+ routerLink="//rgw/multisite/sync-policy"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n
+ >Sync Policy</a
+ >
</li>
</ul>
-
-<cds-modal size="lg"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- data-testid="rgw-multisite-wizard-header"
- i18n>Set up Multi-site Replication</h3>
+ <h3
+ cdsModalHeaderHeading
+ data-testid="rgw-multisite-wizard-header"
+ i18n
+ >
+ Set up Multi-site Replication
+ </h3>
</cds-modal-header>
<div cdsModalContent>
<div cdsRow>
- <div cdsCol
- [columnNumbers]="{'lg': 2, 'md': 2, 'sm': 2}"
- class="indicator-wrapper">
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 2, md: 2, sm: 2 }"
+ class="indicator-wrapper"
+ >
<cd-wizard [stepsTitle]="stepTitles"></cd-wizard>
</div>
- <div cdsCol
- [columnNumbers]="{'lg': 14, 'md': 14, 'sm': 14}">
- <form [formGroup]="multisiteSetupForm"
- #formDir="ngForm"
- novalidate>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 14, md: 14, sm: 14 }"
+ >
+ <form
+ [formGroup]="multisiteSetupForm"
+ #formDir="ngForm"
+ novalidate
+ >
<ng-container [ngSwitch]="currentStep?.stepIndex">
- <div *ngSwitchCase="0"
- class="ms-5">
- <cd-alert-panel type="info"
- spacingClass="mb-3">
- This wizard enables you to set up multi-site replication within your
- Ceph environment.If you have already added another cluster to your
- multi-cluster setup, you can select that cluster in the wizard to
- automate the replication process.If no additional cluster is currently
- added, the wizard will guide you through creating the necessary realm,
- zonegroup, and zone, and provide a realm token.This token can be used
- later to manually import into a desired cluster to establish replication
- between the clusters.
+ <div
+ *ngSwitchCase="0"
+ class="ms-5"
+ >
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ >
+ This wizard enables you to set up multi-site replication within your Ceph
+ environment.If you have already added another cluster to your multi-cluster setup,
+ you can select that cluster in the wizard to automate the replication process.If no
+ additional cluster is currently added, the wizard will guide you through creating
+ the necessary realm, zonegroup, and zone, and provide a realm token.This token can
+ be used later to manually import into a desired cluster to establish replication
+ between the clusters.
</cd-alert-panel>
- <div class="form-group row"
- *ngIf="showConfigType && isMultiClusterConfigured">
- <label class="cd-col-form-label required"
- for="configType"
- i18n>Realm configuration mode</label>
- <div class="col-md-auto custom-checkbox form-check-inline ms-3">
- <input class="form-check-input"
- formControlName="configType"
- id="newRealm"
- value="newRealm"
- (change)="onConfigTypeChange()"
- type="radio">
- <label class="custom-check-label"
- for="newRealm"
- i18n>Create new realm/zonegroup/zone</label>
+ <div
+ class="form-group row"
+ *ngIf="showConfigType && isMultiClusterConfigured"
+ >
+ <label
+ class="cd-col-form-label required"
+ for="configType"
+ i18n
+ >Realm configuration mode</label
+ >
+ <div class="col-md-auto custom-checkbox form-check-inline ms-3">
+ <input
+ class="form-check-input"
+ formControlName="configType"
+ id="newRealm"
+ value="newRealm"
+ (change)="onConfigTypeChange()"
+ type="radio"
+ />
+ <label
+ class="custom-check-label"
+ for="newRealm"
+ i18n
+ >Create new realm/zonegroup/zone</label
+ >
</div>
<div class="col-md-auto custom-checkbox form-check-inline">
- <input class="form-check-input"
- formControlName="configType"
- id="existingRealm"
- type="radio"
- (change)="onConfigTypeChange()"
- value="existingRealm">
- <label class="custom-check-label"
- for="existingRealm"
- i18n>Select existing realm</label>
+ <input
+ class="form-check-input"
+ formControlName="configType"
+ id="existingRealm"
+ type="radio"
+ (change)="onConfigTypeChange()"
+ value="existingRealm"
+ />
+ <label
+ class="custom-check-label"
+ for="existingRealm"
+ i18n
+ >Select existing realm</label
+ >
</div>
</div>
- <div class="form-group row"
- *ngIf="multisiteSetupForm.get('configType').value === 'existingRealm' && showConfigType && isMultiClusterConfigured">
- <label class="cd-col-form-label"
- for="selectedRealm"
- i18n>Select Realm</label>
+ <div
+ class="form-group row"
+ *ngIf="
+ multisiteSetupForm.get('configType').value === 'existingRealm' &&
+ showConfigType &&
+ isMultiClusterConfigured
+ "
+ >
+ <label
+ class="cd-col-form-label"
+ for="selectedRealm"
+ i18n
+ >Select Realm</label
+ >
<div class="cd-col-form-input">
- <select class="form-select"
- id="selectedRealm"
- formControlName="selectedRealm">
- <option *ngFor="let realm of realmList"
- [value]="realm">
- {{ realm }}
+ <select
+ class="form-select"
+ id="selectedRealm"
+ formControlName="selectedRealm"
+ >
+ <option
+ *ngFor="let realm of realmList"
+ [value]="realm"
+ >
+ {{ realm }}
</option>
</select>
</div>
</div>
- <div *ngIf="multisiteSetupForm.get('configType').value === 'newRealm' || !showConfigType">
+ <div
+ *ngIf="multisiteSetupForm.get('configType').value === 'newRealm' || !showConfigType"
+ >
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="realmName"
- i18n>Realm Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="realmName"
+ i18n
+ >Realm Name</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="realmName"
- formControlName="realmName">
+ <input
+ class="form-control"
+ type="text"
+ id="realmName"
+ formControlName="realmName"
+ />
<cd-help-text>
- <span i18n>Enter a unique name for the Realm. The Realm is a logical grouping of all your Zonegroups.</span>
+ <span i18n
+ >Enter a unique name for the Realm. The Realm is a logical grouping of all
+ your Zonegroups.</span
+ >
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('realmName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('realmName', formDir, 'uniqueName')"
- i18n>This realm name is already in use. Choose a unique name.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('realmName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('realmName', formDir, 'uniqueName')"
+ i18n
+ >This realm name is already in use. Choose a unique name.</span
+ >
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroupName"
- i18n>Zonegroup Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="zonegroupName"
+ i18n
+ >Zonegroup Name</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="zonegroupName"
- formControlName="zonegroupName">
+ <input
+ class="form-control"
+ type="text"
+ id="zonegroupName"
+ formControlName="zonegroupName"
+ />
<cd-help-text>
- <span i18n>Enter a name for the Zonegroup. Zonegroup will help you identify and manage the group of zones.</span>
+ <span i18n
+ >Enter a name for the Zonegroup. Zonegroup will help you identify and manage
+ the group of zones.</span
+ >
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('zonegroupName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('zonegroupName', formDir, 'uniqueName')"
- i18n>This zonegroup name is already in use. Choose a unique name.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('zonegroupName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('zonegroupName', formDir, 'uniqueName')"
+ i18n
+ >This zonegroup name is already in use. Choose a unique name.</span
+ >
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroup_endpoints"
- i18n>Zonegroup Endpoints</label>
+ <label
+ class="cd-col-form-label required"
+ for="zonegroup_endpoints"
+ i18n
+ >Zonegroup Endpoints</label
+ >
<div class="cd-col-form-input">
- <cd-select-badges id="zonegroup_endpoints"
- [data]="rgwEndpoints.value"
- [options]="rgwEndpoints.options"
- [customBadges]="true">
+ <cd-select-badges
+ id="zonegroup_endpoints"
+ [data]="rgwEndpoints.value"
+ [options]="rgwEndpoints.options"
+ [customBadges]="true"
+ >
</cd-select-badges>
<cd-help-text>
- <span i18n>Select the endpoints for the Zonegroup. Endpoints are the URLs or IP addresses from which the rgw gateways in that zonegroup can be accessed. You can select multiple endpoints in case you have multiple rgw gateways in a zonegroup</span>
+ <span i18n
+ >Select the endpoints for the Zonegroup. Endpoints are the URLs or IP
+ addresses from which the rgw gateways in that zonegroup can be accessed. You
+ can select multiple endpoints in case you have multiple rgw gateways in a
+ zonegroup</span
+ >
</cd-help-text>
</div>
</div>
</div>
</div>
<ng-container *ngSwitchCase="1">
- <div *ngIf="multisiteSetupForm.get('configType').value === 'newRealm'"
- class="ms-5">
+ <div
+ *ngIf="multisiteSetupForm.get('configType').value === 'newRealm'"
+ class="ms-5"
+ >
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroupName"
- i18n>Zone Name</label>
+ <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"
- id="zoneName"
- formControlName="zoneName">
+ <input
+ class="form-control"
+ type="text"
+ id="zoneName"
+ formControlName="zoneName"
+ />
<cd-help-text>
- <span i18n>Enter a unique name for the Zone. A Zone represents a distinct data center or geographical location within a Zonegroup.</span>
+ <span i18n
+ >Enter a unique name for the Zone. A Zone represents a distinct data center
+ or geographical location within a Zonegroup.</span
+ >
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('zoneName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('zoneName', formDir, 'uniqueName')"
- i18n>This zone name is already in use. Choose a unique name.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('zoneName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('zoneName', formDir, 'uniqueName')"
+ i18n
+ >This zone name is already in use. Choose a unique name.</span
+ >
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="zone_endpoints"
- i18n>Zone Endpoints</label>
+ <label
+ class="cd-col-form-label required"
+ for="zone_endpoints"
+ i18n
+ >Zone Endpoints</label
+ >
<div class="cd-col-form-input">
- <cd-select-badges id="zone_endpoints"
- [data]="rgwEndpoints.value"
- [options]="rgwEndpoints.options"
- [customBadges]="true"></cd-select-badges>
+ <cd-select-badges
+ id="zone_endpoints"
+ [data]="rgwEndpoints.value"
+ [options]="rgwEndpoints.options"
+ [customBadges]="true"
+ ></cd-select-badges>
<cd-help-text>
- <span i18n>Select the endpoints for the Zone. Endpoints are the URLs or IP addresses from which the rgw gateways in that zone can be accessed. You can select multiple endpoints in case you have multiple rgw gateways in a zone</span>
+ <span i18n
+ >Select the endpoints for the Zone. Endpoints are the URLs or IP addresses
+ from which the rgw gateways in that zone can be accessed. You can select
+ multiple endpoints in case you have multiple rgw gateways in a zone</span
+ >
</cd-help-text>
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="username"
- i18n>Username</label>
+ <label
+ class="cd-col-form-label required"
+ for="username"
+ i18n
+ >Username</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="username"
- formControlName="username"
- ngbTooltip="White spaces at the beginning and end will be trimmed"
- i18n-ngbTooltip
- cdTrim>
+ <input
+ class="form-control"
+ type="text"
+ id="username"
+ formControlName="username"
+ ngbTooltip="White spaces at the beginning and end will be trimmed"
+ i18n-ngbTooltip
+ cdTrim
+ />
<cd-help-text>
<span i18n>Specify the username for the system user.</span>
</cd-help-text>
- <cd-alert-panel type="info"
- [showTitle]="false">
- <span i18n>This user will be created automatically as part of the process, and it will have the necessary permissions to manage and synchronize resources across zones.</span>
+ <cd-alert-panel
+ type="info"
+ [showTitle]="false"
+ >
+ <span i18n
+ >This user will be created automatically as part of the process, and it will
+ have the necessary permissions to manage and synchronize resources across
+ zones.</span
+ >
</cd-alert-panel>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('username', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('username', formDir, 'notUnique')"
- i18n>This username is already in use. Choose a unique name.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('username', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('username', formDir, 'notUnique')"
+ i18n
+ >This username is already in use. Choose a unique name.</span
+ >
</div>
</div>
</div>
- <div *ngIf="isMultiClusterConfigured && (multisiteSetupForm.get('configType').value === 'existingRealm')"
- class="ms-5">
+ <div
+ *ngIf="
+ isMultiClusterConfigured &&
+ multisiteSetupForm.get('configType').value === 'existingRealm'
+ "
+ class="ms-5"
+ >
<ng-container *ngTemplateOutlet="replicationTemplate"></ng-container>
</div>
</ng-container>
<ng-container *ngSwitchCase="2">
- <div *ngIf="multisiteSetupForm.get('configType').value === 'newRealm' && !isMultiClusterConfigured"
- class="ms-5">
+ <div
+ *ngIf="
+ multisiteSetupForm.get('configType').value === 'newRealm' &&
+ !isMultiClusterConfigured
+ "
+ class="ms-5"
+ >
<ng-container *ngIf="loading; else nonMultiClusterFinal">
<ng-container *ngTemplateOutlet="progressTemplate"></ng-container>
</ng-container>
<ng-container *ngTemplateOutlet="reviewTemplate"></ng-container>
</ng-container>
</ng-template>
- <div *ngIf="multisiteSetupForm.get('configType').value === 'newRealm' && isMultiClusterConfigured"
- class="ms-5">
+ <div
+ *ngIf="
+ multisiteSetupForm.get('configType').value === 'newRealm' &&
+ isMultiClusterConfigured
+ "
+ class="ms-5"
+ >
<ng-container *ngTemplateOutlet="replicationTemplate"></ng-container>
</div>
- <div *ngIf="multisiteSetupForm.get('configType').value === 'existingRealm' && isMultiClusterConfigured"
- class="ms-5">
+ <div
+ *ngIf="
+ multisiteSetupForm.get('configType').value === 'existingRealm' &&
+ isMultiClusterConfigured
+ "
+ class="ms-5"
+ >
<ng-container *ngIf="!loading; else loadingTemplate">
<ng-container *ngIf="!setupCompleted; else progressCompleteTemplate">
<ng-container *ngTemplateOutlet="reviewTemplate"></ng-container>
</ng-container>
<ng-template #replicationTemplate>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="cluster"
- i18n>Replication Cluster</label>
+ <label
+ class="cd-col-form-label required"
+ for="cluster"
+ i18n
+ >Replication Cluster</label
+ >
<div class="cd-col-form-input">
- <select class="form-select"
- id="cluster"
- [(ngModel)]="selectedCluster"
- formControlName="cluster"
- name="cluster">
- <option *ngFor="let cluster_detail of clusterDetailsArray"
- [value]="cluster_detail.name">
+ <select
+ class="form-select"
+ id="cluster"
+ [(ngModel)]="selectedCluster"
+ formControlName="cluster"
+ name="cluster"
+ >
+ <option
+ *ngFor="let cluster_detail of clusterDetailsArray"
+ [value]="cluster_detail.name"
+ >
{{ cluster_detail.cluster_alias }} - {{ cluster_detail.name }}
</option>
</select>
<cd-help-text>
- <span i18n>Choose the cluster where you want to apply this multisite configuration. The selected cluster will integrate the defined Realm, Zonegroup, and Zones, enabling data synchronization and management across the multisite setup.</span>
+ <span i18n
+ >Choose the cluster where you want to apply this multisite configuration. The
+ selected cluster will integrate the defined Realm, Zonegroup, and Zones,
+ enabling data synchronization and management across the multisite setup.</span
+ >
</cd-help-text>
- <cd-alert-panel type="info"
- [showTitle]="false">
- <span i18n>Before submitting this form, please verify that the selected cluster has an active RGW (Rados Gateway) service running.</span>
+ <cd-alert-panel
+ type="info"
+ [showTitle]="false"
+ >
+ <span i18n
+ >Before submitting this form, please verify that the selected cluster has an
+ active RGW (Rados Gateway) service running.</span
+ >
</cd-alert-panel>
</div>
</div>
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="replicationZoneName"
- i18n>Replication Zone Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="replicationZoneName"
+ i18n
+ >Replication Zone Name</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- id="replicationZoneName"
- name="replicationZoneName"
- formControlName="replicationZoneName">
+ <input
+ class="form-control"
+ type="text"
+ id="replicationZoneName"
+ name="replicationZoneName"
+ formControlName="replicationZoneName"
+ />
<cd-help-text>
- <span i18n>Replication zone represents the zone to be created in the replication cluster where your data will be replicated.</span>
+ <span i18n
+ >Replication zone represents the zone to be created in the replication cluster
+ where your data will be replicated.</span
+ >
</cd-help-text>
- <span class="invalid-feedback"
- *ngIf="multisiteSetupForm.showError('replicationZoneName', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSetupForm.showError('replicationZoneName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</div>
</div>
<div class="form-group row">
<div class="cd-col-form-offset">
- <input type="checkbox"
- formControlName="secondary_archive_zone"
- id="secondary_archive_zone">
- <label for="secondary_archive_zone"
- class="custom-control-label cds-ml-3"
- i18n>Archive</label>
+ <input
+ type="checkbox"
+ formControlName="secondary_archive_zone"
+ id="secondary_archive_zone"
+ />
+ <label
+ for="secondary_archive_zone"
+ class="custom-control-label cds-ml-3"
+ i18n
+ >Archive</label
+ >
<cd-help-text>
- <span i18n>Enable archival storage to keep all object versions and protect data from deletion or corruption.</span>
+ <span i18n
+ >Enable archival storage to keep all object versions and protect data from
+ deletion or corruption.</span
+ >
</cd-help-text>
</div>
</div>
</ng-template>
- <div *ngSwitchCase="3"
- class="ms-5">
+ <div
+ *ngSwitchCase="3"
+ class="ms-5"
+ >
<div *ngIf="isMultiClusterConfigured">
<ng-container *ngIf="!loading; else loadingTemplate">
<ng-container *ngIf="!setupCompleted; else progressCompleteTemplate">
</div>
</div>
<cds-modal-footer>
- <button cdsButton="secondary"
- name="skip-cluster-selection"
- aria-label="Skip"
- (click)="onSkip()"
- type="button"
- *ngIf="stepTitles[currentStep.stepIndex]['label'] === 'Select Cluster' && multisiteSetupForm.get('configType').value === 'newRealm'"
- i18n>Skip</button>
- <button cdsButton="secondary"
- (click)="onPreviousStep()"
- [attr.aria-label]="showCancelButtonLabel()"
- type="button"
- i18n>{{ showCancelButtonLabel() }}</button>
- <button cdsButton="primary"
- (click)="onNextStep()"
- aria-label="Next"
- [disabled]="loading"
- type="button"
- i18n>{{ showSubmitButtonLabel() }}
- <cds-loading [isActive]="loading"
- [overlay]="false"
- size="sm"
- *ngIf="loading">
+ <button
+ cdsButton="secondary"
+ name="skip-cluster-selection"
+ aria-label="Skip"
+ (click)="onSkip()"
+ type="button"
+ *ngIf="
+ stepTitles[currentStep.stepIndex]['label'] === 'Select Cluster' &&
+ multisiteSetupForm.get('configType').value === 'newRealm'
+ "
+ i18n
+ >
+ Skip
+ </button>
+ <button
+ cdsButton="secondary"
+ (click)="onPreviousStep()"
+ [attr.aria-label]="showCancelButtonLabel()"
+ type="button"
+ i18n
+ >
+ {{ showCancelButtonLabel() }}
+ </button>
+ <button
+ cdsButton="primary"
+ (click)="onNextStep()"
+ aria-label="Next"
+ [disabled]="loading"
+ type="button"
+ i18n
+ >
+ {{ showSubmitButtonLabel() }}
+ <cds-loading
+ [isActive]="loading"
+ [overlay]="false"
+ size="sm"
+ *ngIf="loading"
+ >
</cds-loading>
</button>
</cds-modal-footer>
</cds-modal>
-
<ng-template #nonMultiClusterTemplate>
<ng-container *ngIf="!loading; else loadingTemplate">
- <ng-container *ngIf="!setupCompleted else exportTokenTemplate">
+ <ng-container *ngIf="!setupCompleted; else exportTokenTemplate">
<ng-container *ngTemplateOutlet="reviewTemplate"></ng-container>
</ng-container>
</ng-container>
<ng-template #progressCompleteTemplate>
<div *ngIf="isMultiClusterConfigured && !stepsToSkip['Select Cluster']; else exportTokenTemplate">
- <div class="text-center text-success"
- i18n>
+ <div
+ class="text-center text-success"
+ i18n
+ >
Multi-site replication setup is complete.
</div>
</div>
</ng-template>
<ng-template #progressTemplate>
- <cd-progress [value]="executingTask?.progress"
- [description]="executingTask?.name?.replace('progress/Multisite-Setup:', '')?.split('||')[0]?.trim()"
- [subDescription]="executingTask?.name?.replace('progress/Multisite-Setup:', '')?.split('||')[1]?.trim()">
+ <cd-progress
+ [value]="executingTask?.progress"
+ [description]="
+ executingTask?.name?.replace('progress/Multisite-Setup:', '')?.split('||')[0]?.trim()
+ "
+ [subDescription]="
+ executingTask?.name?.replace('progress/Multisite-Setup:', '')?.split('||')[1]?.trim()
+ "
+ >
</cd-progress>
</ng-template>
<ng-template #exportTokenTemplate>
@for (realminfo of realms; track realminfo; let i = $index) {
- <div class="form-item">
- <cds-text-label
- [labelInputID]="'wizard-export-realm-' + i"
- i18n
- helperText="Name of the realm that will be involved in replication."
- i18n-helperText
- >
- Realm Name
- <input
- cdsText
- readonly
- type="text"
- [id]="'wizard-export-realm-' + i"
- [value]="realminfo.realm"
- />
- </cds-text-label>
- </div>
+ <div class="form-item">
+ <cds-text-label
+ [labelInputID]="'wizard-export-realm-' + i"
+ i18n
+ helperText="Name of the realm that will be involved in replication."
+ i18n-helperText
+ >
+ Realm Name
+ <input
+ cdsText
+ readonly
+ type="text"
+ [id]="'wizard-export-realm-' + i"
+ [value]="realminfo.realm"
+ />
+ </cds-text-label>
+ </div>
- <div class="form-item form-item-append">
- <cds-text-label
- [labelInputID]="'wizard-export-token-' + i"
- i18n
- helperText="This field displays the token needed to import the multisite configuration into a secondary cluster. Copy this token securely and use it on the secondary cluster to replicate the current multisite setup. Ensure that the token is handled securely to prevent unauthorized access."
- i18n-helperText
- >
- Token
- <input
- cdsText
- readonly
- type="text"
- [id]="'wizard-export-token-' + i"
- [value]="realminfo.token"
- />
- </cds-text-label>
- <cd-copy-2-clipboard-button
- class="cds-mt-6"
- [source]="realminfo.token"
- [byId]="false"
- size="md"
- >
- </cd-copy-2-clipboard-button>
- </div>
+ <div class="form-item form-item-append">
+ <cds-text-label
+ [labelInputID]="'wizard-export-token-' + i"
+ i18n
+ helperText="This field displays the token needed to import the multisite configuration into a secondary cluster. Copy this token securely and use it on the secondary cluster to replicate the current multisite setup. Ensure that the token is handled securely to prevent unauthorized access."
+ i18n-helperText
+ >
+ Token
+ <input
+ cdsText
+ readonly
+ type="text"
+ [id]="'wizard-export-token-' + i"
+ [value]="realminfo.token"
+ />
+ </cds-text-label>
+ <cd-copy-2-clipboard-button
+ class="cds-mt-6"
+ [source]="realminfo.token"
+ [byId]="false"
+ size="md"
+ >
+ </cd-copy-2-clipboard-button>
+ </div>
- @if (i < realms.length - 1) {
- <hr />
- }
+ @if (i < realms.length - 1) {
+ <hr />
+ }
}
</ng-template>
<ng-template #reviewTemplate>
- <cd-alert-panel type="warning"
- [showTitle]="false">
+ <cd-alert-panel
+ type="warning"
+ [showTitle]="false"
+ >
<span i18n>
- During the automation process, the RGW module will be enabled on both the source and target clusters, if it is not already enabled.
- This action may cause a temporary downtime (5-10 seconds) on each cluster.
+ During the automation process, the RGW module will be enabled on both the source and target
+ clusters, if it is not already enabled. This action may cause a temporary downtime (5-10
+ seconds) on each cluster.
</span>
</cd-alert-panel>
<ng-container [ngSwitch]="multisiteSetupForm.get('configType').value">
<ng-template #newRealmInfo>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Realm Name:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b id="realmName">{{ multisiteSetupForm.get('realmName').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Realm Name:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b id="realmName">{{ multisiteSetupForm.get('realmName').value }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Zonegroup Name:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b id="zonegroupName">{{ multisiteSetupForm.get('zonegroupName').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Zonegroup Name:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b id="zonegroupName">{{ multisiteSetupForm.get('zonegroupName').value }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Zonegroup Endpoints:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ rgwEndpoints.value.join(', ') }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Zonegroup Endpoints:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ rgwEndpoints.value.join(', ') }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Zone Name:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b id="zoneName">{{ multisiteSetupForm.get('zoneName').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Zone Name:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b id="zoneName">{{ multisiteSetupForm.get('zoneName').value }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Zone Endpoints:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ rgwEndpoints.value.join(', ') }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Zone Endpoints:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ rgwEndpoints.value.join(', ') }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Username:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ multisiteSetupForm.get('username').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Username:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ multisiteSetupForm.get('username').value }}</b>
+ </div>
</div>
</ng-template>
<ng-template #existingRealmInfo>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Selected Realm:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ multisiteSetupForm.get('selectedRealm').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Selected Realm:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ multisiteSetupForm.get('selectedRealm').value }}</b>
+ </div>
</div>
</ng-template>
<ng-template #replicationInfo>
<div *ngIf="isMultiClusterConfigured && !stepsToSkip['Select Cluster']">
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Selected Replication Cluster:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ selectedCluster }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Selected Replication Cluster:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ selectedCluster }}</b>
+ </div>
</div>
<div class="form-group row">
- <legend class="cd-col-form-label"
- i18n>Replication Zone Name:</legend>
- <div class="cd-col-form-input mt-2 text-muted"><b>{{ multisiteSetupForm.get('replicationZoneName').value }}</b></div>
+ <legend
+ class="cd-col-form-label"
+ i18n
+ >
+ Replication Zone Name:
+ </legend>
+ <div class="cd-col-form-input mt-2 text-muted">
+ <b>{{ multisiteSetupForm.get('replicationZoneName').value }}</b>
+ </div>
</div>
</div>
</ng-template>
-<cds-modal size="lg"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="lg"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource }}</h3>
+ <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">
+ <form
+ name="multisiteZoneForm"
+ #formDir="ngForm"
+ [formGroup]="multisiteZoneForm"
+ novalidate
+ >
+ <div
+ cdsModalContent
+ class="modal-wrapper scroll-overflow"
+ >
<div class="form-item">
<cds-select
formControlName="selectedZonegroup"
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 zonegroup.
+ <cd-help-text *ngIf="disableDefault && action === actionLabels.CREATE"
+ >Default zone can only exist in a default zonegroup.
</cd-help-text>
<cd-help-text *ngIf="isDefaultZone">
<span>You cannot unset the default flag.</span>
[disabled]="action === actionLabels.EDIT ? true : null"
i18n
>Master
- <cd-help-text *ngIf="disableMaster">Master zone already exist for the selected zonegroup.
+ <cd-help-text *ngIf="disableMaster"
+ >Master zone already exist for the selected zonegroup.
</cd-help-text>
<cd-help-text *ngIf="isMasterZone">
<span>You cannot unset the master flag. </span>
</cd-help-text>
</cds-checkbox>
</div>
- <div *ngIf="multisiteZoneForm.get('master_zone')?.value === false"
- class="form-item">
+ <div
+ *ngIf="multisiteZoneForm.get('master_zone')?.value === false"
+ class="form-item"
+ >
<cds-checkbox
id="archive_zone"
formControlName="archive_zone"
>Archive
<cd-help-text>
<span
- >Enable archival storage to keep all object versions and protect data from deletion or corruption.</span
+ >Enable archival storage to keep all object versions and protect data from deletion or
+ corruption.</span
>
</cd-help-text>
</cds-checkbox>
i18n
>Sync from all zones
<cd-help-text>
- <span
- >Enable this option to synchronize data from all zones.</span
- >
+ <span>Enable this option to synchronize data from all zones.</span>
</cd-help-text>
<div class="cds-mt-3">
- <cd-alert-panel *ngIf="multisiteZoneForm.get('archive_zone')?.value === true"
- type="warning">
- “Sync from all zones” is disabled to avoid duplicate objects in archive zones. Please select specific zones instead.
+ <cd-alert-panel
+ *ngIf="multisiteZoneForm.get('archive_zone')?.value === true"
+ type="warning"
+ >
+ “Sync from all zones” is disabled to avoid duplicate objects in archive zones. Please
+ select specific zones instead.
</cd-alert-panel>
</div>
</cds-checkbox>
</div>
- <div *ngIf="multisiteZoneForm.get('sync_from_all')?.value === false"
- class="form-item">
- <cds-combo-box type="multi"
- selectionFeedback="top-after-reopen"
- label="Sync from zones"
- formControlName="sync_from_zones"
- id="sync_from_zones"
- [appendInline]="true"
- [items]="syncFromZonesOptions"
- i18n>
+ <div
+ *ngIf="multisiteZoneForm.get('sync_from_all')?.value === false"
+ class="form-item"
+ >
+ <cds-combo-box
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ label="Sync from zones"
+ formControlName="sync_from_zones"
+ id="sync_from_zones"
+ [appendInline]="true"
+ [items]="syncFromZonesOptions"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
<cd-help-text>
- <span i18n>Select specific zones to synchronize data from when "Sync from all zones" is disabled.</span>
+ <span i18n
+ >Select specific zones to synchronize data from when "Sync from all zones" is
+ disabled.</span
+ >
</cd-help-text>
</div>
<div class="form-item">
"
cdRequiredField="Endpoints"
[invalidText]="
- multisiteZoneForm.controls['zone_endpoints'].errors?.['required'] ? 'This field is required.' :
- multisiteZoneForm.controls['zone_endpoints'].errors?.['invalidURL'] ? 'Please enter a valid URL.' : ''
- "
+ 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
</div>
<div class="form-item">
- <cds-password-label labelInputID="access_key"
- [helperText]="AccessKeyText"
- i18n>S3 access key
+ <cds-password-label
+ labelInputID="access_key"
+ [helperText]="AccessKeyText"
+ i18n
+ >S3 access key
<input
cdsPassword
type="password"
</cds-password-label>
</div>
<div class="form-item">
- <cds-password-label labelInputID="secret_key"
- [helperText]="SecretKeyText"
- i18n>S3 secret key
+ <cds-password-label
+ labelInputID="secret_key"
+ [helperText]="SecretKeyText"
+ i18n
+ >S3 secret key
<input
cdsPassword
type="password"
</cds-password-label>
</div>
<div *ngIf="action === actionLabels.EDIT">
- <legend class="cd-header"
- i18n>Placement Targets</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Placement Targets
+ </legend>
<div class="form-item">
<cds-select
formControlName="placementTarget"
</cds-select>
</div>
<div class="form-item">
- <cds-select formControlName="placementDataPool"
- label="Data pool"
- i18n>Data pool
+ <cds-select
+ formControlName="placementDataPool"
+ label="Data pool"
+ i18n
+ >Data pool
<option
*ngFor="let pool of poolList"
</cds-select>
</div>
<div class="form-item">
- <cds-select formControlName="placementIndexPool"
- label="Index pool"
- i18n>Index pool
+ <cds-select
+ formControlName="placementIndexPool"
+ label="Index pool"
+ i18n
+ >Index pool
<option
*ngFor="let pool of poolList"
</cds-select>
</div>
<div class="form-item">
- <cds-select formControlName="placementDataExtraPool"
- label="Data extra pool"
- i18n>Data extra pool
+ <cds-select
+ formControlName="placementDataExtraPool"
+ label="Data extra pool"
+ i18n
+ >Data extra pool
<option
*ngFor="let pool of poolList"
[value]="pool.poolname"
</div>
<div>
- <legend class="cd-header"
- i18n>Storage Classes</legend>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Storage Classes
+ </legend>
<div class="form-item">
<cds-select
formControlName="storageClass"
i18n
>Storage class
- <option *ngFor="let storageClass of storageClassList"
- [value]="storageClass.key">
+ <option
+ *ngFor="let storageClass of storageClassList"
+ [value]="storageClass.key"
+ >
{{ storageClass.key }}
</option>
</cds-select>
</div>
<div class="form-item">
- <cds-select formControlName="storageDataPool"
- label="Data pool"
- i18n>Data pool
+ <cds-select
+ formControlName="storageDataPool"
+ label="Data pool"
+ i18n
+ >Data pool
<option
*ngFor="let pool of poolList"
[value]="pool.poolname"
</cds-select>
</div>
<div class="form-item">
- <cds-select formControlName="storageCompression"
- label="Compression"
- i18n>Compression
- <option *ngFor="let compression of compressionTypes"
- [value]="compression">
+ <cds-select
+ formControlName="storageCompression"
+ label="Compression"
+ i18n
+ >Compression
+ <option
+ *ngFor="let compression of compressionTypes"
+ [value]="compression"
+ >
{{ compression }}
</option>
</cds-select>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">{{ action | titlecase }} Zonegroup</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >{{ action | titlecase }} Zonegroup</ng-container
+ >
<ng-container class="modal-content">
- <form name="multisiteZonegroupForm"
- #formDir="ngForm"
- [formGroup]="multisiteZonegroupForm"
- novalidate>
- <div class="modal-body">
- <div class="form-group row">
- <label class="cd-col-form-label"
- for="selectedRealm"
- i18n>Select Realm</label>
- <div class="cd-col-form-input">
- <select class="form-select"
- id="selectedRealm"
- formControlName="selectedRealm"
- name="selectedRealm">
- <option ngValue=""
- i18n>-- Select a realm --</option>
- <option *ngFor="let realmName of realmList"
- [value]="realmName.name"
- [selected]="realmName.name === multisiteZonegroupForm.getValue('selectedRealm')">
+ <form
+ name="multisiteZonegroupForm"
+ #formDir="ngForm"
+ [formGroup]="multisiteZonegroupForm"
+ novalidate
+ >
+ <div class="modal-body">
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="selectedRealm"
+ i18n
+ >Select Realm</label
+ >
+ <div class="cd-col-form-input">
+ <select
+ class="form-select"
+ id="selectedRealm"
+ formControlName="selectedRealm"
+ name="selectedRealm"
+ >
+ <option
+ ngValue=""
+ i18n
+ >
+ -- Select a realm --
+ </option>
+ <option
+ *ngFor="let realmName of realmList"
+ [value]="realmName.name"
+ [selected]="realmName.name === multisiteZonegroupForm.getValue('selectedRealm')"
+ >
{{ realmName.name }}
- </option>
- </select>
- </div>
- </div>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroupName"
- i18n>Zonegroup Name</label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="Zonegroup name..."
- id="zonegroupName"
- name="zonegroupName"
- formControlName="zonegroupName">
- <span class="invalid-feedback"
- *ngIf="multisiteZonegroupForm.showError('zonegroupName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteZonegroupForm.showError('zonegroupName', formDir, 'uniqueName')"
- i18n>The chosen zonegroup name is already in use.</span>
- <div class="custom-control custom-checkbox">
- <input class="form-check-input"
- id="default_zonegroup"
- name="default_zonegroup"
- formControlName="default_zonegroup"
- [attr.disabled]="action === actionLabels.EDIT ? true : null"
- type="checkbox">
- <label class="form-check-label"
- for="default_zonegroup"
- i18n>Default</label>
- <span *ngIf="disableDefault && action === actionLabels.CREATE">
- <cd-helper i18n>Zonegroup doesn't belong to the default realm.</cd-helper>
- </span>
- <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_default">
- <span i18n>Please consult the <cd-doc section="rgw-multisite"></cd-doc> to follow the failover mechanism</span>
- </cd-helper>
- <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 === actionLabels.EDIT ? true : null"
- type="checkbox">
- <label class="form-check-label"
- for="master_zonegroup"
- i18n>Master</label>
- <span *ngIf="disableMaster && action === actionLabels.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>
- <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_master">
- <span i18n>Please consult the <cd-doc section="rgw-multisite"></cd-doc> to follow the failover mechanism</span>
- </cd-helper>
- <cd-helper *ngIf="action === actionLabels.EDIT && info.data.is_master">
- <span i18n>You cannot unset the master flag.</span>
- </cd-helper>
+ </option>
+ </select>
+ </div>
</div>
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zonegroupName"
+ i18n
+ >Zonegroup Name</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="Zonegroup name..."
+ id="zonegroupName"
+ name="zonegroupName"
+ formControlName="zonegroupName"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteZonegroupForm.showError('zonegroupName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteZonegroupForm.showError('zonegroupName', formDir, 'uniqueName')"
+ i18n
+ >The chosen zonegroup name is already in use.</span
+ >
+ <div class="custom-control custom-checkbox">
+ <input
+ class="form-check-input"
+ id="default_zonegroup"
+ name="default_zonegroup"
+ formControlName="default_zonegroup"
+ [attr.disabled]="action === actionLabels.EDIT ? true : null"
+ type="checkbox"
+ />
+ <label
+ class="form-check-label"
+ for="default_zonegroup"
+ i18n
+ >Default</label
+ >
+ <span *ngIf="disableDefault && action === actionLabels.CREATE">
+ <cd-helper i18n>Zonegroup doesn't belong to the default realm.</cd-helper>
+ </span>
+ <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_default">
+ <span i18n
+ >Please consult the <cd-doc section="rgw-multisite"></cd-doc> to follow
+ the failover mechanism</span
+ >
+ </cd-helper>
+ <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 === actionLabels.EDIT ? true : null"
+ type="checkbox"
+ />
+ <label
+ class="form-check-label"
+ for="master_zonegroup"
+ i18n
+ >Master</label
+ >
+ <span *ngIf="disableMaster && action === actionLabels.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>
+ <cd-helper *ngIf="action === actionLabels.EDIT && !info.data.is_master">
+ <span i18n
+ >Please consult the <cd-doc section="rgw-multisite"></cd-doc> to follow
+ the failover mechanism</span
+ >
+ </cd-helper>
+ <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>
- <div class="form-group row">
- <label class="cd-col-form-label required"
- for="zonegroup_endpoints"
- i18n>Endpoints</label>
- <div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="http://ceph-node-00.com:80"
- id="zonegroup_endpoints"
- name="zonegroup_endpoints"
- formControlName="zonegroup_endpoints">
- <span class="invalid-feedback"
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="zonegroup_endpoints"
+ i18n
+ >Endpoints</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ class="form-control"
+ type="text"
+ placeholder="http://ceph-node-00.com:80"
+ id="zonegroup_endpoints"
+ name="zonegroup_endpoints"
+ formControlName="zonegroup_endpoints"
+ />
+ <span
+ class="invalid-feedback"
*ngIf="multisiteZonegroupForm.showError('zonegroup_endpoints', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
*ngIf="multisiteZonegroupForm.showError('zonegroup_endpoints', formDir, 'invalidURL')"
- i18n>Please enter a valid URL.</span>
+ i18n
+ >Please enter a valid URL.</span
+ >
+ </div>
</div>
- </div>
- <div class="form-group row"
- *ngIf="action === actionLabels.EDIT">
- <label i18n
- for="zones"
- class="cd-col-form-label">Zones</label>
- <div class="cd-col-form-input">
- <cd-select-badges id="zones"
- [data]="zonegroupZoneNames"
- [options]="labelsOption"
- [customBadges]="true">
- </cd-select-badges><br>
- <span class="invalid-feedback"
- *ngIf="isRemoveMasterZone"
- i18n>Cannot remove master zone.</span>
+ <div
+ class="form-group row"
+ *ngIf="action === actionLabels.EDIT"
+ >
+ <label
+ i18n
+ for="zones"
+ class="cd-col-form-label"
+ >Zones</label
+ >
+ <div class="cd-col-form-input">
+ <cd-select-badges
+ id="zones"
+ [data]="zonegroupZoneNames"
+ [options]="labelsOption"
+ [customBadges]="true"
+ >
+ </cd-select-badges
+ ><br />
+ <span
+ class="invalid-feedback"
+ *ngIf="isRemoveMasterZone"
+ i18n
+ >Cannot remove master zone.</span
+ >
+ </div>
</div>
- </div>
- <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">
- <div class="card"
- [formGroup]="item">
- <div class="card-header">
- {{ (index + 1) | ordinal }}
- <span class="float-end clickable"
- name="remove_placement_target"
- (click)="removePlacementTarget(index)"
- tabindex="0"
- (keydown.enter)="removePlacementTarget(index)"
- ngbTooltip="Remove">×</span>
- </div>
+ <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"
+ >
+ <div
+ class="card"
+ [formGroup]="item"
+ >
+ <div class="card-header">
+ {{ index + 1 | ordinal }}
+ <span
+ class="float-end clickable"
+ name="remove_placement_target"
+ (click)="removePlacementTarget(index)"
+ tabindex="0"
+ (keydown.enter)="removePlacementTarget(index)"
+ ngbTooltip="Remove"
+ >×</span
+ >
+ </div>
- <div class="card-body">
- <!-- Placement Id -->
- <div class="form-group row">
- <label i18n
- class="cd-col-form-label required"
- for="placement_id">Placement Id</label>
- <div class="cd-col-form-input">
- <input type="text"
- class="form-control"
- name="placement_id"
- id="placement_id"
- formControlName="placement_id"
- placeholder="eg. default-placement">
- <span class="invalid-feedback">
- <span *ngIf="showError(index, 'placement_id', formDir, 'required')"
- i18n>This field is required.</span>
- </span>
+ <div class="card-body">
+ <!-- Placement Id -->
+ <div class="form-group row">
+ <label
+ i18n
+ class="cd-col-form-label required"
+ for="placement_id"
+ >Placement Id</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ class="form-control"
+ name="placement_id"
+ id="placement_id"
+ formControlName="placement_id"
+ placeholder="eg. default-placement"
+ />
+ <span class="invalid-feedback">
+ <span
+ *ngIf="showError(index, 'placement_id', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </span>
+ </div>
</div>
- </div>
- <!-- Tags-->
- <div class="form-group row">
- <label i18n
- class="cd-col-form-label"
- for="tags">Tags</label>
- <div class="cd-col-form-input">
- <input type="text"
- class="form-control"
- name="tags"
- id="tags"
- formControlName="tags"
- placeholder="comma separated tags, eg. default-placement, ssd">
+ <!-- Tags-->
+ <div class="form-group row">
+ <label
+ i18n
+ class="cd-col-form-label"
+ for="tags"
+ >Tags</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ class="form-control"
+ name="tags"
+ id="tags"
+ formControlName="tags"
+ placeholder="comma separated tags, eg. default-placement, ssd"
+ />
+ </div>
</div>
- </div>
- <!-- Storage Class -->
- <div class="form-group row">
- <label i18n
- class="cd-col-form-label"
- for="storage_class">Storage Class</label>
- <div class="cd-col-form-input">
- <input type="text"
- class="form-control"
- name="storage_class"
- id="storage_class"
- formControlName="storage_class"
- placeholder="eg. Standard-tier">
+ <!-- Storage Class -->
+ <div class="form-group row">
+ <label
+ i18n
+ class="cd-col-form-label"
+ for="storage_class"
+ >Storage Class</label
+ >
+ <div class="cd-col-form-input">
+ <input
+ type="text"
+ class="form-control"
+ name="storage_class"
+ id="storage_class"
+ formControlName="storage_class"
+ placeholder="eg. Standard-tier"
+ />
+ </div>
</div>
</div>
</div>
</div>
- </div>
- </ng-container>
- <button type="button"
- id="add-plc"
- class="btn btn-light float-end my-3"
- (click)="addPlacementTarget()">
- <svg [cdsIcon]="icons.add"
- [size]="icons.size16"
- class="cds-info-color">
- </svg>
- <ng-container i18n>Add placement target</ng-container>
- </button>
+ </ng-container>
+ <button
+ type="button"
+ id="add-plc"
+ class="btn btn-light float-end my-3"
+ (click)="addPlacementTarget()"
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size16"
+ class="cds-info-color"
+ ></svg>
+ <ng-container i18n>Add placement target</ng-container>
+ </button>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="multisiteZonegroupForm"
+ [submitText]="(action | titlecase) + ' ' + 'Zonegroup'"
+ ></cd-form-button-panel>
</div>
- </div>
- <div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="multisiteZonegroupForm"
- [submitText]="(action | titlecase) + ' ' + 'Zonegroup'"></cd-form-button-panel>
- </div>
</form>
</ng-container>
</cd-modal>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()">
- <cds-modal-header (closeSelect)="closeModal()"
- i18n>
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
+ <cds-modal-header
+ (closeSelect)="closeModal()"
+ i18n
+ >
{{ editing ? 'Edit' : 'Create' }} Notification configuration
- <cd-help-text [formAllFieldsRequired]="false">All fields are optional, except where marked required.</cd-help-text>
+ <cd-help-text [formAllFieldsRequired]="false"
+ >All fields are optional, except where marked required.</cd-help-text
+ >
</cds-modal-header>
<ng-container>
<section cdsModalContent>
- <form name="notificationForm"
- #formDir="ngForm"
- [formGroup]="notificationForm"
- novalidate>
+ <form
+ name="notificationForm"
+ #formDir="ngForm"
+ [formGroup]="notificationForm"
+ novalidate
+ >
<!-- Id-->
- <div cdsRow
- class="form-item form-item-append">
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<div cdsCol>
- <cds-text-label labelInputID="name"
- i18n
- i18n-helperText
- cdRequiredField="Name"
- [invalid]="notificationForm.controls.id.invalid && notificationForm.controls.id.dirty"
- [invalidText]="nameError"
- [helperText]="helpertext">Topic Name
- <input cdsText
- type="text"
- placeholder="Name..."
- i18n-placeholder
- id="name"
- autoFocus
- formControlName="id"
- [invalid]="notificationForm.controls.id.invalid && notificationForm.controls.id.dirty"/>
+ <cds-text-label
+ labelInputID="name"
+ i18n
+ i18n-helperText
+ cdRequiredField="Name"
+ [invalid]="notificationForm.controls.id.invalid && notificationForm.controls.id.dirty"
+ [invalidText]="nameError"
+ [helperText]="helpertext"
+ >Topic Name
+ <input
+ cdsText
+ type="text"
+ placeholder="Name..."
+ i18n-placeholder
+ id="name"
+ autoFocus
+ formControlName="id"
+ [invalid]="
+ notificationForm.controls.id.invalid && notificationForm.controls.id.dirty
+ "
+ />
</cds-text-label>
<ng-template #helpertext>
<span i18n>Enter a unique notification name</span>
</ng-template>
<ng-template #nameError>
- <span *ngIf="notificationForm.showError('id', formDir, 'required')"
- class="invalid-feedback">
+ <span
+ *ngIf="notificationForm.showError('id', formDir, 'required')"
+ class="invalid-feedback"
+ >
<ng-container i18n>This field is required.</ng-container>
</span>
- <span class="invalid-feedback"
- *ngIf="notificationForm.showError('id', formDir, 'duplicate')"
- i18n>The name is already in use. Please choose a different one</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="notificationForm.showError('id', formDir, 'duplicate')"
+ i18n
+ >The name is already in use. Please choose a different one</span
+ >
</ng-template>
</div>
<!-- Topic -->
<div cdsCol>
- <cds-select id="topic"
- formControlName="topic"
- cdRequiredField="Topic"
- label="Topic"
- i18n-label
- placeholder="Select a topic..."
- i18n-placeholder
- [invalid]="notificationForm.controls.topic.invalid && notificationForm.controls.topic.dirty"
- [invalidText]="topicError"
- helperText="This topic will define and control the notification settings"
- i18n-helperText>
- <option *ngIf="topicArn === null"
- value="">Loading...
- </option>
- <option [ngValue]="null"
- i18n>
- -- Select a topic --
- </option>
- <option *ngFor="let data of topicArn"
- i18n
- [ngValue]="data">
- {{ data }}
- </option>
- </cds-select>
+ <cds-select
+ id="topic"
+ formControlName="topic"
+ cdRequiredField="Topic"
+ label="Topic"
+ i18n-label
+ placeholder="Select a topic..."
+ i18n-placeholder
+ [invalid]="
+ notificationForm.controls.topic.invalid && notificationForm.controls.topic.dirty
+ "
+ [invalidText]="topicError"
+ helperText="This topic will define and control the notification settings"
+ i18n-helperText
+ >
+ <option
+ *ngIf="topicArn === null"
+ value=""
+ >
+ Loading...
+ </option>
+ <option
+ [ngValue]="null"
+ i18n
+ >
+ -- Select a topic --
+ </option>
+ <option
+ *ngFor="let data of topicArn"
+ i18n
+ [ngValue]="data"
+ >
+ {{ data }}
+ </option>
+ </cds-select>
<ng-template #topicError>
- <span *ngIf="notificationForm.showError('topic', formDir, 'required')"
- class="invalid-feedback">
+ <span
+ *ngIf="notificationForm.showError('topic', formDir, 'required')"
+ class="invalid-feedback"
+ >
<ng-container i18n>This field is required.</ng-container>
</span>
</ng-template>
</div>
<!-- Events -->
- <div cdsRow
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<div cdsCol>
- <cds-combo-box label="Event"
- type="multi"
- formControlName="event"
- placeholder="Select event..."
- [items]="eventOption"
- itemValueKey="content"
- id="event"
- cdDynamicInputCombobox
- (updatedItems)="eventOption = $event"
- i18n-placeholder
- helperText="Choose the S3 event type that will trigger the notification, such as object creation or deletion"
- i18n-helperText>
+ <cds-combo-box
+ label="Event"
+ type="multi"
+ formControlName="event"
+ placeholder="Select event..."
+ [items]="eventOption"
+ itemValueKey="content"
+ id="event"
+ cdDynamicInputCombobox
+ (updatedItems)="eventOption = $event"
+ i18n-placeholder
+ helperText="Choose the S3 event type that will trigger the notification, such as object creation or deletion"
+ i18n-helperText
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</div>
</div>
<cd-form-advanced-fieldset class="cd-header">
- <ng-container *ngFor="let key of filterTypes">
- <ng-container
- *ngTemplateOutlet="
- filterTemplate;
- context: {
- type: key,
- controls: filterControls[key],
- options: filterSettings[key].options,
- isDropdown: filterSettings[key].isDropdown,
- namePlaceholder: filterSettings[key].namePlaceholder,
- valuePlaceholder: filterSettings[key].valuePlaceholder,
- nameHelper: filterSettings[key].nameHelper,
- valueHelper: filterSettings[key].valueHelper
- }
- ">
+ <ng-container *ngFor="let key of filterTypes">
+ <ng-container
+ *ngTemplateOutlet="
+ filterTemplate;
+ context: {
+ type: key,
+ controls: filterControls[key],
+ options: filterSettings[key].options,
+ isDropdown: filterSettings[key].isDropdown,
+ namePlaceholder: filterSettings[key].namePlaceholder,
+ valuePlaceholder: filterSettings[key].valuePlaceholder,
+ nameHelper: filterSettings[key].nameHelper,
+ valueHelper: filterSettings[key].valueHelper
+ }
+ "
+ >
+ </ng-container>
</ng-container>
- </ng-container>
- </cd-form-advanced-fieldset>
+ </cd-form-advanced-fieldset>
</form>
</section>
</ng-container>
<!-- Submit Button -->
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="notificationForm"
- [submitText]="editing ? actionLabels.EDIT : actionLabels.CREATE"
- [modalForm]="true"> </cd-form-button-panel>
- </cds-modal>
-
-
- <ng-template #filterTemplate
- let-type="type"
- let-controls="controls"
- let-options="options"
- let-isDropdown="isDropdown"
- let-namePlaceholder="namePlaceholder"
- let-valuePlaceholder="valuePlaceholder"
- let-nameHelper="nameHelper"
- let-valueHelper="valueHelper">
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="notificationForm"
+ [submitText]="editing ? actionLabels.EDIT : actionLabels.CREATE"
+ [modalForm]="true"
+ >
+ </cd-form-button-panel>
+</cds-modal>
+<ng-template
+ #filterTemplate
+ let-type="type"
+ let-controls="controls"
+ let-options="options"
+ let-isDropdown="isDropdown"
+ let-namePlaceholder="namePlaceholder"
+ let-valuePlaceholder="valuePlaceholder"
+ let-nameHelper="nameHelper"
+ let-valueHelper="valueHelper"
+>
<h6 i18n>{{ typeLabels[type] }}</h6>
<div [formGroup]="notificationForm.get('filter')">
<div [formArrayName]="type">
- <div *ngFor="let group of controls.controls; let i = index"
- [formGroupName]="i">
- <div cdsRow
- class="form-item form-item-append">
+ <div
+ *ngFor="let group of controls.controls; let i = index"
+ [formGroupName]="i"
+ >
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<div cdsCol>
<ng-container *ngIf="isDropdown; else textInputName">
- <cds-select [id]="type + '-name-' + i"
- formControlName="Name"
- label="Name"
- i18n-label
- [helperText]="nameHelper"
- i18n-helperText>
- <option *ngFor="let filter of s3KeyFilterValue"
- [value]="filter">{{ filter }}</option>
+ <cds-select
+ [id]="type + '-name-' + i"
+ formControlName="Name"
+ label="Name"
+ i18n-label
+ [helperText]="nameHelper"
+ i18n-helperText
+ >
+ <option
+ *ngFor="let filter of s3KeyFilterValue"
+ [value]="filter"
+ >
+ {{ filter }}
+ </option>
</cds-select>
</ng-container>
<ng-template #textInputName>
- <cds-text-label [labelInputID]="type + '-name-' + i"
- i18n-label
- [helperText]="nameHelper"
- i18n-helperText>
+ <cds-text-label
+ [labelInputID]="type + '-name-' + i"
+ i18n-label
+ [helperText]="nameHelper"
+ i18n-helperText
+ >
Name
- <input cdsText
- type="text"
- [placeholder]="namePlaceholder"
- formControlName="Name"
- i18n />
+ <input
+ cdsText
+ type="text"
+ [placeholder]="namePlaceholder"
+ formControlName="Name"
+ i18n
+ />
</cds-text-label>
</ng-template>
</div>
<div cdsCol>
- <cds-text-label [labelInputID]="type + '-value-' + i"
- i18n-label
- [helperText]="valueHelper"
- i18n-helperText>
+ <cds-text-label
+ [labelInputID]="type + '-value-' + i"
+ i18n-label
+ [helperText]="valueHelper"
+ i18n-helperText
+ >
Value
- <input cdsText
- type="text"
- [placeholder]="valuePlaceholder"
- formControlName="Value"
- i18n />
+ <input
+ cdsText
+ type="text"
+ [placeholder]="valuePlaceholder"
+ formControlName="Value"
+ i18n
+ />
</cds-text-label>
</div>
- <div cdsCol
- [columnNumbers]="{ lg: 1, md: 1 }"
- class="item-action-btn spacing">
- <cds-icon-button kind="primary"
- size="sm"
- (click)="addRow(type, i)">
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"></svg>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1, md: 1 }"
+ class="item-action-btn spacing"
+ >
+ <cds-icon-button
+ kind="primary"
+ size="sm"
+ (click)="addRow(type, i)"
+ >
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
- <div cdsCol
- [columnNumbers]="{ lg: 1, md: 1 }"
- class="item-action-btn spacing">
- <cds-icon-button kind="danger"
- size="sm"
- (click)="removeRow(type, i)">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1, md: 1 }"
+ class="item-action-btn spacing"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="sm"
+ (click)="removeRow(type, i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
</div>
</div>
</div>
</ng-template>
-
-<main cdsGrid
- [fullWidth]="true"
- [narrow]="true"
- class="rgw-overview cds-mt-5">
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 16}">
- <cd-productive-card
- [applyShadow]="false">
+<main
+ cdsGrid
+ [fullWidth]="true"
+ [narrow]="true"
+ class="rgw-overview cds-mt-5"
+>
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
+ <cd-productive-card [applyShadow]="false">
<ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>Overview</h2>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Overview
+ </h2>
</ng-template>
<div class="rgw-overview-grid">
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Gateway</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/daemon">{{ rgwDaemonCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Gateway</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/daemon"
+ >{{ rgwDaemonCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Realm</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/multisite">{{ rgwRealmCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Realm</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/multisite"
+ >{{ rgwRealmCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Zonegroup</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/multisite">{{ rgwZonegroupCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Zonegroup</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/multisite"
+ >{{ rgwZonegroupCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Zone</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/multisite">{{ rgwZoneCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Zone</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/multisite"
+ >{{ rgwZoneCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Bucket</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/bucket">{{ rgwBucketCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Bucket</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/bucket"
+ >{{ rgwBucketCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>User</span>
- <a class="cds--link cds--type-body-compact-01"
- routerLink="/rgw/user">{{ UserCount }}</a>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >User</span
+ >
+ <a
+ class="cds--link cds--type-body-compact-01"
+ routerLink="/rgw/user"
+ >{{ UserCount }}</a
+ >
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Object</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Object</span
+ >
<span class="cds--type-body-compact-01">{{ objectCount }}</span>
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Used Capacity</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Used Capacity</span
+ >
<span class="cds--type-body-compact-01">{{ totalPoolUsedBytes | dimlessBinary }}</span>
</div>
<div class="rgw-overview-grid__item">
- <span class="cds--type-label-01"
- i18n>Average Object Size</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Average Object Size</span
+ >
<span class="cds--type-body-compact-01">{{ averageObjectSize | dimlessBinary }}</span>
</div>
</div>
</div>
</div>
- <div cdsRow
- class="cds-mb-5">
- <div cdsCol
- [columnNumbers]="{lg: 16}">
- <cd-productive-card
- [applyShadow]="false">
+ <div
+ cdsRow
+ class="cds-mb-5"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
+ <cd-productive-card [applyShadow]="false">
<ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>Performance Statistics</h2>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Performance Statistics
+ </h2>
<cd-time-picker
[dropdownSize]="'sm'"
[label]="'Time Span'"
(selectedTime)="getPrometheusData($event)"
></cd-time-picker>
</ng-template>
- <div cdsGrid
- [narrow]="true"
- [condensed]="false"
- [fullWidth]="true">
- <div cdsRow
- [narrow]="true">
- <div cdsCol
- class="cds-mb-5"
- [columnNumbers]="{lg: 5, md: 8, sm: 12}">
+ <div
+ cdsGrid
+ [narrow]="true"
+ [condensed]="false"
+ [fullWidth]="true"
+ >
+ <div
+ cdsRow
+ [narrow]="true"
+ >
+ <div
+ cdsCol
+ class="cds-mb-5"
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ >
<cd-area-chart
chartTitle="Requests/sec"
i18n-chartTitle
[dataUnit]="''"
- [rawData]="requestsChartData">
+ [rawData]="requestsChartData"
+ >
</cd-area-chart>
</div>
- <div cdsCol
- class="cds-mb-5"
- [columnNumbers]="{lg: 5, md: 8, sm: 12}">
+ <div
+ cdsCol
+ class="cds-mb-5"
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ >
<cd-area-chart
chartTitle="Latency"
i18n-chartTitle
[dataUnit]="'ms'"
[decimals]="2"
- [rawData]="latencyChartData">
+ [rawData]="latencyChartData"
+ >
</cd-area-chart>
</div>
- <div cdsCol
- class="cds-mb-5"
- [columnNumbers]="{lg: 5, md: 8, sm: 12}">
+ <div
+ cdsCol
+ class="cds-mb-5"
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ >
<cd-area-chart
chartTitle="Bandwidth"
i18n-chartTitle
[dataUnit]="'B'"
- [rawData]="bandwidthChartData">
+ [rawData]="bandwidthChartData"
+ >
</cd-area-chart>
</div>
</div>
</div>
<div cdsRow>
- <div cdsCol
- [columnNumbers]="{lg: 16}">
- <cd-productive-card
- [applyShadow]="false">
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 16 }"
+ >
+ <cd-productive-card [applyShadow]="false">
<ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>Multi-Site Sync Status</h2>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Multi-Site Sync Status
+ </h2>
</ng-template>
<ng-template #notConfigured>
- <cd-alert-panel type="info"
- i18n>
- Multi-site needs to be configured in order to see the multi-site sync status.
- Please consult the <cd-doc section="multisite"></cd-doc> on how to configure and enable the multi-site functionality.
+ <cd-alert-panel
+ type="info"
+ i18n
+ >
+ Multi-site needs to be configured in order to see the multi-site sync status. Please
+ consult the <cd-doc section="multisite"></cd-doc> on how to configure and
+ enable the multi-site functionality.
</cd-alert-panel>
</ng-template>
@if (loading) {
<div class="multisite-sync__loading">
- <cds-loading [isActive]="true"
- size="sm"></cds-loading>
+ <cds-loading
+ [isActive]="true"
+ size="sm"
+ ></cds-loading>
</div>
}
@if (multisiteSyncStatus$ | async) {
@if (showMultisiteCard) {
<div class="multisite-sync__layout">
<div class="multisite-sync__primary">
- <h4 class="cds--type-heading-compact-01 multisite-sync__section-title"
- i18n>Primary Source Zone</h4>
+ <h4
+ class="cds--type-heading-compact-01 multisite-sync__section-title"
+ i18n
+ >
+ Primary Source Zone
+ </h4>
<div class="multisite-sync__primary-content">
@if (loading) {
<div class="multisite-sync__loading">
- <cds-loading [isActive]="true"
- size="sm"></cds-loading>
+ <cds-loading
+ [isActive]="true"
+ size="sm"
+ ></cds-loading>
</div>
} @else {
- <cd-rgw-sync-primary-zone [realm]="realm"
- [zonegroup]="zonegroup"
- [zone]="zone">
+ <cd-rgw-sync-primary-zone
+ [realm]="realm"
+ [zonegroup]="zonegroup"
+ [zone]="zone"
+ >
</cd-rgw-sync-primary-zone>
}
</div>
</div>
<div class="multisite-sync__source-zones">
- <h4 class="cds--type-heading-compact-01 multisite-sync__section-title multisite-sync__section-title--centered"
- i18n>Source Zones</h4>
+ <h4
+ class="cds--type-heading-compact-01 multisite-sync__section-title multisite-sync__section-title--centered"
+ i18n
+ >
+ Source Zones
+ </h4>
@if (loading) {
<div class="multisite-sync__loading">
- <cds-loading [isActive]="true"
- size="sm"></cds-loading>
+ <cds-loading
+ [isActive]="true"
+ size="sm"
+ ></cds-loading>
</div>
} @else {
<div class="multisite-sync__zones-grid">
@for (zone of replicaZonesInfo; track zone) {
<cds-tile class="multisite-sync__zone-tile">
<h5 class="multisite-sync__zone-header">
- <svg [cdsIcon]="icons.deploy"
- [size]="icons.size20"></svg>
+ <svg
+ [cdsIcon]="icons.deploy"
+ [size]="icons.size20"
+ ></svg>
<cds-tag class="tag-info">{{ zone.name }}</cds-tag>
</h5>
<div class="multisite-sync__sync-columns">
@for (title of chartTitles; track title) {
- <div class="multisite-sync__sync-item"
- [class.multisite-sync__sync-item--bordered]="title === 'Data Sync'">
- <span class="cds--type-body-compact-01 multisite-sync__sync-title">{{ title }}</span>
+ <div
+ class="multisite-sync__sync-item"
+ [class.multisite-sync__sync-item--bordered]="title === 'Data Sync'"
+ >
+ <span class="cds--type-body-compact-01 multisite-sync__sync-title">{{
+ title
+ }}</span>
@if (title === 'Metadata Sync') {
<cd-rgw-sync-metadata-info [metadataSyncInfo]="metadataSyncInfo">
</cd-rgw-sync-metadata-info>
}
@if (title === 'Data Sync') {
- <cd-rgw-sync-data-info [zone]="zone">
- </cd-rgw-sync-data-info>
+ <cd-rgw-sync-data-info [zone]="zone"> </cd-rgw-sync-data-info>
}
</div>
}
</div>
</div>
</main>
-
-<legend i18n>{{type === 'user'? 'User Rate Limit': 'Bucket Rate Limit'}}</legend>
+<legend i18n>{{ type === 'user' ? 'User Rate Limit' : 'Bucket Rate Limit' }}</legend>
<table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr>
- <td i18n
- class="bold w-25">Enabled</td>
- <td class="w-75">{{ rateLimitConfig.enabled | booleanText }}</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Enabled
+ </td>
+ <td class="w-75">{{ rateLimitConfig.enabled | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum Read Ops</td>
- <td *ngIf="!rateLimitConfig.enabled">-</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_ops <= 0"
- i18n>Unlimited</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_ops > 0">
- {{ rateLimitConfig.max_read_ops}}
- </td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum Read Ops
+ </td>
+ <td *ngIf="!rateLimitConfig.enabled">-</td>
+ <td
+ *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_ops <= 0"
+ i18n
+ >
+ Unlimited
+ </td>
+ <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_ops > 0">
+ {{ rateLimitConfig.max_read_ops }}
+ </td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum Write Ops</td>
- <td *ngIf="!rateLimitConfig.enabled">-</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_ops <= 0"
- i18n>Unlimited</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_ops > 0">
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum Write Ops
+ </td>
+ <td *ngIf="!rateLimitConfig.enabled">-</td>
+ <td
+ *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_ops <= 0"
+ i18n
+ >
+ Unlimited
+ </td>
+ <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_ops > 0">
{{ rateLimitConfig.max_write_ops }}
- </td>
+ </td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum Read Bytes</td>
- <td *ngIf="!rateLimitConfig.enabled">-</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_bytes <= 0"
- i18n>Unlimited</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_bytes > 0">
- {{ rateLimitConfig.max_read_bytes | dimlessBinaryPerMinute}}
- </td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum Read Bytes
+ </td>
+ <td *ngIf="!rateLimitConfig.enabled">-</td>
+ <td
+ *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_bytes <= 0"
+ i18n
+ >
+ Unlimited
+ </td>
+ <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_read_bytes > 0">
+ {{ rateLimitConfig.max_read_bytes | dimlessBinaryPerMinute }}
+ </td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum Write Bytes</td>
- <td *ngIf="!rateLimitConfig.enabled">-</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_bytes <= 0"
- i18n>Unlimited</td>
- <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_bytes > 0">
- {{ rateLimitConfig.max_write_bytes | dimlessBinaryPerMinute}}
- </td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum Write Bytes
+ </td>
+ <td *ngIf="!rateLimitConfig.enabled">-</td>
+ <td
+ *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_bytes <= 0"
+ i18n
+ >
+ Unlimited
+ </td>
+ <td *ngIf="rateLimitConfig.enabled && rateLimitConfig.max_write_bytes > 0">
+ {{ rateLimitConfig.max_write_bytes | dimlessBinaryPerMinute }}
+ </td>
</tr>
</tbody>
</table>
-
<fieldset *ngIf="type">
- <legend class="cd-header"
- i18n>
+ <legend
+ class="cd-header"
+ i18n
+ >
Rate Limit
<cd-help-text *ngIf="type === 'user'">
The User Rate Limit controls the max read/write operations and data per minute for each user.
bucket.
</cd-help-text>
</legend>
- <form name="form"
- #frm="ngForm"
- [formGroup]="form"
- novalidate>
- <div class="row"
- *ngIf="!!globalRateLimit && globalRateLimit.enabled">
+ <form
+ name="form"
+ #frm="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
+ <div
+ class="row"
+ *ngIf="!!globalRateLimit && globalRateLimit.enabled"
+ >
<div class="col-3"></div>
<div class="col-9">
<div>
- <cd-alert-panel type="info"
- class="me-1"
- id="global-ratelimit-info"
- i18n>
+ <cd-alert-panel
+ type="info"
+ class="me-1"
+ id="global-ratelimit-info"
+ i18n
+ >
<div>
<span class="bold">Global Rate Limit</span> <br />Max. read bytes :
{{ globalRateLimit.max_read_bytes | dimlessBinaryPerMinute }} <br />Max. read ops :
<!-- Enabled -->
<div class="form-item">
- <cds-checkbox id="rate_limit_enabled"
- formControlName="rate_limit_enabled">
+ <cds-checkbox
+ id="rate_limit_enabled"
+ formControlName="rate_limit_enabled"
+ >
<ng-container i18n>Enabled</ng-container>
<cd-help-text i18n>Toggle to enable or disable the rate limit settings.</cd-help-text>
</cds-checkbox>
</div>
<!-- Unlimited read ops -->
- <div class="form-item"
- *ngIf="form.controls.rate_limit_enabled.value">
- <cds-checkbox id="rate_limit_max_readOps_unlimited"
- formControlName="rate_limit_max_readOps_unlimited">
+ <div
+ class="form-item"
+ *ngIf="form.controls.rate_limit_enabled.value"
+ >
+ <cds-checkbox
+ id="rate_limit_max_readOps_unlimited"
+ formControlName="rate_limit_max_readOps_unlimited"
+ >
<ng-container i18n>Unlimited read ops</ng-container>
<cd-help-text i18n>Select this box to allow unlimited read operations.</cd-help-text>
</cds-checkbox>
form.controls.rate_limit_enabled.value && !form.getValue('rate_limit_max_readOps_unlimited')
"
>
- <cds-number id="rate_limit_max_readOps"
- formControlName="rate_limit_max_readOps"
- label="Maximum read ops"
- i18n-label
- cdRequiredField="Maximum read ops"
- helperText="Limits the number of read operations per minute for a user."
- i18n-helperText
- [invalid]="form.controls.rate_limit_max_readOps.invalid && form.controls.rate_limit_max_readOps.dirty"
- [invalidText]="rateLimitMaxReadOpsError">
+ <cds-number
+ id="rate_limit_max_readOps"
+ formControlName="rate_limit_max_readOps"
+ label="Maximum read ops"
+ i18n-label
+ cdRequiredField="Maximum read ops"
+ helperText="Limits the number of read operations per minute for a user."
+ i18n-helperText
+ [invalid]="
+ form.controls.rate_limit_max_readOps.invalid && form.controls.rate_limit_max_readOps.dirty
+ "
+ [invalidText]="rateLimitMaxReadOpsError"
+ >
</cds-number>
<ng-template #rateLimitMaxReadOpsError>
</div>
<!-- Unlimited Write Ops -->
- <div class="form-item"
- *ngIf="form.controls.rate_limit_enabled.value">
- <cds-checkbox id="rate_limit_max_writeOps_unlimited"
- formControlName="rate_limit_max_writeOps_unlimited">
+ <div
+ class="form-item"
+ *ngIf="form.controls.rate_limit_enabled.value"
+ >
+ <cds-checkbox
+ id="rate_limit_max_writeOps_unlimited"
+ formControlName="rate_limit_max_writeOps_unlimited"
+ >
<ng-container i18n>Unlimited write ops</ng-container>
<cd-help-text i18n>Select this box to allow unlimited write operations.</cd-help-text>
</cds-checkbox>
!form.getValue('rate_limit_max_writeOps_unlimited')
"
>
- <cds-number id="rate_limit_max_writeOps"
- formControlName="rate_limit_max_writeOps"
- label="Maximum write ops"
- i18n-label
- cdRequiredField="Maximum write ops"
- helperText="Limits the number of write operations per minute for a user."
- i18n-helperText
- [invalid]="form.controls.rate_limit_max_writeOps.invalid && form.controls.rate_limit_max_writeOps.dirty"
- [invalidText]="rateLimitMaxWriteOpsError">
+ <cds-number
+ id="rate_limit_max_writeOps"
+ formControlName="rate_limit_max_writeOps"
+ label="Maximum write ops"
+ i18n-label
+ cdRequiredField="Maximum write ops"
+ helperText="Limits the number of write operations per minute for a user."
+ i18n-helperText
+ [invalid]="
+ form.controls.rate_limit_max_writeOps.invalid &&
+ form.controls.rate_limit_max_writeOps.dirty
+ "
+ [invalidText]="rateLimitMaxWriteOpsError"
+ >
</cds-number>
<ng-template #rateLimitMaxWriteOpsError>
</div>
<!-- Unlimited Read Bytes -->
- <div class="form-item"
- *ngIf="form.controls.rate_limit_enabled.value">
- <cds-checkbox id="rate_limit_max_readBytes_unlimited"
- formControlName="rate_limit_max_readBytes_unlimited">
+ <div
+ class="form-item"
+ *ngIf="form.controls.rate_limit_enabled.value"
+ >
+ <cds-checkbox
+ id="rate_limit_max_readBytes_unlimited"
+ formControlName="rate_limit_max_readBytes_unlimited"
+ >
<ng-container i18n>Unlimited read bytes</ng-container>
<cd-help-text i18n>Select this box to allow unlimited read bytes.</cd-help-text>
</cds-checkbox>
!form.getValue('rate_limit_max_readBytes_unlimited')
"
>
- <cds-text-label labelInputID="rate_limit_max_readBytes"
- cdRequiredField="Maximum read bytes"
- helperText="Limits the number of read bytes per minute for a user."
- i18n-helperText
- [invalid]="form.controls.rate_limit_max_readBytes.invalid && form.controls.rate_limit_max_readBytes.dirty"
- [invalidText]="maxReadBytesError">
- <input cdsText
- id="rate_limit_max_readBytes"
- formControlName="rate_limit_max_readBytes"
- defaultUnit="b"
- [invalid]="form.controls.rate_limit_max_readBytes.invalid && form.controls.rate_limit_max_readBytes.dirty"
- cdDimlessBinaryPerMinute>
+ <cds-text-label
+ labelInputID="rate_limit_max_readBytes"
+ cdRequiredField="Maximum read bytes"
+ helperText="Limits the number of read bytes per minute for a user."
+ i18n-helperText
+ [invalid]="
+ form.controls.rate_limit_max_readBytes.invalid &&
+ form.controls.rate_limit_max_readBytes.dirty
+ "
+ [invalidText]="maxReadBytesError"
+ >
+ <input
+ cdsText
+ id="rate_limit_max_readBytes"
+ formControlName="rate_limit_max_readBytes"
+ defaultUnit="b"
+ [invalid]="
+ form.controls.rate_limit_max_readBytes.invalid &&
+ form.controls.rate_limit_max_readBytes.dirty
+ "
+ cdDimlessBinaryPerMinute
+ />
</cds-text-label>
<ng-template #maxReadBytesError>
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'required')"
- i18n>This field is required.</span>
+ i18n
+ >This field is required.</span
+ >
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'rateByteMaxSize')"
- i18n>The value is not valid.</span>
+ i18n
+ >The value is not valid.</span
+ >
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'min')"
- i18n>Enter a positive number.</span>
+ i18n
+ >Enter a positive number.</span
+ >
</ng-template>
</div>
<!-- Unlimited Write Bytes -->
- <div class="form-item"
- *ngIf="form.controls.rate_limit_enabled.value">
- <cds-checkbox id="rate_limit_max_writeBytes_unlimited"
- formControlName="rate_limit_max_writeBytes_unlimited">
+ <div
+ class="form-item"
+ *ngIf="form.controls.rate_limit_enabled.value"
+ >
+ <cds-checkbox
+ id="rate_limit_max_writeBytes_unlimited"
+ formControlName="rate_limit_max_writeBytes_unlimited"
+ >
<ng-container i18n>Unlimited write bytes</ng-container>
<cd-help-text i18n>Select this box to allow unlimited write bytes.</cd-help-text>
</cds-checkbox>
*ngIf="
form.controls.rate_limit_enabled.value &&
!form.getValue('rate_limit_max_writeBytes_unlimited')
- ">
- <cds-text-label labelInputID="rate_limit_max_writeBytes"
- cdRequiredField="Maximum write bytes"
- helperText="Limits the number of write bytes per minute for a user."
- i18n-helperText
- [invalid]="form.controls.rate_limit_max_writeBytes.invalid && form.controls.rate_limit_max_writeBytes.dirty"
- [invalidText]="maxWriteBytesError">
- <input cdsText
- id="rate_limit_max_writeBytes"
- formControlName="rate_limit_max_writeBytes"
- defaultUnit="b"
- [invalid]="form.controls.rate_limit_max_writeBytes.invalid && form.controls.rate_limit_max_writeBytes.dirty"
- cdDimlessBinaryPerMinute>
+ "
+ >
+ <cds-text-label
+ labelInputID="rate_limit_max_writeBytes"
+ cdRequiredField="Maximum write bytes"
+ helperText="Limits the number of write bytes per minute for a user."
+ i18n-helperText
+ [invalid]="
+ form.controls.rate_limit_max_writeBytes.invalid &&
+ form.controls.rate_limit_max_writeBytes.dirty
+ "
+ [invalidText]="maxWriteBytesError"
+ >
+ <input
+ cdsText
+ id="rate_limit_max_writeBytes"
+ formControlName="rate_limit_max_writeBytes"
+ defaultUnit="b"
+ [invalid]="
+ form.controls.rate_limit_max_writeBytes.invalid &&
+ form.controls.rate_limit_max_writeBytes.dirty
+ "
+ cdDimlessBinaryPerMinute
+ />
</cds-text-label>
<ng-template #maxWriteBytesError>
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'required')"
- i18n>This field is required.</span>
+ i18n
+ >This field is required.</span
+ >
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'rateByteMaxSize')"
- i18n>The value is not valid.</span>
+ i18n
+ >The value is not valid.</span
+ >
<span
class="invalid-feedback"
*ngIf="form.showError('rate_limit_max_readBytes', frm, 'min')"
- i18n>Enter a positive number.</span>
+ i18n
+ >Enter a positive number.</span
+ >
</ng-template>
</div>
</form>
<ng-container *ngIf="!!selection">
- <cds-tabs type="contained"
- theme="light">
+ <cds-tabs
+ type="contained"
+ theme="light"
+ >
<cds-tab heading="Details">
<table
class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
data-testid="rgw-storage-details"
>
<tbody>
- @if(isTierMatch( TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)){
- <tr>
- <td class="bold"
- i18n>
- Target Path
- <cd-helper class="text-pre-wrap">
- <span>
- {{ targetPathText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.target_path }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Access key
- <cd-helper class="text-pre-wrap">
- <span>
- {{ targetAccessKeyText }}
- </span>
- </cd-helper>
- </td>
- <td>
- <div cdsCol
- [columnNumbers]="{ md: 4 }"
- class="d-flex">
- <input
- cdsPassword
- type="password"
- readonly
- id="access_key"
- [value]="selection?.access_key"
- />
- <button type="button"
- class="btn btn-light"
- cdPasswordButton="access_key"
- aria-label="Toggle access key visibility"
- i18n-aria-label></button>
- <cd-copy-2-clipboard-button source="access_key"> </cd-copy-2-clipboard-button>
- </div>
- </td>
- </tr>
- }
- @if(isTierMatch( TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)){
- <tr>
- <td class="bold"
- i18n>
- Host Style
- <cd-helper class="text-pre-wrap">
- <span>{{ hostStyleText }}</span>
- </cd-helper>
- </td>
- <td>{{ selection?.host_style }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Head Object (Stub File)
- <cd-helper class="text-pre-wrap">
- <span> {{ retainHeadObjectText }}</span>
- </cd-helper>
- </td>
- <td>{{ selection?.retain_head_object ? 'Enabled' : 'Disabled' }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Allow Read Through
- <cd-helper class="text-pre-wrap">
- <span>
- {{ allowReadThroughText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.allow_read_through ? 'Enabled' : 'Disabled' }}</td>
- </tr>
- } @if(isTierMatch(TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER) &&
- (selection?.allow_read_through)) {
- <tr>
- <td class="bold"
- i18n>
- Read through Restore Days
- <cd-helper class="text-pre-wrap">
- <span>
- {{ readthroughrestoreDaysText }}
- </span>
- </cd-helper>
- </td>
- <td>
- {{ selection?.read_through_restore_days }}
- {{ selection?.read_through_restore_days === 1 ? 'Day' : 'Days' }}
- </td>
- </tr>
- } @if(isTierMatch( TIER_TYPE_DISPLAY.GLACIER)){
- <tr>
- <td class="bold"
- i18n>
- Glacier Restore Days
- <cd-helper class="text-pre-wrap">
- <span>
- {{ glacierRestoreDayText }}
- </span>
- </cd-helper>
- </td>
- <td> {{ selection?.glacier_restore_days }}
- {{ selection?.glacier_restore_days === 1 ? 'Day' : 'Days' }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Glacier Restore Tier Type
- <cd-helper class="text-pre-wrap">
- <span>
- {{ glacierRestoreTiertypeText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.glacier_restore_tier_type }}</td>
- </tr>
- } @if(isTierMatch( TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)){
- <tr>
- <td class="bold"
- i18n>
- Restore Storage Class
- <cd-helper class="text-pre-wrap">
- <span>
- {{ restoreStorageClassText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.restore_storage_class }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Multipart Minimum Part Size
- <cd-helper class="text-pre-wrap">
- <span>
- {{ multipartMinPartText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.multipart_min_part_size | dimlessBinary }}</td>
- </tr>
- <tr>
- <td class="bold"
- i18n>
- Multipart Sync Threshold
- <cd-helper class="text-pre-wrap">
- <span>
- {{ multipartSyncThreholdText }}
- </span>
- </cd-helper>
- </td>
- <td>{{ selection?.multipart_sync_threshold | dimlessBinary }}</td>
- </tr>
- } @if(selection?.acl_mappings?.length > 0) {
- <tr>
- <td class="bold w-25"
- i18n>ACLs</td>
- <td>
- <ng-container *ngFor="let type of groupedACLs | keyvalue">
- <div class="mb-2">
- <div class="cds--label">{{ type.key }}:</div>
- <div *ngFor="let item of type.value"
- [cdsStack]="'horizontal'"
- class="mt-1">
- <cds-tag size="sm"
- class="tags-background-gray">
- {{ item.source_id }} : {{ item.dest_id }}
- </cds-tag>
- </div>
+ @if (isTierMatch(TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)) {
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Target Path
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ targetPathText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.target_path }}</td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Access key
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ targetAccessKeyText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>
+ <div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ class="d-flex"
+ >
+ <input
+ cdsPassword
+ type="password"
+ readonly
+ id="access_key"
+ [value]="selection?.access_key"
+ />
+ <button
+ type="button"
+ class="btn btn-light"
+ cdPasswordButton="access_key"
+ aria-label="Toggle access key visibility"
+ i18n-aria-label
+ ></button>
+ <cd-copy-2-clipboard-button source="access_key"> </cd-copy-2-clipboard-button>
</div>
- </ng-container>
- </td>
- </tr>
- }
- @if (isTierMatch(TIER_TYPE.LOCAL)) {
- <tr>
- <td class="bold">
- Zone
- <cd-helper class="text-pre-wrap">
- <span i18n>
- A zone defines a logical group that consists of one or more Ceph Object Gateway instances.
- </span>
- </cd-helper>
- </td>
- <td>
-@if (loading) {
- <cds-skeleton-text
- [lines]="1"
- [minLineWidth]="100"
- [maxLineWidth]="200">
- </cds-skeleton-text>
- } @else {
- <span>{{ localStorageClassDetails?.zone_name }}</span>
- }
- </td>
- </tr>
- <tr>
- <td class="bold">
- Data Pool
- <cd-helper class="text-pre-wrap">
- <span i18n>
+ </td>
+ </tr>
+ }
+ @if (isTierMatch(TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)) {
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Host Style
+ <cd-helper class="text-pre-wrap">
+ <span>{{ hostStyleText }}</span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.host_style }}</td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Head Object (Stub File)
+ <cd-helper class="text-pre-wrap">
+ <span> {{ retainHeadObjectText }}</span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.retain_head_object ? 'Enabled' : 'Disabled' }}</td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Allow Read Through
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ allowReadThroughText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.allow_read_through ? 'Enabled' : 'Disabled' }}</td>
+ </tr>
+ }
+ @if (
+ isTierMatch(TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER) &&
+ selection?.allow_read_through
+ ) {
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Read through Restore Days
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ readthroughrestoreDaysText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>
+ {{ selection?.read_through_restore_days }}
+ {{ selection?.read_through_restore_days === 1 ? 'Day' : 'Days' }}
+ </td>
+ </tr>
+ }
+ @if (isTierMatch(TIER_TYPE_DISPLAY.GLACIER)) {
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Glacier Restore Days
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ glacierRestoreDayText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>
+ {{ selection?.glacier_restore_days }}
+ {{ selection?.glacier_restore_days === 1 ? 'Day' : 'Days' }}
+ </td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Glacier Restore Tier Type
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ glacierRestoreTiertypeText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.glacier_restore_tier_type }}</td>
+ </tr>
+ }
+ @if (isTierMatch(TIER_TYPE_DISPLAY.CLOUD_TIER, TIER_TYPE_DISPLAY.GLACIER)) {
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Restore Storage Class
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ restoreStorageClassText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.restore_storage_class }}</td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Multipart Minimum Part Size
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ multipartMinPartText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.multipart_min_part_size | dimlessBinary }}</td>
+ </tr>
+ <tr>
+ <td
+ class="bold"
+ i18n
+ >
+ Multipart Sync Threshold
+ <cd-helper class="text-pre-wrap">
+ <span>
+ {{ multipartSyncThreholdText }}
+ </span>
+ </cd-helper>
+ </td>
+ <td>{{ selection?.multipart_sync_threshold | dimlessBinary }}</td>
+ </tr>
+ }
+ @if (selection?.acl_mappings?.length > 0) {
+ <tr>
+ <td
+ class="bold w-25"
+ i18n
+ >
+ ACLs
+ </td>
+ <td>
+ <ng-container *ngFor="let type of groupedACLs | keyvalue">
+ <div class="mb-2">
+ <div class="cds--label">{{ type.key }}:</div>
+ <div
+ *ngFor="let item of type.value"
+ [cdsStack]="'horizontal'"
+ class="mt-1"
+ >
+ <cds-tag
+ size="sm"
+ class="tags-background-gray"
+ >
+ {{ item.source_id }} : {{ item.dest_id }}
+ </cds-tag>
+ </div>
+ </div>
+ </ng-container>
+ </td>
+ </tr>
+ }
+ @if (isTierMatch(TIER_TYPE.LOCAL)) {
+ <tr>
+ <td class="bold">
+ Zone
+ <cd-helper class="text-pre-wrap">
+ <span i18n>
+ A zone defines a logical group that consists of one or more Ceph Object Gateway
+ instances.
+ </span>
+ </cd-helper>
+ </td>
+ <td>
+ @if (loading) {
+ <cds-skeleton-text
+ [lines]="1"
+ [minLineWidth]="100"
+ [maxLineWidth]="200"
+ >
+ </cds-skeleton-text>
+ } @else {
+ <span>{{ localStorageClassDetails?.zone_name }}</span>
+ }
+ </td>
+ </tr>
+ <tr>
+ <td class="bold">
+ Data Pool
+ <cd-helper class="text-pre-wrap">
+ <span i18n>
The data pool contains the objects associated with this storage class.
- </span>
- </cd-helper>
- </td>
- <td>
- @if (loading) {
- <cds-skeleton-text
- [lines]="1"
- [minLineWidth]="100"
- [maxLineWidth]="200">
- </cds-skeleton-text>
- } @else {
- <span>{{ localStorageClassDetails?.data_pool }}</span>
- }
- </td>
- </tr>
- }
+ </span>
+ </cd-helper>
+ </td>
+ <td>
+ @if (loading) {
+ <cds-skeleton-text
+ [lines]="1"
+ [minLineWidth]="100"
+ [maxLineWidth]="200"
+ >
+ </cds-skeleton-text>
+ } @else {
+ <span>{{ localStorageClassDetails?.data_pool }}</span>
+ }
+ </td>
+ </tr>
+ }
<tr>
<td class="bold">
Placement Target
-<div cdsCol
- [columnNumbers]="{ md: 4 }">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="storageClassForm"
- #formDir="ngForm"
- [formGroup]="storageClassForm"
- novalidate>
- <div i18n="form title"
- class="form-header">
+ <form
+ name="storageClassForm"
+ #formDir="ngForm"
+ [formGroup]="storageClassForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
{{ action | titlecase }} {{ resource | upperFirst }}
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
[invalid]="storageClassForm.showError('storageClassType', formDir, 'required')"
[invalidText]="storageError"
>
- <option *ngFor="let opt of storageClassOptions"
- [value]="opt.value"
- i18n>
+ <option
+ *ngFor="let opt of storageClassOptions"
+ [value]="opt.value"
+ i18n
+ >
{{ opt.label }}
</option>
</cds-select>
<ng-template #storageError>
@if (storageClassForm.showError('storageClassType', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
}
</ng-template>
</div>
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<!-- Zonegroup -->
<div cdsCol>
<cds-select
</cds-select>
<ng-template #zonegroupError>
@if (storageClassForm.showError('zonegroup', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
}
</ng-template>
</div>
- @if( isTierMatch(TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER )){
+ @if (isTierMatch(TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER)) {
<div cdsCol>
<ng-container *ngTemplateOutlet="storageClassField"></ng-container>
</div>
}
- @if( isTierMatch(TIER_TYPE.LOCAL )){
- <div cdsCol>
+ @if (isTierMatch(TIER_TYPE.LOCAL)) {
+ <div cdsCol>
+ <cds-select
+ label="Zone"
+ i18n-label
+ formControlName="zone"
+ id="zone"
+ [invalid]="storageClassForm.showError('zone', formDir, 'required')"
+ [invalidText]="zoneError"
+ >
+ <option
+ [value]="''"
+ i18n
+ >
+ --Select--
+ </option>
+ <option
+ *ngFor="let zone of zones"
+ [value]="zone?.name"
+ [selected]="zone.name === storageClassForm.getValue('zone')"
+ i18n
+ >
+ {{ zone.name }}
+ </option>
+ </cds-select>
+ <ng-template #zoneError>
+ <span
+ class="invalid-feedback"
+ *ngIf="storageClassForm.showError('zone', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
+ }
+ </div>
+ @if (isTierMatch(TIER_TYPE.LOCAL)) {
+ <ng-container *ngTemplateOutlet="storageClassField"></ng-container>
+ <div class="form-item clipboard">
+ <cd-alert-panel
+ type="info"
+ [showTitle]="false"
+ spacingClass="mb-2"
+ (action)="navigateCreatePool()"
+ >
+ <span i18n>To create a new pool click <a [routerLink]="[POOL.PATH]">here</a></span>
+ </cd-alert-panel>
<cds-select
- label="Zone"
+ label="Pool"
i18n-label
- formControlName="zone"
- id="zone"
- [invalid]="storageClassForm.showError('zone', formDir, 'required')"
- [invalidText]="zoneError"
+ formControlName="pool"
+ id="pool"
+ [invalid]="storageClassForm.showError('pool', formDir, 'required')"
+ [invalidText]="poolError"
>
- <option [value]="''"
- i18n>--Select--</option>
- <option *ngFor="let zone of zones"
- [value]="zone?.name"
- [selected]="zone.name === storageClassForm.getValue('zone')"
- i18n>
- {{ zone.name }}
+ <option
+ [value]="''"
+ i18n
+ >
+ --Select--
+ </option>
+ <option
+ *ngFor="let pool of rgwPools"
+ [value]="pool.pool_name"
+ i18n
+ >
+ {{ pool.pool_name }}
</option>
</cds-select>
- <ng-template #zoneError>
+ <ng-template #poolError>
<span
class="invalid-feedback"
- *ngIf="storageClassForm.showError('zone', formDir, 'required')"
+ *ngIf="storageClassForm.showError('pool', formDir, 'required')"
i18n
>This field is required.</span
>
</ng-template>
</div>
- }
- </div>
- @if( isTierMatch(TIER_TYPE.LOCAL )){
- <ng-container *ngTemplateOutlet="storageClassField"></ng-container>
- <div class="form-item clipboard">
- <cd-alert-panel type="info"
- [showTitle]="false"
- spacingClass="mb-2"
- (action)="navigateCreatePool()">
- <span i18n>To create a new pool click <a [routerLink]="[POOL.PATH]">here</a></span>
- </cd-alert-panel>
- <cds-select
- label="Pool"
- i18n-label
- formControlName="pool"
- id="pool"
- [invalid]="storageClassForm.showError('pool', formDir, 'required')"
- [invalidText]="poolError"
- >
- <option [value]="''"
- i18n>--Select--</option>
- <option *ngFor="let pool of rgwPools"
- [value]="pool.pool_name"
- i18n>
- {{ pool.pool_name }}
- </option>
- </cds-select>
- <ng-template #poolError>
- <span
- class="invalid-feedback"
- *ngIf="storageClassForm.showError('pool', formDir, 'required')"
- i18n
- >This field is required.</span
+ }
+ @if (isTierMatch(TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER)) {
+ <div>
+ <div
+ class="form-item form-item-append"
+ cdsRow
>
- </ng-template>
- </div>
- } @if( isTierMatch( TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER )){
- <div>
- <div class="form-item form-item-append"
- cdsRow>
- <div cdsCol>
- <!-- Target Region -->
- <cds-text-label
- labelInputID="region"
- i18n
- [invalid]="storageClassForm.showError('region', formDir, 'required')"
- [invalidText]="regionError"
- [helperText]="helpTextLabels.targetRegionText"
- >Target Region
- <input
- cdsText
- type="text"
- id="region"
- formControlName="region"
- placeholder="e.g, us-east-1"
- i18n-placeholder
+ <div cdsCol>
+ <!-- Target Region -->
+ <cds-text-label
+ labelInputID="region"
+ i18n
[invalid]="storageClassForm.showError('region', formDir, 'required')"
- />
- </cds-text-label>
- <ng-template #regionError>
- @if (storageClassForm.showError('region', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
- }
- </ng-template>
- </div>
- <div cdsCol>
- <!-- Target Endpoint -->
- <cds-text-label
- labelInputID="target_endpoint"
- i18n
- [invalid]="
- storageClassForm.showError('target_endpoint', formDir, 'invalidURL') ||
- storageClassForm.showError('target_endpoint', formDir, 'required')
- "
- [invalidText]="endpointError"
- [helperText]="helpTextLabels.targetEndpointText"
- >Target Endpoint
- <input
- cdsText
- type="text"
- placeholder="http://ceph-node-00.com:80"
- i18n-placeholder
- id="target_endpoint"
- formControlName="target_endpoint"
+ [invalidText]="regionError"
+ [helperText]="helpTextLabels.targetRegionText"
+ >Target Region
+ <input
+ cdsText
+ type="text"
+ id="region"
+ formControlName="region"
+ placeholder="e.g, us-east-1"
+ i18n-placeholder
+ [invalid]="storageClassForm.showError('region', formDir, 'required')"
+ />
+ </cds-text-label>
+ <ng-template #regionError>
+ @if (storageClassForm.showError('region', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ }
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <!-- Target Endpoint -->
+ <cds-text-label
+ labelInputID="target_endpoint"
+ i18n
[invalid]="
storageClassForm.showError('target_endpoint', formDir, 'invalidURL') ||
storageClassForm.showError('target_endpoint', formDir, 'required')
"
[invalidText]="endpointError"
- />
- </cds-text-label>
- <ng-template #endpointError>
- @if (storageClassForm.showError('target_endpoint', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
- } @else if (storageClassForm.showError('target_endpoint', formDir, 'invalidURL')) {
- <span class="invalid-feedback"
- i18n> Please enter a valid URL.</span>
- }
- </ng-template>
+ [helperText]="helpTextLabels.targetEndpointText"
+ >Target Endpoint
+ <input
+ cdsText
+ type="text"
+ placeholder="http://ceph-node-00.com:80"
+ i18n-placeholder
+ id="target_endpoint"
+ formControlName="target_endpoint"
+ [invalid]="
+ storageClassForm.showError('target_endpoint', formDir, 'invalidURL') ||
+ storageClassForm.showError('target_endpoint', formDir, 'required')
+ "
+ [invalidText]="endpointError"
+ />
+ </cds-text-label>
+ <ng-template #endpointError>
+ @if (storageClassForm.showError('target_endpoint', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
+ } @else if (storageClassForm.showError('target_endpoint', formDir, 'invalidURL')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ Please enter a valid URL.</span
+ >
+ }
+ </ng-template>
+ </div>
</div>
- </div>
- <!-- Access Key -->
- <div class="form-item">
- <div cdsCol
- [columnNumbers]="{ md: 12 }"
- class="d-flex">
- <cds-password-label
- labelInputID="access_key"
- [invalid]="storageClassForm.showError('access_key', formDir, 'required')"
- [invalidText]="accessError"
- [helperText]="helpTextLabels.targetAccessKeyText"
- i18n
- >Target Access Key
- <input
- cdsPassword
- type="password"
- id="access_key"
- formControlName="access_key"
+ <!-- Access Key -->
+ <div class="form-item">
+ <div
+ cdsCol
+ [columnNumbers]="{ md: 12 }"
+ class="d-flex"
+ >
+ <cds-password-label
+ labelInputID="access_key"
[invalid]="storageClassForm.showError('access_key', formDir, 'required')"
- />
- </cds-password-label>
- <cd-copy-2-clipboard-button class="clipboard"></cd-copy-2-clipboard-button>
- <ng-template #accessError>
- @if (storageClassForm.showError('access_key', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
- }
- </ng-template>
+ [invalidText]="accessError"
+ [helperText]="helpTextLabels.targetAccessKeyText"
+ i18n
+ >Target Access Key
+ <input
+ cdsPassword
+ type="password"
+ id="access_key"
+ formControlName="access_key"
+ [invalid]="storageClassForm.showError('access_key', formDir, 'required')"
+ />
+ </cds-password-label>
+ <cd-copy-2-clipboard-button class="clipboard"></cd-copy-2-clipboard-button>
+ <ng-template #accessError>
+ @if (storageClassForm.showError('access_key', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
+ }
+ </ng-template>
+ </div>
</div>
- </div>
- <!-- Secret Key -->
- <div class="form-item">
- <div cdsCol
- [columnNumbers]="{ md: 12 }"
- class="d-flex">
- <cds-password-label
- labelInputID="secret_key"
- [helperText]="helpTextLabels.targetSecretKeyText"
- [invalid]="storageClassForm.showError('secret_key', formDir, 'required')"
- [invalidText]="secretError"
+ <!-- Secret Key -->
+ <div class="form-item">
+ <div
+ cdsCol
+ [columnNumbers]="{ md: 12 }"
+ class="d-flex"
+ >
+ <cds-password-label
+ labelInputID="secret_key"
+ [helperText]="helpTextLabels.targetSecretKeyText"
+ [invalid]="storageClassForm.showError('secret_key', formDir, 'required')"
+ [invalidText]="secretError"
+ i18n
+ >Target Secret Key
+ <input
+ cdsPassword
+ type="password"
+ id="secret_key"
+ formControlName="secret_key"
+ [invalid]="storageClassForm.showError('secret_key', formDir, 'required')"
+ />
+ </cds-password-label>
+ <cd-copy-2-clipboard-button class="clipboard"> </cd-copy-2-clipboard-button>
+ <ng-template #secretError>
+ @if (storageClassForm.showError('secret_key', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
+ }
+ </ng-template>
+ </div>
+ </div>
+ <!-- Target Path -->
+ <div class="form-item">
+ <cds-text-label
+ labelInputID="target_path"
i18n
- >Target Secret Key
+ [invalid]="storageClassForm.showError('target_path', formDir, 'required')"
+ [invalidText]="targetError"
+ [helperText]="helpTextLabels.targetPathText"
+ >Target Path
<input
- cdsPassword
- type="password"
- id="secret_key"
- formControlName="secret_key"
- [invalid]="storageClassForm.showError('secret_key', formDir, 'required')"
+ cdsText
+ type="text"
+ id="target_path"
+ formControlName="target_path"
+ [invalid]="storageClassForm.showError('target_path', formDir, 'required')"
/>
- </cds-password-label>
- <cd-copy-2-clipboard-button class="clipboard"> </cd-copy-2-clipboard-button>
- <ng-template #secretError>
- @if (storageClassForm.showError('secret_key', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
+ </cds-text-label>
+ <ng-template #targetError>
+ @if (storageClassForm.showError('target_path', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
}
</ng-template>
</div>
- </div>
- <!-- Target Path -->
- <div class="form-item">
- <cds-text-label
- labelInputID="target_path"
- i18n
- [invalid]="storageClassForm.showError('target_path', formDir, 'required')"
- [invalidText]="targetError"
- [helperText]="helpTextLabels.targetPathText"
- >Target Path
- <input
- cdsText
- type="text"
- id="target_path"
- formControlName="target_path"
- [invalid]="storageClassForm.showError('target_path', formDir, 'required')"
- />
- </cds-text-label>
- <ng-template #targetError>
- @if (storageClassForm.showError('target_path', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
- }
- </ng-template>
- </div>
- <div class="form-item">
- <cds-checkbox
- id="allow_read_through"
- formControlName="allow_read_through"
- cdOptionalField="Allow Read Through"
- i18n
- (change)="onAllowReadThroughChange($event)"
- >Allow Read Through
- <cd-help-text>{{ helpTextLabels?.allowReadThroughText }}</cd-help-text>
- </cds-checkbox>
- </div>
- <div class="form-item">
- <cds-checkbox
- id="retain_head_object"
- formControlName="retain_head_object"
- cdOptionalField="Head Object (Stub File)"
- i18n
- >Head Object (Stub File)
- <cd-help-text>{{ helpTextLabels?.retainHeadObjectText }}</cd-help-text>
- </cds-checkbox>
- </div>
- <div class="form-item form-item-append"
- cdsRow>
- <div cdsCol>
- <cds-number
- name="read_through_restore_days"
- formControlName="read_through_restore_days"
- id="read_through_restore_days"
- min="1"
- label="ReadThrough Restore Days"
- [helperText]="helpTextLabels.readthroughrestoreDaysText"
- i18n-helperText
- i18n-label
+ <div class="form-item">
+ <cds-checkbox
+ id="allow_read_through"
+ formControlName="allow_read_through"
+ cdOptionalField="Allow Read Through"
i18n
- [invalid]="
- storageClassForm.controls.read_through_restore_days.invalid &&
- storageClassForm.controls.read_through_restore_days.dirty
- "
- [invalidText]="readThroughError"
- ></cds-number>
- <ng-template #readThroughError>
- @if (storageClassForm.showError('read_through_restore_days', formDir, 'pattern')) {
- <span class="invalid-feedback"
- i18n>
- ReadThrough Restore Days must be positive.
- </span>
- }
- </ng-template>
+ (change)="onAllowReadThroughChange($event)"
+ >Allow Read Through
+ <cd-help-text>{{ helpTextLabels?.allowReadThroughText }}</cd-help-text>
+ </cds-checkbox>
</div>
- <div cdsCol>
- <cds-select
- formControlName="restore_storage_class"
- label="Restore Storage Class"
- id="restore_storage_class"
- [helperText]="helpTextLabels.restoreStorageClassText"
- i18n-label
- >
- <option [value]="''"
- i18n>-- Select the glacier restore storage class --</option>
- <option [ngValue]="standard"
- i18n>Standard</option>
- </cds-select>
+ <div class="form-item">
+ <cds-checkbox
+ id="retain_head_object"
+ formControlName="retain_head_object"
+ cdOptionalField="Head Object (Stub File)"
+ i18n
+ >Head Object (Stub File)
+ <cd-help-text>{{ helpTextLabels?.retainHeadObjectText }}</cd-help-text>
+ </cds-checkbox>
</div>
- </div>
- </div>
- } @if(isTierMatch(TIER_TYPE.GLACIER)){
- <div>
- <legend class="cd-header"
- i18n>Glacier Configuration</legend>
- <div class="form-item form-item-append"
- cdsRow>
- <div cdsCol>
- <cds-select
- formControlName="glacier_restore_tier_type"
- label="Glacier Restore Tier Type"
- cdRequiredField="Glacier Restore Tier Type"
- id="glacier_restore_tier_type"
- [invalid]="
- storageClassForm.controls.glacier_restore_tier_type.invalid &&
- storageClassForm.controls.glacier_restore_tier_type.dirty
- "
- [invalidText]="glacierError"
- [helperText]="helpTextLabels.tiertypeText"
- i18n-label
- >
- <option value="''"
- i18n>-- Select the glacier restore tier type --</option>
- <option [ngValue]="standard"
- i18n>Standard</option>
- <option [ngValue]="expedited"
- i18n>Expedited</option>
- </cds-select>
- <ng-template #glacierError>
- @if (storageClassForm.showError('glacier_restore_tier_type', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
- }
- </ng-template>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
+ <div cdsCol>
+ <cds-number
+ name="read_through_restore_days"
+ formControlName="read_through_restore_days"
+ id="read_through_restore_days"
+ min="1"
+ label="ReadThrough Restore Days"
+ [helperText]="helpTextLabels.readthroughrestoreDaysText"
+ i18n-helperText
+ i18n-label
+ i18n
+ [invalid]="
+ storageClassForm.controls.read_through_restore_days.invalid &&
+ storageClassForm.controls.read_through_restore_days.dirty
+ "
+ [invalidText]="readThroughError"
+ ></cds-number>
+ <ng-template #readThroughError>
+ @if (storageClassForm.showError('read_through_restore_days', formDir, 'pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ ReadThrough Restore Days must be positive.
+ </span>
+ }
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <cds-select
+ formControlName="restore_storage_class"
+ label="Restore Storage Class"
+ id="restore_storage_class"
+ [helperText]="helpTextLabels.restoreStorageClassText"
+ i18n-label
+ >
+ <option
+ [value]="''"
+ i18n
+ >
+ -- Select the glacier restore storage class --
+ </option>
+ <option
+ [ngValue]="standard"
+ i18n
+ >
+ Standard
+ </option>
+ </cds-select>
+ </div>
</div>
- <div cdsCol>
- <cds-number
- [id]="'glacier_restore_days'"
- [formControlName]="'glacier_restore_days'"
- [label]="'Glacier Restore Days'"
- [helperText]="helpTextLabels.restoreDaysText"
- [min]="1"
- i18n-helperText
- i18n-label
- i18n
- [invalid]="
- storageClassForm.controls.glacier_restore_days.invalid &&
- storageClassForm.controls.glacier_restore_days.dirty
- "
- [invalidText]="glacierRestoreError"
- >
- </cds-number>
- <ng-template #glacierRestoreError>
- @if (storageClassForm.showError('glacier_restore_days', formDir, 'pattern')) {
- <span class="invalid-feedback"
- i18n>
- The entered value must be a positive integer.
- </span>
- }
- </ng-template>
+ </div>
+ }
+ @if (isTierMatch(TIER_TYPE.GLACIER)) {
+ <div>
+ <legend
+ class="cd-header"
+ i18n
+ >
+ Glacier Configuration
+ </legend>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
+ <div cdsCol>
+ <cds-select
+ formControlName="glacier_restore_tier_type"
+ label="Glacier Restore Tier Type"
+ cdRequiredField="Glacier Restore Tier Type"
+ id="glacier_restore_tier_type"
+ [invalid]="
+ storageClassForm.controls.glacier_restore_tier_type.invalid &&
+ storageClassForm.controls.glacier_restore_tier_type.dirty
+ "
+ [invalidText]="glacierError"
+ [helperText]="helpTextLabels.tiertypeText"
+ i18n-label
+ >
+ <option
+ value="''"
+ i18n
+ >
+ -- Select the glacier restore tier type --
+ </option>
+ <option
+ [ngValue]="standard"
+ i18n
+ >
+ Standard
+ </option>
+ <option
+ [ngValue]="expedited"
+ i18n
+ >
+ Expedited
+ </option>
+ </cds-select>
+ <ng-template #glacierError>
+ @if (storageClassForm.showError('glacier_restore_tier_type', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
+ }
+ </ng-template>
+ </div>
+ <div cdsCol>
+ <cds-number
+ [id]="'glacier_restore_days'"
+ [formControlName]="'glacier_restore_days'"
+ [label]="'Glacier Restore Days'"
+ [helperText]="helpTextLabels.restoreDaysText"
+ [min]="1"
+ i18n-helperText
+ i18n-label
+ i18n
+ [invalid]="
+ storageClassForm.controls.glacier_restore_days.invalid &&
+ storageClassForm.controls.glacier_restore_days.dirty
+ "
+ [invalidText]="glacierRestoreError"
+ >
+ </cds-number>
+ <ng-template #glacierRestoreError>
+ @if (storageClassForm.showError('glacier_restore_days', formDir, 'pattern')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ The entered value must be a positive integer.
+ </span>
+ }
+ </ng-template>
+ </div>
</div>
</div>
- </div>
}
<fieldset>
<div>
<h5 class="cds--accordion__title cd-header">Advanced</h5>
</ng-template>
<fieldset>
- <cds-accordion size="lg"
- class="form-item">
+ <cds-accordion
+ size="lg"
+ class="form-item"
+ >
<cds-accordion-item
[title]="title"
id="advanced-fieldset"
(selected)="showAdvanced = !showAdvanced"
>
- @if( isTierMatch( TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER )){
- <!-- Multi Part Sync Threshold -->
- <div class="form-item form-item-append"
- cdsRow>
- <div cdsCol>
- <cds-text-label
- labelInputID="multipart_sync_threshold"
- i18n
- [helperText]="helpTextLabels.multipartSyncThresholdText"
- cdOptionalField="Multipart Sync Threshold"
- >Multipart Sync Threshold
- <input
- cdsText
- type="text"
- id="multipart_sync_threshold"
- formControlName="multipart_sync_threshold"
- cdDimlessBinary
- />
- </cds-text-label>
+ @if (isTierMatch(TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER)) {
+ <!-- Multi Part Sync Threshold -->
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="multipart_sync_threshold"
+ i18n
+ [helperText]="helpTextLabels.multipartSyncThresholdText"
+ cdOptionalField="Multipart Sync Threshold"
+ >Multipart Sync Threshold
+ <input
+ cdsText
+ type="text"
+ id="multipart_sync_threshold"
+ formControlName="multipart_sync_threshold"
+ cdDimlessBinary
+ />
+ </cds-text-label>
+ </div>
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="multipart_min_part_size"
+ i18n
+ [helperText]="helpTextLabels.multipartMinPartText"
+ cdOptionalField="Multipart Minimum Part Size"
+ >Multipart Minimum Part Size
+ <input
+ cdsText
+ type="text"
+ id="multipart_min_part_size"
+ formControlName="multipart_min_part_size"
+ cdDimlessBinary
+ />
+ </cds-text-label>
+ </div>
</div>
- <div cdsCol>
- <cds-text-label
- labelInputID="multipart_min_part_size"
+ <!-- ACLs -->
+ <div>
+ <legend
+ class="cd-header"
i18n
- [helperText]="helpTextLabels.multipartMinPartText"
- cdOptionalField="Multipart Minimum Part Size"
- >Multipart Minimum Part Size
- <input
- cdsText
- type="text"
- id="multipart_min_part_size"
- formControlName="multipart_min_part_size"
- cdDimlessBinary
- />
- </cds-text-label>
- </div>
- </div>
- <!-- ACLs -->
- <div>
- <legend class="cd-header"
- i18n>ACLs Mapping</legend>
- <ng-container formArrayName="acls">
- @for (acl of acls.controls; let i = $index; track acl) {
- <ng-container [formGroupName]="i">
- <div class="form-item form-item-append"
- cdsRow>
- <div cdsCol
- [columnNumbers]="{ lg: 7 }">
- <cds-select id="type"
- formControlName="type"
- i18n-label
- label="Type">
- @for (type of typeOptions; track type.value) {
- <option [value]="type.value"
- i18n>
- {{ type.label }}
- </option>
- }
- </cds-select>
- </div>
- </div>
- <div cdsRow
- class="form-item form-item-append">
- <div cdsCol>
- <cds-text-label
- labelInputID="source_id"
- i18n
- [helperText]="getAclHelperText(acl.get('type')?.value, 'source')"
- [invalid]="
- acl.get('source_id')?.invalid && acl.get('source_id')?.touched
- "
- [invalidText]="
- acl.get('source_id')?.errors?.['required'] ? 'This field is required.' :
- acl.get('source_id')?.errors?.['email'] ? 'Please enter a valid email address.' :
- acl.get('source_id')?.errors?.['invalidUrl'] ? 'Please enter a valid URL.' : ''
- "
+ >
+ ACLs Mapping
+ </legend>
+ <ng-container formArrayName="acls">
+ @for (acl of acls.controls; let i = $index; track acl) {
+ <ng-container [formGroupName]="i">
+ <div
+ class="form-item form-item-append"
+ cdsRow
>
- {{ getAclLabel('source', acl.get('type')?.value) }}
- <input
- cdsText
- type="text"
- formControlName="source_id"
- [invalidText]="
- acl.get('source_id')?.errors?.['required'] ? 'This field is required.' :
- acl.get('source_id')?.errors?.['email'] ? 'Please enter a valid email address.' :
- acl.get('source_id')?.errors?.['invalidUrl'] ? 'Please enter a valid URL.' : ''
- "
- />
- </cds-text-label>
- </div>
- <div cdsCol>
- <cds-text-label
- labelInputID="dest_id"
- i18n
- [helperText]="getAclHelperText(acl.get('type')?.value, 'destination')"
- [invalid]="acl.get('dest_id')?.invalid && acl.get('dest_id')?.touched"
- [invalidText]="
- acl.get('dest_id')?.errors?.['required'] ? 'This field is required.' :
- acl.get('dest_id')?.errors?.['email'] ? 'Please enter a valid email address.' :
- acl.get('dest_id')?.errors?.['invalidUrl'] ? 'Please enter a valid URL.' : ''
- "
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 7 }"
+ >
+ <cds-select
+ id="type"
+ formControlName="type"
+ i18n-label
+ label="Type"
+ >
+ @for (type of typeOptions; track type.value) {
+ <option
+ [value]="type.value"
+ i18n
+ >
+ {{ type.label }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ </div>
+ <div
+ cdsRow
+ class="form-item form-item-append"
>
- {{ getAclLabel('destination', acl.get('type')?.value) }}
- <input
- cdsText
- type="text"
- formControlName="dest_id"
- [invalidText]="
- acl.get('dest_id')?.errors?.['required'] ? 'This field is required.' :
- acl.get('dest_id')?.errors?.['email'] ? 'Please enter a valid email address.' :
- acl.get('dest_id')?.errors?.['invalidUrl'] ? 'Please enter a valid URL.' : ''
- "
- />
- </cds-text-label>
- </div>
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="source_id"
+ i18n
+ [helperText]="getAclHelperText(acl.get('type')?.value, 'source')"
+ [invalid]="
+ acl.get('source_id')?.invalid && acl.get('source_id')?.touched
+ "
+ [invalidText]="
+ acl.get('source_id')?.errors?.['required']
+ ? 'This field is required.'
+ : acl.get('source_id')?.errors?.['email']
+ ? 'Please enter a valid email address.'
+ : acl.get('source_id')?.errors?.['invalidUrl']
+ ? 'Please enter a valid URL.'
+ : ''
+ "
+ >
+ {{ getAclLabel('source', acl.get('type')?.value) }}
+ <input
+ cdsText
+ type="text"
+ formControlName="source_id"
+ [invalidText]="
+ acl.get('source_id')?.errors?.['required']
+ ? 'This field is required.'
+ : acl.get('source_id')?.errors?.['email']
+ ? 'Please enter a valid email address.'
+ : acl.get('source_id')?.errors?.['invalidUrl']
+ ? 'Please enter a valid URL.'
+ : ''
+ "
+ />
+ </cds-text-label>
+ </div>
+ <div cdsCol>
+ <cds-text-label
+ labelInputID="dest_id"
+ i18n
+ [helperText]="
+ getAclHelperText(acl.get('type')?.value, 'destination')
+ "
+ [invalid]="
+ acl.get('dest_id')?.invalid && acl.get('dest_id')?.touched
+ "
+ [invalidText]="
+ acl.get('dest_id')?.errors?.['required']
+ ? 'This field is required.'
+ : acl.get('dest_id')?.errors?.['email']
+ ? 'Please enter a valid email address.'
+ : acl.get('dest_id')?.errors?.['invalidUrl']
+ ? 'Please enter a valid URL.'
+ : ''
+ "
+ >
+ {{ getAclLabel('destination', acl.get('type')?.value) }}
+ <input
+ cdsText
+ type="text"
+ formControlName="dest_id"
+ [invalidText]="
+ acl.get('dest_id')?.errors?.['required']
+ ? 'This field is required.'
+ : acl.get('dest_id')?.errors?.['email']
+ ? 'Please enter a valid email address.'
+ : acl.get('dest_id')?.errors?.['invalidUrl']
+ ? 'Please enter a valid URL.'
+ : ''
+ "
+ />
+ </cds-text-label>
+ </div>
- <div
- cdsCol
- [columnNumbers]="{ lg: 1, md: 1 }"
- class="item-action-btn spacing"
- >
- <cds-icon-button kind="primary"
- size="sm"
- (click)="addAcls(acls, i)">
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"></svg>
- </cds-icon-button>
- </div>
- <div cdsCol
- [columnNumbers]="{ lg: 1, md: 1 }"
- class="item-action-btn">
- <cds-icon-button kind="danger"
- size="sm"
- (click)="removeAcl(i)">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
- </cds-icon-button>
- </div>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1, md: 1 }"
+ class="item-action-btn spacing"
+ >
+ <cds-icon-button
+ kind="primary"
+ size="sm"
+ (click)="addAcls(acls, i)"
+ >
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1, md: 1 }"
+ class="item-action-btn"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="sm"
+ (click)="removeAcl(i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
+ </div>
+ </ng-container>
+ }
</ng-container>
- }
- </ng-container>
- </div>
+ </div>
}
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Placement Target -->
<cds-select
[invalidText]="placementError"
>
@for (placementTarget of placementTargets; track placementTarget) {
- <option
- [value]="placementTarget"
- [selected]="
- placementTarget === storageClassForm.getValue('placement_target')
- "
- i18n
- >
- {{ placementTarget }}
- </option>
+ <option
+ [value]="placementTarget"
+ [selected]="
+ placementTarget === storageClassForm.getValue('placement_target')
+ "
+ i18n
+ >
+ {{ placementTarget }}
+ </option>
}
</cds-select>
<ng-template #placementError>
@if (storageClassForm.showError('placement_target', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n> This field is required. </span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >
+ This field is required.
+ </span>
}
</ng-template>
</div>
</fieldset>
</div>
</fieldset>
- @if( isTierMatch( TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER )){
- <cd-alert-panel type="warning"
- spacingClass="mb-2">
- <span i18n>RGW service would be restarted after creating the storage class.</span>
- </cd-alert-panel>
+ @if (isTierMatch(TIER_TYPE.CLOUD_TIER, TIER_TYPE.GLACIER)) {
+ <cd-alert-panel
+ type="warning"
+ spacingClass="mb-2"
+ >
+ <span i18n>RGW service would be restarted after creating the storage class.</span>
+ </cd-alert-panel>
}
<cd-form-button-panel
(submitActionEvent)="submitAction()"
</ng-container>
</div>
-<ng-template #storageClassField
- [formGroup]="storageClassForm">
- <cds-text-label labelInputID="storage_class"
- i18n
- [disabled]="editing"
- [invalid]="storageClass.isInvalid"
- [invalidText]="storageClassError"
- >Name
- <input cdsText
- cdValidate
- #storageClass="cdValidate"
- type="text"
- id="storage_class"
- formControlName="storage_class"
- [invalid]="storageClass.isInvalid"/>
+<ng-template
+ #storageClassField
+ [formGroup]="storageClassForm"
+>
+ <cds-text-label
+ labelInputID="storage_class"
+ i18n
+ [disabled]="editing"
+ [invalid]="storageClass.isInvalid"
+ [invalidText]="storageClassError"
+ >Name
+ <input
+ cdsText
+ cdValidate
+ #storageClass="cdValidate"
+ type="text"
+ id="storage_class"
+ formControlName="storage_class"
+ [invalid]="storageClass.isInvalid"
+ />
</cds-text-label>
<ng-template #storageClassError>
@if (storageClassForm.showError('storage_class', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
} @else if (storageClassForm.showError('storage_class', formDir, 'uniqueName')) {
- <span class="invalid-feedback"
- i18n>The Storage Class name is already in use.</span>
+ <span
+ class="invalid-feedback"
+ i18n
+ >The Storage Class name is already in use.</span
+ >
}
</ng-template>
</ng-template>
<legend>
<cd-help-text i18n>
- A storage class for tiering defines the policies for automatically moving objects between different storage tiers.
+ A storage class for tiering defines the policies for automatically moving objects between
+ different storage tiers.
</cd-help-text>
</legend>
<cd-table
[hasDetails]="true"
(setExpandedRow)="setExpandedRow($event)"
(updateSelection)="updateSelection($event)"
- [autoReload]="false">
+ [autoReload]="false"
+>
<div class="table-actions">
- <cd-table-actions class="btn-group"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+ <cd-table-actions
+ class="btn-group"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
- <cd-rgw-storage-class-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-rgw-storage-class-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rgw-storage-class-details>
</cd-table>
<div class="sync-info">
- <cds-toggletip [dropShadow]="true"
- [align]="align">
- <div cdsToggletipButton
- class="toggleTipBtn">
- <span class="cds--type-label-01" i18n>Status:</span>
+ <cds-toggletip
+ [dropShadow]="true"
+ [align]="align"
+ >
+ <div
+ cdsToggletipButton
+ class="toggleTipBtn"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Status:</span
+ >
@if (zone.syncstatus?.includes('failed') || zone.syncstatus?.includes('error')) {
<span class="sync-info__status">
- <svg [cdsIcon]="icons.danger"
- [size]="icons.size16"
- class="cds-danger-color"></svg>
- <a class="cds--link cds--type-label-01 cds-danger-color sync-status-link"
- i18n>Error</a>
+ <svg
+ [cdsIcon]="icons.danger"
+ [size]="icons.size16"
+ class="cds-danger-color"
+ ></svg>
+ <a
+ class="cds--link cds--type-label-01 cds-danger-color sync-status-link"
+ i18n
+ >Error</a
+ >
</span>
} @else {
@if (zone.syncstatus === 'Not Syncing From Zone') {
- <a class="cds--link cds--type-label-01 sync-status-link"
- i18n>Not Syncing</a>
+ <a
+ class="cds--link cds--type-label-01 sync-status-link"
+ i18n
+ >Not Syncing</a
+ >
} @else {
- <a class="cds--link cds--type-label-01 sync-status-link"
- i18n>{{ zone.syncstatus | titlecase }}</a>
+ <a
+ class="cds--link cds--type-label-01 sync-status-link"
+ i18n
+ >{{ zone.syncstatus | titlecase }}</a
+ >
}
}
</div>
<div cdsToggletipContent>
<div class="cds--popover-scroll-container">
<div class="toggletip-content">
- @for (status of zone.fullSyncStatus; track status) {
- @if (status?.includes('failed') || status?.includes('error')) {
+ @for (status of zone.fullSyncStatus; track status) {
+ @if (status?.includes('failed') || status?.includes('error')) {
+ <div class="toggletip-content__item">
+ <span class="cds--type-body-compact-01 cds-danger-color">{{
+ status | titlecase
+ }}</span>
+ </div>
+ } @else if (
+ !status?.includes(zone.name) && !status?.includes(zone.syncstatus) && status?.trim()
+ ) {
+ @if (status?.includes(':')) {
<div class="toggletip-content__item">
- <span class="cds--type-body-compact-01 cds-danger-color">{{ status | titlecase }}</span>
+ <span class="cds--type-label-01">{{ status.split(': ')[0] | titlecase }}</span>
+ <span class="cds--type-body-compact-01">{{
+ status.split(': ')[1] | titlecase
+ }}</span>
+ </div>
+ } @else {
+ <div class="toggletip-content__item">
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Summary</span
+ >
+ <span class="cds--type-body-compact-01">{{ status | titlecase }}</span>
</div>
- } @else if (!status?.includes(zone.name) && !status?.includes(zone.syncstatus) && status?.trim()) {
- @if (status?.includes(':')) {
- <div class="toggletip-content__item">
- <span class="cds--type-label-01">{{ status.split(': ')[0] | titlecase }}</span>
- <span class="cds--type-body-compact-01">{{ status.split(': ')[1] | titlecase }}</span>
- </div>
- } @else {
- <div class="toggletip-content__item">
- <span class="cds--type-label-01" i18n>Summary</span>
- <span class="cds--type-body-compact-01">{{ status | titlecase }}</span>
- </div>
- }
}
}
+ }
</div>
</div>
</div>
</cds-toggletip>
<div class="sync-info__last-synced cds-mt-3">
- <span class="cds--type-label-01" i18n>Last Synced:</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Last Synced:</span
+ >
@if (zone.timestamp) {
- <cds-tag class="tag-info" size="sm">
+ <cds-tag
+ class="tag-info"
+ size="sm"
+ >
{{ zone.timestamp | relativeDate }}
</cds-tag>
} @else {
- <cds-tag class="tag-success"
- size="sm"
- i18n>Up to Date</cds-tag>
+ <cds-tag
+ class="tag-success"
+ size="sm"
+ i18n
+ >Up to Date</cds-tag
+ >
}
</div>
</div>
@if (metadataSyncInfo === 'no sync (zone is master)') {
<div class="sync-info">
- <span class="cds--type-label-01" i18n>Status:</span>
- <span class="cds--type-label-01"
- style="color: var(--cds-text-secondary)">No Sync</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Status:</span
+ >
+ <span
+ class="cds--type-label-01"
+ style="color: var(--cds-text-secondary)"
+ >No Sync</span
+ >
</div>
} @else {
<div class="sync-info">
- <cds-toggletip [dropShadow]="true"
- [align]="align">
- <div cdsToggletipButton
- class="toggleTipBtn">
- <span class="cds--type-label-01" i18n>Status:</span>
- @if (metadataSyncInfo.syncstatus?.includes('failed') || metadataSyncInfo.syncstatus?.includes('error')) {
+ <cds-toggletip
+ [dropShadow]="true"
+ [align]="align"
+ >
+ <div
+ cdsToggletipButton
+ class="toggleTipBtn"
+ >
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Status:</span
+ >
+ @if (
+ metadataSyncInfo.syncstatus?.includes('failed') ||
+ metadataSyncInfo.syncstatus?.includes('error')
+ ) {
<span class="sync-info__status">
- <svg [cdsIcon]="icons.danger"
- [size]="icons.size16"
- class="cds-danger-color"></svg>
- <a class="cds--link cds--type-label-01 cds-danger-color sync-status-link"
- i18n>Error</a>
+ <svg
+ [cdsIcon]="icons.danger"
+ [size]="icons.size16"
+ class="cds-danger-color"
+ ></svg>
+ <a
+ class="cds--link cds--type-label-01 cds-danger-color sync-status-link"
+ i18n
+ >Error</a
+ >
</span>
} @else {
@if (metadataSyncInfo.syncstatus === 'Not Syncing From Zone') {
- <a class="cds--link cds--type-label-01 sync-status-link"
- i18n>Not Syncing</a>
+ <a
+ class="cds--link cds--type-label-01 sync-status-link"
+ i18n
+ >Not Syncing</a
+ >
} @else {
- <a class="cds--link cds--type-label-01 sync-status-link"
- i18n>{{ metadataSyncInfo.syncstatus | titlecase }}</a>
+ <a
+ class="cds--link cds--type-label-01 sync-status-link"
+ i18n
+ >{{ metadataSyncInfo.syncstatus | titlecase }}</a
+ >
}
}
</div>
<div cdsToggletipContent>
<div class="cds--popover-scroll-container">
<div class="toggletip-content">
- @for (status of metadataSyncInfo.fullSyncStatus; track status; let last = $last) {
- @if (status?.includes('failed') || status?.includes('error')) {
+ @for (status of metadataSyncInfo.fullSyncStatus; track status; let last = $last) {
+ @if (status?.includes('failed') || status?.includes('error')) {
+ <div class="toggletip-content__item">
+ <span class="cds--type-body-compact-01 cds-danger-color">{{
+ status | titlecase
+ }}</span>
+ </div>
+ } @else if (!status?.includes(metadataSyncInfo.syncstatus) && status?.trim()) {
+ @if (status?.includes(':')) {
<div class="toggletip-content__item">
- <span class="cds--type-body-compact-01 cds-danger-color">{{ status | titlecase }}</span>
+ <span class="cds--type-label-01">{{ status.split(':')[0] | titlecase }}</span>
+ <span class="cds--type-body-compact-01">{{
+ status.split(':')[1] | titlecase
+ }}</span>
+ </div>
+ } @else {
+ <div class="toggletip-content__item">
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Summary</span
+ >
+ <span class="cds--type-body-compact-01">{{ status | titlecase }}</span>
</div>
- } @else if (!status?.includes(metadataSyncInfo.syncstatus) && status?.trim()) {
- @if (status?.includes(':')) {
- <div class="toggletip-content__item">
- <span class="cds--type-label-01">{{ status.split(':')[0] | titlecase }}</span>
- <span class="cds--type-body-compact-01">{{ status.split(':')[1] | titlecase }}</span>
- </div>
- } @else {
- <div class="toggletip-content__item">
- <span class="cds--type-label-01" i18n>Summary</span>
- <span class="cds--type-body-compact-01">{{ status | titlecase }}</span>
- </div>
- }
}
}
+ }
</div>
</div>
</div>
</cds-toggletip>
<div class="sync-info__last-synced cds-mt-3">
- <span class="cds--type-label-01" i18n>Last Synced:</span>
+ <span
+ class="cds--type-label-01"
+ i18n
+ >Last Synced:</span
+ >
@if (metadataSyncInfo.timestamp) {
- <cds-tag class="tag-info" size="sm">
+ <cds-tag
+ class="tag-info"
+ size="sm"
+ >
{{ metadataSyncInfo.timestamp | relativeDate }}
</cds-tag>
} @else {
- <cds-tag class="tag-success"
- size="sm"
- i18n>Up to Date</cds-tag>
+ <cds-tag
+ class="tag-success"
+ size="sm"
+ i18n
+ >Up to Date</cds-tag
+ >
}
</div>
</div>
<ul class="pb-5">
<li>
- <svg [cdsIcon]="icons.reweight"
- [size]="icons.size20"
- class="cds-icon--size-07"></svg>
+ <svg
+ [cdsIcon]="icons.reweight"
+ [size]="icons.size20"
+ class="cds-icon--size-07"
+ ></svg>
+ </li>
+ <li class="mt-2">
+ <cds-tag class="tag-info">{{ realm }}</cds-tag>
</li>
- <li class="mt-2"><cds-tag class="tag-info">{{realm}}</cds-tag></li>
<li>
- <svg [cdsIcon]="icons.down"
- class=" cds-icon--size-07"></svg>
+ <svg
+ [cdsIcon]="icons.down"
+ class="cds-icon--size-07"
+ ></svg>
</li>
<li class="mt-2">
- <cd-icon type="clusterIcon"
- [size]="icons.size32"></cd-icon>
+ <cd-icon
+ type="clusterIcon"
+ [size]="icons.size32"
+ ></cd-icon>
</li>
- <p class="mt-2"> <cds-tag class="tag-info">{{zonegroup}}</cds-tag></p>
+ <p class="mt-2">
+ <cds-tag class="tag-info">{{ zonegroup }}</cds-tag>
+ </p>
<li>
- <svg [cdsIcon]="icons.down"
- class="cds-icon--size-07"></svg>
+ <svg
+ [cdsIcon]="icons.down"
+ class="cds-icon--size-07"
+ ></svg>
</li>
<li>
- <svg [cdsIcon]="icons.deploy"
- [size]="icons.size20"
- class="cds-icon--size-07 cds-icon"></svg>
+ <svg
+ [cdsIcon]="icons.deploy"
+ [size]="icons.size20"
+ class="cds-icon--size-07 cds-icon"
+ ></svg>
+ </li>
+ <li class="mt-2">
+ <cds-tag class="tag-info">{{ zone }}</cds-tag>
</li>
- <li class="mt-2"><cds-tag class="tag-info">{{zone}}</cds-tag></li>
</ul>
<cd-modal [modalRef]="activeModal">
- <ng-container i18n="form title"
- class="modal-title">Create System User</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >Create System User</ng-container
+ >
<ng-container class="modal-content">
- <form name="multisiteSystemUserForm"
- #formDir="ngForm"
- [formGroup]="multisiteSystemUserForm"
- novalidate>
+ <form
+ name="multisiteSystemUserForm"
+ #formDir="ngForm"
+ [formGroup]="multisiteSystemUserForm"
+ novalidate
+ >
<div class="modal-body">
<div class="form-group row">
- <label class="cd-col-form-label required"
- for="userName"
- i18n>User Name</label>
+ <label
+ class="cd-col-form-label required"
+ for="userName"
+ i18n
+ >User Name</label
+ >
<div class="cd-col-form-input">
- <input class="form-control"
- type="text"
- placeholder="User name..."
- id="userName"
- name="userName"
- formControlName="userName">
- <span class="invalid-feedback"
- *ngIf="multisiteSystemUserForm.showError('userName', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="multisiteSystemUserForm.showError('userName', formDir, 'uniqueName')"
- i18n>The chosen realm name is already in use.</span>
+ <input
+ class="form-control"
+ type="text"
+ placeholder="User name..."
+ id="userName"
+ name="userName"
+ formControlName="userName"
+ />
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSystemUserForm.showError('userName', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="multisiteSystemUserForm.showError('userName', formDir, 'uniqueName')"
+ i18n
+ >The chosen realm name is already in use.</span
+ >
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="multisiteSystemUserForm"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="multisiteSystemUserForm"
+ ></cd-form-button-panel>
</div>
</form>
</ng-container>
<ng-container *ngIf="!!selection">
- <cds-tabs type="contained"
- theme="light">
- <cds-tab heading="Details"
- i18n-heading>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- data-testid="rgw-topic-details">
+ <cds-tabs
+ type="contained"
+ theme="light"
+ >
+ <cds-tab
+ heading="Details"
+ i18n-heading
+ >
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-topic-details"
+ >
<tbody>
<tr>
- <td i18n
- class="bold">Push endpoint arguments</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Push endpoint arguments
+ </td>
<td>{{ selection?.dest?.push_endpoint_args }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Stored secret</td>
- <td class="w-75">{{ selection?.dest?.stored_secret}}</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Stored secret
+ </td>
+ <td class="w-75">{{ selection?.dest?.stored_secret }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Persistent</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Persistent
+ </td>
<td>{{ selection?.dest?.persistent }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Persistent queue</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Persistent queue
+ </td>
<td>{{ selection?.dest?.persistent_queue }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Time to live</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Time to live
+ </td>
<td>{{ selection?.dest?.time_to_live }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Max retries</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Max retries
+ </td>
<td>{{ selection?.dest?.max_retries }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Retry sleep duration</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Retry sleep duration
+ </td>
<td>{{ selection?.dest?.retry_sleep_duration }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Opaque data</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Opaque data
+ </td>
<td>{{ selection?.opaqueData }}</td>
</tr>
</tbody>
</table>
</cds-tab>
- <cds-tab heading="Policies"
- i18n-heading>
+ <cds-tab
+ heading="Policies"
+ i18n-heading
+ >
<div>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25 ">Policy</td>
- <td><pre>{{ policy | json }}</pre></td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Policy
+ </td>
+ <td>
+ <pre>{{ policy | json }}</pre>
+ </td>
</tr>
</tbody>
</table>
</div>
</cds-tab>
- <cds-tab heading="Subscribed buckets"
- i18n-heading>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <cds-tab
+ heading="Subscribed buckets"
+ i18n-heading
+ >
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Subscribed buckets</td>
- <td><pre>{{ selection.subscribed_buckets | json}}</pre></td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Subscribed buckets
+ </td>
+ <td>
+ <pre>{{ selection.subscribed_buckets | json }}</pre>
+ </td>
</tr>
</tbody>
</table>
-<div cdsCol
- *cdFormLoading="loading"
- [columnNumbers]="{ md: 4 }">
- <form name="topicForm"
- #formDir="ngForm"
- [formGroup]="topicForm"
- novalidate>
+<div
+ cdsCol
+ *cdFormLoading="loading"
+ [columnNumbers]="{ md: 4 }"
+>
+ <form
+ name="topicForm"
+ #formDir="ngForm"
+ [formGroup]="topicForm"
+ novalidate
+ >
<div class="form-header">
{{ action | titlecase }} {{ resource | upperFirst }}
<cd-help-text>
<span i18n>
- Configure the push endpoint parameters to send notifications. On successful creation, you'll receive the destination's unique Amazon Resource Name
+ Configure the push endpoint parameters to send notifications. On successful creation,
+ you'll receive the destination's unique Amazon Resource Name
</span>
</cd-help-text>
</div>
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<!-- Destination Type-->
<div cdsCol>
- <cds-select formControlName="endpointType"
- label="Type"
- i18n-label
- cdRequiredField="Type"
- id="endpointType"
- (change)="onEndpointTypeChange();"
- [invalid]="topicForm.controls.endpointType.invalid && topicForm.controls.endpointType.dirty"
- [invalidText]="topicTypeError">
- <option i18n
- *ngIf="endpointType === null"
- value="null">Loading... </option>
- <option i18n
- *ngIf="endpointType !== null"
- value="">-- Select a destination type --</option>
- <option *ngFor="let data of endpointType"
- i18n>{{ data | upperFirst }} </option>
+ <cds-select
+ formControlName="endpointType"
+ label="Type"
+ i18n-label
+ cdRequiredField="Type"
+ id="endpointType"
+ (change)="onEndpointTypeChange()"
+ [invalid]="
+ topicForm.controls.endpointType.invalid && topicForm.controls.endpointType.dirty
+ "
+ [invalidText]="topicTypeError"
+ >
+ <option
+ i18n
+ *ngIf="endpointType === null"
+ value="null"
+ >
+ Loading...
+ </option>
+ <option
+ i18n
+ *ngIf="endpointType !== null"
+ value=""
+ >
+ -- Select a destination type --
+ </option>
+ <option
+ *ngFor="let data of endpointType"
+ i18n
+ >
+ {{ data | upperFirst }}
+ </option>
</cds-select>
<ng-template #topicTypeError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('endpointType', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('endpointType', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
cdRequiredField="Owner"
[invalid]="topicForm.controls.owner.invalid && topicForm.controls.owner.dirty"
id="owner"
- [invalidText]="ownerError">
- <option i18n
- *ngIf="owners === null"
- value="null">Loading... </option>
- <option i18n
- *ngIf="owners !== null"
- value="">-- Select a user --</option>
- <option *ngFor="let data of owners"
- i18n
- [value]="data">{{ data }}</option>
+ [invalidText]="ownerError"
+ >
+ <option
+ i18n
+ *ngIf="owners === null"
+ value="null"
+ >
+ Loading...
+ </option>
+ <option
+ i18n
+ *ngIf="owners !== null"
+ value=""
+ >
+ -- Select a user --
+ </option>
+ <option
+ *ngFor="let data of owners"
+ i18n
+ [value]="data"
+ >
+ {{ data }}
+ </option>
</cds-select>
<ng-template #ownerError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('owner', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('owner', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</div>
<ng-container *ngIf="selectedOption">
- <div class="form-item form-item-append"
- cdsRow>
-
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<!-- Destination Name -->
<div cdsCol>
<cds-text-label
i18n-helperText
cdRequiredField="Name"
[invalid]="topicForm.controls.name.invalid && topicForm.controls.name.dirty"
- [invalidText]="nameError">Name
+ [invalidText]="nameError"
+ >Name
- <input cdsText
- type="text"
- id="name"
- autofocus
- formControlName="name"
- [invalid]="topicForm.controls.name.invalid && topicForm.controls.name.dirty"/>
+ <input
+ cdsText
+ type="text"
+ id="name"
+ autofocus
+ formControlName="name"
+ [invalid]="topicForm.controls.name.invalid && topicForm.controls.name.dirty"
+ />
</cds-text-label>
<ng-template #nameError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('name', formDir, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('name', formDir, 'notUnique')"
- i18n>The name is already in use. Please choose a different one</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('name', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('name', formDir, 'notUnique')"
+ i18n
+ >The name is already in use. Please choose a different one</span
+ >
</ng-template>
</div>
</div>
- <div class="form-item"
- cdsRow>
+ <div
+ class="form-item"
+ cdsRow
+ >
<fieldset>
- <legend i18n
- cdsCol
- class="cd-header">
- Generate push endpoint
+ <legend
+ i18n
+ cdsCol
+ class="cd-header"
+ >
+ Generate push endpoint
<cd-help-text> Configure the endpoint URL to receive push notifications</cd-help-text>
</legend>
<!-- Enable SSL -->
- <div cdsCol
- [columnNumbers]="{sm: 4}">
- <cds-checkbox id="enable_ssl"
- formControlName="enable_ssl"
- (checkedChange)="onSecureSSLChange($event)">
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4 }"
+ >
+ <cds-checkbox
+ id="enable_ssl"
+ formControlName="enable_ssl"
+ (checkedChange)="onSecureSSLChange($event)"
+ >
<ng-container i18n>SSL</ng-container>
<cd-help-text i18n>
- Enabling SSL ensures that your connection is encrypted and secure. You must have a valid SSL certificate installed on your server.
+ Enabling SSL ensures that your connection is encrypted and secure. You must have a
+ valid SSL certificate installed on your server.
</cd-help-text>
</cds-checkbox>
</div>
<!-- Verify ssl -->
- <div cdsCol
- *ngIf="(selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.HTTP)"
- [columnNumbers]="{sm: 4}">
-
- <cds-checkbox id="verify_ssl"
- formControlName="verify_ssl">
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.HTTP"
+ [columnNumbers]="{ sm: 4 }"
+ >
+ <cds-checkbox
+ id="verify_ssl"
+ formControlName="verify_ssl"
+ >
<ng-container i18n>Verify SSL</ng-container>
- <cd-help-text i18n>Ensures that the server's SSL certificate is valid and trusted.</cd-help-text>
+ <cd-help-text i18n
+ >Ensures that the server's SSL certificate is valid and trusted.</cd-help-text
+ >
</cds-checkbox>
</div>
<!-- Cloud Event-->
- <div cdsCol
- *ngIf="(selectedOption == hostProtocols.HTTP)"
- [columnNumbers]="{sm: 4}">
- <cds-checkbox id="cloud_events"
- formControlName="cloud_events">
+ <div
+ cdsCol
+ *ngIf="selectedOption == hostProtocols.HTTP"
+ [columnNumbers]="{ sm: 4 }"
+ >
+ <cds-checkbox
+ id="cloud_events"
+ formControlName="cloud_events"
+ >
<ng-container i18n>Cloud events</ng-container>
<cd-help-text i18n>Captures cloud events as triggers for notifications.</cd-help-text>
</cds-checkbox>
</fieldset>
</div>
- <div cdsRow
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<!-- Fqdn-->
<div cdsCol>
<cds-text-label
[invalidText]="fqdnError"
helperText="Enter the FQDN/hostname/IP address for the push endpoint"
i18n-helperText
- i18n>
- Destination address
- <input cdsText
- type="text"
- id="fqdn"
- placeholder="e.g., 127.0.0.1 or localhost"
- formControlName="fqdn"
- [invalid]="topicForm.controls.fqdn.invalid && topicForm.controls.fqdn.dirty"
- (change)="generatePushEndpoint()"/>
+ i18n
+ >
+ Destination address
+ <input
+ cdsText
+ type="text"
+ id="fqdn"
+ placeholder="e.g., 127.0.0.1 or localhost"
+ formControlName="fqdn"
+ [invalid]="topicForm.controls.fqdn.invalid && topicForm.controls.fqdn.dirty"
+ (change)="generatePushEndpoint()"
+ />
</cds-text-label>
<ng-template #fqdnError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('fqdn', formDir, 'required')">This field is required</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('fqdn', formDir, 'required')"
+ >This field is required</span
+ >
</ng-template>
</div>
i18n-helperText
></cds-number>
<ng-template #portError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('port', formDir, 'required')"
- i18n>This field is required</span>
- <span class="invalid-feedback"
- *ngIf="topicForm.controls.port.hasError('pattern') && topicForm.controls.port.touched"
- i18n> Port must be a valid integer</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('port', formDir, 'required')"
+ i18n
+ >This field is required</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.controls.port.hasError('pattern') && topicForm.controls.port.touched"
+ i18n
+ >
+ Port must be a valid integer</span
+ >
</ng-template>
</div>
</div>
- <div cdsRow
- *ngIf="(selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA)"
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA"
+ class="form-item form-item-append"
+ >
<!-- User-->
<div cdsCol>
- <cds-text-label labelInputID="User"
- i18n
- helperText="Enter the user for the push endpoint"
- i18n-helperText>
+ <cds-text-label
+ labelInputID="User"
+ i18n
+ helperText="Enter the user for the push endpoint"
+ i18n-helperText
+ >
User
- <input cdsText
- type="text"
- id="user"
- formControlName="user"
- (change)="generatePushEndpoint()"/>
+ <input
+ cdsText
+ type="text"
+ id="user"
+ formControlName="user"
+ (change)="generatePushEndpoint()"
+ />
</cds-text-label>
</div>
<!-- password-->
- <div cdsCol
- *ngIf="(selectedOption !==hostProtocols.HTTP)">
- <cds-password-label labelInputID="password"
- [invalid]="!topicForm.controls.password.valid && topicForm.controls.password.dirty"
- [invalidText]="passwordError"
- i18n
- helperText="Enter the password for the push endpoint"
- i18n-helperText
- >
+ <div
+ cdsCol
+ *ngIf="selectedOption !== hostProtocols.HTTP"
+ >
+ <cds-password-label
+ labelInputID="password"
+ [invalid]="!topicForm.controls.password.valid && topicForm.controls.password.dirty"
+ [invalidText]="passwordError"
+ i18n
+ helperText="Enter the password for the push endpoint"
+ i18n-helperText
+ >
Password
- <input cdsPassword
- type="password"
- autocomplete="new-password"
- formControlName="password"
- (change)="generatePushEndpoint()"/>
+ <input
+ cdsPassword
+ type="password"
+ autocomplete="new-password"
+ formControlName="password"
+ (change)="generatePushEndpoint()"
+ />
</cds-password-label>
<ng-template #passwordError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('password', formDir, 'required')"
- i18n>This field is required</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('password', formDir, 'passwordPolicy')">
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('password', formDir, 'required')"
+ i18n
+ >This field is required</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('password', formDir, 'passwordPolicy')"
+ >
{{ passwordValuation }}
</span>
</ng-template>
</div>
<!--Vhost-->
- <div cdsRow
- class="form-item form-item-append"
- *ngIf="(selectedOption === hostProtocols.AMQP)">
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ *ngIf="selectedOption === hostProtocols.AMQP"
+ >
<div cdsCol>
- <cds-text-label labelInputID="Virtual Host(vhost)"
- i18n
- helperText="Enter the vhost for the push endpoint"
- i18n-helperText>
+ <cds-text-label
+ labelInputID="Virtual Host(vhost)"
+ i18n
+ helperText="Enter the vhost for the push endpoint"
+ i18n-helperText
+ >
Virtual Host(vhost)
- <input cdsText
- type="text"
- id="vhost"
- (change)="generatePushEndpoint()"
- formControlName="vhost" />
+ <input
+ cdsText
+ type="text"
+ id="vhost"
+ (change)="generatePushEndpoint()"
+ formControlName="vhost"
+ />
</cds-text-label>
</div>
</div>
- <div cdsRow
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<!--push_endpoint -->
<div cdsCol>
<cds-text-label
labelInputID="push_endpoint"
i18n
cdRequiredField="Push endpoint"
- [invalid]="topicForm.controls.push_endpoint.invalid && topicForm.controls.push_endpoint.dirty"
+ [invalid]="
+ topicForm.controls.push_endpoint.invalid && topicForm.controls.push_endpoint.dirty
+ "
[invalidText]="endpointError"
helperText="Specify the endpoint URL for receiving push notifications"
- i18n-helperText>
+ i18n-helperText
+ >
Push endpoint
<input
cdsText
i18n-placeholder
id="push_endpoint"
formControlName="push_endpoint"
- [invalid]="topicForm.controls.push_endpoint.invalid && topicForm.controls.push_endpoint.dirty"
+ [invalid]="
+ topicForm.controls.push_endpoint.invalid && topicForm.controls.push_endpoint.dirty
+ "
/>
</cds-text-label>
<ng-template #endpointError>
- <span class="invalid-feedback"
- *ngIf="topicForm.showError('push_endpoint', formDir, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="topicForm.showError('push_endpoint', formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</div>
- <ng-container *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA">
+ <ng-container
+ *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA"
+ >
<div class="form-item">
- <fieldset>
- <legend i18n
- class="cd-header">
- {{ selectedOption === 'AMQP' ? 'AMQP attributes' : 'KAFKA attributes' }}
- <cd-help-text> {{ attributeHelpText }}</cd-help-text>
- </legend>
- </fieldset>
+ <fieldset>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ {{ selectedOption === 'AMQP' ? 'AMQP attributes' : 'KAFKA attributes' }}
+ <cd-help-text> {{ attributeHelpText }}</cd-help-text>
+ </legend>
+ </fieldset>
<ng-container *ngIf="selectedOption === 'KAFKA'">
- <div cdsRow
- class="form-item-append">
-
- <div cdsCol
- *ngIf="selectedOption === 'KAFKA'">
- <cds-checkbox id="use-ssl"
- formControlName="use_ssl">
+ <div
+ cdsRow
+ class="form-item-append"
+ >
+ <div
+ cdsCol
+ *ngIf="selectedOption === 'KAFKA'"
+ >
+ <cds-checkbox
+ id="use-ssl"
+ formControlName="use_ssl"
+ >
<ng-container i18n>Use SSL</ng-container>
<cd-help-text i18n>
- Enabling SSL encrypts communication between your Kafka client and broker, ensuring the confidentiality and integrity of your messages
+ Enabling SSL encrypts communication between your Kafka client and broker,
+ ensuring the confidentiality and integrity of your messages
</cd-help-text>
</cds-checkbox>
</div>
</ng-container>
</div>
- <div class="form-item form-item-append"
- cdsRow>
-
- <!---CA location--->
- <div cdsCol
- *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA">
- <cds-text-label labelInputID="Ca-location"
- i18n
- helperText="The file path of the CA certificate used to verify the server"
- i18n-helperText>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
+ <!---CA location--->
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA"
+ >
+ <cds-text-label
+ labelInputID="Ca-location"
+ i18n
+ helperText="The file path of the CA certificate used to verify the server"
+ i18n-helperText
+ >
CA location
- <input cdsText
- type="text"
- id="ca_location"
- formControlName="ca_location"/>
+ <input
+ cdsText
+ type="text"
+ id="ca_location"
+ formControlName="ca_location"
+ />
</cds-text-label>
</div>
- <div cdsCol
- *ngIf="selectedOption === hostProtocols.AMQP">
- <cds-text-label labelInputID="AMQP exchange"
- i18n
- helperText="Name of the AMQP exchange to publish messages to; must exist on the broker"
- i18n-helperText>
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.AMQP"
+ >
+ <cds-text-label
+ labelInputID="AMQP exchange"
+ i18n
+ helperText="Name of the AMQP exchange to publish messages to; must exist on the broker"
+ i18n-helperText
+ >
AMQP exchange
- <input cdsText
- type="text"
- id="amqp_exchange"
- formControlName="amqp_exchange"/>
+ <input
+ cdsText
+ type="text"
+ id="amqp_exchange"
+ formControlName="amqp_exchange"
+ />
</cds-text-label>
</div>
<!-- mechanism-->
- <div cdsCol
- *ngIf="selectedOption ===hostProtocols.KAFKA">
- <cds-select formControlName="mechanism"
- label="Mechanism"
- i18n-label
- id="mechanism"
- helperText="Select the authentication mechanism to connect to the Kafka broker"
- i18n-helperText>
- <option i18n
- value="">-- Select a KAFKA mechanism --</option>
- <option *ngFor="let data of kafkaMechanism"
- i18n>{{ data }}</option>
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.KAFKA"
+ >
+ <cds-select
+ formControlName="mechanism"
+ label="Mechanism"
+ i18n-label
+ id="mechanism"
+ helperText="Select the authentication mechanism to connect to the Kafka broker"
+ i18n-helperText
+ >
+ <option
+ i18n
+ value=""
+ >
+ -- Select a KAFKA mechanism --
+ </option>
+ <option
+ *ngFor="let data of kafkaMechanism"
+ i18n
+ >
+ {{ data }}
+ </option>
</cds-select>
</div>
</div>
- <div class="form-item form-item-append"
- cdsRow>
-
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<!-- Ack level -->
- <div cdsCol
- *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA">
- <cds-select formControlName="ack_level"
- label="Ack level"
- i18n-label
- id="ack_level"
- helperText="Select the acknowledgment level to control message delivery guarantees between client and broker"
- i18n-helperText>
- <option i18n
- value="">-- Select the {{ selectedOption }} ack level --</option>
- <option *ngFor="let level of ackLevels"
- [value]="level"
- i18n>{{ level }}</option>
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.AMQP || selectedOption === hostProtocols.KAFKA"
+ >
+ <cds-select
+ formControlName="ack_level"
+ label="Ack level"
+ i18n-label
+ id="ack_level"
+ helperText="Select the acknowledgment level to control message delivery guarantees between client and broker"
+ i18n-helperText
+ >
+ <option
+ i18n
+ value=""
+ >
+ -- Select the {{ selectedOption }} ack level --
+ </option>
+ <option
+ *ngFor="let level of ackLevels"
+ [value]="level"
+ i18n
+ >
+ {{ level }}
+ </option>
</cds-select>
</div>
<!-- kafka-brokers-->
- <div cdsCol
- *ngIf="selectedOption === hostProtocols.KAFKA">
- <cds-text-label labelInputID="kafka_brokers"
- i18n
- helperText="Specify the address of the Kafka broker (e.g., host:9092) "
- i18n-helperText>
+ <div
+ cdsCol
+ *ngIf="selectedOption === hostProtocols.KAFKA"
+ >
+ <cds-text-label
+ labelInputID="kafka_brokers"
+ i18n
+ helperText="Specify the address of the Kafka broker (e.g., host:9092) "
+ i18n-helperText
+ >
Kafka brokers
- <input cdsText
- type="text"
- id="kafka_brokers"
- formControlName="kafka_brokers"/>
+ <input
+ cdsText
+ type="text"
+ id="kafka_brokers"
+ formControlName="kafka_brokers"
+ />
</cds-text-label>
</div>
</div>
</ng-container>
<ng-container>
- <div cdsRow
- class="form-item form-item-append">
- <legend i18n
- cdsCol
- class="cd-header">
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
+ <legend
+ i18n
+ cdsCol
+ class="cd-header"
+ >
Additional common attributes
- <cd-help-text>Configure additional attributes to customize the destination behavior and settings</cd-help-text>
+ <cd-help-text
+ >Configure additional attributes to customize the destination behavior and
+ settings</cd-help-text
+ >
</legend>
<!-- Persistent-->
- <div cdsCol
- [columnNumbers]="{sm: 4}">
- <cds-checkbox id="persistent"
- formControlName="persistent">
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4 }"
+ >
+ <cds-checkbox
+ id="persistent"
+ formControlName="persistent"
+ >
<ng-container i18n>Persistent</ng-container>
- <cd-help-text i18n> Select the checkbox to ensure notifications are retried.</cd-help-text>
+ <cd-help-text i18n>
+ Select the checkbox to ensure notifications are retried.</cd-help-text
+ >
</cds-checkbox>
</div>
</div>
- <div cdsRow
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<!-- Opaque data-->
<div cdsCol>
- <cds-text-label labelInputID="opaque_data"
- i18n
- i18n-helperText
- helperText="A user-defined metadata added to all notifications that are triggered by the destination.">
+ <cds-text-label
+ labelInputID="opaque_data"
+ i18n
+ i18n-helperText
+ helperText="A user-defined metadata added to all notifications that are triggered by the destination."
+ >
Opaque data
- <input cdsText
- type="text"
- id="opaqueData"
- formControlName="OpaqueData"/>
+ <input
+ cdsText
+ type="text"
+ id="opaqueData"
+ formControlName="OpaqueData"
+ />
</cds-text-label>
</div>
<!-- Time to live-->
<div cdsCol>
- <cds-number id="time_to_live"
- formControlName="time_to_live"
- label="Time to live"
- i18n-label
- [min]="1"
- helperText="Time limit (in seconds) for retaining notifications"
- i18n-helperText>Time to live </cds-number>
+ <cds-number
+ id="time_to_live"
+ formControlName="time_to_live"
+ label="Time to live"
+ i18n-label
+ [min]="1"
+ helperText="Time limit (in seconds) for retaining notifications"
+ i18n-helperText
+ >Time to live
+ </cds-number>
</div>
<!-- Max retries-->
<div cdsCol>
- <cds-number id="max_retries"
- label="Max retries"
- formControlName="max_retries"
- i18n-label
- [min]="1"
- helperText="Max retries before expiring notifications"
- i18n-helperText> Max retries </cds-number>
+ <cds-number
+ id="max_retries"
+ label="Max retries"
+ formControlName="max_retries"
+ i18n-label
+ [min]="1"
+ helperText="Max retries before expiring notifications"
+ i18n-helperText
+ >
+ Max retries
+ </cds-number>
</div>
<!-- Retry sleep duration-->
</div>
</div>
- <div cdsRow
- class="form-item form-item-append">
-
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
<!-- policy-->
<div cdsCol>
<cds-textarea-label i18n>
- <span> {{'Policy'}}</span>
- <textarea cdsTextArea
- #topicPolicyTextArea
- row="4"
- cols="200"
- formControlName="policy"
- aria-label="textarea"
- (change)="textAreaOnChange('topicPolicyTextArea')"></textarea>
+ <span> {{ 'Policy' }}</span>
+ <textarea
+ cdsTextArea
+ #topicPolicyTextArea
+ row="4"
+ cols="200"
+ formControlName="policy"
+ aria-label="textarea"
+ (change)="textAreaOnChange('topicPolicyTextArea')"
+ ></textarea>
</cds-textarea-label>
<cd-help-text i18n>JSON formatted document</cd-help-text>
<div cdsRow>
<div cdsCol>
<cds-button-set class="mt-1">
- <button cdsButton="tertiary"
- id="example-generator-button"
- (click)="openUrl('https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html?icmpid=docs_amazons3_console')"
- type="button"
- i18n>
+ <button
+ cdsButton="tertiary"
+ id="example-generator-button"
+ (click)="
+ openUrl(
+ 'https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html?icmpid=docs_amazons3_console'
+ )
+ "
+ type="button"
+ i18n
+ >
Policy examples
- <svg cdsIcon="launch"
- size="16"
- class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="launch"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
</button>
- <button cdsButton="tertiary"
- id="example-generator-button"
- type="button"
- (click)="openUrl('https://awspolicygen.s3.amazonaws.com/policygen.html')"
- i18n>
+ <button
+ cdsButton="tertiary"
+ id="example-generator-button"
+ type="button"
+ (click)="openUrl('https://awspolicygen.s3.amazonaws.com/policygen.html')"
+ i18n
+ >
Policy generator
- <svg cdsIcon="launch"
- size="16"
- class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="launch"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
<div cdsCol>
<cds-button-set class="float-end mt-1">
- <button cdsButton="tertiary"
- id="clear-bucket-policy"
- type="button"
- (click)="clearTextArea('policy', '{}')"
- i18n>
+ <button
+ cdsButton="tertiary"
+ id="clear-bucket-policy"
+ type="button"
+ (click)="clearTextArea('policy', '{}')"
+ i18n
+ >
Clear
- <svg cdsIcon="close"
- size="32"
- class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="close"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</button>
</cds-button-set>
</div>
</ng-container>
</ng-container>
<div class="card-footer">
- <cd-form-button-panel (submitActionEvent)="submitAction()"
- [form]="topicForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submitAction()"
+ [form]="topicForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</div>
</form>
- </div>
+</div>
- <ng-container>
+<ng-container>
<legend>
- <cd-help-text i18n>
- A topic specifies where and how event notifications from a bucket are delivered, including the target system (e.g., Kafka or HTTP) and its configuration.
- </cd-help-text>
+ <cd-help-text i18n>
+ A topic specifies where and how event notifications from a bucket are delivered, including the
+ target system (e.g., Kafka or HTTP) and its configuration.
+ </cd-help-text>
</legend>
- <cd-table #table
- headerTitle="Notification destination"
- headerDescription="Delivers bucket and object change notifications to external services like Kafka or AMQP."
- [autoReload]="true"
- [data]="topics$ | async"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- [hasDetails]="true"
- id="key"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- (fetchData)="fetchData()">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
- </cd-table-actions>
- <cd-rgw-topic-details *cdTableDetail
- [selection]="expandedRow"></cd-rgw-topic-details>
+ <cd-table
+ #table
+ headerTitle="Notification destination"
+ headerDescription="Delivers bucket and object change notifications to external services like Kafka or AMQP."
+ [autoReload]="true"
+ [data]="topics$ | async"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ [hasDetails]="true"
+ id="key"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ (fetchData)="fetchData()"
+ >
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ <cd-rgw-topic-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ ></cd-rgw-topic-details>
</cd-table>
- </ng-container>
+</ng-container>
@if (selection) {
-<cds-tabs>
- <cds-tab heading="Quotas" i18n-heading>
- <div class="row">
- @if (selection.quota) {
- <div class="col-sm-6">
- <legend i18n>Account quota</legend>
- <cd-table-key-value [data]="quota"> </cd-table-key-value>
+ <cds-tabs>
+ <cds-tab
+ heading="Quotas"
+ i18n-heading
+ >
+ <div class="row">
+ @if (selection.quota) {
+ <div class="col-sm-6">
+ <legend i18n>Account quota</legend>
+ <cd-table-key-value [data]="quota"> </cd-table-key-value>
+ </div>
+ }
+ @if (selection.bucket_quota) {
+ <div class="col-sm-6">
+ <legend i18n>Bucket quota</legend>
+ <cd-table-key-value [data]="bucket_quota"> </cd-table-key-value>
+ </div>
+ }
</div>
- } @if (selection.bucket_quota) {
- <div class="col-sm-6">
- <legend i18n>Bucket quota</legend>
- <cd-table-key-value [data]="bucket_quota"> </cd-table-key-value>
+ </cds-tab>
+ <cds-tab
+ heading="Roles"
+ i18n-heading
+ >
+ <div class="mt-4">
+ <cd-rgw-account-roles-list
+ [accountId]="selection.id"
+ [accountName]="selection.name"
+ ></cd-rgw-account-roles-list>
</div>
- }
- </div>
- </cds-tab>
- <cds-tab heading="Roles" i18n-heading>
- <div class="mt-4">
- <cd-rgw-account-roles-list
- [accountId]="selection.id"
- [accountName]="selection.name"
- ></cd-rgw-account-roles-list>
- </div>
- </cds-tab>
-</cds-tabs>
+ </cds-tab>
+ </cds-tabs>
}
-<div cdsCol
- [columnNumbers]="{md: 4}">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="accountForm"
- #formDir="ngForm"
- [formGroup]="accountForm"
- novalidate>
-
- <div i18n="form title"
- class="form-header cds--type-heading-04 cds-mb-5">{{ action | titlecase }} {{ resource | lowercase }}
+ <form
+ name="accountForm"
+ #formDir="ngForm"
+ [formGroup]="accountForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header cds--type-heading-04 cds-mb-5"
+ >
+ {{ action | titlecase }} {{ resource | lowercase }}
</div>
- <h4 class="cds--type-heading-03 cds-mb-4" i18n>Account details</h4>
+ <h4
+ class="cds--type-heading-03 cds-mb-4"
+ i18n
+ >
+ Account details
+ </h4>
<!-- Account Name -->
<div class="form-item">
- <cds-text-label label="Account name"
- for="acc_name"
- [invalid]="!accountForm.controls.name.valid && accountForm.controls.name.dirty"
- [invalidText]="accountIdError"
- helperText="Name must start and end in alphanumeric characters (3 to 63). Characters allowed: lowercase, numbers and nonconsecutive dots and hyphens."
- i18n-helperText
- i18n>Account name
- <input cdsText
- type="text"
- placeholder="for example, team-storage-01"
- id="acc_name"
- name="acc_name"
- cdValidate
- #accName="cdValidate"
- [invalid]="accName.isInvalid"
- formControlName="name"/>
+ <cds-text-label
+ label="Account name"
+ for="acc_name"
+ [invalid]="!accountForm.controls.name.valid && accountForm.controls.name.dirty"
+ [invalidText]="accountIdError"
+ helperText="Name must start and end in alphanumeric characters (3 to 63). Characters allowed: lowercase, numbers and nonconsecutive dots and hyphens."
+ i18n-helperText
+ i18n
+ >Account name
+ <input
+ cdsText
+ type="text"
+ placeholder="for example, team-storage-01"
+ id="acc_name"
+ name="acc_name"
+ cdValidate
+ #accName="cdValidate"
+ [invalid]="accName.isInvalid"
+ formControlName="name"
+ />
</cds-text-label>
<ng-template #accountIdError>
- <span *ngIf="accountForm.showError('name', formDir, 'required')"
- class="invalid-feedback">
+ <span
+ *ngIf="accountForm.showError('name', formDir, 'required')"
+ class="invalid-feedback"
+ >
<ng-container i18n>This field is required.</ng-container>
</span>
- @if(accountForm.showError('name', formDir, 'notUnique')) {
+ @if (accountForm.showError('name', formDir, 'notUnique')) {
<div class="invalid-feedback">
- <ng-container i18n>An account with this name already exists.</ng-container>
+ <ng-container i18n>An account with this name already exists.</ng-container>
</div>
}
</ng-template>
</div>
<!-- Tenant -->
<div class="form-item">
- <cds-text-label label="Tenant (optional)"
- for="tenant"
- helperText="Associates this account with an existing tenant namespace."
- i18n-helperText
- i18n>Tenant (optional)
- <input cdsText
- type="text"
- placeholder="for example, finance-team"
- id="tenant"
- name="tenant"
- formControlName="tenant"/>
+ <cds-text-label
+ label="Tenant (optional)"
+ for="tenant"
+ helperText="Associates this account with an existing tenant namespace."
+ i18n-helperText
+ i18n
+ >Tenant (optional)
+ <input
+ cdsText
+ type="text"
+ placeholder="for example, finance-team"
+ id="tenant"
+ name="tenant"
+ formControlName="tenant"
+ />
</cds-text-label>
</div>
<!-- Email -->
<div class="form-item">
- <cds-text-label label="Email address (optional)"
- for="email"
- [invalid]="!accountForm.controls.email.valid && accountForm.controls.email.dirty"
- [invalidText]="emailError"
- helperText="Contact for quota alerts and notifications."
- i18n-helperText
- i18n>Email address (optional)
- <input cdsText
- type="text"
- placeholder="for example, admin@example.com"
- id="email"
- name="email"
- formControlName="email"/>
+ <cds-text-label
+ label="Email address (optional)"
+ for="email"
+ [invalid]="!accountForm.controls.email.valid && accountForm.controls.email.dirty"
+ [invalidText]="emailError"
+ helperText="Contact for quota alerts and notifications."
+ i18n-helperText
+ i18n
+ >Email address (optional)
+ <input
+ cdsText
+ type="text"
+ placeholder="for example, admin@example.com"
+ id="email"
+ name="email"
+ formControlName="email"
+ />
</cds-text-label>
<ng-template #emailError>
<span *ngIf="accountForm.showError('email', formDir, 'email')">
</div>
<div class="form-item cds-mt-5 cds-mb-3">
- <h4 class="cds--type-heading-03" i18n>Advanced settings</h4>
- <p class="cds--type-body-01" i18n>Configure resource limits and quota for this account</p>
+ <h4
+ class="cds--type-heading-03"
+ i18n
+ >
+ Advanced settings
+ </h4>
+ <p
+ class="cds--type-body-01"
+ i18n
+ >
+ Configure resource limits and quota for this account
+ </p>
<div class="cds-mt-3">
- <button type="button" class="cds--btn cds--btn--ghost advanced-settings-btn" (click)="showAdvanced = !showAdvanced">
+ <button
+ type="button"
+ class="cds--btn cds--btn--ghost advanced-settings-btn"
+ (click)="showAdvanced = !showAdvanced"
+ >
{{ showAdvanced ? 'Hide advanced settings' : 'Show advanced settings' }}
- <svg cdsIcon="chevron--down" *ngIf="!showAdvanced" size="16" class="cds--btn__icon"></svg>
- <svg cdsIcon="chevron--up" *ngIf="showAdvanced" size="16" class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="chevron--down"
+ *ngIf="!showAdvanced"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
+ <svg
+ cdsIcon="chevron--up"
+ *ngIf="showAdvanced"
+ size="16"
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
</div>
<div *ngIf="showAdvanced">
- <h5 class="cds--type-heading-02 cds-mb-2" i18n>Resource limits</h5>
- <p class="cds--type-body-01 cds-mb-4" i18n>Set the mode and maximum allowed values for each resource type. Select Custom to specify a limit.</p>
+ <h5
+ class="cds--type-heading-02 cds-mb-2"
+ i18n
+ >
+ Resource limits
+ </h5>
+ <p
+ class="cds--type-body-01 cds-mb-4"
+ i18n
+ >
+ Set the mode and maximum allowed values for each resource type. Select Custom to specify a
+ limit.
+ </p>
- <div class="form-item form-item-append" cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Max. bucket mode -->
- <ng-container *ngTemplateOutlet="selectModeTemplate;context: { formControl: 'max_buckets_mode' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="selectModeTemplate; context: { formControl: 'max_buckets_mode' }"
+ ></ng-container>
</div>
<div cdsCol>
<!-- Max buckets -->
- <ng-container *ngTemplateOutlet="accountMaxValueTemplate;context: { formControl: 'max_buckets' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="accountMaxValueTemplate; context: { formControl: 'max_buckets' }"
+ ></ng-container>
</div>
</div>
- <div class="form-item form-item-append" cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Max. users mode -->
- <ng-container *ngTemplateOutlet="selectModeTemplate;context: { formControl: 'max_users_mode' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="selectModeTemplate; context: { formControl: 'max_users_mode' }"
+ ></ng-container>
</div>
<div cdsCol>
<!-- Max users -->
- <ng-container *ngTemplateOutlet="accountMaxValueTemplate;context: { formControl: 'max_users' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="accountMaxValueTemplate; context: { formControl: 'max_users' }"
+ ></ng-container>
</div>
</div>
- <div class="form-item form-item-append" cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Max. roles mode -->
- <ng-container *ngTemplateOutlet="selectModeTemplate;context: { formControl: 'max_roles_mode' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="selectModeTemplate; context: { formControl: 'max_roles_mode' }"
+ ></ng-container>
</div>
<div cdsCol>
<!-- Max roles -->
- <ng-container *ngTemplateOutlet="accountMaxValueTemplate;context: { formControl: 'max_roles' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="accountMaxValueTemplate; context: { formControl: 'max_roles' }"
+ ></ng-container>
</div>
</div>
- <div class="form-item form-item-append" cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Max. group mode -->
- <ng-container *ngTemplateOutlet="selectModeTemplate;context: { formControl: 'max_groups_mode' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="selectModeTemplate; context: { formControl: 'max_groups_mode' }"
+ ></ng-container>
</div>
<div cdsCol>
<!-- Max group -->
- <ng-container *ngTemplateOutlet="accountMaxValueTemplate;context: { formControl: 'max_groups' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="accountMaxValueTemplate; context: { formControl: 'max_groups' }"
+ ></ng-container>
</div>
</div>
- <div class="form-item form-item-append" cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<!-- Max. access keys mode -->
- <ng-container *ngTemplateOutlet="selectModeTemplate;context: { formControl: 'max_access_keys_mode' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ selectModeTemplate;
+ context: { formControl: 'max_access_keys_mode' }
+ "
+ ></ng-container>
</div>
<div cdsCol>
<!-- Max access keys -->
- <ng-container *ngTemplateOutlet="accountMaxValueTemplate;context: { formControl: 'max_access_keys' }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="
+ accountMaxValueTemplate;
+ context: { formControl: 'max_access_keys' }
+ "
+ ></ng-container>
</div>
</div>
- <h5 class="cds--type-heading-02 cds-mb-2 cds-mt-5" i18n>Quotas</h5>
- <p class="cds--type-body-01 cds-mb-4" i18n>Define storage usage limits for the account and the buckets it owns. Quotas help control capacity consumption and enforce resource allocation policies.</p>
+ <h5
+ class="cds--type-heading-02 cds-mb-2 cds-mt-5"
+ i18n
+ >
+ Quotas
+ </h5>
+ <p
+ class="cds--type-body-01 cds-mb-4"
+ i18n
+ >
+ Define storage usage limits for the account and the buckets it owns. Quotas help control
+ capacity consumption and enforce resource allocation policies.
+ </p>
<!-- Account Quota -->
<div class="form-item">
- <ng-container *ngTemplateOutlet="quotaTemplate;context: { formControl: {
- enabled: 'account_quota_enabled',
- unlimitedSize: 'account_quota_max_size_unlimited',
- maxSize: 'account_quota_max_size',
- unlimitedObjects: 'account_quota_max_objects_unlimited',
- maxObjects: 'account_quota_max_objects'
- },
- quotaType: 'account'
- }">
+ <ng-container
+ *ngTemplateOutlet="
+ quotaTemplate;
+ context: {
+ formControl: {
+ enabled: 'account_quota_enabled',
+ unlimitedSize: 'account_quota_max_size_unlimited',
+ maxSize: 'account_quota_max_size',
+ unlimitedObjects: 'account_quota_max_objects_unlimited',
+ maxObjects: 'account_quota_max_objects'
+ },
+ quotaType: 'account'
+ }
+ "
+ >
</ng-container>
</div>
<!-- Bucket Quota -->
<div class="form-item">
- <ng-container *ngTemplateOutlet="quotaTemplate;
- context: {
- formControl: {
- enabled: 'bucket_quota_enabled',
- unlimitedSize: 'bucket_quota_max_size_unlimited',
- maxSize: 'bucket_quota_max_size',
- unlimitedObjects: 'bucket_quota_max_objects_unlimited',
- maxObjects: 'bucket_quota_max_objects'
- },
- quotaType: 'bucket'
- }">
+ <ng-container
+ *ngTemplateOutlet="
+ quotaTemplate;
+ context: {
+ formControl: {
+ enabled: 'bucket_quota_enabled',
+ unlimitedSize: 'bucket_quota_max_size_unlimited',
+ maxSize: 'bucket_quota_max_size',
+ unlimitedObjects: 'bucket_quota_max_objects_unlimited',
+ maxObjects: 'bucket_quota_max_objects'
+ },
+ quotaType: 'bucket'
+ }
+ "
+ >
</ng-container>
</div>
</div>
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="formDir"
- [submitText]="(action | titlecase) + ' ' + (resource | lowercase)"
- wrappingClass="text-right"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="formDir"
+ [submitText]="(action | titlecase) + ' ' + (resource | lowercase)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</ng-container>
</div>
-<ng-template #selectModeTemplate
- [formGroup]="accountForm"
- let-formControl="formControl">
- <cds-select [formControlName]="formControl"
- [name]="formControl"
- [id]="formControl"
- label="{{formControl.split('_')[1] | upperFirst}} mode"
- (change)="onModeChange($event.target.value, formControl)"
- [helperText]="getHelperTextForMode(formControl)">
+<ng-template
+ #selectModeTemplate
+ [formGroup]="accountForm"
+ let-formControl="formControl"
+>
+ <cds-select
+ [formControlName]="formControl"
+ [name]="formControl"
+ [id]="formControl"
+ label="{{ formControl.split('_')[1] | upperFirst }} mode"
+ (change)="onModeChange($event.target.value, formControl)"
+ [helperText]="getHelperTextForMode(formControl)"
+ >
<option value="0">Unlimited</option>
<option value="-1">Disabled</option>
<option value="1">Custom</option>
</cds-select>
</ng-template>
-<ng-template #accountMaxValueTemplate
- let-formControl="formControl"
- [formGroup]="accountForm">
- <cds-number *ngIf="accountForm.get(formControl + '_mode').value == '1'"
- [id]="formControl"
- [name]="formControl"
- formControlName="{{formControl}}"
- label="Maximum {{formControl.replace('max_', '').replace('_', ' ')}}"
- [min]="1"
- [invalid]="!accountForm.controls[formControl].valid && accountForm.controls[formControl].dirty"
- [invalidText]="maxValError"></cds-number>
-
- <cds-text-label *ngIf="accountForm.get(formControl + '_mode').value != '1'"
- label="Maximum {{formControl.replace('max_', '').replace('_', ' ')}}"
- for="{{formControl}}_disabled">
- Maximum {{formControl.replace('max_', '').replace('_', ' ')}}
- <input cdsText
- type="text"
- [id]="formControl + '_disabled'"
- name="{{formControl}}_disabled"
- [ngModel]="'-'"
- [ngModelOptions]="{standalone: true}"
- [disabled]="true" />
+<ng-template
+ #accountMaxValueTemplate
+ let-formControl="formControl"
+ [formGroup]="accountForm"
+>
+ <cds-number
+ *ngIf="accountForm.get(formControl + '_mode').value == '1'"
+ [id]="formControl"
+ [name]="formControl"
+ formControlName="{{ formControl }}"
+ label="Maximum {{ formControl.replace('max_', '').replace('_', ' ') }}"
+ [min]="1"
+ [invalid]="!accountForm.controls[formControl].valid && accountForm.controls[formControl].dirty"
+ [invalidText]="maxValError"
+ ></cds-number>
+
+ <cds-text-label
+ *ngIf="accountForm.get(formControl + '_mode').value != '1'"
+ label="Maximum {{ formControl.replace('max_', '').replace('_', ' ') }}"
+ for="{{ formControl }}_disabled"
+ >
+ Maximum {{ formControl.replace('max_', '').replace('_', ' ') }}
+ <input
+ cdsText
+ type="text"
+ [id]="formControl + '_disabled'"
+ name="{{ formControl }}_disabled"
+ [ngModel]="'-'"
+ [ngModelOptions]="{ standalone: true }"
+ [disabled]="true"
+ />
</cds-text-label>
-<ng-template #maxValError>
- <span *ngIf="accountForm.showError(formControl, formDir, 'required')"
- i18n>This field is required.</span>
- <span *ngIf="accountForm.controls[formControl].value == 0 && accountForm.showError(formControl, formDir, 'min')"
- i18n>Enter number greater than 0</span>
- <span *ngIf="accountForm.showError(formControl, formDir, 'pattern')"
- i18n>Enter a valid positive number</span>
-</ng-template>
+ <ng-template #maxValError>
+ <span
+ *ngIf="accountForm.showError(formControl, formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="
+ accountForm.controls[formControl].value == 0 &&
+ accountForm.showError(formControl, formDir, 'min')
+ "
+ i18n
+ >Enter number greater than 0</span
+ >
+ <span
+ *ngIf="accountForm.showError(formControl, formDir, 'pattern')"
+ i18n
+ >Enter a valid positive number</span
+ >
+ </ng-template>
</ng-template>
-<ng-template #quotaTemplate
- let-quotaType="quotaType"
- let-formControl="formControl"
- [formGroup]="accountForm">
+<ng-template
+ #quotaTemplate
+ let-quotaType="quotaType"
+ let-formControl="formControl"
+ [formGroup]="accountForm"
+>
<fieldset class="cds--fieldset cds-mb-4">
- <legend class="cds--label">{{quotaType | upperFirst}} quota</legend>
+ <legend class="cds--label">{{ quotaType | upperFirst }} quota</legend>
<!-- Enabled -->
- <cds-checkbox *ngIf="quotaType == 'account'" [formControlName]="formControl.enabled"
- [id]="quotaType+'_checkbox'" class="cds-mb-3">
+ <cds-checkbox
+ *ngIf="quotaType == 'account'"
+ [formControlName]="formControl.enabled"
+ [id]="quotaType + '_checkbox'"
+ class="cds-mb-3"
+ >
Enable account quota
- </cds-checkbox >
- <cds-checkbox *ngIf="quotaType == 'bucket'" [formControlName]="formControl.enabled"
- [id]="quotaType+'_checkbox'" class="cds-mb-3">
+ </cds-checkbox>
+ <cds-checkbox
+ *ngIf="quotaType == 'bucket'"
+ [formControlName]="formControl.enabled"
+ [id]="quotaType + '_checkbox'"
+ class="cds-mb-3"
+ >
Enable bucket quota
- </cds-checkbox >
- <p class="cds--type-body-01 cds-mb-4" *ngIf="quotaType == 'account'">Applies a storage quota to each user account.</p>
- <p class="cds--type-body-01 cds-mb-4" *ngIf="quotaType == 'bucket'">Limits the total storage available across all buckets in an account.</p>
- <div class="quota-sub-block"
- *ngIf="accountForm.controls[formControl.enabled].value">
+ </cds-checkbox>
+ <p
+ class="cds--type-body-01 cds-mb-4"
+ *ngIf="quotaType == 'account'"
+ >
+ Applies a storage quota to each user account.
+ </p>
+ <p
+ class="cds--type-body-01 cds-mb-4"
+ *ngIf="quotaType == 'bucket'"
+ >
+ Limits the total storage available across all buckets in an account.
+ </p>
+ <div
+ class="quota-sub-block"
+ *ngIf="accountForm.controls[formControl.enabled].value"
+ >
<!-- Unlimited size -->
- <cds-checkbox *ngIf="accountForm.controls[formControl.enabled].value"
- [formControlName]="formControl.unlimitedSize"
- [id]="quotaType+'unlimitedSize_checkbox'">
- Unlimited size
+ <cds-checkbox
+ *ngIf="accountForm.controls[formControl.enabled].value"
+ [formControlName]="formControl.unlimitedSize"
+ [id]="quotaType + 'unlimitedSize_checkbox'"
+ >
+ Unlimited size
</cds-checkbox>
<!-- Maximum size -->
- <div class="input-wrapper"
- *ngIf="accountForm.controls[formControl.enabled].value && !accountForm.getValue(formControl.unlimitedSize)">
- <cds-text-label [label]="formControl.maxSize"
- [for]="formControl.maxSize"
- [invalid]="!accountForm.controls[formControl.maxSize].valid && accountForm.controls[formControl.maxSize].dirty"
- [invalidText]="quotaSizeError"
- i18n>Maximum size
- <input cdsText
- type="text"
- placeholder="Enter size"
- [id]="formControl.maxSize"
- [name]="formControl.maxSize"
- [formControlName]="formControl.maxSize"
- cdDimlessBinary/>
+ <div
+ class="input-wrapper"
+ *ngIf="
+ accountForm.controls[formControl.enabled].value &&
+ !accountForm.getValue(formControl.unlimitedSize)
+ "
+ >
+ <cds-text-label
+ [label]="formControl.maxSize"
+ [for]="formControl.maxSize"
+ [invalid]="
+ !accountForm.controls[formControl.maxSize].valid &&
+ accountForm.controls[formControl.maxSize].dirty
+ "
+ [invalidText]="quotaSizeError"
+ i18n
+ >Maximum size
+ <input
+ cdsText
+ type="text"
+ placeholder="Enter size"
+ [id]="formControl.maxSize"
+ [name]="formControl.maxSize"
+ [formControlName]="formControl.maxSize"
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #quotaSizeError>
- <span *ngIf="accountForm.showError(formControl.maxSize, formDir, 'required')"
- i18n>This field is required.</span>
- <span *ngIf="accountForm.showError(formControl.maxSize, formDir, 'quotaMaxSize')"
- i18n>Enter a valid value.</span>
- <span *ngIf="accountForm.showError(formControl.maxSize, formDir, 'pattern')"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ *ngIf="accountForm.showError(formControl.maxSize, formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="accountForm.showError(formControl.maxSize, formDir, 'quotaMaxSize')"
+ i18n
+ >Enter a valid value.</span
+ >
+ <span
+ *ngIf="accountForm.showError(formControl.maxSize, formDir, 'pattern')"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
<!-- Unlimited objects -->
- <cds-checkbox *ngIf="accountForm.controls[formControl.enabled].value"
- [formControlName]="formControl.unlimitedObjects"
- [id]="quotaType+'unlimitedObjects_checkbox'">
- Unlimited objects
+ <cds-checkbox
+ *ngIf="accountForm.controls[formControl.enabled].value"
+ [formControlName]="formControl.unlimitedObjects"
+ [id]="quotaType + 'unlimitedObjects_checkbox'"
+ >
+ Unlimited objects
</cds-checkbox>
- <!-- Maximum objects -->
- <div class="input-wrapper"
- *ngIf="accountForm.controls[formControl.enabled].value && !accountForm.getValue(formControl.unlimitedObjects)">
- <cds-text-label [label]="formControl.maxObjects"
- [for]="formControl.maxObjects"
- [invalid]="!accountForm.controls[formControl.maxObjects].valid && accountForm.controls[formControl.maxObjects].dirty"
- [invalidText]="quotaObjectError"
- i18n>Maximum objects
- <input cdsText
- type="number"
- placeholder="Enter number of objects"
- [id]="formControl.maxObjects"
- [name]="formControl.maxObjects"
- [formControlName]="formControl.maxObjects"/>
+ <!-- Maximum objects -->
+ <div
+ class="input-wrapper"
+ *ngIf="
+ accountForm.controls[formControl.enabled].value &&
+ !accountForm.getValue(formControl.unlimitedObjects)
+ "
+ >
+ <cds-text-label
+ [label]="formControl.maxObjects"
+ [for]="formControl.maxObjects"
+ [invalid]="
+ !accountForm.controls[formControl.maxObjects].valid &&
+ accountForm.controls[formControl.maxObjects].dirty
+ "
+ [invalidText]="quotaObjectError"
+ i18n
+ >Maximum objects
+ <input
+ cdsText
+ type="number"
+ placeholder="Enter number of objects"
+ [id]="formControl.maxObjects"
+ [name]="formControl.maxObjects"
+ [formControlName]="formControl.maxObjects"
+ />
</cds-text-label>
<ng-template #quotaObjectError>
- <span *ngIf="accountForm.showError(formControl.maxObjects, formDir, 'required')"
- i18n>This field is required.</span>
- <span *ngIf="accountForm.showError(formControl.maxObjects, formDir, 'pattern')"
- i18n>Enter a valid positive number</span>
+ <span
+ *ngIf="accountForm.showError(formControl.maxObjects, formDir, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ *ngIf="accountForm.showError(formControl.maxObjects, formDir, 'pattern')"
+ i18n
+ >Enter a valid positive number</span
+ >
</ng-template>
</div>
</div>
<cd-rgw-user-tabs></cd-rgw-user-tabs>
<legend i18n>
User Accounts
- <cd-help-text>
- Create and manage accounts and their permissions.
- </cd-help-text>
+ <cd-help-text> Create and manage accounts and their permissions. </cd-help-text>
</legend>
-<cd-table #table
- [autoReload]="false"
- [data]="accounts"
- [columns]="columns"
- selectionType="single"
- columnMode="flex"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- identifier="id"
- (fetchData)="getAccountsList($event)"
- [status]="tableStatus">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [autoReload]="false"
+ [data]="accounts"
+ [columns]="columns"
+ selectionType="single"
+ columnMode="flex"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ identifier="id"
+ (fetchData)="getAccountsList($event)"
+ [status]="tableStatus"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-rgw-user-accounts-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-rgw-user-accounts-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rgw-user-accounts-details>
</cd-table>
-
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
- <form #frm="ngForm"
- [formGroup]="formGroup"
- novalidate>
- <div cdsModalContent>
- <!-- Type -->
- <div class="form-item">
- <cds-text-label for="type"
- [invalid]="formGroup.controls.type.invalid && formGroup.controls.type.dirty"
- [invalidText]="typeError"
- *ngIf="editing"
- i18n>Type
- <input cdsText
- id="type"
- name="type"
- formControlName="type"
- [readonly]="true"
- modal-primary-focus>
- </cds-text-label>
+ <form
+ #frm="ngForm"
+ [formGroup]="formGroup"
+ novalidate
+ >
+ <div cdsModalContent>
+ <!-- Type -->
+ <div class="form-item">
+ <cds-text-label
+ for="type"
+ [invalid]="formGroup.controls.type.invalid && formGroup.controls.type.dirty"
+ [invalidText]="typeError"
+ *ngIf="editing"
+ i18n
+ >Type
+ <input
+ cdsText
+ id="type"
+ name="type"
+ formControlName="type"
+ [readonly]="true"
+ modal-primary-focus
+ />
+ </cds-text-label>
- <cds-select *ngIf="!editing"
- label="Type"
- i18n-label
- for="type"
- formControlName="type"
- [invalid]="formGroup.controls.type.invalid && formGroup.controls.type.dirty"
- [invalidText]="typeError">
- <option value="">--- Select a type ---</option>
- <option *ngFor="let type of types"
- [value]="type">{{ type }}</option>
- </cds-select>
- <ng-template #typeError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('type', frm, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <cds-select
+ *ngIf="!editing"
+ label="Type"
+ i18n-label
+ for="type"
+ formControlName="type"
+ [invalid]="formGroup.controls.type.invalid && formGroup.controls.type.dirty"
+ [invalidText]="typeError"
+ >
+ <option value="">--- Select a type ---</option>
+ <option
+ *ngFor="let type of types"
+ [value]="type"
+ >
+ {{ type }}
+ </option>
+ </cds-select>
+ <ng-template #typeError>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('type', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
+ </div>
- <!-- Permission -->
- <div class="form-item">
- <cds-select label="Permission"
- i18n-label
- for="perm"
- formControlName="perm"
- [invalid]="formGroup.controls.perm.invalid && formGroup.controls.perm.dirty"
- [invalidText]="permError">
- <option value="">--- Select a permission ---</option>
- <option *ngFor="let perm of ['read', 'write', '*']"
- [value]="perm">
- {{ perm }}
- </option>
- </cds-select>
+ <!-- Permission -->
+ <div class="form-item">
+ <cds-select
+ label="Permission"
+ i18n-label
+ for="perm"
+ formControlName="perm"
+ [invalid]="formGroup.controls.perm.invalid && formGroup.controls.perm.dirty"
+ [invalidText]="permError"
+ >
+ <option value="">--- Select a permission ---</option>
+ <option
+ *ngFor="let perm of ['read', 'write', '*']"
+ [value]="perm"
+ >
+ {{ perm }}
+ </option>
+ </cds-select>
- <ng-template #permError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('perm', frm, 'required')"
- i18n>This field is required.</span>
- </ng-template>
- </div>
+ <ng-template #permError>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('perm', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
</div>
+ </div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="formGroup"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</cds-modal>
>
<tbody>
<tr>
- <td i18n
- class="bold w-25">Tenant</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Tenant
+ </td>
<td class="w-75">{{ user.tenant }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">User ID</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ User ID
+ </td>
<td class="w-75">{{ user.uid }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Username</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Username
+ </td>
<td class="w-75">{{ user.uid }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Full name</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Full name
+ </td>
<td>{{ user.display_name }}</td>
</tr>
<tr *ngIf="user.email?.length">
- <td i18n
- class="bold">Email address</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Email address
+ </td>
<td>{{ user.email }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Suspended</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Suspended
+ </td>
<td>{{ user.suspended | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">System user</td>
+ <td
+ i18n
+ class="bold"
+ >
+ System user
+ </td>
<td>{{ user.system | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum buckets</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum buckets
+ </td>
<td>{{ user.max_buckets | map: maxBucketsMap }}</td>
</tr>
- @if (user.type === 'rgw' && selection.account?.id){
- <tr>
- <td i18n
- class="bold">Managed policies</td>
- <td i18n>{{ extractPolicyNamesFromArns(user.managed_user_policies) }}</td>
- </tr>
+ @if (user.type === 'rgw' && selection.account?.id) {
+ <tr>
+ <td
+ i18n
+ class="bold"
+ >
+ Managed policies
+ </td>
+ <td i18n>{{ extractPolicyNamesFromArns(user.managed_user_policies) }}</td>
+ </tr>
}
<tr *ngIf="user.subusers && user.subusers.length">
- <td i18n
- class="bold">Subusers</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Subusers
+ </td>
<td>
<div *ngFor="let subuser of user.subusers">
{{ subuser.id }} ({{ subuser.permissions }})
</td>
</tr>
<tr *ngIf="user.caps && user.caps.length">
- <td i18n
- class="bold">Capabilities</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Capabilities
+ </td>
<td>
<div *ngFor="let cap of user.caps">{{ cap.type }} ({{ cap.perm }})</div>
</td>
</tr>
<tr *ngIf="user.mfa_ids?.length">
- <td i18n
- class="bold">MFAs(Id)</td>
+ <td
+ i18n
+ class="bold"
+ >
+ MFAs(Id)
+ </td>
<td>{{ user.mfa_ids | join }}</td>
</tr>
</tbody>
<ng-container *ngIf="selection.account && selection.account?.id">
<legend i18n>Account Details</legend>
- <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
- id="accountsDetails">
+ <table
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ id="accountsDetails"
+ >
<tbody>
<tr>
- <td i18n
- class="bold w-25">Account ID</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Account ID
+ </td>
<td class="w-75">{{ selection.account?.id }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Name</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Name
+ </td>
<td class="w-75">{{ selection.account?.name }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">Tenant</td>
- <td class="w-75">{{ selection.account?.tenant || '-'}}</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Tenant
+ </td>
+ <td class="w-75">{{ selection.account?.tenant || '-' }}</td>
</tr>
<tr>
- <td i18n
- class="bold w-25">User type</td>
- <td class="w-75"
- i18n>{{ user?.type === 'root' ? 'Account root user' : 'rgw user' }}</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ User type
+ </td>
+ <td
+ class="w-75"
+ i18n
+ >
+ {{ user?.type === 'root' ? 'Account root user' : 'rgw user' }}
+ </td>
</tr>
</tbody>
</table>
>
<tbody>
<tr>
- <td i18n
- class="bold w-25">Enabled</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Enabled
+ </td>
<td class="w-75">{{ user.user_quota.enabled | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum size</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum size
+ </td>
<td *ngIf="!user.user_quota.enabled">-</td>
- <td *ngIf="user.user_quota.enabled && user.user_quota.max_size <= -1"
- i18n>
+ <td
+ *ngIf="user.user_quota.enabled && user.user_quota.max_size <= -1"
+ i18n
+ >
Unlimited
</td>
<td *ngIf="user.user_quota.enabled && user.user_quota.max_size > -1">
</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum objects</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum objects
+ </td>
<td *ngIf="!user.user_quota.enabled">-</td>
- <td *ngIf="user.user_quota.enabled && user.user_quota.max_objects <= -1"
- i18n>
+ <td
+ *ngIf="user.user_quota.enabled && user.user_quota.max_objects <= -1"
+ i18n
+ >
Unlimited
</td>
<td *ngIf="user.user_quota.enabled && user.user_quota.max_objects > -1">
>
<tbody>
<tr>
- <td i18n
- class="bold w-25">Enabled</td>
+ <td
+ i18n
+ class="bold w-25"
+ >
+ Enabled
+ </td>
<td class="w-75">{{ user.bucket_quota.enabled | booleanText }}</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum size</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum size
+ </td>
<td *ngIf="!user.bucket_quota.enabled">-</td>
- <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size <= -1"
- i18n>
+ <td
+ *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size <= -1"
+ i18n
+ >
Unlimited
</td>
<td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_size > -1">
</td>
</tr>
<tr>
- <td i18n
- class="bold">Maximum objects</td>
+ <td
+ i18n
+ class="bold"
+ >
+ Maximum objects
+ </td>
<td *ngIf="!user.bucket_quota.enabled">-</td>
- <td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects <= -1"
- i18n>
+ <td
+ *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects <= -1"
+ i18n
+ >
Unlimited
</td>
<td *ngIf="user.bucket_quota.enabled && user.bucket_quota.max_objects > -1">
-<div cdsCol
- [columnNumbers]="{md: 4}"
- *cdFormLoading="loading">
- <form #frm="ngForm"
- [formGroup]="userForm"
- novalidate>
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
-
- @if(accounts.length > 0){
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ *cdFormLoading="loading"
+>
+ <form
+ #frm="ngForm"
+ [formGroup]="userForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
+
+ @if (accounts.length > 0) {
<!-- Link Account -->
<div class="form-item">
- <cds-select label="Link Account"
- i18n-label
- id="link_account"
- for="link_account"
- formControlName="account_id"
- [invalid]="userForm.controls.account_id.invalid && userForm.controls.account_id.dirty"
- [invalidText]="accountError"
- [helperText]="accountsHelper">
- <option i18n
- *ngIf="accounts === null"
- [ngValue]="null">Loading...</option>
- <option i18n
- *ngIf="accounts !== null"
- [value]="''">-- Select an Account --</option>
- <option *ngFor="let account of accounts"
- [value]="account.id">{{ account.name }} {{account.tenant ? '- '+account.tenant : ''}}</option>
+ <cds-select
+ label="Link Account"
+ i18n-label
+ id="link_account"
+ for="link_account"
+ formControlName="account_id"
+ [invalid]="userForm.controls.account_id.invalid && userForm.controls.account_id.dirty"
+ [invalidText]="accountError"
+ [helperText]="accountsHelper"
+ >
+ <option
+ i18n
+ *ngIf="accounts === null"
+ [ngValue]="null"
+ >
+ Loading...
+ </option>
+ <option
+ i18n
+ *ngIf="accounts !== null"
+ [value]="''"
+ >
+ -- Select an Account --
+ </option>
+ <option
+ *ngFor="let account of accounts"
+ [value]="account.id"
+ >
+ {{ account.name }} {{ account.tenant ? '- ' + account.tenant : '' }}
+ </option>
</cds-select>
<ng-template #accountError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('account_id', frm, 'tenantedAccount')"
- i18n>Only accounts with the same tenant name can be linked to a tenanted user.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('account_id', frm, 'tenantedAccount')"
+ i18n
+ >Only accounts with the same tenant name can be linked to a tenanted user.</span
+ >
</ng-template>
<ng-template #accountsHelper>
- <div i18n>Account membership is permanent. Once added, users cannot be removed from their account.</div>
+ <div i18n>
+ Account membership is permanent. Once added, users cannot be removed from their account.
+ </div>
<div i18n>Ownership of all of the user's buckets will be transferred to the account.</div>
</ng-template>
</div>
<!-- Account Root user -->
- <div *ngIf="userForm.getValue('account_id')"
- class="form-item">
- <cds-checkbox formControlName="account_root_user"
- id="account_root_user"
- i18n>Account Root user
- <cd-help-text>The account root user has full access to all resources and manages the account.
- It's recommended to use this account for management tasks only and create additional users with specific permissions.
+ <div
+ *ngIf="userForm.getValue('account_id')"
+ class="form-item"
+ >
+ <cds-checkbox
+ formControlName="account_root_user"
+ id="account_root_user"
+ i18n
+ >Account Root user
+ <cd-help-text
+ >The account root user has full access to all resources and manages the account. It's
+ recommended to use this account for management tasks only and create additional users
+ with specific permissions.
</cd-help-text>
</cds-checkbox>
</div>
<!-- User ID -->
<div class="form-item">
- <cds-text-label for="user_id"
- i18n
- cdRequiredField="User ID"
- [invalid]="userForm.controls.user_id.invalid && (userForm.controls.user_id.dirty)"
- [invalidText]="userError">User ID
- <input cdsText
- formControlName="user_id"
- name="user_id"
- id="user_id"
- [invalid]="userForm.controls.user_id.invalid && (userForm.controls.user_id.dirty)"
- [readonly]="editing"
- [autofocus]="!editing"/>
+ <cds-text-label
+ for="user_id"
+ i18n
+ cdRequiredField="User ID"
+ [invalid]="userForm.controls.user_id.invalid && userForm.controls.user_id.dirty"
+ [invalidText]="userError"
+ >User ID
+ <input
+ cdsText
+ formControlName="user_id"
+ name="user_id"
+ id="user_id"
+ [invalid]="userForm.controls.user_id.invalid && userForm.controls.user_id.dirty"
+ [readonly]="editing"
+ [autofocus]="!editing"
+ />
</cds-text-label>
<ng-template #userError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_id', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_id', frm, 'pattern')"
- i18n>The value is not valid.</span>
- <span class="invalid-feedback"
- *ngIf="!userForm.getValue('show_tenant') && userForm.showError('user_id', frm, 'notUnique')"
- i18n>The chosen user ID is already in use.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_id', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_id', frm, 'pattern')"
+ i18n
+ >The value is not valid.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="
+ !userForm.getValue('show_tenant') && userForm.showError('user_id', frm, 'notUnique')
+ "
+ i18n
+ >The chosen user ID is already in use.</span
+ >
</ng-template>
</div>
<!-- Show Tenant -->
<div class="form-item">
- <cds-checkbox formControlName="show_tenant"
- id="show_tenant"
- [readonly]="true"
- (checkedChange)="updateFieldsWhenTenanted()">Show Tenant
+ <cds-checkbox
+ formControlName="show_tenant"
+ id="show_tenant"
+ [readonly]="true"
+ (checkedChange)="updateFieldsWhenTenanted()"
+ >Show Tenant
</cds-checkbox>
</div>
<!-- Tenant -->
- <div class="form-item"
- *ngIf="userForm.getValue('show_tenant')">
- <cds-text-label for="tenant"
- i18n
- [invalid]="userForm.controls.tenant.invalid && (userForm.controls.tenant.dirty)"
- [invalidText]="tenantError">Tenant
- <input cdsText
- formControlName="tenant"
- name="tenant"
- id="tenant"
- [invalid]="userForm.controls.tenant.invalid && (userForm.controls.tenant.dirty)"
- [readonly]="editing"
- autofocus/>
+ <div
+ class="form-item"
+ *ngIf="userForm.getValue('show_tenant')"
+ >
+ <cds-text-label
+ for="tenant"
+ i18n
+ [invalid]="userForm.controls.tenant.invalid && userForm.controls.tenant.dirty"
+ [invalidText]="tenantError"
+ >Tenant
+ <input
+ cdsText
+ formControlName="tenant"
+ name="tenant"
+ id="tenant"
+ [invalid]="userForm.controls.tenant.invalid && userForm.controls.tenant.dirty"
+ [readonly]="editing"
+ autofocus
+ />
</cds-text-label>
<ng-template #tenantError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('tenant', frm, 'pattern')"
- i18n>The value is not valid.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('tenant', frm, 'notUnique')"
- i18n>The chosen user ID exists in this tenant.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('tenant', frm, 'pattern')"
+ i18n
+ >The value is not valid.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('tenant', frm, 'notUnique')"
+ i18n
+ >The chosen user ID exists in this tenant.</span
+ >
</ng-template>
</div>
<!-- Full name -->
<div class="form-item">
- <cds-text-label for="display_name"
- i18n
- cdRequiredField="Full name"
- [invalid]="userForm.controls.display_name.invalid && (userForm.controls.display_name.dirty)"
- [invalidText]="displayNameError">Full name
- <input cdsText
- formControlName="display_name"
- name="display_name"
- id="display_name"
- [invalid]="userForm.showError('display_name', formDir)"/>
+ <cds-text-label
+ for="display_name"
+ i18n
+ cdRequiredField="Full name"
+ [invalid]="userForm.controls.display_name.invalid && userForm.controls.display_name.dirty"
+ [invalidText]="displayNameError"
+ >Full name
+ <input
+ cdsText
+ formControlName="display_name"
+ name="display_name"
+ id="display_name"
+ [invalid]="userForm.showError('display_name', formDir)"
+ />
</cds-text-label>
<ng-template #displayNameError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('display_name', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('display_name', frm, 'pattern')"
- i18n>The value is not valid.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('display_name', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('display_name', frm, 'pattern')"
+ i18n
+ >The value is not valid.</span
+ >
</ng-template>
</div>
<!-- Email address -->
<div class="form-item">
- <cds-text-label for="email"
- i18n
- [invalid]="userForm.controls.email.invalid && (userForm.controls.email.dirty)"
- [invalidText]="emailError">Email address
- <input cdsText
- formControlName="email"
- name="email"
- id="email"
- [invalid]="userForm.controls.email.invalid && (userForm.controls.email.dirty)"/>
+ <cds-text-label
+ for="email"
+ i18n
+ [invalid]="userForm.controls.email.invalid && userForm.controls.email.dirty"
+ [invalidText]="emailError"
+ >Email address
+ <input
+ cdsText
+ formControlName="email"
+ name="email"
+ id="email"
+ [invalid]="userForm.controls.email.invalid && userForm.controls.email.dirty"
+ />
</cds-text-label>
<ng-template #emailError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('email', frm, 'email')"
- i18n>This is not a valid email address.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('email', frm, 'notUnique')"
- i18n>The chosen email address is already in use.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('email', frm, 'email')"
+ i18n
+ >This is not a valid email address.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('email', frm, 'notUnique')"
+ i18n
+ >The chosen email address is already in use.</span
+ >
</ng-template>
</div>
<!-- Max. buckets -->
<div class="form-item">
- <cds-select label="Maximum buckets"
- for="max_buckets_mode"
- formControlName="max_buckets_mode"
- id="max_buckets_mode"
- (valueChange)="onMaxBucketsModeChange($event)">
- <option value="-1"
- i18n>Disabled</option>
- <option value="0"
- i18n>Unlimited</option>
- <option value="1"
- i18n>Custom</option>
+ <cds-select
+ label="Maximum buckets"
+ for="max_buckets_mode"
+ formControlName="max_buckets_mode"
+ id="max_buckets_mode"
+ (valueChange)="onMaxBucketsModeChange($event)"
+ >
+ <option
+ value="-1"
+ i18n
+ >
+ Disabled
+ </option>
+ <option
+ value="0"
+ i18n
+ >
+ Unlimited
+ </option>
+ <option
+ value="1"
+ i18n
+ >
+ Custom
+ </option>
</cds-select>
</div>
- <div *ngIf="1 == userForm.get('max_buckets_mode').value"
- class="form-item">
- <cds-number for="max_buckets"
- formControlName="max_buckets"
- id="max_buckets"
- min="1"
- [invalid]="userForm.controls.max_buckets.invalid && (userForm.controls.max_buckets.dirty)"
- [invalidText]="maxBucketsError"></cds-number>
+ <div
+ *ngIf="1 == userForm.get('max_buckets_mode').value"
+ class="form-item"
+ >
+ <cds-number
+ for="max_buckets"
+ formControlName="max_buckets"
+ id="max_buckets"
+ min="1"
+ [invalid]="userForm.controls.max_buckets.invalid && userForm.controls.max_buckets.dirty"
+ [invalidText]="maxBucketsError"
+ ></cds-number>
<ng-template #maxBucketsError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('max_buckets', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- i18n>The entered value must be >= 1.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('max_buckets', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ i18n
+ >The entered value must be >= 1.</span
+ >
</ng-template>
</div>
<!-- Suspended -->
<div class="form-item">
- <cds-checkbox formControlName="suspended"
- id="suspended"
- i18n>Suspended
+ <cds-checkbox
+ formControlName="suspended"
+ id="suspended"
+ i18n
+ >Suspended
<cd-help-text>Suspending the user disables the user and subuser.</cd-help-text>
</cds-checkbox>
</div>
<!-- System User -->
<div class="form-item">
- <cds-checkbox formControlName="system"
- id="system"
- i18n>System user
- <cd-help-text>System users are distinct from regular users, they are used by the RGW service to perform administrative tasks, manage buckets and objects</cd-help-text>
+ <cds-checkbox
+ formControlName="system"
+ id="system"
+ i18n
+ >System user
+ <cd-help-text
+ >System users are distinct from regular users, they are used by the RGW service to perform
+ administrative tasks, manage buckets and objects</cd-help-text
+ >
</cds-checkbox>
</div>
- @if(userForm.getValue('account_id') && !userForm.getValue('account_root_user')) {
- <!-- Managed policies -->
- <fieldset>
- <div class="form-item">
- <legend i18n
- class="cd-header">Managed policies</legend>
- <cds-combo-box label="Policies"
- type="multi"
- selectionFeedback="top-after-reopen"
- formControlName="account_policies"
- id="account_policies"
- placeholder="Select managed policies..."
- i18n-placeholder
- [appendInline]="true"
- [items]="managedPolicies"
- (selected)="multiSelector($event)"
- itemValueKey="name"
- i18n-label
- i18n>
- <cds-dropdown-list></cds-dropdown-list>
- </cds-combo-box>
- </div>
- </fieldset>
+ @if (userForm.getValue('account_id') && !userForm.getValue('account_root_user')) {
+ <!-- Managed policies -->
+ <fieldset>
+ <div class="form-item">
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Managed policies
+ </legend>
+ <cds-combo-box
+ label="Policies"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ formControlName="account_policies"
+ id="account_policies"
+ placeholder="Select managed policies..."
+ i18n-placeholder
+ [appendInline]="true"
+ [items]="managedPolicies"
+ (selected)="multiSelector($event)"
+ itemValueKey="name"
+ i18n-label
+ i18n
+ >
+ <cds-dropdown-list></cds-dropdown-list>
+ </cds-combo-box>
+ </div>
+ </fieldset>
}
<!-- S3 key -->
<fieldset *ngIf="!editing">
- <legend i18n
- class="cd-header">S3 key</legend>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ S3 key
+ </legend>
<!-- Auto-generate key -->
<div class="form-item">
- <cds-checkbox formControlName="generate_key"
- id="generate_key"
- i18n>Auto-generate key</cds-checkbox>
+ <cds-checkbox
+ formControlName="generate_key"
+ id="generate_key"
+ i18n
+ >Auto-generate key</cds-checkbox
+ >
</div>
<!-- Access key -->
- <div class="form-item form-item-append"
- *ngIf="!editing && !userForm.getValue('generate_key')">
- <cds-password-label for="access_key"
- i18n
- cdRequiredField="Access key"
- [invalid]="userForm.controls.access_key.invalid && (userForm.controls.access_key.dirty)"
- [invalidText]="accessKeyError">Access key
- <input cdsPassword
- type="password"
- formControlName="access_key"
- name="access_key"
- id="access_key"
- [invalid]="userForm.controls.access_key.invalid && (userForm.controls.access_key.dirty)"/>
+ <div
+ class="form-item form-item-append"
+ *ngIf="!editing && !userForm.getValue('generate_key')"
+ >
+ <cds-password-label
+ for="access_key"
+ i18n
+ cdRequiredField="Access key"
+ [invalid]="userForm.controls.access_key.invalid && userForm.controls.access_key.dirty"
+ [invalidText]="accessKeyError"
+ >Access key
+ <input
+ cdsPassword
+ type="password"
+ formControlName="access_key"
+ name="access_key"
+ id="access_key"
+ [invalid]="userForm.controls.access_key.invalid && userForm.controls.access_key.dirty"
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="access_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="access_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
<ng-template #accessKeyError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('access_key', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('access_key', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Secret key -->
- <div class="form-item form-item-append"
- *ngIf="!editing && !userForm.getValue('generate_key')">
- <cds-password-label for="secret"
- i18n
- cdRequiredField="Secret key"
- [invalid]="userForm.controls.secret_key.invalid && (userForm.controls.secret_key.dirty)"
- [invalidText]="secretKeyError">Secret key
- <input cdsPassword
- type="password"
- formControlName="secret_key"
- name="secret_key"
- id="secret_key"
- [invalid]="userForm.controls.secret_key.invalid && (userForm.controls.secret_key.dirty)"/>
+ <div
+ class="form-item form-item-append"
+ *ngIf="!editing && !userForm.getValue('generate_key')"
+ >
+ <cds-password-label
+ for="secret"
+ i18n
+ cdRequiredField="Secret key"
+ [invalid]="userForm.controls.secret_key.invalid && userForm.controls.secret_key.dirty"
+ [invalidText]="secretKeyError"
+ >Secret key
+ <input
+ cdsPassword
+ type="password"
+ formControlName="secret_key"
+ name="secret_key"
+ id="secret_key"
+ [invalid]="userForm.controls.secret_key.invalid && userForm.controls.secret_key.dirty"
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="secret_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="secret_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
<ng-template #secretKeyError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('secret_key', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('secret_key', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
</fieldset>
<!-- Subusers -->
<fieldset *ngIf="editing">
<div class="form-item">
- <legend i18n
- class="cd-header">Subusers</legend>
- <span *ngIf="subusers.length === 0"
- class="no-border">
- <span class="form-text text-muted"
- i18n>There are no subusers.</span>
- </span>
-
- <ng-container *ngFor="let subuser of subusers; let i=index;">
-
- <div cdsRow
- class="form-item-append"
- [ngClass]="{'form-item': i > 0}">
- <div cdsCol>
- <cds-text-label>Subuser id
- <input cdsText
- [value]="subuser.id"
- readonly>
- </cds-text-label>
- </div>
- <div cdsCol>
- <cds-text-label>Permissions
- <input cdsText
- [value]="('full-control' === subuser.permissions) ? 'full' : subuser.permissions"
- readonly>
- </cds-text-label>
- </div>
- <cds-icon-button kind="tertiary"
- size="md"
- title="Edit"
- class="mt-4 tc_showSubuserButton"
- (click)="showSubuserModal(i)">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
- </cds-icon-button>
- <cds-icon-button kind="danger"
- size="md"
- title="Delete"
- class="mt-4 tc_deleteSubuserButton"
- (click)="deleteSubuser(i)">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size32"
- class="cds--btn__icon">></svg>
- </cds-icon-button>
- </div>
- </ng-container>
- <div cdsRow
- class="form-item">
- <div cdsCol>
- <button cdsButton="tertiary"
- type="button"
- class="tc_addSubuserButton"
- (click)="showSubuserModal()">
- <ng-container i18n>{{ actionLabels.CREATE | titlecase }}
- {{ subuserLabel | upperFirst }}</ng-container>
- <svg [cdsIcon]="icons.add"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
- </button>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Subusers
+ </legend>
+ <span
+ *ngIf="subusers.length === 0"
+ class="no-border"
+ >
+ <span
+ class="form-text text-muted"
+ i18n
+ >There are no subusers.</span
+ >
+ </span>
+
+ <ng-container *ngFor="let subuser of subusers; let i = index">
+ <div
+ cdsRow
+ class="form-item-append"
+ [ngClass]="{ 'form-item': i > 0 }"
+ >
+ <div cdsCol>
+ <cds-text-label
+ >Subuser id
+ <input
+ cdsText
+ [value]="subuser.id"
+ readonly
+ />
+ </cds-text-label>
+ </div>
+ <div cdsCol>
+ <cds-text-label
+ >Permissions
+ <input
+ cdsText
+ [value]="'full-control' === subuser.permissions ? 'full' : subuser.permissions"
+ readonly
+ />
+ </cds-text-label>
+ </div>
+ <cds-icon-button
+ kind="tertiary"
+ size="md"
+ title="Edit"
+ class="mt-4 tc_showSubuserButton"
+ (click)="showSubuserModal(i)"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ title="Delete"
+ class="mt-4 tc_deleteSubuserButton"
+ (click)="deleteSubuser(i)"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ >
+ >
+ </svg>
+ </cds-icon-button>
+ </div>
+ </ng-container>
+ <div
+ cdsRow
+ class="form-item"
+ >
+ <div cdsCol>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ class="tc_addSubuserButton"
+ (click)="showSubuserModal()"
+ >
+ <ng-container i18n
+ >{{ actionLabels.CREATE | titlecase }} {{ subuserLabel | upperFirst }}</ng-container
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
+ </button>
+ </div>
</div>
</div>
- </div>
</fieldset>
<!-- Keys -->
<fieldset *ngIf="editing">
<div class="form-item">
- <legend i18n
- class="cd-header">Keys</legend>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Keys
+ </legend>
<!-- S3 keys -->
<h6>S3</h6>
- <span *ngIf="s3Keys.length === 0"
- class="no-border">
- <span class="form-text text-muted"
- i18n>There are no keys.</span>
+ <span
+ *ngIf="s3Keys.length === 0"
+ class="no-border"
+ >
+ <span
+ class="form-text text-muted"
+ i18n
+ >There are no keys.</span
+ >
</span>
- <span *ngFor="let key of s3Keys; let i=index;">
- <div class="form-item-append"
- cdsRow>
+ <span *ngFor="let key of s3Keys; let i = index">
+ <div
+ class="form-item-append"
+ cdsRow
+ >
<div cdsCol>
<cds-text-label>
- <input cdsText
- [value]="key.user"
- readonly>
+ <input
+ cdsText
+ [value]="key.user"
+ readonly
+ />
</cds-text-label>
</div>
- <cds-icon-button kind="tertiary"
- size="md"
- title="Show"
- i18n-title
- class="mt-2 tc_showS3KeyButton"
- (click)="showS3KeyModal(i)">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="tertiary"
+ size="md"
+ title="Show"
+ i18n-title
+ class="mt-2 tc_showS3KeyButton"
+ (click)="showS3KeyModal(i)"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
- <cds-icon-button kind="danger"
- size="md"
- title="Delete"
- class="mt-2 tc_deleteS3KeyButton"
- (click)="deleteS3Key(i)">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ title="Delete"
+ class="mt-2 tc_deleteS3KeyButton"
+ (click)="deleteS3Key(i)"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
<span class="form-text text-muted"></span>
</span>
- <div class="form-item"
- cdsRow>
+ <div
+ class="form-item"
+ cdsRow
+ >
<div cdsCol>
- <button type="button"
- cdsButton="tertiary"
- class="tc_addS3KeyButton"
- (click)="showS3KeyModal()">
- <ng-container i18n>{{ actionLabels.CREATE | titlecase }}
- {{ s3keyLabel | upperFirst }}</ng-container>
- <svg [cdsIcon]="icons.add"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
+ <button
+ type="button"
+ cdsButton="tertiary"
+ class="tc_addS3KeyButton"
+ (click)="showS3KeyModal()"
+ >
+ <ng-container i18n
+ >{{ actionLabels.CREATE | titlecase }} {{ s3keyLabel | upperFirst }}</ng-container
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
</div>
- <hr>
+ <hr />
</div>
<!-- Swift keys -->
<div class="form-item">
-
<h6>Swift</h6>
- <span *ngIf="swiftKeys.length === 0"
- class="no-border">
- <span class="form-text text-muted"
- i18n>There are no keys.</span>
+ <span
+ *ngIf="swiftKeys.length === 0"
+ class="no-border"
+ >
+ <span
+ class="form-text text-muted"
+ i18n
+ >There are no keys.</span
+ >
</span>
- <span *ngFor="let key of swiftKeys; let i=index;">
- <div class="form-item-append"
- cdsRow>
+ <span *ngFor="let key of swiftKeys; let i = index">
+ <div
+ class="form-item-append"
+ cdsRow
+ >
<div cdsCol>
<cds-text-label>
- <input cdsText
- [value]="key.user"
- readonly>
+ <input
+ cdsText
+ [value]="key.user"
+ readonly
+ />
</cds-text-label>
</div>
- <cds-icon-button kind="tertiary"
- size="md"
- title="Show"
- i18n-title
- class="mt-2 tc_showSwiftKeyButton"
- (click)="showSwiftKeyModal(i)">
- <svg [cdsIcon]="icons.show"
- [size]="icons.size16"
- class="cds--btn__icon">
- </svg>
- </cds-icon-button>
+ <cds-icon-button
+ kind="tertiary"
+ size="md"
+ title="Show"
+ i18n-title
+ class="mt-2 tc_showSwiftKeyButton"
+ (click)="showSwiftKeyModal(i)"
+ >
+ <svg
+ [cdsIcon]="icons.show"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
</div>
</span>
</div>
<!-- Capabilities -->
<fieldset *ngIf="editing">
-
<div class="form-item">
- <legend i18n
- class="cd-header">Capabilities</legend>
- <span *ngIf="capabilities.length === 0"
- class="no-border">
- <span class="form-text text-muted"
- i18n>There are no capabilities.</span>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Capabilities
+ </legend>
+ <span
+ *ngIf="capabilities.length === 0"
+ class="no-border"
+ >
+ <span
+ class="form-text text-muted"
+ i18n
+ >There are no capabilities.</span
+ >
</span>
- <span *ngFor="let cap of capabilities; let i=index;">
- <div class="form-item-append"
- [ngClass]="{'form-item': i > 0}"
- cdsRow>
+ <span *ngFor="let cap of capabilities; let i = index">
+ <div
+ class="form-item-append"
+ [ngClass]="{ 'form-item': i > 0 }"
+ cdsRow
+ >
<div cdsCol>
- <cds-text-label i18n>Type
- <input cdsText
- [value]="cap.type"
- readonly>
+ <cds-text-label i18n
+ >Type
+ <input
+ cdsText
+ [value]="cap.type"
+ readonly
+ />
</cds-text-label>
</div>
<div cdsCol>
- <cds-text-label i18n>Permission
- <input cdsText
- [value]="cap.perm"
- readonly>
+ <cds-text-label i18n
+ >Permission
+ <input
+ cdsText
+ [value]="cap.perm"
+ readonly
+ />
</cds-text-label>
</div>
- <cds-icon-button kind="tertiary"
- size="md"
- title="Edit"
- class="mt-4 tc_editCapButton"
- (click)="showCapabilityModal(i)">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size16"
- class="cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="tertiary"
+ size="md"
+ title="Edit"
+ class="mt-4 tc_editCapButton"
+ (click)="showCapabilityModal(i)"
+ >
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size16"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
- <cds-icon-button kind="danger"
- size="md"
- title="Delete"
- class="mt-4 tc_deleteCapButton"
- (click)="deleteCapability(i)">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
+ <cds-icon-button
+ kind="danger"
+ size="md"
+ title="Delete"
+ class="mt-4 tc_deleteCapButton"
+ (click)="deleteCapability(i)"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
<span class="form-text text-muted"></span>
</span>
- <div class="form-item"
- cdsRow>
+ <div
+ class="form-item"
+ cdsRow
+ >
<div cdsCol>
- <button type="button"
- class="tc_addCapButton"
- cdsButton="tertiary"
- [disabled]="capabilities | pipeFunction:hasAllCapabilities"
- i18n-ngbTooltip
- ngbTooltip="All capabilities are already added."
- [disableTooltip]="!(capabilities | pipeFunction:hasAllCapabilities)"
- triggers="pointerenter:pointerleave"
- (click)="showCapabilityModal()">
- <ng-container i18n>{{ actionLabels.ADD | titlecase }}
- {{ capabilityLabel | upperFirst }}</ng-container>
- <svg [cdsIcon]="icons.add"
- [size]="icons.size32"
- class="cds--btn__icon"></svg>
+ <button
+ type="button"
+ class="tc_addCapButton"
+ cdsButton="tertiary"
+ [disabled]="capabilities | pipeFunction: hasAllCapabilities"
+ i18n-ngbTooltip
+ ngbTooltip="All capabilities are already added."
+ [disableTooltip]="!(capabilities | pipeFunction: hasAllCapabilities)"
+ triggers="pointerenter:pointerleave"
+ (click)="showCapabilityModal()"
+ >
+ <ng-container i18n
+ >{{ actionLabels.ADD | titlecase }} {{ capabilityLabel | upperFirst }}</ng-container
+ >
+ <svg
+ [cdsIcon]="icons.add"
+ [size]="icons.size32"
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
</div>
<!-- User quota -->
<fieldset>
<div class="form-item">
- <legend i18n
- class="cd-header">User quota</legend>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ User quota
+ </legend>
- <!-- Enabled -->
- <cds-checkbox formControlName="user_quota_enabled"
- id="user_quota_enabled"
- i18n>Enabled
+ <!-- Enabled -->
+ <cds-checkbox
+ formControlName="user_quota_enabled"
+ id="user_quota_enabled"
+ i18n
+ >Enabled
</cds-checkbox>
</div>
<!-- Unlimited size -->
- <div class="form-item"
- *ngIf="userForm.controls.user_quota_enabled.value">
- <cds-checkbox formControlName="user_quota_max_size_unlimited"
- id="user_quota_max_size_unlimited"
- i18n>Unlimited size</cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="userForm.controls.user_quota_enabled.value"
+ >
+ <cds-checkbox
+ formControlName="user_quota_max_size_unlimited"
+ id="user_quota_max_size_unlimited"
+ i18n
+ >Unlimited size</cds-checkbox
+ >
</div>
<!-- Maximum size -->
- <div class="form-item"
- *ngIf="userForm.controls.user_quota_enabled.value && !userForm.getValue('user_quota_max_size_unlimited')">
- <cds-text-label for="user_quota_max_size"
- i18n
- cdRequiredField="Maximum size"
- [invalid]="userForm.controls.user_quota_max_size.invalid && (userForm.controls.user_quota_max_size.dirty)"
- [invalidText]="quotaMaxSizeError">Maximum size
- <input cdsText
- formControlName="user_quota_max_size"
- name="user_quota_max_size"
- id="user_quota_max_size"
- [invalid]="userForm.controls.user_quota_max_size.invalid && (userForm.controls.user_quota_max_size.dirty)"
- cdDimlessBinary/>
+ <div
+ class="form-item"
+ *ngIf="
+ userForm.controls.user_quota_enabled.value &&
+ !userForm.getValue('user_quota_max_size_unlimited')
+ "
+ >
+ <cds-text-label
+ for="user_quota_max_size"
+ i18n
+ cdRequiredField="Maximum size"
+ [invalid]="
+ userForm.controls.user_quota_max_size.invalid &&
+ userForm.controls.user_quota_max_size.dirty
+ "
+ [invalidText]="quotaMaxSizeError"
+ >Maximum size
+ <input
+ cdsText
+ formControlName="user_quota_max_size"
+ name="user_quota_max_size"
+ id="user_quota_max_size"
+ [invalid]="
+ userForm.controls.user_quota_max_size.invalid &&
+ userForm.controls.user_quota_max_size.dirty
+ "
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #quotaMaxSizeError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_quota_max_size', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_quota_max_size', frm, 'quotaMaxSize')"
- i18n>The value is not valid.</span>
- <span *ngIf="userForm.showError('user_quota_max_size', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_quota_max_size', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_quota_max_size', frm, 'quotaMaxSize')"
+ i18n
+ >The value is not valid.</span
+ >
+ <span
+ *ngIf="userForm.showError('user_quota_max_size', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
<!-- Unlimited objects -->
- <div class="form-item"
- *ngIf="userForm.controls.user_quota_enabled.value">
- <cds-checkbox formControlName="user_quota_max_objects_unlimited"
- id="user_quota_max_objects_unlimited"
- i18n>Unlimited objects</cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="userForm.controls.user_quota_enabled.value"
+ >
+ <cds-checkbox
+ formControlName="user_quota_max_objects_unlimited"
+ id="user_quota_max_objects_unlimited"
+ i18n
+ >Unlimited objects</cds-checkbox
+ >
</div>
<!-- Maximum objects -->
- <div class="form-item"
- *ngIf="userForm.controls.user_quota_enabled.value && !userForm.getValue('user_quota_max_objects_unlimited')">
- <cds-number for="user_quota_max_objects"
- formControlName="user_quota_max_objects"
- id="user_quota_max_objects"
- [min]="0"
- [invalid]="userForm.controls.user_quota_max_objects.invalid && (userForm.controls.user_quota_max_objects.dirty)"
- [invalidText]="maxObjectsError"
- label="Maximum Objects"
- cdRequiredField="Maximum Objects"></cds-number>
+ <div
+ class="form-item"
+ *ngIf="
+ userForm.controls.user_quota_enabled.value &&
+ !userForm.getValue('user_quota_max_objects_unlimited')
+ "
+ >
+ <cds-number
+ for="user_quota_max_objects"
+ formControlName="user_quota_max_objects"
+ id="user_quota_max_objects"
+ [min]="0"
+ [invalid]="
+ userForm.controls.user_quota_max_objects.invalid &&
+ userForm.controls.user_quota_max_objects.dirty
+ "
+ [invalidText]="maxObjectsError"
+ label="Maximum Objects"
+ cdRequiredField="Maximum Objects"
+ ></cds-number>
<ng-template #maxObjectsError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_quota_max_objects', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('user_quota_max_objects', frm, 'min')"
- i18n>The entered value must be >= 0.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_quota_max_objects', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('user_quota_max_objects', frm, 'min')"
+ i18n
+ >The entered value must be >= 0.</span
+ >
</ng-template>
</div>
</fieldset>
<!-- Bucket quota -->
<fieldset>
<div class="form-item">
- <legend i18n
- class="cd-header">Bucket quota</legend>
+ <legend
+ i18n
+ class="cd-header"
+ >
+ Bucket quota
+ </legend>
- <!-- Enabled -->
- <cds-checkbox formControlName="bucket_quota_enabled"
- id="bucket_quota_enabled"
- i18n>Enabled</cds-checkbox>
+ <!-- Enabled -->
+ <cds-checkbox
+ formControlName="bucket_quota_enabled"
+ id="bucket_quota_enabled"
+ i18n
+ >Enabled</cds-checkbox
+ >
</div>
<!-- Unlimited size -->
- <div class="form-item"
- *ngIf="userForm.controls.bucket_quota_enabled.value">
- <cds-checkbox formControlName="bucket_quota_max_size_unlimited"
- id="bucket_quota_max_size_unlimited"
- i18n>Unlimited size</cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="userForm.controls.bucket_quota_enabled.value"
+ >
+ <cds-checkbox
+ formControlName="bucket_quota_max_size_unlimited"
+ id="bucket_quota_max_size_unlimited"
+ i18n
+ >Unlimited size</cds-checkbox
+ >
</div>
<!-- Maximum size -->
- <div class="form-item"
- *ngIf="userForm.controls.bucket_quota_enabled.value && !userForm.getValue('bucket_quota_max_size_unlimited')">
- <cds-text-label for="bucket_quota_max_size"
- i18n
- cdRequiredField="Maximum size"
- [invalid]="userForm.controls.bucket_quota_max_size.invalid && (userForm.controls.bucket_quota_max_size.dirty)"
- [invalidText]="bucketQuotaMaxSizeError">Maximum size
- <input cdsText
- formControlName="bucket_quota_max_size"
- name="bucket_quota_max_size"
- id="bucket_quota_max_size"
- [invalid]="userForm.controls.bucket_quota_max_size.invalid && (userForm.controls.bucket_quota_max_size.dirty)"
- cdDimlessBinary/>
+ <div
+ class="form-item"
+ *ngIf="
+ userForm.controls.bucket_quota_enabled.value &&
+ !userForm.getValue('bucket_quota_max_size_unlimited')
+ "
+ >
+ <cds-text-label
+ for="bucket_quota_max_size"
+ i18n
+ cdRequiredField="Maximum size"
+ [invalid]="
+ userForm.controls.bucket_quota_max_size.invalid &&
+ userForm.controls.bucket_quota_max_size.dirty
+ "
+ [invalidText]="bucketQuotaMaxSizeError"
+ >Maximum size
+ <input
+ cdsText
+ formControlName="bucket_quota_max_size"
+ name="bucket_quota_max_size"
+ id="bucket_quota_max_size"
+ [invalid]="
+ userForm.controls.bucket_quota_max_size.invalid &&
+ userForm.controls.bucket_quota_max_size.dirty
+ "
+ cdDimlessBinary
+ />
</cds-text-label>
<ng-template #bucketQuotaMaxSizeError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('bucket_quota_max_size', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('bucket_quota_max_size', frm, 'quotaMaxSize')"
- i18n>The value is not valid.</span>
- <span *ngIf="userForm.showError('bucket_quota_max_size', formDir, 'pattern')"
- class="invalid-feedback"
- i18n>Size must be a number or in a valid format. eg: 5 GiB</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('bucket_quota_max_size', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('bucket_quota_max_size', frm, 'quotaMaxSize')"
+ i18n
+ >The value is not valid.</span
+ >
+ <span
+ *ngIf="userForm.showError('bucket_quota_max_size', formDir, 'pattern')"
+ class="invalid-feedback"
+ i18n
+ >Size must be a number or in a valid format. eg: 5 GiB</span
+ >
</ng-template>
</div>
<!-- Unlimited objects -->
- <div class="form-item"
- *ngIf="userForm.controls.bucket_quota_enabled.value">
- <cds-checkbox formControlName="bucket_quota_max_objects_unlimited"
- id="bucket_quota_max_objects_unlimited"
- i18n>Unlimited objects</cds-checkbox>
+ <div
+ class="form-item"
+ *ngIf="userForm.controls.bucket_quota_enabled.value"
+ >
+ <cds-checkbox
+ formControlName="bucket_quota_max_objects_unlimited"
+ id="bucket_quota_max_objects_unlimited"
+ i18n
+ >Unlimited objects</cds-checkbox
+ >
</div>
<!-- Maximum objects -->
- <div class="form-item"
- *ngIf="userForm.controls.bucket_quota_enabled.value && !userForm.getValue('bucket_quota_max_objects_unlimited')">
- <cds-number for="bucket_quota_max_objects"
- formControlName="bucket_quota_max_objects"
- id="bucket_quota_max_objects"
- [min]="0"
- [invalid]="userForm.controls.bucket_quota_max_objects.invalid && ( userForm.controls.bucket_quota_max_objects.dirty)"
- [invalidText]="bucketMaxObjectsError"
- label="Maximum objects"
- cdRequiredField="Maximum objects"></cds-number>
+ <div
+ class="form-item"
+ *ngIf="
+ userForm.controls.bucket_quota_enabled.value &&
+ !userForm.getValue('bucket_quota_max_objects_unlimited')
+ "
+ >
+ <cds-number
+ for="bucket_quota_max_objects"
+ formControlName="bucket_quota_max_objects"
+ id="bucket_quota_max_objects"
+ [min]="0"
+ [invalid]="
+ userForm.controls.bucket_quota_max_objects.invalid &&
+ userForm.controls.bucket_quota_max_objects.dirty
+ "
+ [invalidText]="bucketMaxObjectsError"
+ label="Maximum objects"
+ cdRequiredField="Maximum objects"
+ ></cds-number>
<ng-template #bucketMaxObjectsError>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'min')"
- i18n>The entered value must be >= 0.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('bucket_quota_max_objects', frm, 'min')"
+ i18n
+ >The entered value must be >= 0.</span
+ >
</ng-template>
</div>
</fieldset>
<!-- Advanced Section -->
<cd-form-advanced-fieldset>
<!-- User Rate Limit -->
- <cd-rgw-rate-limit [type]="'user'"
- [isEditing]="editing"
- [id]="uid"
- (rateLimitFormGroup)="rateLimitFormInit($event)">
+ <cd-rgw-rate-limit
+ [type]="'user'"
+ [isEditing]="editing"
+ [id]="uid"
+ (rateLimitFormGroup)="rateLimitFormInit($event)"
+ >
</cd-rgw-rate-limit>
</cd-form-advanced-fieldset>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="userForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</div>
<cd-rgw-user-tabs></cd-rgw-user-tabs>
-<cd-table #table
- [autoReload]="false"
- [data]="users"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (updateSelection)="updateSelection($event)"
- identifier="uid"
- (fetchData)="getUserList($event)"
- [status]="tableStatus">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ #table
+ [autoReload]="false"
+ [data]="users"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (updateSelection)="updateSelection($event)"
+ identifier="uid"
+ (fetchData)="getUserList($event)"
+ [status]="tableStatus"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-rgw-user-details *cdTableDetail
- [selection]="expandedRow">
+ <cd-rgw-user-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ >
</cd-rgw-user-details>
</cd-table>
-<ng-template #userSizeTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.user_quota.max_size > 0 && row.user_quota.enabled; else noSizeQuota"
- [total]="row.user_quota.max_size"
- [used]="row.stats.size_actual">
+<ng-template
+ #userSizeTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.user_quota.max_size > 0 && row.user_quota.enabled; else noSizeQuota"
+ [total]="row.user_quota.max_size"
+ [used]="row.stats.size_actual"
+ >
</cd-usage-bar>
- <ng-template #noSizeQuota
- i18n>No Limit</ng-template>
+ <ng-template
+ #noSizeQuota
+ i18n
+ >No Limit</ng-template
+ >
</ng-template>
-<ng-template #userObjectTpl
- let-row="data.row">
- <cd-usage-bar *ngIf="row.user_quota.max_objects > 0 && row.user_quota.enabled; else noObjectQuota"
- [total]="row.user_quota.max_objects"
- [used]="row.stats.num_objects"
- [isBinary]="false">
+<ng-template
+ #userObjectTpl
+ let-row="data.row"
+>
+ <cd-usage-bar
+ *ngIf="row.user_quota.max_objects > 0 && row.user_quota.enabled; else noObjectQuota"
+ [total]="row.user_quota.max_objects"
+ [used]="row.stats.num_objects"
+ [isBinary]="false"
+ >
</cd-usage-bar>
- <ng-template #noObjectQuota
- i18n>No Limit</ng-template>
+ <ng-template
+ #noObjectQuota
+ i18n
+ >No Limit</ng-template
+ >
</ng-template>
-<ng-template #usernameTpl
- let-row="data.row">
+<ng-template
+ #usernameTpl
+ let-row="data.row"
+>
<div cdsRow>
<span i18n>{{ row.uid }}</span>
@if (row.type === 'root') {
- <cds-tooltip [description]="'Account root user'"
- [align]="'top'"
- i18n-description>
- <svg [cdsIcon]="icons.userAccessLocked"
- [size]="icons.size16"
- class="account-root-icon"></svg>
- </cds-tooltip>
+ <cds-tooltip
+ [description]="'Account root user'"
+ [align]="'top'"
+ i18n-description
+ >
+ <svg
+ [cdsIcon]="icons.userAccessLocked"
+ [size]="icons.size16"
+ class="account-root-icon"
+ ></svg>
+ </cds-tooltip>
}
</div>
</ng-template>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <ng-container i18n="form title"
- class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
+ <ng-container
+ i18n="form title"
+ class="modal-title"
+ >{{ action | titlecase }} {{ resource | upperFirst }}</ng-container
+ >
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
- <form #frm="ngForm"
- [formGroup]="formGroup"
- novalidate>
+ <form
+ #frm="ngForm"
+ [formGroup]="formGroup"
+ novalidate
+ >
<div cdsModalContent>
-
<!-- Username -->
<div class="form-item">
- <cds-text-label for="user"
- [invalid]="formGroup.controls.user.invalid && formGroup.controls.user.dirty"
- [invalidText]="userError"
- *ngIf="viewing"
- i18n>Username
- <input cdsText
- id="user"
- name="user"
- formControlName="user"
- [readonly]="true"
- modal-primary-focus>
+ <cds-text-label
+ for="user"
+ [invalid]="formGroup.controls.user.invalid && formGroup.controls.user.dirty"
+ [invalidText]="userError"
+ *ngIf="viewing"
+ i18n
+ >Username
+ <input
+ cdsText
+ id="user"
+ name="user"
+ formControlName="user"
+ [readonly]="true"
+ modal-primary-focus
+ />
</cds-text-label>
- <cds-select *ngIf="!viewing"
- label="Username"
- i18n-label
- for="user"
- formControlName="user"
- [invalid]="formGroup.controls.user.invalid && formGroup.controls.user.dirty"
- [invalidText]="userError">
+ <cds-select
+ *ngIf="!viewing"
+ label="Username"
+ i18n-label
+ for="user"
+ formControlName="user"
+ [invalid]="formGroup.controls.user.invalid && formGroup.controls.user.dirty"
+ [invalidText]="userError"
+ >
<option value="">--- Select a username ---</option>
- <option *ngFor="let userCandidate of userCandidates"
- [value]="userCandidate">{{ userCandidate }}</option>
+ <option
+ *ngFor="let userCandidate of userCandidates"
+ [value]="userCandidate"
+ >
+ {{ userCandidate }}
+ </option>
</cds-select>
<ng-template #userError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('user', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('user', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Auto-generate key -->
- <div class="form-item"
- *ngIf="!viewing">
- <cds-checkbox id="generate_key"
- formControlName="generate_key"
- i18n>Auto-generate key
+ <div
+ class="form-item"
+ *ngIf="!viewing"
+ >
+ <cds-checkbox
+ id="generate_key"
+ formControlName="generate_key"
+ i18n
+ >Auto-generate key
</cds-checkbox>
</div>
<!-- Access key -->
- <div class="form-item form-item-append"
- *ngIf="!formGroup.getValue('generate_key')">
- <cds-password-label for="access_key"
- [invalid]="formGroup.controls.access_key.invalid && formGroup.controls.access_key.dirty"
- [invalidText]="accessKeyError"
- i18n>Access key
- <input cdsPassword
- id="access_key"
- name="access_key"
- formControlName="access_key"
- [readonly]="viewing">
+ <div
+ class="form-item form-item-append"
+ *ngIf="!formGroup.getValue('generate_key')"
+ >
+ <cds-password-label
+ for="access_key"
+ [invalid]="formGroup.controls.access_key.invalid && formGroup.controls.access_key.dirty"
+ [invalidText]="accessKeyError"
+ i18n
+ >Access key
+ <input
+ cdsPassword
+ id="access_key"
+ name="access_key"
+ formControlName="access_key"
+ [readonly]="viewing"
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="access_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="access_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
<ng-template #accessKeyError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('access_key', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('access_key', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Secret key -->
- <div class="form-item form-item-append"
- *ngIf="!formGroup.getValue('generate_key')">
- <cds-password-label for="secret_key"
- [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
- [invalidText]="secretKeyError"
- i18n>Secret key
- <input cdsPassword
- id="secret_key"
- name="secret_key"
- formControlName="secret_key"
- [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
- [readonly]="viewing">
+ <div
+ class="form-item form-item-append"
+ *ngIf="!formGroup.getValue('generate_key')"
+ >
+ <cds-password-label
+ for="secret_key"
+ [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
+ [invalidText]="secretKeyError"
+ i18n
+ >Secret key
+ <input
+ cdsPassword
+ id="secret_key"
+ name="secret_key"
+ formControlName="secret_key"
+ [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
+ [readonly]="viewing"
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="secret_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="secret_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
<ng-template #secretKeyError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('secret_key', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('secret_key', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
-
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="formGroup"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [showSubmit]="!viewing"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [showSubmit]="!viewing"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</cds-modal>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</cds-modal-header>
- <form #frm="ngForm"
- [formGroup]="formGroup"
- novalidate>
+ <form
+ #frm="ngForm"
+ [formGroup]="formGroup"
+ novalidate
+ >
<div cdsModalContent>
<!-- Username -->
<div class="form-item">
- <cds-text-label for="uid"
- i18n>Username
- <input cdsText
- id="uid"
- name="uid"
- formControlName="uid"
- readonly
- modal-primary-focus>
+ <cds-text-label
+ for="uid"
+ i18n
+ >Username
+ <input
+ cdsText
+ id="uid"
+ name="uid"
+ formControlName="uid"
+ readonly
+ modal-primary-focus
+ />
</cds-text-label>
</div>
<!-- Subuser -->
<div class="form-item">
- <cds-text-label for="subuid"
- [invalid]="formGroup.controls.subuid.invalid && formGroup.controls.subuid.dirty"
- [invalidText]="subuserHelper">Subuser
- <input cdsText
- id="subuid"
- name="subuid"
- formControlName="subuid"
- [readonly]="editing"
- autofocus>
+ <cds-text-label
+ for="subuid"
+ [invalid]="formGroup.controls.subuid.invalid && formGroup.controls.subuid.dirty"
+ [invalidText]="subuserHelper"
+ >Subuser
+ <input
+ cdsText
+ id="subuid"
+ name="subuid"
+ formControlName="subuid"
+ [readonly]="editing"
+ autofocus
+ />
</cds-text-label>
<ng-template #subuserHelper>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('subuid', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('subuid', frm, 'subuserIdExists')"
- i18n>The chosen subuser ID is already in use.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('subuid', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('subuid', frm, 'subuserIdExists')"
+ i18n
+ >The chosen subuser ID is already in use.</span
+ >
</ng-template>
</div>
<!-- Permission -->
<div class="form-item">
- <cds-select label="Permission"
- i18n-label
- for="perm"
- formControlName="perm"
- [invalid]="formGroup.controls.perm.invalid && formGroup.controls.perm.dirty"
- [invalidText]="permError">
+ <cds-select
+ label="Permission"
+ i18n-label
+ for="perm"
+ formControlName="perm"
+ [invalid]="formGroup.controls.perm.invalid && formGroup.controls.perm.dirty"
+ [invalidText]="permError"
+ >
<option value="">--- Select a permission ---</option>
- <option *ngFor="let perm of ['read', 'write']"
- [value]="perm">
+ <option
+ *ngFor="let perm of ['read', 'write']"
+ [value]="perm"
+ >
{{ perm }}
</option>
- <option i18n
- value="read-write">read, write</option>
- <option i18n
- value="full-control">full</option>
+ <option
+ i18n
+ value="read-write"
+ >
+ read, write
+ </option>
+ <option
+ i18n
+ value="full-control"
+ >
+ full
+ </option>
</cds-select>
<ng-template #permError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('perm', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('perm', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
<!-- Auto-generate key -->
<div class="form-item">
- <cds-checkbox id="generate_secret"
- formControlName="generate_secret"
- i18n>Auto-generate key
+ <cds-checkbox
+ id="generate_secret"
+ formControlName="generate_secret"
+ i18n
+ >Auto-generate key
</cds-checkbox>
</div>
<!-- Secret key -->
- <div class="form-item form-item-append"
- *ngIf="!editing && !formGroup.getValue('generate_secret')">
- <cds-password-label for="secret_key"
- [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
- [invalidText]="secretKeyError"
- i18n>Secret key
- <input cdsPassword
- id="secret_key"
- name="secret_key"
- formControlName="secret_key"
- [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
- [autofocus]="true">
+ <div
+ class="form-item form-item-append"
+ *ngIf="!editing && !formGroup.getValue('generate_secret')"
+ >
+ <cds-password-label
+ for="secret_key"
+ [invalid]="formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty"
+ [invalidText]="secretKeyError"
+ i18n
+ >Secret key
+ <input
+ cdsPassword
+ id="secret_key"
+ name="secret_key"
+ formControlName="secret_key"
+ [invalid]="
+ formGroup.controls.secret_key.invalid && formGroup.controls.secret_key.dirty
+ "
+ [autofocus]="true"
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="secret_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="secret_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
<ng-template #secretKeyError>
- <span class="invalid-feedback"
- *ngIf="formGroup.showError('secret_key', frm, 'required')"
- i18n>This field is required.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="formGroup.showError('secret_key', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
</ng-template>
</div>
-
</fieldset>
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="formGroup"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</cds-modal>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="false"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="false"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<form novalidate>
<div cdsModalContent>
<!-- Username -->
<div class="form-item">
- <cds-text-label for="user"
- i18n>Username
- <input cdsText
- id="user"
- name="user"
- readonly
- [(ngModel)]="user"
- modal-primary-focus>
+ <cds-text-label
+ for="user"
+ i18n
+ >Username
+ <input
+ cdsText
+ id="user"
+ name="user"
+ readonly
+ [(ngModel)]="user"
+ modal-primary-focus
+ />
</cds-text-label>
</div>
<!-- Secret key -->
<div class="form-item form-item-append">
- <cds-password-label for="secret_key"
- i18n>Secret key
- <input cdsPassword
- id="secret_key"
- name="secret_key"
- [(ngModel)]="secret_key"
- readonly>
+ <cds-password-label
+ for="secret_key"
+ i18n
+ >Secret key
+ <input
+ cdsPassword
+ id="secret_key"
+ name="secret_key"
+ [(ngModel)]="secret_key"
+ readonly
+ />
</cds-password-label>
- <cd-copy-2-clipboard-button source="secret_key"
- class="mt-4">
+ <cd-copy-2-clipboard-button
+ source="secret_key"
+ class="mt-4"
+ >
</cd-copy-2-clipboard-button>
</div>
</div>
- <cd-form-button-panel [showSubmit]="false"
- (cancel)="closeModal()"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ [showSubmit]="false"
+ (cancel)="closeModal()"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</form>
</cds-modal>
<ul class="nav nav-tabs">
<li class="nav-item">
- <a class="nav-link"
- routerLink="/rgw/user"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Users</a>
+ <a
+ class="nav-link"
+ routerLink="/rgw/user"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Users</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="/rgw/accounts"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Accounts</a>
+ <a
+ class="nav-link"
+ routerLink="/rgw/accounts"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Accounts</a
+ >
</li>
-
</ul>
-<cd-table *ngIf="hostname || osdId !== null"
- [data]="devices"
- [columns]="columns"></cd-table>
+<cd-table
+ *ngIf="hostname || osdId !== null"
+ [data]="devices"
+ [columns]="columns"
+></cd-table>
-<cd-alert-panel type="warning"
- *ngIf="hostname === '' && osdId === null"
- i18n>Neither hostname nor OSD ID given</cd-alert-panel>
+<cd-alert-panel
+ type="warning"
+ *ngIf="hostname === '' && osdId === null"
+ i18n
+ >Neither hostname nor OSD ID given</cd-alert-panel
+>
-<ng-template #deviceLocation
- let-value="data.value">
+<ng-template
+ #deviceLocation
+ let-value="data.value"
+>
<ng-container *ngFor="let location of value">
- <cd-label *ngIf="location.host === hostname"
- [value]="location.dev"></cd-label>
+ <cd-label
+ *ngIf="location.host === hostname"
+ [value]="location.dev"
+ ></cd-label>
</ng-container>
</ng-template>
-<ng-template #daemonName
- let-value="data.value">
- <ng-container [ngTemplateOutlet]="osdId !== null ? osdIdDaemon : readableDaemons"
- [ngTemplateOutletContext]="{daemons: value}">
+<ng-template
+ #daemonName
+ let-value="data.value"
+>
+ <ng-container
+ [ngTemplateOutlet]="osdId !== null ? osdIdDaemon : readableDaemons"
+ [ngTemplateOutletContext]="{ daemons: value }"
+ >
</ng-container>
</ng-template>
-<ng-template #osdIdDaemon
- let-daemons="daemons">
+<ng-template
+ #osdIdDaemon
+ let-daemons="daemons"
+>
<ng-container *ngFor="let daemon of daemons">
- <cd-label *ngIf="daemon.includes(osdId)"
- [value]="daemon"></cd-label>
+ <cd-label
+ *ngIf="daemon.includes(osdId)"
+ [value]="daemon"
+ ></cd-label>
</ng-container>
</ng-template>
-<ng-template #readableDaemons
- let-daemons="daemons">
+<ng-template
+ #readableDaemons
+ let-daemons="daemons"
+>
<ng-container *ngFor="let daemon of daemons">
- <cd-label class="me-1"
- [value]="daemon"></cd-label>
+ <cd-label
+ class="me-1"
+ [value]="daemon"
+ ></cd-label>
</ng-container>
</ng-template>
-
-<ng-template #lifeExpectancy
- let-value="data.value">
- <span *ngIf="!value?.life_expectancy_enabled"
- i18n>{{ "" | notAvailable }}</span>
- <span *ngIf="value?.min && !value?.max">> {{value.min | i18nPlural: translationMapping}}</span>
- <span *ngIf="value?.max && !value?.min">< {{value.max | i18nPlural: translationMapping}}</span>
- <span *ngIf="value?.max && value?.min">{{value.min}} to {{value.max | i18nPlural: translationMapping}}</span>
+<ng-template
+ #lifeExpectancy
+ let-value="data.value"
+>
+ <span
+ *ngIf="!value?.life_expectancy_enabled"
+ i18n
+ >{{ '' | notAvailable }}</span
+ >
+ <span *ngIf="value?.min && !value?.max"
+ >> {{ value.min | i18nPlural: translationMapping }}</span
+ >
+ <span *ngIf="value?.max && !value?.min"
+ >< {{ value.max | i18nPlural: translationMapping }}</span
+ >
+ <span *ngIf="value?.max && value?.min"
+ >{{ value.min }} to {{ value.max | i18nPlural: translationMapping }}</span
+ >
</ng-template>
-<ng-template #lifeExpectancyTimestamp
- let-value="data.value">
- {{value}}
+<ng-template
+ #lifeExpectancyTimestamp
+ let-value="data.value"
+>
+ {{ value }}
</ng-template>
[open]="open"
[hasScrollingContent]="false"
(overlaySelected)="closeModal()"
- >
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>Report an issue</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ Report an issue
+ </h3>
</cds-modal-header>
- <form name="feedbackForm"
- [formGroup]="feedbackForm"
- #formDir="ngForm">
+ <form
+ name="feedbackForm"
+ [formGroup]="feedbackForm"
+ #formDir="ngForm"
+ >
<div
cdsModalContent
class="modal-wrapper"
>
@if (!isFeedbackEnabled) {
- <cd-alert-panel type="info"
- spacingClass="mb-3"
- actionName="Enable feedback"
- class="align-items-center"
- (action)="enableFeedbackModule()"
- i18n-actionName>
- Enable the feedback service to report issues.
- </cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ spacingClass="mb-3"
+ actionName="Enable feedback"
+ class="align-items-center"
+ (action)="enableFeedbackModule()"
+ i18n-actionName
+ >
+ Enable the feedback service to report issues.
+ </cd-alert-panel>
}
<!-- api_key -->
@if (!isAPIKeySet) {
- <div class="form-item">
- <cds-password-label
- labelInputID="api_key"
- [invalid]="!feedbackForm.controls.api_key.valid && feedbackForm.controls.api_key.dirty"
- [invalidText]="apiKeyError"
- [helperText]="apiKeyHelperTpl"
- [disabled]="!isFeedbackEnabled"
- i18n
- >
- API key
- <input
- cdsPassword
- id="api_key"
- type="password"
- formControlName="api_key"
- />
- </cds-password-label>
+ <div class="form-item">
+ <cds-password-label
+ labelInputID="api_key"
+ [invalid]="!feedbackForm.controls.api_key.valid && feedbackForm.controls.api_key.dirty"
+ [invalidText]="apiKeyError"
+ [helperText]="apiKeyHelperTpl"
+ [disabled]="!isFeedbackEnabled"
+ i18n
+ >
+ API key
+ <input
+ cdsPassword
+ id="api_key"
+ type="password"
+ formControlName="api_key"
+ />
+ </cds-password-label>
- <ng-template #apiKeyError>
- @if (feedbackForm.showError('api_key', formDir, 'required')) {
- <span class="invalid-feedback"
- i18n>API key is required.</span>
- } @if (feedbackForm.showError('api_key', formDir, 'invalidApiKey')) {
- <span class="invalid-feedback"
- i18n>API key is invalid.</span>
- }
- </ng-template>
+ <ng-template #apiKeyError>
+ @if (feedbackForm.showError('api_key', formDir, 'required')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >API key is required.</span
+ >
+ }
+ @if (feedbackForm.showError('api_key', formDir, 'invalidApiKey')) {
+ <span
+ class="invalid-feedback"
+ i18n
+ >API key is invalid.</span
+ >
+ }
+ </ng-template>
- <ng-template #apiKeyHelperTpl>
- <ng-container i18n>
- Enter your Ceph Tracker API key. You can find your API key in your
- <a href="https://tracker.ceph.com/my/account"
- target="_blank">Ceph Tracker account</a>.
- </ng-container>
- </ng-template>
- </div>
+ <ng-template #apiKeyHelperTpl>
+ <ng-container i18n>
+ Enter your Ceph Tracker API key. You can find your API key in your
+ <a
+ href="https://tracker.ceph.com/my/account"
+ target="_blank"
+ >Ceph Tracker account</a
+ >.
+ </ng-container>
+ </ng-template>
+ </div>
}
<!-- project -->
i18n
>
@for (project of projects; track project) {
- <option [value]="project">{{ project }}</option>
+ <option [value]="project">{{ project }}</option>
}
</cds-select>
<ng-template #projectError>
@if (feedbackForm.showError('project', formDir, 'required')) {
- <span i18n>This field is required!</span>
+ <span i18n>This field is required!</span>
}
</ng-template>
</div>
i18n
>
@for (issueType of issueTypes; track issueType.value) {
- <option [value]="issueType.value">{{ issueType.label }}</option>
+ <option [value]="issueType.value">{{ issueType.label }}</option>
}
</cds-select>
<ng-template #trackerError>
@if (feedbackForm.showError('tracker', formDir, 'required')) {
- <span i18n>Issue type is required.</span>
+ <span i18n>Issue type is required.</span>
}
</ng-template>
</div>
<ng-template #subjectError>
@if (feedbackForm.showError('subject', formDir, 'required')) {
- <span i18n>Issue title is required.</span>
+ <span i18n>Issue title is required.</span>
}
</ng-template>
</div>
<!-- description -->
<div class="form-item">
<cds-text-label
- [invalid]="!feedbackForm.controls.description.valid && feedbackForm.controls.description.dirty"
+ [invalid]="
+ !feedbackForm.controls.description.valid && feedbackForm.controls.description.dirty
+ "
[invalidText]="descriptionError"
[disabled]="!isFeedbackEnabled"
i18n
<ng-template #descriptionError>
@if (feedbackForm.showError('description', formDir, 'required')) {
- <span i18n>Description is required.</span>
+ <span i18n>Description is required.</span>
}
</ng-template>
</div>
</div>
@if (isFeedbackEnabled) {
- <cd-form-button-panel
- (submitActionEvent)="onSubmit()"
- [form]="feedbackForm"
- [submitText]="submit"
- [modalForm]="true"
- ></cd-form-button-panel>
- }
- @else {
- <cd-form-button-panel
- [showSubmit]="false"
- [modalForm]="true"
- ></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="feedbackForm"
+ [submitText]="submit"
+ [modalForm]="true"
+ ></cd-form-button-panel>
+ } @else {
+ <cd-form-button-panel
+ [showSubmit]="false"
+ [modalForm]="true"
+ ></cd-form-button-panel>
}
</form>
</cds-modal>
-<p i18n
- *ngIf="permissions.log.read">
- <cd-icon type="infoCircle"></cd-icon >
+<p
+ i18n
+ *ngIf="permissions.log.read"
+>
+ <cd-icon type="infoCircle"></cd-icon>
See <a routerLink="/logs">Logs</a> for more details.
</p>
<ul>
- <li *ngFor="let check of healthData | keyvalue">
- <span [ngStyle]="check.value.severity | healthColor"
- [class.health-warn-description]="check.value.severity === 'HEALTH_WARN'">
- @if (legacyHealthChecks) {
- {{ check.value.type }}
- } @else {
- {{ check.key }}
- }
- </span>: {{ check.value.summary.message }} <br>
+ <li *ngFor="let check of healthData | keyvalue">
+ <span
+ [ngStyle]="check.value.severity | healthColor"
+ [class.health-warn-description]="check.value.severity === 'HEALTH_WARN'"
+ >
+ @if (legacyHealthChecks) {
+ {{ check.value.type }}
+ } @else {
+ {{ check.key }}
+ }</span
+ >: {{ check.value.summary.message }} <br />
</li>
</ul>
<ng-container *ngIf="!loading; else isLoading">
- <cd-alert-panel *ngIf="error"
- type="error"
- i18n>Failed to retrieve SMART data.</cd-alert-panel>
- <cd-alert-panel *ngIf="incompatible"
- type="warning"
- i18n>The data received has the JSON format version 2.x and is currently incompatible with the
- dashboard.</cd-alert-panel>
+ <cd-alert-panel
+ *ngIf="error"
+ type="error"
+ i18n
+ >Failed to retrieve SMART data.</cd-alert-panel
+ >
+ <cd-alert-panel
+ *ngIf="incompatible"
+ type="warning"
+ i18n
+ >The data received has the JSON format version 2.x and is currently incompatible with the
+ dashboard.</cd-alert-panel
+ >
<ng-container *ngIf="!error && !incompatible">
- <cd-alert-panel *ngIf="data | pipeFunction:isEmpty"
- type="info"
- i18n>No SMART data available.</cd-alert-panel>
+ <cd-alert-panel
+ *ngIf="data | pipeFunction: isEmpty"
+ type="info"
+ i18n
+ >No SMART data available.</cd-alert-panel
+ >
- <ng-container *ngIf="!(data | pipeFunction:isEmpty)">
- <nav ngbNav
- #nav="ngbNav"
- class="nav-tabs">
- <ng-container ngbNavItem
- *ngFor="let device of data | keyvalue">
+ <ng-container *ngIf="!(data | pipeFunction: isEmpty)">
+ <nav
+ ngbNav
+ #nav="ngbNav"
+ class="nav-tabs"
+ >
+ <ng-container
+ ngbNavItem
+ *ngFor="let device of data | keyvalue"
+ >
<a ngbNavLink>{{ device.value.device }} ({{ device.value.identifier }})</a>
<ng-template ngbNavContent>
<ng-container *ngIf="device.value.error; else noError">
- <cd-alert-panel id="alert-error"
- type="warning">{{ device.value.userMessage }}</cd-alert-panel>
+ <cd-alert-panel
+ id="alert-error"
+ type="warning"
+ >{{ device.value.userMessage }}</cd-alert-panel
+ >
</ng-container>
<ng-template #noError>
- <cd-alert-panel *ngIf="device.value.info?.smart_status | pipeFunction:isEmpty; else hasSmartStatus"
- id="alert-self-test-unknown"
- size="slim"
- type="warning"
- i18n-title
- title="SMART overall-health self-assessment test result"
- i18n>unknown</cd-alert-panel>
+ <cd-alert-panel
+ *ngIf="device.value.info?.smart_status | pipeFunction: isEmpty; else hasSmartStatus"
+ id="alert-self-test-unknown"
+ size="slim"
+ type="warning"
+ i18n-title
+ title="SMART overall-health self-assessment test result"
+ i18n
+ >unknown</cd-alert-panel
+ >
<ng-template #hasSmartStatus>
<!-- HDD/NVMe self test -->
<ng-container *ngIf="device.value.info.smart_status.passed; else selfTestFailed">
- <cd-alert-panel id="alert-self-test-passed"
- size="slim"
- type="info"
- i18n-title
- title="SMART overall-health self-assessment test result"
- i18n>passed</cd-alert-panel>
+ <cd-alert-panel
+ id="alert-self-test-passed"
+ size="slim"
+ type="info"
+ i18n-title
+ title="SMART overall-health self-assessment test result"
+ i18n
+ >passed</cd-alert-panel
+ >
</ng-container>
<ng-template #selfTestFailed>
- <cd-alert-panel id="alert-self-test-failed"
- size="slim"
- type="warning"
- i18n-title
- title="SMART overall-health self-assessment test result"
- i18n>failed</cd-alert-panel>
+ <cd-alert-panel
+ id="alert-self-test-failed"
+ size="slim"
+ type="warning"
+ i18n-title
+ title="SMART overall-health self-assessment test result"
+ i18n
+ >failed</cd-alert-panel
+ >
</ng-template>
</ng-template>
</ng-template>
- <ng-container *ngIf="!(device.value.info | pipeFunction:isEmpty) || !(device.value.smart | pipeFunction:isEmpty)">
- <nav ngbNav
- #innerNav="ngbNav"
- class="nav-tabs">
+ <ng-container
+ *ngIf="
+ !(device.value.info | pipeFunction: isEmpty) ||
+ !(device.value.smart | pipeFunction: isEmpty)
+ "
+ >
+ <nav
+ ngbNav
+ #innerNav="ngbNav"
+ class="nav-tabs"
+ >
<li [ngbNavItem]="1">
- <a ngbNavLink
- i18n>Device Information</a>
+ <a
+ ngbNavLink
+ i18n
+ >Device Information</a
+ >
<ng-template ngbNavContent>
- <cd-table-key-value *ngIf="!(device.value.info | pipeFunction:isEmpty)"
- [renderObjects]="true"
- [data]="device.value.info"></cd-table-key-value>
- <cd-alert-panel *ngIf="device.value.info | pipeFunction:isEmpty"
- id="alert-device-info-unavailable"
- type="info"
- i18n>No device information available for this device.</cd-alert-panel>
+ <cd-table-key-value
+ *ngIf="!(device.value.info | pipeFunction: isEmpty)"
+ [renderObjects]="true"
+ [data]="device.value.info"
+ ></cd-table-key-value>
+ <cd-alert-panel
+ *ngIf="device.value.info | pipeFunction: isEmpty"
+ id="alert-device-info-unavailable"
+ type="info"
+ i18n
+ >No device information available for this device.</cd-alert-panel
+ >
</ng-template>
</li>
<li [ngbNavItem]="2">
- <a ngbNavLink
- i18n>SMART</a>
+ <a
+ ngbNavLink
+ i18n
+ >SMART</a
+ >
<ng-template ngbNavContent>
- <cd-table *ngIf="device.value.smart?.attributes"
- [data]="device.value.smart.attributes.table"
- updateSelectionOnRefresh="never"
- [columns]="smartDataColumns"></cd-table>
- <cd-table-key-value *ngIf="device.value.smart?.scsi_error_counter_log"
- [renderObjects]="true"
- [data]="device.value.smart"
- updateSelectionOnRefresh="never"></cd-table-key-value>
- <cd-table-key-value *ngIf="device.value.smart?.nvmeData"
- [renderObjects]="true"
- [data]="device.value.smart.nvmeData"
- updateSelectionOnRefresh="never"></cd-table-key-value>
- <cd-alert-panel *ngIf="!device.value.smart?.attributes && !device.value.smart?.nvmeData && !device.value.smart?.scsi_error_counter_log"
- id="alert-device-smart-data-unavailable"
- type="info"
- i18n>No SMART data available for this device.</cd-alert-panel>
+ <cd-table
+ *ngIf="device.value.smart?.attributes"
+ [data]="device.value.smart.attributes.table"
+ updateSelectionOnRefresh="never"
+ [columns]="smartDataColumns"
+ ></cd-table>
+ <cd-table-key-value
+ *ngIf="device.value.smart?.scsi_error_counter_log"
+ [renderObjects]="true"
+ [data]="device.value.smart"
+ updateSelectionOnRefresh="never"
+ ></cd-table-key-value>
+ <cd-table-key-value
+ *ngIf="device.value.smart?.nvmeData"
+ [renderObjects]="true"
+ [data]="device.value.smart.nvmeData"
+ updateSelectionOnRefresh="never"
+ ></cd-table-key-value>
+ <cd-alert-panel
+ *ngIf="
+ !device.value.smart?.attributes &&
+ !device.value.smart?.nvmeData &&
+ !device.value.smart?.scsi_error_counter_log
+ "
+ id="alert-device-smart-data-unavailable"
+ type="info"
+ i18n
+ >No SMART data available for this device.</cd-alert-panel
+ >
</ng-template>
</li>
</nav>
-<div cdsCol
- [columnNumbers]="{ md: 4 }"
- *ngIf="orchStatus$ | async as orchStatus">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+ *ngIf="orchStatus$ | async as orchStatus"
+>
<ng-container *cdFormLoading="loading">
- <form name="smbForm"
- #formDir="ngForm"
- [formGroup]="smbForm"
- novalidate>
- <div i18n="form title"
- class="form-header">
+ <form
+ name="smbForm"
+ #formDir="ngForm"
+ [formGroup]="smbForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
{{ action | titlecase }} {{ resource | upperFirst }}
</div>
Stand-alone servers configuration."
i18n-helperText
>
- <option value="active-directory"
- i18n>Active Directory</option>
- <option value="user"
- i18n>User</option>
+ <option
+ value="active-directory"
+ i18n
+ >
+ Active Directory
+ </option>
+ <option
+ value="user"
+ i18n
+ >
+ User
+ </option>
</cds-select>
<ng-template #authModeError>
<span
</div>
<!-- Domain Settings -->
- <div class="form-item"
- *ngIf="smbForm.get('auth_mode').value === AUTHMODE.ActiveDirectory">
- <div cdsCol
- [columnNumbers]="{ md: 12 }"
- class="d-flex">
- <cds-text-label labelInputID="domain_settings"
- i18n
- cdRequiredField="Domain Settings">Active Directory (AD) Settings
+ <div
+ class="form-item"
+ *ngIf="smbForm.get('auth_mode').value === AUTHMODE.ActiveDirectory"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ md: 12 }"
+ class="d-flex"
+ >
+ <cds-text-label
+ labelInputID="domain_settings"
+ i18n
+ cdRequiredField="Domain Settings"
+ >Active Directory (AD) Settings
<div class="cds-input-group">
<input
cdsText
smbForm.controls.domain_settings.touched
"
/>
- <cds-icon-button kind="ghost"
- (click)="editDomainSettingsModal()"
- size="md">
- <svg cdsIcon="edit"
- size="32"
- class="cds--btn__icon"
- icon></svg>
+ <cds-icon-button
+ kind="ghost"
+ (click)="editDomainSettingsModal()"
+ size="md"
+ >
+ <svg
+ cdsIcon="edit"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
</cds-icon-button>
- <cds-icon-button kind="danger"
- (click)="deleteDomainSettingsModal()"
- size="md">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"
- icon></svg>
+ <cds-icon-button
+ kind="danger"
+ (click)="deleteDomainSettingsModal()"
+ size="md"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
</cds-icon-button>
</div>
</cds-text-label>
smbForm.get('domain_settings').hasError('required') &&
smbForm.controls.domain_settings.touched
"
- i18n>Specify the Realm and AD access resources in the Domain Settings field.</span
+ i18n
+ >Specify the Realm and AD access resources in the Domain Settings field.</span
>
<div></div>
</div>
<!-- User Group Settings -->
- <ng-container formArrayName="joinSources"
- *ngFor="let _ of joinSources.controls; index as i">
+ <ng-container
+ formArrayName="joinSources"
+ *ngFor="let _ of joinSources.controls; index as i"
+ >
<div
cdsRow
- *ngIf="smbForm.get('auth_mode').value === AUTHMODE.User && usersGroups$ | async as usersGroups"
+ *ngIf="
+ smbForm.get('auth_mode').value === AUTHMODE.User && usersGroups$ | async as usersGroups
+ "
class="form-item form-item-append"
>
<div
label="Standalone user access resources"
i18n-label
[formControlName]="i"
- [invalid]="smbForm.controls.joinSources.controls[i].invalid && smbForm.controls.joinSources.controls[i].dirty"
+ [invalid]="
+ smbForm.controls.joinSources.controls[i].invalid &&
+ smbForm.controls.joinSources.controls[i].dirty
+ "
[invalidText]="ugError"
>
<option
[value]="null"
i18n
- >-- List of users and groups access resources --
+ >
+ -- List of users and groups access resources --
+ </option>
+ <option
+ *ngFor="let ug of usersGroups"
+ [value]="ug.users_groups_id"
+ >
+ {{ ug.users_groups_id }}
</option>
- <option *ngFor="let ug of usersGroups"
- [value]="ug.users_groups_id">{{ ug.users_groups_id }}</option>
</cds-select>
<ng-template #ugError>
<span
class="invalid-feedback"
i18n
- >This field is required.</span>
+ >This field is required.</span
+ >
</ng-template>
</div>
<div
<svg
cdsIcon="trash-can"
size="32"
- class="cds--btn__icon"></svg>
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
</div>
</ng-container>
- <div class="form-item"
- *ngIf="smbForm.get('auth_mode').value === AUTHMODE.User">
- <button cdsButton="tertiary"
- type="button"
- (click)="addUserGroupSetting()"
- i18n>
+ <div
+ class="form-item"
+ *ngIf="smbForm.get('auth_mode').value === AUTHMODE.User"
+ >
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addUserGroupSetting()"
+ i18n
+ >
Add user group
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- icon></svg>
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
</button>
<button
i18n
>
Create user group
- <svg
- cdsIcon="launch"
- size="32"
- class="cds--btn__icon"></svg>
+ <svg
+ cdsIcon="launch"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
formControlName="placement"
id="placement"
>
- <option value="hosts"
- i18n>Hosts</option>
- <option value="label"
- i18n>Labels</option>
+ <option
+ value="hosts"
+ i18n
+ >
+ Hosts
+ </option>
+ <option
+ value="label"
+ i18n
+ >
+ Labels
+ </option>
</cds-select>
</div>
<ng-container *ngIf="hostsAndLabels$ | async as data">
<!-- Label -->
- <div *ngIf="smbForm.controls.placement.value === 'label'"
- class="form-item">
+ <div
+ *ngIf="smbForm.controls.placement.value === 'label'"
+ class="form-item"
+ >
<cds-combo-box
type="multi"
selectionFeedback="top-after-reopen"
</div>
<!-- Hosts -->
- <div *ngIf="smbForm.controls.placement.value === 'hosts'"
- class="form-item">
+ <div
+ *ngIf="smbForm.controls.placement.value === 'hosts'"
+ class="form-item"
+ >
<cds-combo-box
type="multi"
selectionFeedback="top-after-reopen"
<!-- Custom DNS -->
@if (smbForm.get('auth_mode').value === AUTHMODE.ActiveDirectory) {
- <ng-container formArrayName="custom_dns"
- *ngFor="let _ of custom_dns.controls; index as i">
- <div cdsRow
- class="form-item form-item-append">
- <div cdsCol
- [columnNumbers]="{ lg: 14 }">
+ <ng-container
+ formArrayName="custom_dns"
+ *ngFor="let _ of custom_dns.controls; index as i"
+ >
+ <div
+ cdsRow
+ class="form-item form-item-append"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 14 }"
+ >
<cds-text-label
for="custom_dns"
i18n
- >DNS
- <input cdsText
- [formControlName]="i"
- placeholder="192.168.76.204"/>
+ >DNS
+ <input
+ cdsText
+ [formControlName]="i"
+ placeholder="192.168.76.204"
+ />
</cds-text-label>
</div>
<div
cdsIcon="trash-can"
size="32"
class="cds--btn__icon"
- >
- </svg>
+ ></svg>
</cds-icon-button>
</div>
</div>
</ng-container>
<div class="form-item">
- <button cdsButton="tertiary"
- type="button"
- (click)="addCustomDns()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addCustomDns()"
+ i18n
+ >
Add custom DNS
<svg
cdsIcon="add"
size="32"
class="cds--btn__icon"
- icon></svg>
+ icon
+ ></svg>
</button>
- <cd-helper i18n>One or more IP Addresses that will be
- applied to the Samba containers to override
- the default DNS resolver(s). This option is
- intended to be used when the host Ceph node
- is not configured to resolve DNS entries within
- AD domain(s).
+ <cd-helper i18n
+ >One or more IP Addresses that will be applied to the Samba containers to override the
+ default DNS resolver(s). This option is intended to be used when the host Ceph node is
+ not configured to resolve DNS entries within AD domain(s).
</cd-helper>
</div>
}
helperText="Default value indicates that clustering should be enabled if the placement count value is any value other than 1. Always value enables clustering regardless of the placement count. Never value disables clustering regardless of the placement count. "
i18n-helperText
>
- <option *ngFor="let data of allClustering"
- i18n>{{ data | upperFirst }}</option>
+ <option
+ *ngFor="let data of allClustering"
+ i18n
+ >
+ {{ data | upperFirst }}
+ </option>
</cds-select>
</div>
<div
- *ngIf="(smbForm.get('count').value > 1 && smbForm.get('clustering').value.toLowerCase() == CLUSTERING.Default) || smbForm.get('clustering').value.toLowerCase() == CLUSTERING.Always"
+ *ngIf="
+ (smbForm.get('count').value > 1 &&
+ smbForm.get('clustering').value.toLowerCase() == CLUSTERING.Default) ||
+ smbForm.get('clustering').value.toLowerCase() == CLUSTERING.Always
+ "
class="form-item"
>
-
- <!-- Public addrs -->
- <ng-container formArrayName="public_addrs"
- *ngFor="let _ of public_addrs.controls; index as i">
- <ng-container [formGroupName]="i">
- <div cdsRow
- class="form-item form-item-append">
- <!-- Address -->
- <div cdsCol
- [columnNumbers]="{ lg: 7 }">
- <cds-text-label
- for="address"
- i18n
- helperText="This address will be assigned to one of the host's network devices and managed automatically."
- i18n-helperText
- cdrequiredField
- [invalid]="smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.invalid && smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.dirty"
- [invalidText]="addressError"
- >Address
- <input
- cdsText
- type="text"
- formControlName="address"
- placeholder="192.168.4.51/24"
- [invalid]="smbForm?.controls['public_addrs'].controls[i].controls?.address?.invalid && smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.dirty"
- />
- </cds-text-label>
- <ng-template #addressError>
- <span
- class="invalid-feedback"
- >
- <ng-container i18n> This field is required. </ng-container>
- </span>
- </ng-template>
- </div>
- <!-- Destination -->
- <div cdsCol
- [columnNumbers]="{ lg: 7 }">
- <cds-text-label
- for="destination"
- i18n
- helperText="Defines where the system will assign the managed IPs. Each string value must be a network address."
- i18n-helperText
- >Destination
- <input
- cdsText
- type="text"
- formControlName="destination"
- placeholder="192.168.4.0/24"/>
- </cds-text-label>
- </div>
+ <!-- Public addrs -->
+ <ng-container
+ formArrayName="public_addrs"
+ *ngFor="let _ of public_addrs.controls; index as i"
+ >
+ <ng-container [formGroupName]="i">
<div
- cdsCol
- [columnNumbers]="{ lg: 1 }"
- class="item-action-btn spacing"
+ cdsRow
+ class="form-item form-item-append"
>
- <cds-icon-button
- kind="danger"
- size="sm"
- (click)="removePublicAddrs(i)"
+ <!-- Address -->
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 7 }"
>
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
- </cds-icon-button>
+ <cds-text-label
+ for="address"
+ i18n
+ helperText="This address will be assigned to one of the host's network devices and managed automatically."
+ i18n-helperText
+ cdrequiredField
+ [invalid]="
+ smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.invalid &&
+ smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.dirty
+ "
+ [invalidText]="addressError"
+ >Address
+ <input
+ cdsText
+ type="text"
+ formControlName="address"
+ placeholder="192.168.4.51/24"
+ [invalid]="
+ smbForm?.controls['public_addrs'].controls[i].controls?.address?.invalid &&
+ smbForm?.controls['public_addrs']?.controls[i]?.controls?.address?.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #addressError>
+ <span class="invalid-feedback">
+ <ng-container i18n> This field is required. </ng-container>
+ </span>
+ </ng-template>
+ </div>
+ <!-- Destination -->
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 7 }"
+ >
+ <cds-text-label
+ for="destination"
+ i18n
+ helperText="Defines where the system will assign the managed IPs. Each string value must be a network address."
+ i18n-helperText
+ >Destination
+ <input
+ cdsText
+ type="text"
+ formControlName="destination"
+ placeholder="192.168.4.0/24"
+ />
+ </cds-text-label>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn spacing"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="sm"
+ (click)="removePublicAddrs(i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
</div>
- </div>
+ </ng-container>
</ng-container>
- </ng-container>
- <button cdsButton="tertiary"
- type="button"
- (click)="addPublicAddrs()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addPublicAddrs()"
+ i18n
+ >
Add public address
<svg
cdsIcon="add"
size="32"
class="cds--btn__icon"
- icon></svg>
+ icon
+ ></svg>
</button>
- <cd-helper i18n>Assign virtual IP addresses that will be managed
- by the clustering subsystem and may automatically
- move between nodes running Samba containers.</cd-helper>
+ <cd-helper i18n
+ >Assign virtual IP addresses that will be managed by the clustering subsystem and may
+ automatically move between nodes running Samba containers.</cd-helper
+ >
</div>
</cd-form-advanced-fieldset>
<cd-form-button-panel
</div>
<cd-smb-cluster-tabs
*cdTableDetail
- [selection]="expandedRow">
+ [selection]="expandedRow"
+ >
</cd-smb-cluster-tabs>
</cd-table>
</ng-container>
<ng-container *ngIf="selection">
- <cd-smb-share-list
- [clusterId]="selection.cluster_id"
- ></cd-smb-share-list>
+ <cd-smb-share-list [clusterId]="selection.cluster_id"></cd-smb-share-list>
</ng-container>
-<cds-modal size="md"
- [open]="open"
- [hasScrollingContent]="true"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="md"
+ [open]="open"
+ [hasScrollingContent]="true"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </h3>
</cds-modal-header>
<ng-container *cdFormLoading="loading">
<div cdsModalContent>
- <form name="domainSettingsForm"
- #formDir="ngForm"
- [formGroup]="domainSettingsForm"
- novalidate>
+ <form
+ name="domainSettingsForm"
+ #formDir="ngForm"
+ [formGroup]="domainSettingsForm"
+ novalidate
+ >
<div class="form-item">
<cds-text-label
label="realm"
<div
*ngIf="joinAuths$ | async as joinAuths"
- class="form-item">
+ class="form-item"
+ >
<ng-container
formArrayName="join_sources"
*ngFor="let _ of join_sources.controls; index as i"
<ng-container [formGroupName]="i">
<div
cdsRow
- class="form-item form-item-append">
+ class="form-item form-item-append"
+ >
<div
cdsCol
[columnNumbers]="{ lg: 14 }"
label="Active Directory access resources"
i18n-label
formControlName="ref"
- [invalid]="domainSettingsForm.controls?.join_sources.controls[i].invalid && domainSettingsForm.controls?.join_sources.controls[i].controls.ref.dirty"
+ [invalid]="
+ domainSettingsForm.controls?.join_sources.controls[i].invalid &&
+ domainSettingsForm.controls?.join_sources.controls[i].controls.ref.dirty
+ "
[invalidText]="joinSourceError"
>
<option
[value]="null"
i18n
- >-- List of AD access resources --
+ >
+ -- List of AD access resources --
+ </option>
+ <option
+ *ngFor="let jA of joinAuths"
+ [value]="jA.auth_id"
+ >
+ {{ jA.auth_id }}
</option>
- <option *ngFor="let jA of joinAuths"
- [value]="jA.auth_id">{{ jA.auth_id }}</option>
</cds-select>
<ng-template #joinSourceError>
- <span
- class="invalid-feedback"
- >
+ <span class="invalid-feedback">
<ng-container i18n> This field is required. </ng-container>
</span>
</ng-template>
</div>
- <div cdsCol
- *ngIf="i > 0"
- [columnNumbers]="{ lg: 1 }"
- class="item-action-btn spacing">
- <cds-icon-button kind="danger"
- size="sm"
- (click)="removeJoinSource(i)">
- <svg cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon"></svg>
+ <div
+ cdsCol
+ *ngIf="i > 0"
+ [columnNumbers]="{ lg: 1 }"
+ class="item-action-btn spacing"
+ >
+ <cds-icon-button
+ kind="danger"
+ size="sm"
+ (click)="removeJoinSource(i)"
+ >
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
</cds-icon-button>
</div>
</div>
</ng-container>
</ng-container>
<div class="form-item">
- <button cdsButton="tertiary"
- type="button"
- (click)="addJoinSource()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addJoinSource()"
+ i18n
+ >
Add AD access resource
- <svg cdsIcon="add"
- size="32"
- class="cds--btn__icon"
- icon></svg>
+ <svg
+ cdsIcon="add"
+ size="32"
+ class="cds--btn__icon"
+ icon
+ ></svg>
</button>
- <button cdsButton="tertiary"
- type="button"
- (click)="navigateCreateJoinSource()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="navigateCreateJoinSource()"
+ i18n
+ >
Create AD access resource
<svg
cdsIcon="launch"
size="16"
- class="cds--btn__icon"></svg>
+ class="cds--btn__icon"
+ ></svg>
</button>
</div>
</div>
cdsCol
[columnNumbers]="{ md: 4 }"
>
- <form name="form"
- #formDir="ngForm"
- [formGroup]="form"
- novalidate>
- <div i18n="form title"
- class="form-header">
+ <form
+ name="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
{{ action | titlecase }} {{ resource | upperFirst }}
</div>
i18n-helperText
[invalid]="form.controls.authId.invalid && form.controls.authId.dirty"
[invalidText]="jaError"
- >Active directory access resource name
+ >Active directory access resource name
<input
cdsText
type="text"
i18n
[invalid]="form.controls.username.invalid && form.controls.username.dirty"
[invalidText]="usernameError"
- >Username
- <input
+ >Username
+ <input
cdsText
type="text"
id="username"
name="username"
formControlName="username"
[invalid]="form.controls.username.invalid && form.controls.username.dirty"
- />
+ />
</cds-text-label>
<ng-template #usernameError>
<span
- class="invalid-feedback"
- *ngIf="form.showError('username', form, 'required')"
- i18n
- >This field is required.
+ class="invalid-feedback"
+ *ngIf="form.showError('username', form, 'required')"
+ i18n
+ >This field is required.
</span>
</ng-template>
</div>
i18n
[invalid]="form.controls.password.invalid && form.controls.password.dirty"
[invalidText]="passwordError"
- >Password
+ >Password
<input
cdsPassword
type="password"
</cds-password-label>
<ng-template #passwordError>
<span
- class="invalid-feedback"
- *ngIf="form.showError('password', form, 'required')"
- i18n
- >This field is required.
+ class="invalid-feedback"
+ *ngIf="form.showError('password', form, 'required')"
+ i18n
+ >This field is required.
</span>
</ng-template>
</div>
<option
[value]="null"
i18n
- >-- List of clusters --
+ >
+ -- List of clusters --
+ </option>
+ <option
+ *ngFor="let cluster of clusters"
+ [value]="cluster.cluster_id"
+ >
+ {{ cluster.cluster_id }}
</option>
- <option *ngFor="let cluster of clusters"
- [value]="cluster.cluster_id">{{ cluster.cluster_id }}</option>
</cds-select>
</div>
<cd-form-button-panel
- (submitActionEvent)="submit()"
- [form]="form"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ (submitActionEvent)="submit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</div>
<cd-table-actions
[permission]="permission"
[selection]="selection"
- [tableActions]="tableActions">
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</div>
</cd-table>
[grafanaPath]="'ceph-smb-overview?'"
[type]="'metrics'"
uid="feem6ehrmi2o0b"
- grafanaStyle="three">
+ grafanaStyle="three"
+>
</cd-grafana>
-<div cdsCol
- [columnNumbers]="{ md: 4 }">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="smbShareForm"
- #formDir="ngForm"
- [formGroup]="smbShareForm"
- novalidate>
- <div i18n="form title"
- class="form-header">
+ <form
+ name="smbShareForm"
+ #formDir="ngForm"
+ [formGroup]="smbShareForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
{{ action | titlecase }} {{ resource | upperFirst }}
</div>
<!-- Share Id -->
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<cds-text-label
labelInputID="share_id"
<!-- Share Name -->
<div cdsCol>
- <cds-text-label labelInputID="name"
- i18n
- helperText="Name of the Share"
- i18n-helperText>Share Name
- <input cdsText
- type="text"
- id="name"
- formControlName="name" />
+ <cds-text-label
+ labelInputID="name"
+ i18n
+ helperText="Name of the Share"
+ i18n-helperText
+ >Share Name
+ <input
+ cdsText
+ type="text"
+ id="name"
+ formControlName="name"
+ />
</cds-text-label>
</div>
</div>
[invalidText]="volumeError"
i18n-label
>
- <option *ngIf="allFsNames?.length === 0"
- value=""
- i18n>
+ <option
+ *ngIf="allFsNames?.length === 0"
+ value=""
+ i18n
+ >
-- No filesystem available --
</option>
- <option *ngIf="allFsNames !== null && allFsNames?.length > 0"
- value=""
- i18n>
+ <option
+ *ngIf="allFsNames !== null && allFsNames?.length > 0"
+ value=""
+ i18n
+ >
-- Select the filesystem --
</option>
- <option *ngFor="let filesystem of allFsNames"
- [value]="filesystem.name"
- i18n>
+ <option
+ *ngFor="let filesystem of allFsNames"
+ [value]="filesystem.name"
+ i18n
+ >
{{ filesystem.name }}
</option>
</cds-select>
</ng-template>
</div>
- <div class="form-item"
- *ngIf="smbShareForm.getValue('volume')">
+ <div
+ class="form-item"
+ *ngIf="smbShareForm.getValue('volume')"
+ >
<cds-select
formControlName="subvolume_group"
label="Subvolume Group"
[skeleton]="allsubvolgrps === null"
i18n-label
>
- <option *ngIf="allsubvolgrps === null"
- value=""
- i18n>Loading...</option>
- <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
- value=""
- i18n>
+ <option
+ *ngIf="allsubvolgrps === null"
+ value=""
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
+ value=""
+ i18n
+ >
-- Select the CephFS subvolume group --
</option>
<option
</cds-select>
</div>
- <div class="form-group row"
- *ngIf="smbShareForm.getValue('volume')">
+ <div
+ class="form-group row"
+ *ngIf="smbShareForm.getValue('volume')"
+ >
<cds-select
formControlName="subvolume"
label="Subvolume"
(change)="setSubVolPath()"
[skeleton]="allsubvols === null"
>
- <option *ngIf="allsubvols === null"
- value=""
- i18n>Loading...</option>
- <option *ngIf="allsubvols !== null && allsubvols.length === 0"
- value=""
- i18n>
+ <option
+ *ngIf="allsubvols === null"
+ value=""
+ i18n
+ >
+ Loading...
+ </option>
+ <option
+ *ngIf="allsubvols !== null && allsubvols.length === 0"
+ value=""
+ i18n
+ >
-- No SMB subvolume available --
</option>
- <option *ngIf="allsubvols !== null && allsubvols.length > 0"
- value=""
- i18n>
+ <option
+ *ngIf="allsubvols !== null && allsubvols.length > 0"
+ value=""
+ i18n
+ >
-- Select the SMB subvolume --
</option>
<option
</div>
<!-- Path -->
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
- <cds-text-label labelInputID="prefixedPath"
- i18n
- helperText="A path is a relative path.">Prefixed Path
- <input cdsText
- type="text"
- id="prefixedPath"
- formControlName="prefixedPath" />
+ <cds-text-label
+ labelInputID="prefixedPath"
+ i18n
+ helperText="A path is a relative path."
+ >Prefixed Path
+ <input
+ cdsText
+ type="text"
+ id="prefixedPath"
+ formControlName="prefixedPath"
+ />
</cds-text-label>
</div>
<div cdsCol>
<!-- Browseable -->
<div class="form-item">
- <cds-checkbox id="browseable"
- formControlName="browseable"
- i18n>Browseable
+ <cds-checkbox
+ id="browseable"
+ formControlName="browseable"
+ i18n
+ >Browseable
<cd-help-text
>If selected the share will be included in share listings visible to
clients.</cd-help-text
<!-- Readonly -->
<div class="form-item">
- <cds-checkbox id="readonly"
- formControlName="readonly"
- i18n>Readonly
+ <cds-checkbox
+ id="readonly"
+ formControlName="readonly"
+ i18n
+ >Readonly
<cd-help-text>If selected no clients are permitted to write to the share.</cd-help-text>
</cds-checkbox>
</div>
<!-- QoS rate limiting -->
- <div class="form-header"
- i18n>Rate limiting</div>
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-header"
+ i18n
+ >
+ Rate limiting
+ </div>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
- <cds-number formControlName="read_iops_limit"
- cdValidate
- #readIopsRef="cdValidate"
- label="Read IOPS limit"
- i18n-label
- [min]="0"
- [max]="1000000"
- helperText="Max read operations per second (0 = disabled)"
- i18n-helperText
- [invalid]="readIopsRef.isInvalid"
- invalidText="Value must be between 0 and 1,000,000"
- i18n-invalidText>
+ <cds-number
+ formControlName="read_iops_limit"
+ cdValidate
+ #readIopsRef="cdValidate"
+ label="Read IOPS limit"
+ i18n-label
+ [min]="0"
+ [max]="1000000"
+ helperText="Max read operations per second (0 = disabled)"
+ i18n-helperText
+ [invalid]="readIopsRef.isInvalid"
+ invalidText="Value must be between 0 and 1,000,000"
+ i18n-invalidText
+ >
</cds-number>
</div>
<div cdsCol>
- <cds-number formControlName="write_iops_limit"
- cdValidate
- #writeIopsRef="cdValidate"
- label="Write IOPS limit"
- i18n-label
- [min]="0"
- [max]="1000000"
- helperText="Max write operations per second (0 = disabled)"
- i18n-helperText
- [invalid]="writeIopsRef.isInvalid"
- invalidText="Value must be between 0 and 1,000,000"
- i18n-invalidText>
+ <cds-number
+ formControlName="write_iops_limit"
+ cdValidate
+ #writeIopsRef="cdValidate"
+ label="Write IOPS limit"
+ i18n-label
+ [min]="0"
+ [max]="1000000"
+ helperText="Max write operations per second (0 = disabled)"
+ i18n-helperText
+ [invalid]="writeIopsRef.isInvalid"
+ invalidText="Value must be between 0 and 1,000,000"
+ i18n-invalidText
+ >
</cds-number>
</div>
</div>
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
<cd-number-with-unit
[form]="smbShareForm"
></cd-number-with-unit>
</div>
</div>
- <div class="form-item form-item-append"
- cdsRow>
+ <div
+ class="form-item form-item-append"
+ cdsRow
+ >
<div cdsCol>
- <cds-number formControlName="read_delay_max"
- cdValidate
- #readDelayRef="cdValidate"
- label="Read delay max (s)"
- i18n-label
- [min]="0"
- [max]="300"
- helperText="Max allowed delay for read operations in seconds"
- i18n-helperText
- [invalid]="readDelayRef.isInvalid"
- invalidText="Value must be between 0 and 300"
- i18n-invalidText>
+ <cds-number
+ formControlName="read_delay_max"
+ cdValidate
+ #readDelayRef="cdValidate"
+ label="Read delay max (s)"
+ i18n-label
+ [min]="0"
+ [max]="300"
+ helperText="Max allowed delay for read operations in seconds"
+ i18n-helperText
+ [invalid]="readDelayRef.isInvalid"
+ invalidText="Value must be between 0 and 300"
+ i18n-invalidText
+ >
</cds-number>
</div>
<div cdsCol>
- <cds-number formControlName="write_delay_max"
- cdValidate
- #writeDelayRef="cdValidate"
- label="Write delay max (s)"
- i18n-label
- [min]="0"
- [max]="300"
- helperText="Max allowed delay for write operations in seconds"
- i18n-helperText
- [invalid]="writeDelayRef.isInvalid"
- invalidText="Value must be between 0 and 300"
- i18n-invalidText>
+ <cds-number
+ formControlName="write_delay_max"
+ cdValidate
+ #writeDelayRef="cdValidate"
+ label="Write delay max (s)"
+ i18n-label
+ [min]="0"
+ [max]="300"
+ helperText="Max allowed delay for write operations in seconds"
+ i18n-helperText
+ [invalid]="writeDelayRef.isInvalid"
+ invalidText="Value must be between 0 and 300"
+ i18n-invalidText
+ >
</cds-number>
</div>
</div>
</cd-table>
</ng-container>
-<ng-template #iopsLimitTpl
- let-value="data.value">
- R: {{ value?.read_iops_limit ? (value.read_iops_limit | number) : '-' }}
- / W: {{ value?.write_iops_limit ? (value.write_iops_limit | number) : '-' }}
+<ng-template
+ #iopsLimitTpl
+ let-value="data.value"
+>
+ R: {{ value?.read_iops_limit ? (value.read_iops_limit | number) : '-' }} / W:
+ {{ value?.write_iops_limit ? (value.write_iops_limit | number) : '-' }}
</ng-template>
-<ng-template #bwLimitTpl
- let-value="data.value">
- R: {{ value?.read_bw_limit ? (value.read_bw_limit | dimlessBinary) : '-' }}
- / W: {{ value?.write_bw_limit ? (value.write_bw_limit | dimlessBinary) : '-' }}
+<ng-template
+ #bwLimitTpl
+ let-value="data.value"
+>
+ R: {{ value?.read_bw_limit ? (value.read_bw_limit | dimlessBinary) : '-' }} / W:
+ {{ value?.write_bw_limit ? (value.write_bw_limit | dimlessBinary) : '-' }}
</ng-template>
-<ng-template #delayMaxTpl
- let-value="data.value">
- R: {{ value?.read_delay_max ? value.read_delay_max + 's' : '-' }}
- / W: {{ value?.write_delay_max ? value.write_delay_max + 's' : '-' }}
+<ng-template
+ #delayMaxTpl
+ let-value="data.value"
+>
+ R: {{ value?.read_delay_max ? value.read_delay_max + 's' : '-' }} / W:
+ {{ value?.write_delay_max ? value.write_delay_max + 's' : '-' }}
</ng-template>
type="contained"
followFocus="true"
isNavigation="true"
- [cacheActive]="false">
+ [cacheActive]="false"
+>
<cds-tab
heading="Cluster"
i18n-heading
[active]="activeTab === Tabs.cluster"
- (selected)="onSelected(Tabs.cluster)">
+ (selected)="onSelected(Tabs.cluster)"
+ >
</cds-tab>
<cds-tab
heading="Active Directory"
i18n-heading
[active]="activeTab === Tabs.activeDirectory"
- (selected)="onSelected(Tabs.activeDirectory)">
+ (selected)="onSelected(Tabs.activeDirectory)"
+ >
</cds-tab>
<cds-tab
heading="Standalone"
i18n-heading
[active]="activeTab === Tabs.standalone"
- (selected)="onSelected(Tabs.standalone)">
+ (selected)="onSelected(Tabs.standalone)"
+ >
</cds-tab>
<cds-tab
heading="Overview"
i18n-heading
[active]="activeTab === Tabs.overview"
- (selected)="onSelected(Tabs.overview)">
+ (selected)="onSelected(Tabs.overview)"
+ >
</cds-tab>
</cds-tabs>
>
<cds-tab
heading="Users"
- i18n-heading>
+ i18n-heading
+ >
<cd-table
[data]="selection?.values.users"
columnMode="flex"
cdsCol
[columnNumbers]="{ md: 4 }"
>
- <form name="form"
- #formDir="ngForm"
- [formGroup]="form"
- novalidate>
+ <form
+ name="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
<div
i18n="form title"
class="form-header"
i18n-helperText
[invalid]="form.controls.usersGroupsId.invalid && form.controls.usersGroupsId.dirty"
[invalidText]="usersgroupsError"
- >Users and groups access resource name
+ >Users and groups access resource name
<input
cdsText
type="text"
<option
[value]="null"
i18n
- >-- List of clusters --
+ >
+ -- List of clusters --
</option>
<option
*ngFor="let cluster of clusters"
- [value]="cluster.cluster_id">{{ cluster.cluster_id }}
+ [value]="cluster.cluster_id"
+ >
+ {{ cluster.cluster_id }}
</option>
</cds-select>
</div>
<cds-text-label
for="name"
i18n
- [invalid]="form.controls['users'].controls[i].controls.name.invalid &&
- form.controls['users'].controls[i].controls.name.dirty"
+ [invalid]="
+ form.controls['users'].controls[i].controls.name.invalid &&
+ form.controls['users'].controls[i].controls.name.dirty
+ "
[invalidText]="usersNameError"
- >Username
+ >Username
<input
cdsText
type="text"
formControlName="name"
- [invalid]="form.controls['users'].controls[i].controls.name.invalid &&
- form.controls['users'].controls[i].controls.name.dirty"
+ [invalid]="
+ form.controls['users'].controls[i].controls.name.invalid &&
+ form.controls['users'].controls[i].controls.name.dirty
+ "
/>
</cds-text-label>
<ng-template #usersNameError>
<cds-password-label
for="password"
i18n
- [invalid]="form.controls['users'].controls[i].controls.password.invalid &&
- form.controls['users'].controls[i].controls.password.dirty"
+ [invalid]="
+ form.controls['users'].controls[i].controls.password.invalid &&
+ form.controls['users'].controls[i].controls.password.dirty
+ "
[invalidText]="usersPasswordError"
- >Password
- <input
- cdsPassword
- type="password"
- label="Password"
- formControlName="password"
- [invalid]="form.controls['users'].controls[i].controls.password.invalid &&
- form.controls['users'].controls[i].controls.password.dirty"
- >
- </cds-password-label>
- <ng-template #usersPasswordError>
- <span
- class="invalid-feedback"
- i18n
- >This field is required.</span
- >
- </ng-template>
+ >Password
+ <input
+ cdsPassword
+ type="password"
+ label="Password"
+ formControlName="password"
+ [invalid]="
+ form.controls['users'].controls[i].controls.password.invalid &&
+ form.controls['users'].controls[i].controls.password.dirty
+ "
+ />
+ </cds-password-label>
+ <ng-template #usersPasswordError>
+ <span
+ class="invalid-feedback"
+ i18n
+ >This field is required.</span
+ >
+ </ng-template>
</div>
<div
cdsCol
size="sm"
(click)="removeUser(i)"
>
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon">
- </svg>
- </cds-icon-button>
- </div>
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
+ </div>
</div>
</ng-container>
</ng-container>
type="button"
(click)="addUser()"
i18n
- >Add User
+ >
+ Add User
<svg
cdsIcon="add"
size="32"
class="cds--btn__icon"
- icon>
- </svg>
+ icon
+ ></svg>
</button>
</div>
cdsCol
[columnNumbers]="{ lg: 14 }"
>
- <cds-text-label
- for="name"
- i18n
- >Group
- <input
- cdsText
- type="text"
- formControlName="name"
- />
- </cds-text-label>
+ <cds-text-label
+ for="name"
+ i18n
+ >Group
+ <input
+ cdsText
+ type="text"
+ formControlName="name"
+ />
+ </cds-text-label>
</div>
<div
cdsCol
[columnNumbers]="{ lg: 1 }"
- class="item-action-btn spacing">
+ class="item-action-btn spacing"
+ >
<cds-icon-button
kind="danger"
size="sm"
(click)="removeGroup(i)"
>
- <svg
- cdsIcon="trash-can"
- size="32"
- class="cds--btn__icon">
- </svg>
- </cds-icon-button>
+ <svg
+ cdsIcon="trash-can"
+ size="32"
+ class="cds--btn__icon"
+ ></svg>
+ </cds-icon-button>
</div>
</div>
</ng-container>
</ng-container>
<div class="form-item">
- <button cdsButton="tertiary"
- type="button"
- (click)="addGroup()"
- i18n>
+ <button
+ cdsButton="tertiary"
+ type="button"
+ (click)="addGroup()"
+ i18n
+ >
Add Group
<svg
cdsIcon="add"
size="32"
class="cds--btn__icon"
- icon></svg>
+ icon
+ ></svg>
</button>
</div>
(submitActionEvent)="submit()"
[form]="form"
[submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
- </form>
- </div>
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
+ </form>
+</div>
(fetchData)="loadUsersGroups()"
(updateSelection)="updateSelection($event)"
>
- <div class="table-actions">
- <cd-table-actions
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
- <cd-smb-usersgroups-details
- *cdTableDetail
- [selection]="expandedRow"
- ></cd-smb-usersgroups-details>
-</cd-table>
+ <div class="table-actions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
+ </cd-table-actions>
+ </div>
+ <cd-smb-usersgroups-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ ></cd-smb-usersgroups-details>
+ </cd-table>
</ng-container>
<ng-template
<div>
<h2 i18n>Please set a new password.</h2>
<h4 i18n>You will be redirected to the login page afterwards.</h4>
- <form #frm="ngForm"
- [formGroup]="userForm"
- novalidate>
-
+ <form
+ #frm="ngForm"
+ [formGroup]="userForm"
+ novalidate
+ >
<!-- Old password -->
<div class="form-group has-feedback">
<div class="input-group">
- <input class="form-control"
- type="password"
- placeholder="Old password..."
- id="oldpassword"
- formControlName="oldpassword"
- autocomplete="new-password"
- autofocus>
- <button class="btn btn-outline-light btn-password"
- cdPasswordButton="oldpassword"
- type="button">
- </button>
+ <input
+ class="form-control"
+ type="password"
+ placeholder="Old password..."
+ id="oldpassword"
+ formControlName="oldpassword"
+ autocomplete="new-password"
+ autofocus
+ />
+ <button
+ class="btn btn-outline-light btn-password"
+ cdPasswordButton="oldpassword"
+ type="button"
+ ></button>
</div>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('oldpassword', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('oldpassword', frm, 'notmatch')"
- i18n>The old and new passwords must be different.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('oldpassword', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('oldpassword', frm, 'notmatch')"
+ i18n
+ >The old and new passwords must be different.</span
+ >
</div>
<!-- New password -->
<div class="form-group has-feedback">
<div class="input-group">
- <input class="form-control"
- type="password"
- placeholder="New password..."
- id="newpassword"
- autocomplete="new-password"
- formControlName="newpassword">
- <button type="button"
- class="btn btn-outline-light btn-password"
- cdPasswordButton="newpassword">
- </button>
+ <input
+ class="form-control"
+ type="password"
+ placeholder="New password..."
+ id="newpassword"
+ autocomplete="new-password"
+ formControlName="newpassword"
+ />
+ <button
+ type="button"
+ class="btn btn-outline-light btn-password"
+ cdPasswordButton="newpassword"
+ ></button>
</div>
<div class="password-strength-level">
- <div class="{{ passwordStrengthLevelClass }}"
- data-toggle="tooltip"
- title="{{ passwordValuation }}">
- </div>
+ <div
+ class="{{ passwordStrengthLevelClass }}"
+ data-toggle="tooltip"
+ title="{{ passwordValuation }}"
+ ></div>
</div>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('newpassword', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('newpassword', frm, 'notmatch')"
- i18n>The old and new passwords must be different.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('newpassword', frm, 'passwordPolicy')">
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('newpassword', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('newpassword', frm, 'notmatch')"
+ i18n
+ >The old and new passwords must be different.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('newpassword', frm, 'passwordPolicy')"
+ >
{{ passwordValuation }}
</span>
</div>
<!-- Confirm new password -->
<div class="form-group has-feedback">
<div class="input-group">
- <input class="form-control"
- type="password"
- autocomplete="new-password"
- placeholder="Confirm new password..."
- id="confirmnewpassword"
- formControlName="confirmnewpassword">
- <button class="btn btn-outline-light btn-password"
- cdPasswordButton="confirmnewpassword"
- type="button">
- </button>
+ <input
+ class="form-control"
+ type="password"
+ autocomplete="new-password"
+ placeholder="Confirm new password..."
+ id="confirmnewpassword"
+ formControlName="confirmnewpassword"
+ />
+ <button
+ class="btn btn-outline-light btn-password"
+ cdPasswordButton="confirmnewpassword"
+ type="button"
+ ></button>
</div>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('confirmnewpassword', frm, 'required')"
- i18n>This field is required.</span>
- <span class="invalid-feedback"
- *ngIf="userForm.showError('confirmnewpassword', frm, 'match')"
- i18n>Password confirmation doesn't match the new password.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('confirmnewpassword', frm, 'required')"
+ i18n
+ >This field is required.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('confirmnewpassword', frm, 'match')"
+ i18n
+ >Password confirmation doesn't match the new password.</span
+ >
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- (backActionEvent)="onCancel()"
- [form]="userForm"
- [disabled]="userForm.invalid"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ (backActionEvent)="onCancel()"
+ [form]="userForm"
+ [disabled]="userForm.invalid"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</form>
</div>
-<div class="container"
- *ngIf="isLoginActive">
+<div
+ class="container"
+ *ngIf="isLoginActive"
+>
<h1 class="cds--visually-hidden">Ceph login</h1>
- <form name="loginForm"
- (ngSubmit)="login()"
- #loginForm="ngForm"
- novalidate>
-
+ <form
+ name="loginForm"
+ (ngSubmit)="login()"
+ #loginForm="ngForm"
+ novalidate
+ >
<!-- Username -->
<div class="form-group has-feedback d-flex flex-column py-3">
- <label class="ps-3"
- for="username"
- i18n>Username</label>
- <input id="username"
- name="username"
- [(ngModel)]="model.username"
- #username="ngModel"
- type="text"
- [attr.aria-invalid]="username.invalid"
- aria-labelledby="username"
- class="form-control ps-3"
- required
- autofocus>
- <div class="invalid-feedback ps-3"
- *ngIf="(loginForm.submitted || username.dirty) && username.invalid"
- i18n>Username is required</div>
+ <label
+ class="ps-3"
+ for="username"
+ i18n
+ >Username</label
+ >
+ <input
+ id="username"
+ name="username"
+ [(ngModel)]="model.username"
+ #username="ngModel"
+ type="text"
+ [attr.aria-invalid]="username.invalid"
+ aria-labelledby="username"
+ class="form-control ps-3"
+ required
+ autofocus
+ />
+ <div
+ class="invalid-feedback ps-3"
+ *ngIf="(loginForm.submitted || username.dirty) && username.invalid"
+ i18n
+ >
+ Username is required
+ </div>
</div>
<!-- Password -->
- <div class="form-group has-feedback"
- id="password-div">
+ <div
+ class="form-group has-feedback"
+ id="password-div"
+ >
<div class="input-group d-flex flex-nowrap">
<div class="d-flex flex-column flex-grow-1 py-3">
- <label class="ps-3"
- for="password"
- i18n>Password</label>
- <input id="password"
- name="password"
- [(ngModel)]="model.password"
- #password="ngModel"
- type="password"
- [attr.aria-invalid]="password.invalid"
- aria-labelledby="password"
- class="form-control ps-3"
- required>
- <div class="invalid-feedback ps-3"
- *ngIf="(loginForm.submitted || password.dirty) && password.invalid"
- i18n>Password is required</div>
+ <label
+ class="ps-3"
+ for="password"
+ i18n
+ >Password</label
+ >
+ <input
+ id="password"
+ name="password"
+ [(ngModel)]="model.password"
+ #password="ngModel"
+ type="password"
+ [attr.aria-invalid]="password.invalid"
+ aria-labelledby="password"
+ class="form-control ps-3"
+ required
+ />
+ <div
+ class="invalid-feedback ps-3"
+ *ngIf="(loginForm.submitted || password.dirty) && password.invalid"
+ i18n
+ >
+ Password is required
+ </div>
</div>
<span class="form-group-append">
- <button type="button"
- class="btn btn-outline-light btn-password h-100 px-4"
- cdPasswordButton="password"
- aria-label="toggle-password">
- </button>
+ <button
+ type="button"
+ class="btn btn-outline-light btn-password h-100 px-4"
+ cdPasswordButton="password"
+ aria-label="toggle-password"
+ ></button>
</span>
</div>
</div>
- <input type="submit"
- class="btn btn-accent px-5 py-2"
- [disabled]="loginForm.invalid"
- value="Log in"
- i18n-value>
+ <input
+ type="submit"
+ class="btn btn-accent px-5 py-2"
+ [disabled]="loginForm.invalid"
+ value="Log in"
+ i18n-value
+ />
</form>
</div>
<ng-container *ngIf="selection">
- <cd-table [data]="scopes_permissions"
- [columns]="columns"
- columnMode="flex"
- [toolHeader]="false"
- [autoReload]="false"
- [autoSave]="false"
- [footer]="false"
- [limit]="0">
+ <cd-table
+ [data]="scopes_permissions"
+ [columns]="columns"
+ columnMode="flex"
+ [toolHeader]="false"
+ [autoReload]="false"
+ [autoSave]="false"
+ [footer]="false"
+ [limit]="0"
+ >
</cd-table>
</ng-container>
-<div cdsCol
- [columnNumbers]="{md: 4}">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form name="roleForm"
- #formDir="ngForm"
- [formGroup]="roleForm"
- novalidate>
- <div i18n="form title"
- class="form-header">{{ action | titlecase }} {{ resource | upperFirst }}
+ <form
+ name="roleForm"
+ #formDir="ngForm"
+ [formGroup]="roleForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
+ {{ action | titlecase }} {{ resource | upperFirst }}
</div>
- <!--Name -->
+ <!--Name -->
<div class="form-item">
- <cds-text-label for="name"
- cdRequiredField="Name"
- [invalid]="!roleForm.controls.name.valid && roleForm.controls.name.dirty"
- [invalidText]="nameError"
- i18n>Name
- <span [ngClass]="{'required': mode !== roleFormMode.editing}"></span>
- <input cdsText
- placeholder="Name..."
- i18n-placeholder
- id="name"
- name="name"
- formControlName="name"
- [invalid]="!roleForm.controls.name.valid && roleForm.controls.name.dirty"
- autofocus>
+ <cds-text-label
+ for="name"
+ cdRequiredField="Name"
+ [invalid]="!roleForm.controls.name.valid && roleForm.controls.name.dirty"
+ [invalidText]="nameError"
+ i18n
+ >Name
+ <span [ngClass]="{ required: mode !== roleFormMode.editing }"></span>
+ <input
+ cdsText
+ placeholder="Name..."
+ i18n-placeholder
+ id="name"
+ name="name"
+ formControlName="name"
+ [invalid]="!roleForm.controls.name.valid && roleForm.controls.name.dirty"
+ autofocus
+ />
</cds-text-label>
<ng-template #nameError>
<span *ngIf="roleForm.showError('name', formDir, 'required')">
- <ng-container i18n>
- This field is required.
- </ng-container>
+ <ng-container i18n> This field is required. </ng-container>
</span>
<span *ngIf="roleForm.showError('name', formDir, 'notUnique')">
- <ng-container i18n>
- The chosen name is already in use.
- </ng-container>
+ <ng-container i18n> The chosen name is already in use. </ng-container>
</span>
</ng-template>
</div>
- <!-- Description -->
+ <!-- Description -->
<div class="form-item">
- <cds-text-label for="name"
- i18n>Description
- <input cdsText
- type="text"
- class="input-field"
- placeholder="Description.."
- id="description"
- name="description"
- formControlName="description">
+ <cds-text-label
+ for="name"
+ i18n
+ >Description
+ <input
+ cdsText
+ type="text"
+ class="input-field"
+ placeholder="Description.."
+ id="description"
+ name="description"
+ formControlName="description"
+ />
</cds-text-label>
</div>
<!-- Permissions -->
- <div class="form-item">
+ <div class="form-item">
<cds-text-label>Permissions</cds-text-label>
- <cd-checked-table-form [data]="scopes_permissions"
- [columns]="columns"
- [form]="roleForm"
- inputField="scopes_permissions"
- [scopes]="scopes"
- [initialValue]="initialValue"></cd-checked-table-form>
+ <cd-checked-table-form
+ [data]="scopes_permissions"
+ [columns]="columns"
+ [form]="roleForm"
+ inputField="scopes_permissions"
+ [scopes]="scopes"
+ [initialValue]="initialValue"
+ ></cd-checked-table-form>
</div>
<!--Submit Button-->
<div class="form-item">
- <cd-form-button-panel (submitActionEvent)="submit()"
- [form]="roleForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="roleForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"
+ >
</cd-form-button-panel>
</div>
</form>
<cd-user-tabs></cd-user-tabs>
-<cd-table [data]="roles"
- columnMode="flex"
- [columns]="columns"
- identifier="name"
- selectionType="single"
- [hasDetails]="true"
- (setExpandedRow)="setExpandedRow($event)"
- (fetchData)="getRoles()"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="roles"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="name"
+ selectionType="single"
+ [hasDetails]="true"
+ (setExpandedRow)="setExpandedRow($event)"
+ (fetchData)="getRoles()"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
- <cd-role-details *cdTableDetail
- [selection]="expandedRow"
- [scopes]="scopes">
+ <cd-role-details
+ *cdTableDetail
+ [selection]="expandedRow"
+ [scopes]="scopes"
+ >
</cd-role-details>
</cd-table>
-<div cdsCol [columnNumbers]="{ md: 4 }">
+<div
+ cdsCol
+ [columnNumbers]="{ md: 4 }"
+>
<ng-container *cdFormLoading="loading">
- <form #frm="ngForm" #formDir="ngForm" [formGroup]="userForm" novalidate>
- <div i18n="form title" class="form-header">
+ <form
+ #frm="ngForm"
+ #formDir="ngForm"
+ [formGroup]="userForm"
+ novalidate
+ >
+ <div
+ i18n="form title"
+ class="form-header"
+ >
{{ action | titlecase }} {{ resource | upperFirst }}
</div>
<!-- UserName -->
</ng-template>
</div>
<!-- Password expiration date -->
- <div class="form-item" *ngIf="!isSSO">
+ <div
+ class="form-item"
+ *ngIf="!isSSO"
+ >
<cds-text-label [ngClass]="{ required: pwdExpirationSettings.pwdExpirationSpan > 0 }"
>{{ 'Password Expiration Date' }}
- <cd-helper class="text-pre-wrap" *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0">
+ <cd-helper
+ class="text-pre-wrap"
+ *ngIf="pwdExpirationSettings.pwdExpirationSpan == 0"
+ >
<span>
The Dashboard setting defining the expiration interval of passwords is currently set
to <strong>0</strong>. This means if a date is set, the user password will only expire
</span>
<span
>Consider configuring the Dashboard setting
- <a routerLink="/mgr-modules/edit/dashboard" class="alert-link"
+ <a
+ routerLink="/mgr-modules/edit/dashboard"
+ class="alert-link"
>USER_PWD_EXPIRATION_SPAN</a
>
in order to let passwords expire periodically.
</div>
<!--Full Name-->
<div class="form-item">
- <cds-text-label for="name" i18n>
+ <cds-text-label
+ for="name"
+ i18n
+ >
Full Name
- <input cdsText type="text" placeholder="Full Name..." id="name" formControlName="name" />
+ <input
+ cdsText
+ type="text"
+ placeholder="Full Name..."
+ id="name"
+ formControlName="name"
+ />
</cds-text-label>
</div>
<!-- Email -->
i18n
>
Email
- <input cdsText type="email" placeholder="Email..." id="email" formControlName="email" />
+ <input
+ cdsText
+ type="email"
+ placeholder="Email..."
+ id="email"
+ formControlName="email"
+ />
</cds-text-label>
<ng-template #emailError>
- <span class="invalid-feedback" *ngIf="userForm.showError('email', formDir, 'email')" i18n
+ <span
+ class="invalid-feedback"
+ *ngIf="userForm.showError('email', formDir, 'email')"
+ i18n
>Invalid email.
</span>
</ng-template>
</div>
<!-- Roles -->
- <div class="form-item" *ngIf="allRoles">
+ <div
+ class="form-item"
+ *ngIf="allRoles"
+ >
<cds-combo-box
label="Roles"
type="multi"
</ng-template>
</div>
<!-- Enabled -->
- <div class="form-item" *ngIf="!isCurrentUser()">
- <cds-checkbox id="enabled" formControlName="enabled" name="enabled" i18n
+ <div
+ class="form-item"
+ *ngIf="!isCurrentUser()"
+ >
+ <cds-checkbox
+ id="enabled"
+ formControlName="enabled"
+ name="enabled"
+ i18n
>Enabled
</cds-checkbox>
</div>
<!-- Force change password -->
- <div class="form-item" *ngIf="!isCurrentUser() && !isSSO">
+ <div
+ class="form-item"
+ *ngIf="!isCurrentUser() && !isSSO"
+ >
<cds-checkbox
id="pwdUpdateRequired"
formControlName="pwdUpdateRequired"
<cd-user-tabs></cd-user-tabs>
-<cd-table [data]="users"
- columnMode="flex"
- [columns]="columns"
- identifier="username"
- selectionType="single"
- (fetchData)="getUsers()"
- (updateSelection)="updateSelection($event)">
- <cd-table-actions class="table-actions"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="tableActions">
+<cd-table
+ [data]="users"
+ columnMode="flex"
+ [columns]="columns"
+ identifier="username"
+ selectionType="single"
+ (fetchData)="getUsers()"
+ (updateSelection)="updateSelection($event)"
+>
+ <cd-table-actions
+ class="table-actions"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="tableActions"
+ >
</cd-table-actions>
</cd-table>
-<ng-template #userRolesTpl
- let-value="data.value">
- <span *ngFor="let role of value; last as isLast">
- {{ role }}{{ !isLast ? ", " : "" }}
- </span>
+<ng-template
+ #userRolesTpl
+ let-value="data.value"
+>
+ <span *ngFor="let role of value; last as isLast"> {{ role }}{{ !isLast ? ', ' : '' }} </span>
</ng-template>
-<ng-template #warningTpl
- let-column="data.column"
- let-value="data.value"
- let-row="data.row">
- <div [class.border-danger]="row.remainingDays < expirationDangerAlert"
- [class.border-warning]="row.remainingDays < expirationWarningAlert && row.remainingDays >= expirationDangerAlert"
- class="border-margin">
- <div class="warning-content"> {{ value }} </div>
+<ng-template
+ #warningTpl
+ let-column="data.column"
+ let-value="data.value"
+ let-row="data.row"
+>
+ <div
+ [class.border-danger]="row.remainingDays < expirationDangerAlert"
+ [class.border-warning]="
+ row.remainingDays < expirationWarningAlert && row.remainingDays >= expirationDangerAlert
+ "
+ class="border-margin"
+ >
+ <div class="warning-content">{{ value }}</div>
</div>
</ng-template>
-<ng-template #durationTpl
- let-column="data.column"
- let-value="data.value"
- let-row="data.row">
- <i *ngIf="row.remainingDays < expirationWarningAlert"
- i18n-title
- title="User's password is about to expire"
- [class.icon-danger-color]="row.remainingDays < expirationDangerAlert"
- [class.icon-warning-color]="row.remainingDays < expirationWarningAlert && row.remainingDays >= expirationDangerAlert"
- class="{{ icons.warning }}"></i>
+<ng-template
+ #durationTpl
+ let-column="data.column"
+ let-value="data.value"
+ let-row="data.row"
+>
+ <i
+ *ngIf="row.remainingDays < expirationWarningAlert"
+ i18n-title
+ title="User's password is about to expire"
+ [class.icon-danger-color]="row.remainingDays < expirationDangerAlert"
+ [class.icon-warning-color]="
+ row.remainingDays < expirationWarningAlert && row.remainingDays >= expirationDangerAlert
+ "
+ class="{{ icons.warning }}"
+ ></i>
<span title="{{ value | cdDate }}">{{ row.remainingTimeWithoutSeconds / 1000 | duration }}</span>
</ng-template>
-<form [formGroup]="userForm"
- novalidate>
- <div cdsGrid
- [useCssGrid]="true"
- [narrow]="true"
- [fullWidth]="true">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 8}">
- <div cdsRow
- class="form-heading">
+<form
+ [formGroup]="userForm"
+ novalidate
+>
+ <div
+ cdsGrid
+ [useCssGrid]="true"
+ [narrow]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 8 }"
+ >
+ <div
+ cdsRow
+ class="form-heading"
+ >
<h3>{{ action | titlecase }} {{ resource | upperFirst }}</h3>
<cd-help-text [formAllFieldsRequired]="true"></cd-help-text>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-password-label
[invalid]="oldPwd.isInvalid"
- [invalidText]="oldPasswordInvalid">
+ [invalidText]="oldPasswordInvalid"
+ >
Old Password
- <input cdsPassword
- cdValidate
- #oldPwd="cdValidate"
- formControlName="oldpassword"
- autocomplete="oldpassword"
- [invalid]="oldPwd.isInvalid"
- id="oldpassword"
- autofocus>
+ <input
+ cdsPassword
+ cdValidate
+ #oldPwd="cdValidate"
+ formControlName="oldpassword"
+ autocomplete="oldpassword"
+ [invalid]="oldPwd.isInvalid"
+ id="oldpassword"
+ autofocus
+ />
</cds-password-label>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-password-label
[invalid]="newPwd.isInvalid"
[invalidText]="newPasswordInvalid"
- [helperText]="passwordPolicyHelpText">
+ [helperText]="passwordPolicyHelpText"
+ >
New Password
- <input cdsPassword
- cdValidate
- #newPwd="cdValidate"
- formControlName="newpassword"
- autocomplete="newpassword"
- [invalid]="newPwd.isInvalid"
- id="newpassword">
+ <input
+ cdsPassword
+ cdValidate
+ #newPwd="cdValidate"
+ formControlName="newpassword"
+ autocomplete="newpassword"
+ [invalid]="newPwd.isInvalid"
+ id="newpassword"
+ />
</cds-password-label>
</div>
- <div cdsRow
- class="form-item">
+ <div
+ cdsRow
+ class="form-item"
+ >
<cds-password-label
[invalid]="confirmPwd.isInvalid"
- [invalidText]="confirmNewPasswordInvalid">
+ [invalidText]="confirmNewPasswordInvalid"
+ >
Confirm New Password
- <input cdsPassword
- cdValidate
- #confirmPwd="cdValidate"
- formControlName="confirmnewpassword"
- autocomplete="confirmnewpassword"
- [invalid]="confirmPwd.isInvalid"
- id="confirmnewpassword">
+ <input
+ cdsPassword
+ cdValidate
+ #confirmPwd="cdValidate"
+ formControlName="confirmnewpassword"
+ autocomplete="confirmnewpassword"
+ [invalid]="confirmPwd.isInvalid"
+ id="confirmnewpassword"
+ />
</cds-password-label>
</div>
<div cdsRow>
- <cd-form-button-panel (submitActionEvent)="onSubmit()"
- [form]="userForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right form-button"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right form-button"
+ ></cd-form-button-panel>
</div>
</div>
</div>
</form>
-<ng-template #validationErrors
- let-control="control">
-@if (control.errors) {
-@for (err of control.errors | keyvalue; track err.key) {
-<span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
-}
-}
+<ng-template
+ #validationErrors
+ let-control="control"
+>
+ @if (control.errors) {
+ @for (err of control.errors | keyvalue; track err.key) {
+ <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>
+ }
+ }
</ng-template>
<ng-template #oldPasswordInvalid>
- <ng-container *ngTemplateOutlet="validationErrors; context: { control: userForm.get('oldpassword') }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="validationErrors; context: { control: userForm.get('oldpassword') }"
+ ></ng-container>
</ng-template>
<ng-template #newPasswordInvalid>
- <ng-container *ngTemplateOutlet="validationErrors; context: { control: userForm.get('newpassword') }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="validationErrors; context: { control: userForm.get('newpassword') }"
+ ></ng-container>
</ng-template>
<ng-template #confirmNewPasswordInvalid>
- <ng-container *ngTemplateOutlet="validationErrors; context: { control: userForm.get('confirmnewpassword') }"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="validationErrors; context: { control: userForm.get('confirmnewpassword') }"
+ ></ng-container>
</ng-template>
<ul class="nav nav-tabs">
<li class="nav-item">
- <a class="nav-link"
- routerLink="/user-management/users"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Users</a>
+ <a
+ class="nav-link"
+ routerLink="/user-management/users"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Users</a
+ >
</li>
<li class="nav-item">
- <a class="nav-link"
- routerLink="/user-management/roles"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>Roles</a>
+ <a
+ class="nav-link"
+ routerLink="/user-management/roles"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >Roles</a
+ >
</li>
</ul>
-<ng-container *ngIf="{ ftMap: featureToggleMap$ | async, daemons: rgwDaemonService.daemons$ | async, selectedDaemon: rgwDaemonService.selectedDaemon$ | async } as data">
- <ng-container *ngIf="data.ftMap && data.ftMap.rgw && permissions.rgw.read && isRgwRoute && data.daemons.length > 1">
+<ng-container
+ *ngIf="{
+ ftMap: featureToggleMap$ | async,
+ daemons: rgwDaemonService.daemons$ | async,
+ selectedDaemon: rgwDaemonService.selectedDaemon$ | async
+ } as data"
+>
+ <ng-container
+ *ngIf="
+ data.ftMap && data.ftMap.rgw && permissions.rgw.read && isRgwRoute && data.daemons.length > 1
+ "
+ >
<div class="cd-context-bar pt-3 pb-3">
- <span class="me-1"
- i18n>Object gateway:</span>
- <div ngbDropdown
- placement="bottom-left"
- class="d-inline-block ms-2">
- <button ngbDropdownToggle
- class="btn btn-outline-info ctx-bar-selected-rgw-daemon"
- i18n-title
- title="Object gateway">
+ <span
+ class="me-1"
+ i18n
+ >Object gateway:</span
+ >
+ <div
+ ngbDropdown
+ placement="bottom-left"
+ class="d-inline-block ms-2"
+ >
+ <button
+ ngbDropdownToggle
+ class="btn btn-outline-info ctx-bar-selected-rgw-daemon"
+ i18n-title
+ title="Object gateway"
+ type="button"
+ >
{{ data.selectedDaemon.id }}
- <cds-tag type="blue" size="sm">{{ data.selectedDaemon.zonegroup_name }}</cds-tag>
+ <cds-tag
+ type="blue"
+ size="sm"
+ >{{ data.selectedDaemon.zonegroup_name }}</cds-tag
+ >
</button>
<div ngbDropdownMenu>
<ng-container *ngFor="let daemon of data.daemons">
- <button ngbDropdownItem
- class="ctx-bar-available-rgw-daemon"
- (click)="onDaemonSelection(daemon)">
+ <button
+ ngbDropdownItem
+ class="ctx-bar-available-rgw-daemon"
+ (click)="onDaemonSelection(daemon)"
+ type="button"
+ >
{{ daemon.id }}
- <cds-tag type="blue" size="sm">{{ daemon.zonegroup_name }}</cds-tag>
+ <cds-tag
+ type="blue"
+ size="sm"
+ >{{ daemon.zonegroup_name }}</cds-tag
+ >
</button>
</ng-container>
</div>
<head>
<title>Error Page</title>
- <base target="_blank">
+ <base target="_blank" />
</head>
<div class="container h-75">
<div class="row h-100 justify-content-center align-items-center">
<div class="blank-page">
<div *ngIf="header && message; else elseBlock">
- <svg [cdsIcon]="icon"
- class="cds-info-color cds-icon--size-10"></svg>
+ <svg
+ [cdsIcon]="icon"
+ class="cds-info-color cds-icon--size-10"
+ ></svg>
<div class="mt-4 text-center">
- <h3><b>{{ header }}</b></h3>
- <h4 class="mt-3"
- *ngIf="header !== message">{{ message }}</h4>
- <h4 *ngIf="section"
- i18n>Please consult the <a href="{{ docUrl }}">documentation</a> on how to configure and enable
- the {{ sectionInfo }} management functionality.
+ <h3>
+ <b>{{ header }}</b>
+ </h3>
+ <h4
+ class="mt-3"
+ *ngIf="header !== message"
+ >
+ {{ message }}
+ </h4>
+ <h4
+ *ngIf="section"
+ i18n
+ >
+ Please consult the <a href="{{ docUrl }}">documentation</a> on how to
+ configure and enable the {{ sectionInfo }} management functionality.
</h4>
</div>
</div>
<div class="mt-4">
- <div class="text-center"
- *ngIf="(buttonName && buttonRoute) || uiConfig; else dashboardButton">
- <button class="btn btn-primary ms-1"
- [routerLink]="buttonRoute"
- *ngIf="!uiConfig; else configureButtonTpl"
- type="button"
- i18n>{{ buttonName }}</button>
- <button class="btn btn-light ms-1"
- [routerLink]="secondaryButtonRoute"
- *ngIf="secondaryButtonName && secondaryButtonRoute"
- type="button"
- i18n>{{ secondaryButtonName }}</button>
+ <div
+ class="text-center"
+ *ngIf="(buttonName && buttonRoute) || uiConfig; else dashboardButton"
+ >
+ <button
+ class="btn btn-primary ms-1"
+ [routerLink]="buttonRoute"
+ *ngIf="!uiConfig; else configureButtonTpl"
+ type="button"
+ i18n
+ >
+ {{ buttonName }}
+ </button>
+ <button
+ class="btn btn-light ms-1"
+ [routerLink]="secondaryButtonRoute"
+ *ngIf="secondaryButtonName && secondaryButtonRoute"
+ type="button"
+ i18n
+ >
+ {{ secondaryButtonName }}
+ </button>
</div>
</div>
</div>
</div>
<ng-template #configureButtonTpl>
- <button class="btn btn-primary"
- (click)="doConfigure()"
- [attr.title]="buttonTitle"
- type="button"
- *ngIf="uiConfig"
- i18n>{{ buttonName }}</button>
+ <button
+ class="btn btn-primary"
+ (click)="doConfigure()"
+ [attr.title]="buttonTitle"
+ type="button"
+ *ngIf="uiConfig"
+ i18n
+ >
+ {{ buttonName }}
+ </button>
</ng-template>
-
<ng-template #elseBlock>
- <cd-icon type="warningAltFilled"
- customClass="mx-auto d-block text-danger"
- size="32"></cd-icon>
+ <cd-icon
+ type="warningAltFilled"
+ customClass="mx-auto d-block text-danger"
+ size="32"
+ ></cd-icon>
<div class="mt-4 text-center">
<h3 i18n><b>Page not Found</b></h3>
- <h4 class="mt-4"
- i18n>Sorry, we couldn’t find what you were looking for.
- The page you requested may have been changed or moved.</h4>
+ <h4
+ class="mt-4"
+ i18n
+ >
+ Sorry, we couldn’t find what you were looking for. The page you requested may have been
+ changed or moved.
+ </h4>
</div>
</ng-template>
<ng-template #dashboardButton>
- <div class="mt-4 text-center"
- *ngIf="!module_name; else enableButton">
- <button class="btn btn-primary"
- [routerLink]="'/overview'"
- type="button"
- i18n>Go To Overview</button>
+ <div
+ class="mt-4 text-center"
+ *ngIf="!module_name; else enableButton"
+ >
+ <button
+ class="btn btn-primary"
+ [routerLink]="'/overview'"
+ type="button"
+ i18n
+ >
+ Go To Overview
+ </button>
</div>
</ng-template>
<ng-template #enableButton>
- <div class="mt-4 text-center"
- *ngIf="module_name && !(buttonName && buttonRoute)">
- <button class="btn btn-primary"
- (click)="enableModule()"
- type="button"
- i18n>Enable {{ module_name | upperFirst }} module</button>
+ <div
+ class="mt-4 text-center"
+ *ngIf="module_name && !(buttonName && buttonRoute)"
+ >
+ <button
+ class="btn btn-primary"
+ (click)="enableModule()"
+ type="button"
+ i18n
+ >
+ Enable {{ module_name | upperFirst }} module
+ </button>
</div>
</ng-template>
<main class="login full-height">
<header>
<nav class="navbar p-4">
+ <a
+ class="navbar-brand"
+ aria-label="Ceph Dashboard"
+ i18n-aria-label
+ ></a>
<div class="form-inline">
<cd-language-selector></cd-language-selector>
</div>
<router-outlet></router-outlet>
</div>
<div class="col-sm-12 col-md-6 d-sm-block branding-info">
- <img src="assets/Ceph_Ceph_Logo_with_text_white.svg"
- alt="Ceph"
- class="img-fluid pb-3">
+ <img
+ src="assets/Ceph_Ceph_Logo_with_text_white.svg"
+ alt="Ceph"
+ class="img-fluid pb-3"
+ />
<ul class="list-inline">
- <li class="list-inline-item p-3"
- *ngFor="let docItem of docItems">
- <cd-doc section="{{ docItem.section }}"
- docText="{{ docItem.text }}"
- noSubscribe="true"
- i18n-docText></cd-doc>
+ <li
+ class="list-inline-item p-3"
+ *ngFor="let docItem of docItems"
+ >
+ <cd-doc
+ section="{{ docItem.section }}"
+ docText="{{ docItem.text }}"
+ noSubscribe="true"
+ i18n-docText
+ ></cd-doc>
</li>
</ul>
<cd-custom-login-banner></cd-custom-login-banner>
<block-ui name="global">
<cd-navigation>
- <div class="container-fluid h-100"
- [ngClass]="{'overview': (router.url == '/overview' || router.url == '/dashboard_3' || router.url == '/multi-cluster/overview'), 'rgw-dashboard': (router.url == '/rgw/overview')}">
+ <div
+ class="container-fluid h-100"
+ [ngClass]="{
+ overview:
+ router.url == '/overview' ||
+ router.url == '/dashboard_3' ||
+ router.url == '/multi-cluster/overview',
+ 'rgw-dashboard': router.url == '/rgw/overview'
+ }"
+ >
<!-- ************************ -->
<!-- ALERTS BANNER -->
<!-- ************************ -->
- <div class="cd-alert-container"
- [ngClass]="{'ms-4 me-4': (router.url == '/overview' || router.url == '/dashboard_3' || router.url == '/multi-cluster/overview' || router.url == '/rgw/overview')}">
+ <div
+ class="cd-alert-container"
+ [ngClass]="{
+ 'ms-4 me-4':
+ router.url == '/overview' ||
+ router.url == '/dashboard_3' ||
+ router.url == '/multi-cluster/overview' ||
+ router.url == '/rgw/overview'
+ }"
+ >
@if (enabledFeature$ | async; as features) {
- <cd-pwd-expiration-notification></cd-pwd-expiration-notification>
- <cd-motd></cd-motd>
- @if (features.dashboard) {
- <cd-telemetry-notification></cd-telemetry-notification>
- }
+ <cd-pwd-expiration-notification></cd-pwd-expiration-notification>
+ <cd-motd></cd-motd>
+ @if (features.dashboard) {
+ <cd-telemetry-notification></cd-telemetry-notification>
+ }
}
</div>
<cd-context></cd-context>
<div class="breadcrumbs--padding">
<cd-breadcrumbs></cd-breadcrumbs>
</div>
- @if(pageHeaderTitle) {
- <cd-page-header
- [title]="pageHeaderTitle"
- [description]="pageHeaderDescription">
- </cd-page-header>
+ @if (pageHeaderTitle) {
+ <cd-page-header
+ [title]="pageHeaderTitle"
+ [description]="pageHeaderDescription"
+ >
+ </cd-page-header>
}
<router-outlet></router-outlet>
<cds-placeholder></cds-placeholder>
-<cds-modal [open]="open"
- size="md"
- (overlaySelected)="closeModal()">
+<cds-modal
+ [open]="open"
+ size="md"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
<div class="header-content">
- <img src="assets/Ceph_Ceph_Logo_with_text_red_white.svg"
- class="ceph-logo"
- alt="{{ projectConstants.organization }}">
- <h3 class="modal-title">
- <strong>{{ projectConstants.projectName }}</strong>
- </h3>
+ <img
+ src="assets/Ceph_Ceph_Logo_with_text_red_white.svg"
+ class="ceph-logo"
+ alt="{{ projectConstants.organization }}"
+ />
+ <h3 class="modal-title">
+ <strong>{{ projectConstants.projectName }}</strong>
+ </h3>
</div>
-
</cds-modal-header>
- <section cdsModalContent
- modal-primary-focus>
- <div class="modal-body" >
+ <section
+ cdsModalContent
+ modal-primary-focus
+ >
+ <div class="modal-body">
<div class="product-versions">
<strong i18n>Version</strong>
- <br>
+ <br />
{{ versionNumber }}
{{ versionHash }}
- <br>
+ <br />
{{ versionName }}
</div>
- <br>
+ <br />
<dl>
<dt i18n>Ceph Manager</dt>
<dd>{{ modalVariables.browserOS }}</dd>
</dl>
</div>
- </section>
+ </section>
<cds-modal-footer>
<div class="footer-content">
</div>
</cds-modal-footer>
</cds-modal>
-
-
-<cds-overflow-menu [customTrigger]="customTrigger"
- [flip]="true"
- description="">
+<cds-overflow-menu
+ [customTrigger]="customTrigger"
+ [flip]="true"
+ description=""
+>
<li class="cds--overflow-menu-options__option mb-2">
- <button routerLink="/user-management"
- class="cds--overflow-menu-options__btn"
- type="button"
- i18n>User management</button>
+ <button
+ routerLink="/user-management"
+ class="cds--overflow-menu-options__btn"
+ type="button"
+ i18n
+ >
+ User management
+ </button>
</li>
- <li class="cds--overflow-menu-options__option mb-2"
- *ngIf="configOptPermission.read">
- <button routerLink="/telemetry"
- class="cds--overflow-menu-options__btn"
- type="button"
- i18n>Telemetry configuration</button>
+ <li
+ class="cds--overflow-menu-options__option mb-2"
+ *ngIf="configOptPermission.read"
+ >
+ <button
+ routerLink="/telemetry"
+ class="cds--overflow-menu-options__btn"
+ type="button"
+ i18n
+ >
+ Telemetry configuration
+ </button>
</li>
</cds-overflow-menu>
<ng-template #customTrigger>
- <svg cdsIcon="settings"
- size="20"
- title="Settings"
- *ngIf="userPermission.read"></svg>
- <span i18n
- class="d-md-none">Dashboard Settings</span>
+ <svg
+ cdsIcon="settings"
+ size="20"
+ title="Settings"
+ *ngIf="userPermission.read"
+ ></svg>
+ <span
+ i18n
+ class="d-md-none"
+ >Dashboard Settings</span
+ >
</ng-template>
-
-<div id="swagger-ui"
- class="apiDocs"></div>
+<div
+ id="swagger-ui"
+ class="apiDocs"
+></div>
-<cds-breadcrumb [noTrailingSlash]="true"
- *ngIf="crumbs.length">
+<cds-breadcrumb
+ [noTrailingSlash]="true"
+ *ngIf="crumbs.length"
+>
<ng-container *ngFor="let crumb of crumbs; let last = last">
- <cds-breadcrumb-item *ngIf="!last && crumb.path !== null"
- href="#/{{ crumb.path }}">
+ <cds-breadcrumb-item
+ *ngIf="!last && crumb.path !== null"
+ href="#/{{ crumb.path }}"
+ >
{{ crumb.text }}
</cds-breadcrumb-item>
- <cds-breadcrumb-item *ngIf="last || crumb.path === null"
- data-testid="active-breadcrumb-item">
+ <cds-breadcrumb-item
+ *ngIf="last || crumb.path === null"
+ data-testid="active-breadcrumb-item"
+ >
{{ crumb.text }}
</cds-breadcrumb-item>
</ng-container>
-<cds-overflow-menu [customTrigger]="customTrigger"
- [flip]="true"
- description="">
+<cds-overflow-menu
+ [customTrigger]="customTrigger"
+ [flip]="true"
+ description=""
+>
<li>
- <a [ngClass]="{'cds--overflow-menu-options__btn': true, 'disabled': !docsUrl}"
- href="{{ docsUrl }}"
- target="_blank"
- i18n>Documentation
- <svg cdsIcon="launch"
- class="ms-2"
- size="16"></svg>
+ <a
+ [ngClass]="{ 'cds--overflow-menu-options__btn': true, disabled: !docsUrl }"
+ href="{{ docsUrl }}"
+ target="_blank"
+ i18n
+ >Documentation
+ <svg
+ cdsIcon="launch"
+ class="ms-2"
+ size="16"
+ ></svg>
</a>
</li>
<li>
- <a routerLink="/api-docs"
- target="_blank"
- class="cds--overflow-menu-options__btn"
- i18n>API
- <svg cdsIcon="launch"
- class="ms-2"
- size="16"></svg>
+ <a
+ routerLink="/api-docs"
+ target="_blank"
+ class="cds--overflow-menu-options__btn"
+ i18n
+ >API
+ <svg
+ cdsIcon="launch"
+ class="ms-2"
+ size="16"
+ ></svg>
</a>
</li>
- <cds-overflow-menu-option (click)="openAboutModal()"
- i18n>About</cds-overflow-menu-option>
- <cds-overflow-menu-option (click)="openFeedbackModal()"
- i18n>Report an issue...</cds-overflow-menu-option>
+ <cds-overflow-menu-option
+ (click)="openAboutModal()"
+ i18n
+ >About</cds-overflow-menu-option
+ >
+ <cds-overflow-menu-option
+ (click)="openFeedbackModal()"
+ i18n
+ >Report an issue...</cds-overflow-menu-option
+ >
</cds-overflow-menu>
<ng-template #customTrigger>
- <svg cdsIcon="help"
- size="20"
- i18n-title
- title="Help"
- role="button"></svg>
- <span i18n
- class="d-md-none">Help</span>
+ <svg
+ cdsIcon="help"
+ size="20"
+ i18n-title
+ title="Help"
+ role="button"
+ ></svg>
+ <span
+ i18n
+ class="d-md-none"
+ >Help</span
+ >
</ng-template>
-<cds-overflow-menu [customTrigger]="customTrigger"
- [flip]="true"
- description="">
- <li disabled="true"
- class="show cds--overflow-menu-options__option cds--overflow-menu-options__option--disabled my-2"
- i18n>
- <div class="cds--overflow-menu-options__btn">Logged in as {{ username }}
- </div>
+<cds-overflow-menu
+ [customTrigger]="customTrigger"
+ [flip]="true"
+ description=""
+>
+ <li
+ disabled="true"
+ class="show cds--overflow-menu-options__option cds--overflow-menu-options__option--disabled my-2"
+ i18n
+ >
+ <div class="cds--overflow-menu-options__btn">Logged in as {{ username }}</div>
</li>
<li class="cds--overflow-menu-options__option cds--overflow-menu--divider mb-2">
- <button *ngIf="!sso"
- routerLink="/user-profile/edit"
- class="cds--overflow-menu-options__btn"
- type="button"
- i18n>
- <svg cdsIcon="locked"
- class="me-2"
- size="16"></svg>Change password
- </button>
+ <button
+ *ngIf="!sso"
+ routerLink="/user-profile/edit"
+ class="cds--overflow-menu-options__btn"
+ type="button"
+ i18n
+ >
+ <svg
+ cdsIcon="locked"
+ class="me-2"
+ size="16"
+ ></svg
+ >Change password
+ </button>
</li>
<li class="cds--overflow-menu-options__option mb-2">
- <button (click)="logout()"
- data-testid="logout"
- class="cds--overflow-menu-options__btn"
- type="button"
- i18n><svg cdsIcon="logout"
- class="me-2"
- size="16"></svg>Log out
- </button>
+ <button
+ (click)="logout()"
+ data-testid="logout"
+ class="cds--overflow-menu-options__btn"
+ type="button"
+ i18n
+ >
+ <svg
+ cdsIcon="logout"
+ class="me-2"
+ size="16"
+ ></svg
+ >Log out
+ </button>
</li>
</cds-overflow-menu>
<ng-template #customTrigger>
- <svg cdsIcon="user--filled"
- size="20"
- title="User settings"></svg>
- <span i18n
- class="d-md-none">Logged in user</span>
+ <svg
+ cdsIcon="user--filled"
+ size="20"
+ title="User settings"
+ ></svg>
+ <span
+ i18n
+ class="d-md-none"
+ >Logged in user</span
+ >
</ng-template>
<!-- ************************ -->
<!-- NOTIFICATION PANEL -->
<!-- ************************ -->
- @if(notificationService.panelState$ | async; as isNotifPanelOpen) {
- <cd-notification-panel></cd-notification-panel>
- }
+ @if (notificationService.panelState$ | async; as isNotifPanelOpen) {
+ <cd-notification-panel></cd-notification-panel>
+ }
<!-- ************************ -->
<!-- HEADER -->
<!-- ************************ -->
- <cds-header name="Ceph Dashboard"
- class="cd-navbar-top"
- [brand]="brandTemplate">
- <cds-hamburger [active]="showMenuSidebar"
- data-testid="main-menu-toggler"
- (selected)="showMenuSidebar = !showMenuSidebar"></cds-hamburger>
+ <cds-header
+ name="Ceph Dashboard"
+ class="cd-navbar-top"
+ [brand]="brandTemplate"
+ >
+ <cds-hamburger
+ [active]="showMenuSidebar"
+ data-testid="main-menu-toggler"
+ (selected)="showMenuSidebar = !showMenuSidebar"
+ ></cds-hamburger>
<!-- ************************* -->
<!-- CLUSTER SWITCHER TEMPLATE -->
<!-- ************************* -->
- <cds-header-navigation class="cluster-switcher"
- *ngIf="clustersMap?.size > 1">
- <cds-header-menu [title]="currentClusterName"
- data-testid="selected-cluster">
- <ng-container *ngFor="let cluster of clustersMap | keyvalue; trackBy:trackByFn ">
- <cds-header-item (click)="onClusterSelection(cluster.value)"
- [class.disabled]="cluster.value.cluster_connection_status === 1"
- data-testid="select-a-cluster">
- {{ cluster.value.name }} - {{ cluster.value?.cluster_alias }} - {{ cluster.value?.user }}
+ <cds-header-navigation
+ class="cluster-switcher"
+ *ngIf="clustersMap?.size > 1"
+ >
+ <cds-header-menu
+ [title]="currentClusterName"
+ data-testid="selected-cluster"
+ >
+ <ng-container *ngFor="let cluster of clustersMap | keyvalue; trackBy: trackByFn">
+ <cds-header-item
+ (click)="onClusterSelection(cluster.value)"
+ [class.disabled]="cluster.value.cluster_connection_status === 1"
+ data-testid="select-a-cluster"
+ >
+ {{ cluster.value.name }} - {{ cluster.value?.cluster_alias }} -
+ {{ cluster.value?.user }}
</cds-header-item>
</ng-container>
</cds-header-menu>
<cds-header-navigation>
<cd-language-selector class="d-flex"></cd-language-selector>
</cds-header-navigation>
- <div class="cds--btn cds--btn--icon-only cds--header__action"
- data-testid="header-notification-icon"
- (click)="onNotificationSelected($event)"
- tabindex="0"
- (keydown.enter)="onNotificationSelected($event)">
+ <div
+ class="cds--btn cds--btn--icon-only cds--header__action"
+ data-testid="header-notification-icon"
+ (click)="onNotificationSelected($event)"
+ tabindex="0"
+ (keydown.enter)="onNotificationSelected($event)"
+ >
<cd-notifications></cd-notifications>
</div>
<div class="cds--btn cds--btn--icon-only cds--header__action">
<cd-dashboard-help></cd-dashboard-help>
</div>
- <div class="cds--btn cds--btn--icon-only cds--header__action"
- *ngIf="permissions.user.read">
+ <div
+ class="cds--btn cds--btn--icon-only cds--header__action"
+ *ngIf="permissions.user.read"
+ >
<cd-administration></cd-administration>
</div>
<div class="cds--btn cds--btn--icon-only cds--header__action">
<!-- LOGO BRAND TEMPLATE -->
<!-- ***************************** -->
<ng-template #brandTemplate>
- <a class="cds--header__name navbar-brand ms-3"
- routerLink="/overview">
- <img src="assets/Ceph_Ceph_Logo_with_text_white.svg"
- alt="Ceph" />
+ <a
+ class="cds--header__name navbar-brand ms-3"
+ routerLink="/overview"
+ >
+ <img
+ src="assets/Ceph_Ceph_Logo_with_text_white.svg"
+ alt="Ceph"
+ />
</a>
</ng-template>
<!-- **************************************** -->
<!-- **************************************** -->
<div class="wrapper">
<!-- Content -->
- <nav id="sidebar"
- [ngClass]="{'active': !showMenuSidebar}">
+ <nav
+ id="sidebar"
+ [ngClass]="{ active: !showMenuSidebar }"
+ >
<ng-container *ngTemplateOutlet="cd_menu"></ng-container>
</nav>
<!-- Page Content -->
- <div id="content"
- [ngClass]="{'active': !showMenuSidebar, 'content-theme': true}">
+ <div
+ id="content"
+ [ngClass]="{ active: !showMenuSidebar, 'content-theme': true }"
+ >
<ng-content></ng-content>
</div>
</div>
<!-- ************************ -->
<ng-template #cd_menu>
<ng-container *ngIf="enabledFeature$ | async as enabledFeature">
- <cds-sidenav [expanded]="showMenuSidebar"
- class="mt-5"
- (click)="onMenuClick($event)"
- #sidenavContainer>
+ <cds-sidenav
+ [expanded]="showMenuSidebar"
+ class="mt-5"
+ (click)="onMenuClick($event)"
+ #sidenavContainer
+ >
<!-- Overview -->
- <cds-sidenav-item route="/overview"
- [useRouter]="true"
- title="Overview"
- i18n-title
- class="nav-item tc_menuitem_overview">
- <svg cdsIcon="template"
- icon
- size="20"></svg>
- <span i18n>
- Overview</span>
+ <cds-sidenav-item
+ route="/overview"
+ [useRouter]="true"
+ title="Overview"
+ i18n-title
+ class="nav-item tc_menuitem_overview"
+ >
+ <svg
+ cdsIcon="template"
+ icon
+ size="20"
+ ></svg>
+ <span i18n> Overview</span>
</cds-sidenav-item>
<!-- Multi-cluster Dashboard -->
- <cds-sidenav-menu title="Multi-cluster"
- *ngIf="permissions.configOpt.read"
- i18n-title>
- <svg cdsIcon="edge-cluster"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/multi-cluster/overview"
- title="Overview"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_multiCluster_overview"><span i18n>Overview</span></cds-sidenav-item>
- <cds-sidenav-item route="/multi-cluster/manage-clusters"
- title="Manage clusters"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_multiCluster_manage_clusters"><span i18n>Manage clusters</span></cds-sidenav-item>
+ <cds-sidenav-menu
+ title="Multi-cluster"
+ *ngIf="permissions.configOpt.read"
+ i18n-title
+ >
+ <svg
+ cdsIcon="edge-cluster"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/multi-cluster/overview"
+ title="Overview"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_multiCluster_overview"
+ ><span i18n>Overview</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/multi-cluster/manage-clusters"
+ title="Manage clusters"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_multiCluster_manage_clusters"
+ ><span i18n>Manage clusters</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
<!-- Cluster -->
- <cds-sidenav-menu title="Cluster"
- i18n-title
- *ngIf="permissions.hosts.read || permissions.monitor.read || permissions.osd.read || permissions.pool.read"
- class="tc_menuitem_cluster">
- <svg cdsIcon="web-services--cluster"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/pool"
- [useRouter]="true"
- title="Pools"
- i18n-title
- *ngIf="permissions.pool.read"
- class="tc_submenuitem tc_submenuitem_cluster_pool"><span i18n>Pools</span></cds-sidenav-item>
- <cds-sidenav-item route="/hosts"
- [useRouter]="true"
- title="Hosts"
- i18n-title
- *ngIf="permissions.hosts.read"
- class="tc_submenuitem tc_submenuitem_cluster_hosts"><span i18n>Hosts</span></cds-sidenav-item>
- <cds-sidenav-item route="/osd"
- [useRouter]="true"
- title="OSDs"
- i18n-title
- *ngIf="permissions.osd.read"
- class="tc_submenuitem tc_submenuitem_cluster_osds"><span i18n>OSDs</span></cds-sidenav-item>
- <cds-sidenav-item route="/inventory"
- [useRouter]="true"
- title="Physical disks"
- i18n-title
- *ngIf="permissions.hosts.read"
- class="tc_submenuitem tc_submenuitem_cluster_inventory"><span i18n>Physical disks</span></cds-sidenav-item>
- <cds-sidenav-item route="/crush-map"
- [useRouter]="true"
- title="CRUSH map"
- i18n-title
- *ngIf="permissions.osd.read"
- class="tc_submenuitem tc_submenuitem_cluster_crush"><span i18n>CRUSH map</span></cds-sidenav-item>
- <cds-sidenav-item route="/monitor"
- [useRouter]="true"
- title="Monitors"
- i18n-title
- *ngIf="permissions.monitor.read"
- class="tc_submenuitem tc_submenuitem_cluster_monitor"><span i18n>Monitors</span></cds-sidenav-item>
+ <cds-sidenav-menu
+ title="Cluster"
+ i18n-title
+ *ngIf="
+ permissions.hosts.read ||
+ permissions.monitor.read ||
+ permissions.osd.read ||
+ permissions.pool.read
+ "
+ class="tc_menuitem_cluster"
+ >
+ <svg
+ cdsIcon="web-services--cluster"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/pool"
+ [useRouter]="true"
+ title="Pools"
+ i18n-title
+ *ngIf="permissions.pool.read"
+ class="tc_submenuitem tc_submenuitem_cluster_pool"
+ ><span i18n>Pools</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/hosts"
+ [useRouter]="true"
+ title="Hosts"
+ i18n-title
+ *ngIf="permissions.hosts.read"
+ class="tc_submenuitem tc_submenuitem_cluster_hosts"
+ ><span i18n>Hosts</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/osd"
+ [useRouter]="true"
+ title="OSDs"
+ i18n-title
+ *ngIf="permissions.osd.read"
+ class="tc_submenuitem tc_submenuitem_cluster_osds"
+ ><span i18n>OSDs</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/inventory"
+ [useRouter]="true"
+ title="Physical disks"
+ i18n-title
+ *ngIf="permissions.hosts.read"
+ class="tc_submenuitem tc_submenuitem_cluster_inventory"
+ ><span i18n>Physical disks</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/crush-map"
+ [useRouter]="true"
+ title="CRUSH map"
+ i18n-title
+ *ngIf="permissions.osd.read"
+ class="tc_submenuitem tc_submenuitem_cluster_crush"
+ ><span i18n>CRUSH map</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/monitor"
+ [useRouter]="true"
+ title="Monitors"
+ i18n-title
+ *ngIf="permissions.monitor.read"
+ class="tc_submenuitem tc_submenuitem_cluster_monitor"
+ ><span i18n>Monitors</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
<!-- Block Storage -->
- <cds-sidenav-menu title="Block"
- i18n-title
- *ngIf="(permissions.rbdImage.read || permissions.rbdMirroring.read|| permissions.iscsi.read) && (enabledFeature.rbd || enabledFeature.mirroring || enabledFeature.iscsi)"
- class="tc_menuitem_block">
- <svg cdsIcon="datastore"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/block/rbd"
- [useRouter]="true"
- title="Images"
- i18n-title
- *ngIf="permissions.rbdImage.read && enabledFeature.rbd"
- class="tc_submenuitem tc_submenuitem_block_images"><span i18n>Images</span></cds-sidenav-item>
- <cds-sidenav-item route="/block/mirroring"
- [useRouter]="true"
- title="Mirroring"
- i18n-title
- *ngIf="permissions.rbdMirroring.read && enabledFeature.mirroring"
- class="tc_submenuitem tc_submenuitem_block_mirroring">
- <span i18n>Mirroring
- <cds-tag *ngIf="summaryData?.rbd_mirroring?.warnings !== 0"
- class="tag-warning content-theme">
+ <cds-sidenav-menu
+ title="Block"
+ i18n-title
+ *ngIf="
+ (permissions.rbdImage.read ||
+ permissions.rbdMirroring.read ||
+ permissions.iscsi.read) &&
+ (enabledFeature.rbd || enabledFeature.mirroring || enabledFeature.iscsi)
+ "
+ class="tc_menuitem_block"
+ >
+ <svg
+ cdsIcon="datastore"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/block/rbd"
+ [useRouter]="true"
+ title="Images"
+ i18n-title
+ *ngIf="permissions.rbdImage.read && enabledFeature.rbd"
+ class="tc_submenuitem tc_submenuitem_block_images"
+ ><span i18n>Images</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/block/mirroring"
+ [useRouter]="true"
+ title="Mirroring"
+ i18n-title
+ *ngIf="permissions.rbdMirroring.read && enabledFeature.mirroring"
+ class="tc_submenuitem tc_submenuitem_block_mirroring"
+ >
+ <span i18n
+ >Mirroring
+ <cds-tag
+ *ngIf="summaryData?.rbd_mirroring?.warnings !== 0"
+ class="tag-warning content-theme"
+ >
{{ summaryData?.rbd_mirroring?.warnings }}
</cds-tag>
- <cds-tag *ngIf="summaryData?.rbd_mirroring?.errors !== 0"
- class="tag-danger content-theme">
+ <cds-tag
+ *ngIf="summaryData?.rbd_mirroring?.errors !== 0"
+ class="tag-danger content-theme"
+ >
{{ summaryData?.rbd_mirroring?.errors }}
</cds-tag>
</span>
</cds-sidenav-item>
- <cds-sidenav-item route="/block/iscsi"
- [useRouter]="true"
- title="iSCSI"
- i18n-title
- *ngIf="permissions.iscsi.read && enabledFeature.iscsi"
- class="tc_submenuitem tc_submenuitem_block_iscsi"><span i18n>iSCSI</span></cds-sidenav-item>
- <cds-sidenav-item route="/block/nvmeof"
- [useRouter]="true"
- title="NVMe/TCP"
- i18n-title
- class="tc_submenuitem tc_submenuitem_block_nvme"><span i18n>NVMe/TCP</span></cds-sidenav-item>
+ <cds-sidenav-item
+ route="/block/iscsi"
+ [useRouter]="true"
+ title="iSCSI"
+ i18n-title
+ *ngIf="permissions.iscsi.read && enabledFeature.iscsi"
+ class="tc_submenuitem tc_submenuitem_block_iscsi"
+ ><span i18n>iSCSI</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/block/nvmeof"
+ [useRouter]="true"
+ title="NVMe/TCP"
+ i18n-title
+ class="tc_submenuitem tc_submenuitem_block_nvme"
+ ><span i18n>NVMe/TCP</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
<!-- Object Storage -->
- <cds-sidenav-menu title="Object"
- i18n-title
- *ngIf="permissions.rgw.read && enabledFeature.rgw"
- class="nav-item tc_menuitem_rgw">
- <svg cdsIcon="object-storage"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/rgw/overview"
- title="Overview"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_overview"><span i18n>Overview</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/user"
- title="User management"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_users"><span i18n>User management</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/bucket"
- title="Buckets"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_buckets"><span i18n>Buckets</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/destination"
- [useRouter]="true"
- title="Notification destination"
- i18n-title
- class="tc_submenuitem tc_submenuitem_rgw_notification"><span i18n>Notification destination</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/storage-class"
- title="Storage class"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_storage_class"><span i18n>Storage class</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/multisite"
- title="Multi-site"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_multi-site"><span i18n>Multi-site</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/daemon"
- title="Gateways"
- i18n-title
- [useRouter]="true"
- class="tc_submenuitem tc_submenuitem_rgw_daemons"><span i18n>Gateways</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/nfs"
- [useRouter]="true"
- title="NFS"
- i18n-title
- *ngIf="permissions.nfs.read && enabledFeature.nfs"
- class="tc_submenuitem tc_submenuitem_rgw_nfs"><span i18n>NFS</span></cds-sidenav-item>
- <cds-sidenav-item route="/rgw/configuration"
- [useRouter]="true"
- title="Configuration"
- i18n-title
- class="tc_submenuitem tc_submenuitem_rgw_configuration"><span i18n>Configuration</span></cds-sidenav-item>
+ <cds-sidenav-menu
+ title="Object"
+ i18n-title
+ *ngIf="permissions.rgw.read && enabledFeature.rgw"
+ class="nav-item tc_menuitem_rgw"
+ >
+ <svg
+ cdsIcon="object-storage"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/rgw/overview"
+ title="Overview"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_overview"
+ ><span i18n>Overview</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/user"
+ title="User management"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_users"
+ ><span i18n>User management</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/bucket"
+ title="Buckets"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_buckets"
+ ><span i18n>Buckets</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/destination"
+ [useRouter]="true"
+ title="Notification destination"
+ i18n-title
+ class="tc_submenuitem tc_submenuitem_rgw_notification"
+ ><span i18n>Notification destination</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/storage-class"
+ title="Storage class"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_storage_class"
+ ><span i18n>Storage class</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/multisite"
+ title="Multi-site"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_multi-site"
+ ><span i18n>Multi-site</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/daemon"
+ title="Gateways"
+ i18n-title
+ [useRouter]="true"
+ class="tc_submenuitem tc_submenuitem_rgw_daemons"
+ ><span i18n>Gateways</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/nfs"
+ [useRouter]="true"
+ title="NFS"
+ i18n-title
+ *ngIf="permissions.nfs.read && enabledFeature.nfs"
+ class="tc_submenuitem tc_submenuitem_rgw_nfs"
+ ><span i18n>NFS</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/rgw/configuration"
+ [useRouter]="true"
+ title="Configuration"
+ i18n-title
+ class="tc_submenuitem tc_submenuitem_rgw_configuration"
+ ><span i18n>Configuration</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
<!-- Filesystem -->
- <cds-sidenav-menu title="File"
- i18n-title
- *ngIf="permissions.nfs.read && enabledFeature.nfs || permissions.cephfs.read && enabledFeature.cephfs || permissions?.smb?.read"
- class="tc_menuitem_file">
- <svg cdsIcon="file-storage"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/cephfs/fs"
- [useRouter]="true"
- title="File systems"
- i18n-title
- *ngIf="permissions.cephfs.read && enabledFeature.cephfs"
- class="tc_submenuitem tc_submenuitem_file_cephfs"><span i18n>File systems</span></cds-sidenav-item>
+ <cds-sidenav-menu
+ title="File"
+ i18n-title
+ *ngIf="
+ (permissions.nfs.read && enabledFeature.nfs) ||
+ (permissions.cephfs.read && enabledFeature.cephfs) ||
+ permissions?.smb?.read
+ "
+ class="tc_menuitem_file"
+ >
+ <svg
+ cdsIcon="file-storage"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/cephfs/fs"
+ [useRouter]="true"
+ title="File systems"
+ i18n-title
+ *ngIf="permissions.cephfs.read && enabledFeature.cephfs"
+ class="tc_submenuitem tc_submenuitem_file_cephfs"
+ ><span i18n>File systems</span></cds-sidenav-item
+ >
<!-- Removed for umbrella release, will be re-enabled in next release
<cds-sidenav-item route="/cephfs/mirroring"
[useRouter]="true"
*ngIf="permissions.cephfs.read && enabledFeature.cephfs"
class="tc_submenuitem tc_submenuitem_file_cephfs"><span i18n>Mirroring</span></cds-sidenav-item>
-->
- <cds-sidenav-item route="/cephfs/nfs"
- [useRouter]="true"
- title="NFS"
- i18n-title
- *ngIf="permissions.nfs.read && enabledFeature.nfs"
- class="tc_submenuitem tc_submenuitem_file_nfs"><span i18n>NFS</span></cds-sidenav-item>
- <cds-sidenav-item route="/cephfs/smb"
- [useRouter]="true"
- title="SMB"
- i18n-title
- *ngIf="permissions?.smb?.read"
- class="tc_submenuitem tc_submenuitem_file_smb"><span i18n>SMB</span></cds-sidenav-item>
+ <cds-sidenav-item
+ route="/cephfs/nfs"
+ [useRouter]="true"
+ title="NFS"
+ i18n-title
+ *ngIf="permissions.nfs.read && enabledFeature.nfs"
+ class="tc_submenuitem tc_submenuitem_file_nfs"
+ ><span i18n>NFS</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/cephfs/smb"
+ [useRouter]="true"
+ title="SMB"
+ i18n-title
+ *ngIf="permissions?.smb?.read"
+ class="tc_submenuitem tc_submenuitem_file_smb"
+ ><span i18n>SMB</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
<!-- Observability -->
- <cds-sidenav-menu title="Observability"
- i18n-title
- *ngIf="permissions.log.read || permissions.prometheus.read"
- class="tc_menuitem_observe">
- <svg cdsIcon="observed--hail"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/logs"
- [useRouter]="true"
- title="Logs"
- i18n-title
- *ngIf="permissions.log.read"
- class="tc_submenuitem tc_submenuitem_observe_log"><span i18n>Logs</span></cds-sidenav-item>
- <cds-sidenav-item route="/monitoring"
- [useRouter]="true"
- title="Alerts"
- i18n-title
- *ngIf="permissions.prometheus.read"
- class="tc_submenuitem tc_submenuitem_observe_monitoring">
+ <cds-sidenav-menu
+ title="Observability"
+ i18n-title
+ *ngIf="permissions.log.read || permissions.prometheus.read"
+ class="tc_menuitem_observe"
+ >
+ <svg
+ cdsIcon="observed--hail"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/logs"
+ [useRouter]="true"
+ title="Logs"
+ i18n-title
+ *ngIf="permissions.log.read"
+ class="tc_submenuitem tc_submenuitem_observe_log"
+ ><span i18n>Logs</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/monitoring"
+ [useRouter]="true"
+ title="Alerts"
+ i18n-title
+ *ngIf="permissions.prometheus.read"
+ class="tc_submenuitem tc_submenuitem_observe_monitoring"
+ >
<span i18n>
<ng-container>Alerts</ng-container>
- <cds-tag *ngIf="prometheusAlertService.activeCriticalAlerts > 0"
- class="tag-danger ms-1 content-theme">{{ prometheusAlertService.activeCriticalAlerts }}</cds-tag>
- <cds-tag *ngIf="prometheusAlertService.activeWarningAlerts > 0"
- class="tag-warning ms-1 content-theme">{{ prometheusAlertService.activeWarningAlerts }}</cds-tag>
+ <cds-tag
+ *ngIf="prometheusAlertService.activeCriticalAlerts > 0"
+ class="tag-danger ms-1 content-theme"
+ >{{ prometheusAlertService.activeCriticalAlerts }}</cds-tag
+ >
+ <cds-tag
+ *ngIf="prometheusAlertService.activeWarningAlerts > 0"
+ class="tag-warning ms-1 content-theme"
+ >{{ prometheusAlertService.activeWarningAlerts }}</cds-tag
+ >
</span>
</cds-sidenav-item>
</cds-sidenav-menu>
<!-- Administration -->
- <cds-sidenav-menu title="Administration"
- i18n-title
- *ngIf="permissions.configOpt.read || permissions.hosts.read"
- class="tc_menuitem_admin">
- <svg cdsIcon="network--admin-control"
- icon
- size="20"></svg>
- <cds-sidenav-item route="/services/"
- [useRouter]="true"
- title="Services"
- i18n-title
- *ngIf="permissions.hosts.read"
- class="tc_submenuitem tc_submenuitem_admin_services"><span i18n>Services</span></cds-sidenav-item>
- <cds-sidenav-item route="/upgrade"
- [useRouter]="true"
- title="Upgrade"
- i18n-title
- *ngIf="permissions.configOpt.read"
- class="tc_submenuitem tc_submenuitem_admin_upgrade"><span i18n>Upgrade</span></cds-sidenav-item>
- <cds-sidenav-item route="/ceph-users"
- [useRouter]="true"
- title="Ceph users"
- i18n-title
- *ngIf="permissions.configOpt.read"
- class="tc_submenuitem tc_submenuitem_admin_users"><span i18n>Ceph users</span></cds-sidenav-item>
- <cds-sidenav-item route="/mgr-modules"
- [useRouter]="true"
- title="Manager modules"
- i18n-title
- *ngIf="permissions.configOpt.read"
- class="tc_submenuitem tc_submenuitem_admin_modules"><span i18n>Manager modules</span></cds-sidenav-item>
- <cds-sidenav-item route="/configuration"
- [useRouter]="true"
- title="Configuration"
- i18n-title
- *ngIf="permissions.configOpt.read"
- class="tc_submenuitem tc_submenuitem_admin_configuration"><span i18n>Configuration</span></cds-sidenav-item>
+ <cds-sidenav-menu
+ title="Administration"
+ i18n-title
+ *ngIf="permissions.configOpt.read || permissions.hosts.read"
+ class="tc_menuitem_admin"
+ >
+ <svg
+ cdsIcon="network--admin-control"
+ icon
+ size="20"
+ ></svg>
+ <cds-sidenav-item
+ route="/services/"
+ [useRouter]="true"
+ title="Services"
+ i18n-title
+ *ngIf="permissions.hosts.read"
+ class="tc_submenuitem tc_submenuitem_admin_services"
+ ><span i18n>Services</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/upgrade"
+ [useRouter]="true"
+ title="Upgrade"
+ i18n-title
+ *ngIf="permissions.configOpt.read"
+ class="tc_submenuitem tc_submenuitem_admin_upgrade"
+ ><span i18n>Upgrade</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/ceph-users"
+ [useRouter]="true"
+ title="Ceph users"
+ i18n-title
+ *ngIf="permissions.configOpt.read"
+ class="tc_submenuitem tc_submenuitem_admin_users"
+ ><span i18n>Ceph users</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/mgr-modules"
+ [useRouter]="true"
+ title="Manager modules"
+ i18n-title
+ *ngIf="permissions.configOpt.read"
+ class="tc_submenuitem tc_submenuitem_admin_modules"
+ ><span i18n>Manager modules</span></cds-sidenav-item
+ >
+ <cds-sidenav-item
+ route="/configuration"
+ [useRouter]="true"
+ title="Configuration"
+ i18n-title
+ *ngIf="permissions.configOpt.read"
+ class="tc_submenuitem tc_submenuitem_admin_configuration"
+ ><span i18n>Configuration</span></cds-sidenav-item
+ >
</cds-sidenav-menu>
</cds-sidenav>
</ng-container>
</ng-template>
- </div>
+</div>
<div
- [ngClass]="{'empty-body': todayNotifications.length === 0 && previousNotifications.length === 0}"
- class="notification-area">
-@if (executingTasks.length > 0) {
-<div
- class="notification-section-heading"
- i18n>
- Running tasks
-</div>
+ [ngClass]="{
+ 'empty-body': todayNotifications.length === 0 && previousNotifications.length === 0
+ }"
+ class="notification-area"
+>
+ @if (executingTasks.length > 0) {
+ <div
+ class="notification-section-heading"
+ i18n
+ >
+ Running tasks
+ </div>
-@for (task of executingTasks; track task.begin_time) {
-<div class="notification-wrapper">
- <div class="notification-item task-item">
- <cd-icon type="infoCircle"></cd-icon>
+ @for (task of executingTasks; track task.begin_time) {
+ <div class="notification-wrapper">
+ <div class="notification-item task-item">
+ <cd-icon type="infoCircle"></cd-icon>
- <div class="notification-content">
- <div class="notification-title">
- {{ task.description }}
- </div>
+ <div class="notification-content">
+ <div class="notification-title">
+ {{ task.description }}
+ </div>
- <cds-progress-bar
- [max]="100"
- [value]="task.progress || 0"
- status="active"
- type="inline"
- size="small">
- </cds-progress-bar>
+ <cds-progress-bar
+ [max]="100"
+ [value]="task.progress || 0"
+ status="active"
+ type="inline"
+ size="small"
+ >
+ </cds-progress-bar>
- <div class="task-row">
- <span class="notification-timestamp">
- {{ task.begin_time | relativeDate }}
- </span>
+ <div class="task-row">
+ <span class="notification-timestamp">
+ {{ task.begin_time | relativeDate }}
+ </span>
- <span class="task-progress">
- {{ task.progress || 0 }} %
- </span>
- </div>
- </div>
- </div>
+ <span class="task-progress"> {{ task.progress || 0 }} % </span>
+ </div>
+ </div>
+ </div>
- <div class="notification-divider"></div>
-</div>
-}
-}
+ <div class="notification-divider"></div>
+ </div>
+ }
+ }
-<ng-template
- #notificationItemTemplate
- let-notification="notification"
- let-last="last">
- <div class="notification-wrapper">
- <div class="notification-item"
- data-testid="notification-item">
- <cd-icon
- id="notification-icon"
- [type]="notificationIconMap[notification.type] || notificationIconMap['default']">
- </cd-icon>
+ <ng-template
+ #notificationItemTemplate
+ let-notification="notification"
+ let-last="last"
+ >
+ <div class="notification-wrapper">
+ <div
+ class="notification-item"
+ data-testid="notification-item"
+ >
+ <cd-icon
+ id="notification-icon"
+ [type]="notificationIconMap[notification.type] || notificationIconMap['default']"
+ >
+ </cd-icon>
- <div class="notification-content">
- <div class="notification-timestamp">
- {{ notification.timestamp | relativeDate }}
- </div>
- <div class="notification-title">
- {{ notification.title }}
- </div>
- <div
- class="notification-message"
- [innerHTML]="notification.message | sanitizeHtml">
+ <div class="notification-content">
+ <div class="notification-timestamp">
+ {{ notification.timestamp | relativeDate }}
+ </div>
+ <div class="notification-title">
+ {{ notification.title }}
+ </div>
+ <div
+ class="notification-message"
+ [innerHTML]="notification.message | sanitizeHtml"
+ ></div>
</div>
+
+ <button
+ cdsButton="ghost"
+ size="sm"
+ class="notification-close"
+ (click)="removeNotification(notification, $event)"
+ type="button"
+ >
+ <cd-icon type="destroy"></cd-icon>
+ </button>
</div>
- <button
- cdsButton="ghost"
- size="sm"
- class="notification-close"
- (click)="removeNotification(notification, $event)"
- type="button">
- <cd-icon type="destroy"></cd-icon>
- </button>
+ @if (!last) {
+ <div class="notification-divider"></div>
+ }
</div>
+ </ng-template>
- @if (!last) {
- <div class="notification-divider"></div>
- }
- </div>
-</ng-template>
-
-@if (todayNotifications.length > 0) {
-<div
- class="notification-section-heading"
- i18n>
- Today
-</div>
+ @if (todayNotifications.length > 0) {
+ <div
+ class="notification-section-heading"
+ i18n
+ >
+ Today
+ </div>
-@for (notification of todayNotifications; track notification.id; let last = $last) {
-<ng-container
- *ngTemplateOutlet="notificationItemTemplate;
- context: { notification: notification, last: last }">
-</ng-container>
-}
-}
+ @for (notification of todayNotifications; track notification.id; let last = $last) {
+ <ng-container
+ *ngTemplateOutlet="
+ notificationItemTemplate;
+ context: { notification: notification, last: last }
+ "
+ >
+ </ng-container>
+ }
+ }
-@if (previousNotifications.length > 0) {
-<div
- class="notification-section-heading"
- i18n>
- Previous
-</div>
+ @if (previousNotifications.length > 0) {
+ <div
+ class="notification-section-heading"
+ i18n
+ >
+ Previous
+ </div>
-@for (notification of previousNotifications; track notification.id; let last = $last) {
-<ng-container
- *ngTemplateOutlet="notificationItemTemplate;
- context: { notification: notification, last: last }">
-</ng-container>
-}
-}
+ @for (notification of previousNotifications; track notification.id; let last = $last) {
+ <ng-container
+ *ngTemplateOutlet="
+ notificationItemTemplate;
+ context: { notification: notification, last: last }
+ "
+ >
+ </ng-container>
+ }
+ }
-@if (todayNotifications.length === 0 && previousNotifications.length === 0) {
-<div class="notification-empty">
- <div i18n>No notifications</div>
-</div>
-}
+ @if (todayNotifications.length === 0 && previousNotifications.length === 0) {
+ <div class="notification-empty">
+ <div i18n>No notifications</div>
+ </div>
+ }
</div>
class="notification-footer__view-all-button"
[routerLink]="['/notifications']"
(click)="closePanel($event)"
- i18n>View all</cds-button>
+ i18n
+ >View all</cds-button
+ >
</div>
<div class="notification-header__heading-and-button">
<h1
i18n
- class="cds--type-heading-compact-01">Tasks and Notifications</h1>
+ class="cds--type-heading-compact-01"
+ >
+ Tasks and Notifications
+ </h1>
<button
class="notification-header__dismiss-btn"
i18n
cdsButton="ghost"
type="button"
size="sm"
- (click)="onDismissAll()">
+ (click)="onDismissAll()"
+ >
Dismiss all
</button>
</div>
(checkedChange)="onToggleMute()"
label="Mute notifications"
i18n-label
- hideLabel="true"> <!--hides the toggle state values (like "On/Off" in the toggle button)-->
+ hideLabel="true"
+ >
+ <!--hides the toggle state values (like "On/Off" in the toggle button)-->
</cds-toggle>
</div>
<div
class="notification-panel"
- cdsTheme="g10">
+ cdsTheme="g10"
+>
<cd-notification-header></cd-notification-header>
<cd-notification-area></cd-notification-area>
<cd-notification-footer></cd-notification-footer>
cdsGrid
[useCssGrid]="false"
[fullWidth]="true"
- class="notifications-page__container">
+ class="notifications-page__container"
+>
<!-- Left Panel - Notifications List -->
<div cdsRow>
<div
cdsCol
- [columnNumbers]="{sm: 4, md: 4, lg: 6}">
+ [columnNumbers]="{ sm: 4, md: 4, lg: 6 }"
+ >
<cds-search
[size]="'md'"
placeholder="Search notifications..."
i18n-placeholder
[(ngModel)]="searchText"
- (valueChange)="onSearch($event)">
+ (valueChange)="onSearch($event)"
+ >
</cds-search>
<cds-structured-list
class="notifications-list"
- *ngIf="filteredNotifications.length > 0">
+ *ngIf="filteredNotifications.length > 0"
+ >
<cds-list-row
- *ngFor="let notification of filteredNotifications; trackBy trackByNotificationId"
+ *ngFor="let notification of filteredNotifications; trackBy: trackByNotificationId"
[class.active]="selectedNotificationID === notification.id"
(click)="onNotificationSelect(notification)"
- class="notification-row">
+ class="notification-row"
+ >
<cds-list-column>
<div class="notification-item-content">
<h6 class="notification-title">
<ng-container *ngIf="notification.prometheusAlert; else regularTitle">
{{ notification.prometheusAlert.alertName }}
<cds-tag
- [type]="notification.prometheusAlert.status === 'active' || notification.prometheusAlert.status === 'firing'?'red':
- notification.prometheusAlert.status === 'resolved' ? 'green' : 'blue'"
+ [type]="
+ notification.prometheusAlert.status === 'active' ||
+ notification.prometheusAlert.status === 'firing'
+ ? 'red'
+ : notification.prometheusAlert.status === 'resolved'
+ ? 'green'
+ : 'blue'
+ "
[size]="'sm'"
- class="ml-2">
+ class="ml-2"
+ >
{{ notification.prometheusAlert.status }}
</cds-tag>
</ng-container>
<div
*ngIf="filteredNotifications.length === 0"
class="empty-state"
- cdsRow>
+ cdsRow
+ >
<svg
cdsIcon="notification"
size="20"
- class="empty-icon"></svg>
+ class="empty-icon"
+ ></svg>
<p *ngIf="searchText">No notifications match your search</p>
<p *ngIf="!searchText">No notifications available</p>
</div>
<!-- Right Panel - Notifications Details -->
<div
cdsCol
- [columnNumbers]="{sm: 12, md: 12, lg: 10}">
+ [columnNumbers]="{ sm: 12, md: 12, lg: 10 }"
+ >
<div
cdsGrid
[fullWidth]="true"
*ngIf="selectedNotification"
- class="notification-details">
- <div cdsCol
- [columnNumbers]="{sm: 16, md: 16, lg: 16}">
+ class="notification-details"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 16, md: 16, lg: 16 }"
+ >
<h3 cdsRow>{{ selectedNotification.title }}</h3>
<cds-structured-list
cdsRow
- class="details-list mt-4">
+ class="details-list mt-4"
+ >
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Application:</cds-list-column>
+ class="detail-label"
+ >Application:</cds-list-column
+ >
<cds-list-column>{{ selectedNotification.application }}</cds-list-column>
</cds-list-row>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Type:</cds-list-column>
+ class="detail-label"
+ >Type:</cds-list-column
+ >
<cds-list-column>
<cds-tag
- [type]="selectedNotification.type === 0 ? 'red' :
- selectedNotification.type === 1 ? 'blue' :
- selectedNotification.type === 2 ? 'green' : 'yellow'"
- [size]="'sm'">
- {{ selectedNotification.type === 0 ? 'Error' :
- selectedNotification.type === 1 ? 'Info' :
- selectedNotification.type === 2 ? 'Success' : 'Warning' }}
+ [type]="
+ selectedNotification.type === 0
+ ? 'red'
+ : selectedNotification.type === 1
+ ? 'blue'
+ : selectedNotification.type === 2
+ ? 'green'
+ : 'yellow'
+ "
+ [size]="'sm'"
+ >
+ {{
+ selectedNotification.type === 0
+ ? 'Error'
+ : selectedNotification.type === 1
+ ? 'Info'
+ : selectedNotification.type === 2
+ ? 'Success'
+ : 'Warning'
+ }}
</cds-tag>
</cds-list-column>
</cds-list-row>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Date:</cds-list-column>
+ class="detail-label"
+ >Date:</cds-list-column
+ >
<cds-list-column>{{ formatDate(selectedNotification.timestamp) }}</cds-list-column>
</cds-list-row>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Time:</cds-list-column>
+ class="detail-label"
+ >Time:</cds-list-column
+ >
<cds-list-column>{{ formatTime(selectedNotification.timestamp) }}</cds-list-column>
</cds-list-row>
<!-- Prometheus-specific metadata fields -->
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Alert Name:</cds-list-column>
- <cds-list-column>{{ selectedNotification.prometheusAlert.alertName }}</cds-list-column>
+ class="detail-label"
+ >Alert Name:</cds-list-column
+ >
+ <cds-list-column>{{
+ selectedNotification.prometheusAlert.alertName
+ }}</cds-list-column>
</cds-list-row>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Status:</cds-list-column>
+ class="detail-label"
+ >Status:</cds-list-column
+ >
<cds-list-column>
<cds-tag
- [type]="selectedNotification.prometheusAlert.status === 'active' || selectedNotification.prometheusAlert.status === 'firing' ? 'red' :
- selectedNotification.prometheusAlert.status === 'resolved' ? 'green' :
- selectedNotification.prometheusAlert.status === 'suppressed' ? 'gray' : 'blue'"
- [size]="'sm'">
+ [type]="
+ selectedNotification.prometheusAlert.status === 'active' ||
+ selectedNotification.prometheusAlert.status === 'firing'
+ ? 'red'
+ : selectedNotification.prometheusAlert.status === 'resolved'
+ ? 'green'
+ : selectedNotification.prometheusAlert.status === 'suppressed'
+ ? 'gray'
+ : 'blue'
+ "
+ [size]="'sm'"
+ >
{{ selectedNotification.prometheusAlert.status }}
</cds-tag>
</cds-list-column>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Severity:</cds-list-column>
+ class="detail-label"
+ >Severity:</cds-list-column
+ >
<cds-list-column>
<cds-tag
- [type]="selectedNotification.prometheusAlert.severity === 'critical' ? 'red' :
- selectedNotification.prometheusAlert.severity === 'warning' ? 'yellow' :
- selectedNotification.prometheusAlert.severity === 'resolved' ? 'green' : 'blue'"
- [size]="'sm'">
+ [type]="
+ selectedNotification.prometheusAlert.severity === 'critical'
+ ? 'red'
+ : selectedNotification.prometheusAlert.severity === 'warning'
+ ? 'yellow'
+ : selectedNotification.prometheusAlert.severity === 'resolved'
+ ? 'green'
+ : 'blue'
+ "
+ [size]="'sm'"
+ >
{{ selectedNotification.prometheusAlert.severity }}
</cds-tag>
</cds-list-column>
<cds-list-row *ngIf="selectedNotification.prometheusAlert.instance">
<cds-list-column
nowrap="true"
- class="detail-label">Instance:</cds-list-column>
- <cds-list-column>{{ selectedNotification.prometheusAlert.instance }}</cds-list-column>
+ class="detail-label"
+ >Instance:</cds-list-column
+ >
+ <cds-list-column>{{
+ selectedNotification.prometheusAlert.instance
+ }}</cds-list-column>
</cds-list-row>
<cds-list-row *ngIf="selectedNotification.prometheusAlert.job">
<cds-list-column
nowrap="true"
- class="detail-label">Job:</cds-list-column>
+ class="detail-label"
+ >Job:</cds-list-column
+ >
<cds-list-column>{{ selectedNotification.prometheusAlert.job }}</cds-list-column>
</cds-list-row>
<cds-list-row>
<cds-list-column
nowrap="true"
- class="detail-label">Description:</cds-list-column>
+ class="detail-label"
+ >Description:</cds-list-column
+ >
<cds-list-column>
- <p class="message-content">{{ selectedNotification.prometheusAlert.description }}</p>
+ <p class="message-content">
+ {{ selectedNotification.prometheusAlert.description }}
+ </p>
</cds-list-column>
</cds-list-row>
<cds-list-row *ngIf="selectedNotification.prometheusAlert.sourceUrl">
<cds-list-column
nowrap="true"
- class="detail-label">Source:</cds-list-column>
+ class="detail-label"
+ >Source:</cds-list-column
+ >
<cds-list-column>
<a
[href]="selectedNotification.prometheusAlert.sourceUrl"
target="_blank"
- class="source-link">
+ class="source-link"
+ >
<svg
cdsIcon="launch"
- size="16"></svg>
+ size="16"
+ ></svg>
View in Prometheus
</a>
</cds-list-column>
<cds-list-row *ngIf="selectedNotification.prometheusAlert.fingerprint">
<cds-list-column
nowrap="true"
- class="detail-label">Fingerprint:</cds-list-column>
+ class="detail-label"
+ >Fingerprint:</cds-list-column
+ >
<cds-list-column>
- <code class="fingerprint">{{ selectedNotification.prometheusAlert.fingerprint }}</code>
+ <code class="fingerprint">{{
+ selectedNotification.prometheusAlert.fingerprint
+ }}</code>
</cds-list-column>
</cds-list-row>
</ng-container>
<!-- Regular message for non-Prometheus notifications -->
<cds-list-row
cdsRow
- *ngIf="selectedNotification.message && !selectedNotification.prometheusAlert">
+ *ngIf="selectedNotification.message && !selectedNotification.prometheusAlert"
+ >
<cds-list-column
nowrap="true"
- class="detail-label">Message:</cds-list-column>
+ class="detail-label"
+ >Message:</cds-list-column
+ >
<cds-list-column>
<p class="message-content">{{ selectedNotification.message }}</p>
</cds-list-column>
-@if(isMuted) {
-<cd-icon type="notificationOff"
- [size]="iconSize">
-</cd-icon>
-}
-@else if(!isMuted && ( hasRunningTasks || hasNotifications)) {
-<cd-icon type="notificationNew"
- [size]="iconSize">
-</cd-icon>
-}
-@else {
-<cd-icon type="notification"
- [size]="iconSize">
-</cd-icon>
+@if (isMuted) {
+ <cd-icon
+ type="notificationOff"
+ [size]="iconSize"
+ >
+ </cd-icon>
+} @else if (!isMuted && (hasRunningTasks || hasNotifications)) {
+ <cd-icon
+ type="notificationNew"
+ [size]="iconSize"
+ >
+ </cd-icon>
+} @else {
+ <cd-icon
+ type="notification"
+ [size]="iconSize"
+ >
+ </cd-icon>
}
-<cds-actionable-notification class="mb-1 content-theme"
- [ngClass]="spacingClass"
- [notificationObj]="notificationContent"
- (close)="onClose()"></cds-actionable-notification>
+<cds-actionable-notification
+ class="mb-1 content-theme"
+ [ngClass]="spacingClass"
+ [notificationObj]="notificationContent"
+ (close)="onClose()"
+></cds-actionable-notification>
<ng-template #content>
<ng-content></ng-content>
</ng-template>
<ng-template #actionTpl>
- <button cdsActionableButton
- cdsButton="ghost"
- size="md"
- [title]="actionName"
- (click)="onAction()"
- *ngIf="actionName"
- type="button"
- i18n>{{ actionName }}
+ <button
+ cdsActionableButton
+ cdsButton="ghost"
+ size="md"
+ [title]="actionName"
+ (click)="onAction()"
+ *ngIf="actionName"
+ type="button"
+ i18n
+ >
+ {{ actionName }}
</button>
</ng-template>
-@if(chartData && chartOptions){
-<div class="chart-container">
- <div class="chart-header">
- <div class="cds--type-heading-compact-02">
- {{ chartTitle }}
- </div>
- @if(subHeading) {
- <div class="cds--type-body-compact-01 chart-subheading cds-mb-3">
- {{ subHeading }}
+@if (chartData && chartOptions) {
+ <div class="chart-container">
+ <div class="chart-header">
+ <div class="cds--type-heading-compact-02">
+ {{ chartTitle }}
+ </div>
+ @if (subHeading) {
+ <div class="cds--type-body-compact-01 chart-subheading cds-mb-3">
+ {{ subHeading }}
+ </div>
+ }
</div>
+ @if (chartType === 'area') {
+ <ibm-area-chart
+ [data]="chartData"
+ [options]="chartOptions"
+ >
+ </ibm-area-chart>
+ } @else {
+ <ibm-line-chart
+ [data]="chartData"
+ [options]="chartOptions"
+ >
+ </ibm-line-chart>
}
</div>
- @if(chartType === 'area') {
- <ibm-area-chart
- [data]="chartData"
- [options]="chartOptions">
- </ibm-area-chart>
- } @else {
- <ibm-line-chart
- [data]="chartData"
- [options]="chartOptions">
- </ibm-line-chart>
- }
-</div>
}
-<button class="w-100 tc_backButton"
- [ngClass]="{'w-100': modalForm && showSubmit, 'w-50 float-end': modalForm && !showSubmit}"
- aria-label="Back"
- (click)="back()"
- [disabled]="disabled"
- type="button"
- size="lg"
- cdsButton="secondary">
+<button
+ class="w-100 tc_backButton"
+ [ngClass]="{ 'w-100': modalForm && showSubmit, 'w-50 float-end': modalForm && !showSubmit }"
+ aria-label="Back"
+ (click)="back()"
+ [disabled]="disabled"
+ type="button"
+ size="lg"
+ cdsButton="secondary"
+>
{{ name }}
</button>
-<div class="row"
- *ngIf="groupTitle">
+<div
+ class="row"
+ *ngIf="groupTitle"
+>
<div class="info-group-title">
- <span i18n
- data-testid="group-title">{{ groupTitle }}</span>
+ <span
+ i18n
+ data-testid="group-title"
+ >{{ groupTitle }}</span
+ >
</div>
</div>
-<hr>
+<hr />
<li class="list-group-item">
<div class="d-flex pl-1 pb-2 pt-2 position-relative">
<div class="ms-4 me-auto">
- @if (link && data !== null || total) {
- <a [routerLink]="link"
- *ngIf="link && total > 0; else noLinkTitle"
- [ngPlural]="total"
- data-testid="title"
- i18n>
- {{ total }}
- <ng-template ngPluralCase="=0">{{ title }}</ng-template>
- <ng-template ngPluralCase="=1">{{ title }}</ng-template>
- <ng-template ngPluralCase="other">{{ title }}s</ng-template>
- </a>
- } @else {
- <a [routerLink]="link"
- *ngIf="link; else noLinkTitle">{{title}}
- </a>
- }
+ @if ((link && data !== null) || total) {
+ <a
+ [routerLink]="link"
+ *ngIf="link && total > 0; else noLinkTitle"
+ [ngPlural]="total"
+ data-testid="title"
+ i18n
+ >
+ {{ total }}
+ <ng-template ngPluralCase="=0">{{ title }}</ng-template>
+ <ng-template ngPluralCase="=1">{{ title }}</ng-template>
+ <ng-template ngPluralCase="other">{{ title }}s</ng-template>
+ </a>
+ } @else {
+ <a
+ [routerLink]="link"
+ *ngIf="link; else noLinkTitle"
+ >{{ title }}
+ </a>
+ }
</div>
<span class="me-4">
<ng-container [ngSwitch]="summaryType">
</ng-container>
</ng-container>
</span>
- <span *ngIf="dropdownData && dropdownData.total.total.total > 0"
- class="position-absolute end-0 me-2">
- <button type="button"
- (click)="toggleDropdown()"
- class="dropdown-toggle border-0 bg-transparent p-0"
- [attr.aria-expanded]="dropdownToggled"
- aria-controls="row-dropdown">
- <span class="visually-hidden" i18n>Toggle dropdown</span>
+ <span
+ *ngIf="dropdownData && dropdownData.total.total.total > 0"
+ class="position-absolute end-0 me-2"
+ >
+ <button
+ type="button"
+ (click)="toggleDropdown()"
+ class="dropdown-toggle border-0 bg-transparent p-0"
+ [attr.aria-expanded]="dropdownToggled"
+ aria-controls="row-dropdown"
+ >
+ <span
+ class="visually-hidden"
+ i18n
+ >Toggle dropdown</span
+ >
</button>
</span>
</div>
</li>
<div *ngIf="dropdownToggled">
- <hr>
+ <hr />
<ng-container *ngTemplateOutlet="dropdownTemplate"></ng-container>
</div>
<ng-template #defaultSummary>
@if (data === null) {
- <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
+ <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
} @else {
- <span *ngIf="data.success || data.categoryPgAmount?.clean || (data.success === 0 && data.total === 0)">
- <span *ngIf="data.success || (data.success === 0 && data.total === 0)">
- {{ data.success }}
- </span>
- <span *ngIf="data.categoryPgAmount?.clean">
- {{ data.categoryPgAmount?.clean }}
- </span>
- <cd-icon
- type="success">
- </cd-icon >
- </span>
- <span *ngIf="data.info"
- class="ms-2">
- <span *ngIf="data.info">
- {{ data.info }}
+ <span
+ *ngIf="
+ data.success || data.categoryPgAmount?.clean || (data.success === 0 && data.total === 0)
+ "
+ >
+ <span *ngIf="data.success || (data.success === 0 && data.total === 0)">
+ {{ data.success }}
+ </span>
+ <span *ngIf="data.categoryPgAmount?.clean">
+ {{ data.categoryPgAmount?.clean }}
+ </span>
+ <cd-icon type="success"> </cd-icon>
</span>
- <cd-icon
- type="infoCircle">
- </cd-icon >
- </span>
- <span *ngIf="data.warn || data.categoryPgAmount?.warning"
- class="ms-2">
- <span *ngIf="data.warn">
- {{ data.warn }}
+ <span
+ *ngIf="data.info"
+ class="ms-2"
+ >
+ <span *ngIf="data.info">
+ {{ data.info }}
+ </span>
+ <cd-icon type="infoCircle"> </cd-icon>
</span>
- <span *ngIf="data.categoryPgAmount?.warning">
- {{ data.categoryPgAmount?.warning }}
+ <span
+ *ngIf="data.warn || data.categoryPgAmount?.warning"
+ class="ms-2"
+ >
+ <span *ngIf="data.warn">
+ {{ data.warn }}
+ </span>
+ <span *ngIf="data.categoryPgAmount?.warning">
+ {{ data.categoryPgAmount?.warning }}
+ </span>
+ <cd-icon type="warning"> </cd-icon>
</span>
- <cd-icon
- type="warning">
- </cd-icon >
- </span>
- <span *ngIf="data.error || data.categoryPgAmount?.unknown"
- class="ms-2">
- <span *ngIf="data.error">
- {{ data.error }}
+ <span
+ *ngIf="data.error || data.categoryPgAmount?.unknown"
+ class="ms-2"
+ >
+ <span *ngIf="data.error">
+ {{ data.error }}
+ </span>
+ <span *ngIf="data.categoryPgAmount?.unknown">
+ {{ data.categoryPgAmount?.unknown }}
+ </span>
+ <cd-icon type="danger"> </cd-icon>
</span>
- <span *ngIf="data.categoryPgAmount?.unknown">
- {{ data.categoryPgAmount?.unknown }}
+ <span
+ *ngIf="data.categoryPgAmount?.working"
+ class="ms-2"
+ >
+ <span *ngIf="data.categoryPgAmount?.working">
+ {{ data.categoryPgAmount?.working }}
+ </span>
+ <cds-inline-loading
+ class="text-warning"
+ state="active"
+ ></cds-inline-loading>
</span>
- <cd-icon
- type="danger">
- </cd-icon >
- </span>
- <span *ngIf="data.categoryPgAmount?.working"
- class="ms-2">
- <span *ngIf="data.categoryPgAmount?.working">
- {{ data.categoryPgAmount?.working }}
- </span>
- <cds-inline-loading class="text-warning"
- state="active"></cds-inline-loading>
- </span>
}
</ng-template>
<ng-template #osdSummary>
@if (data === null) {
- <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
+ <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
} @else {
- <span *ngIf="data.up === data.in">
- {{ data.up }}
- <cd-icon
- type="success">
- </cd-icon >
- </span>
- <span *ngIf="data.up !== data.in">
- {{ data.up }}
- <span class="fw-bold text-success">
- up
+ <span *ngIf="data.up === data.in">
+ {{ data.up }}
+ <cd-icon type="success"> </cd-icon>
+ </span>
+ <span *ngIf="data.up !== data.in">
+ {{ data.up }}
+ <span class="fw-bold text-success"> up </span>
</span>
- </span>
- <span *ngIf="data.in !== data.up"
- class="ms-2">
- {{ data.in }}
- <span class="fw-bold text-success">
- in
+ <span
+ *ngIf="data.in !== data.up"
+ class="ms-2"
+ >
+ {{ data.in }}
+ <span class="fw-bold text-success"> in </span>
</span>
- </span>
- <span *ngIf="data.down"
- class="ms-2">
- {{ data.down }}
- <span class="fw-bold text-danger me-2">
- down
+ <span
+ *ngIf="data.down"
+ class="ms-2"
+ >
+ {{ data.down }}
+ <span class="fw-bold text-danger me-2"> down </span>
</span>
- </span>
- <span *ngIf="data.out"
- class="ms-2">
- {{ data.out }}
- <span class="fw-bold text-danger me-2">
- out
+ <span
+ *ngIf="data.out"
+ class="ms-2"
+ >
+ {{ data.out }}
+ <span class="fw-bold text-danger me-2"> out </span>
</span>
- </span>
- <span *ngIf="data.nearfull"
- class="ms-2">
- {{ data.nearfull }}
- <span class="fw-bold text-warning me-2">
- nearfull</span></span>
- <span *ngIf="data.full"
- class="ms-2">
- {{ data.full }}
- <span class="fw-bold text-danger">
- full
+ <span
+ *ngIf="data.nearfull"
+ class="ms-2"
+ >
+ {{ data.nearfull }}
+ <span class="fw-bold text-warning me-2"> nearfull</span></span
+ >
+ <span
+ *ngIf="data.full"
+ class="ms-2"
+ >
+ {{ data.full }}
+ <span class="fw-bold text-danger"> full </span>
</span>
- </span>
}
</ng-template>
<ng-template #iscsiSummary>
@if (data === null || total === null) {
- <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
+ <ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
} @else {
- <span>
- {{ data?.up }}
- <cd-icon
- *ngIf="data?.up || data?.up === 0"
- type="success">
- </cd-icon >
- </span>
- <span *ngIf="data?.down"
- class="ms-2">
- {{ data?.down }}
- <cd-icon
- type="danger">
- </cd-icon >
- </span>
-
+ <span>
+ {{ data?.up }}
+ <cd-icon
+ *ngIf="data?.up || data?.up === 0"
+ type="success"
+ >
+ </cd-icon>
+ </span>
+ <span
+ *ngIf="data?.down"
+ class="ms-2"
+ >
+ {{ data?.down }}
+ <cd-icon type="danger"> </cd-icon>
+ </span>
}
</ng-template>
<ng-template #simplifiedSummary>
@if (data === 0 || data) {
- <span *ngIf="!dropdownTotalError else showErrorNum">
- {{ data }}
- <cd-icon
- type="success"></cd-icon >
- </span>
+ <span *ngIf="!dropdownTotalError; else showErrorNum">
+ {{ data }}
+ <cd-icon type="success"></cd-icon>
+ </span>
} @else {
<ng-container *ngTemplateOutlet="loadingTpl"></ng-container>
}
<ng-template #showErrorNum>
- <span *ngIf="data - dropdownTotalError > 0">
- {{ data - dropdownTotalError }}
- <cd-icon
- type="success"></cd-icon >
+ <span *ngIf="data - dropdownTotalError > 0">
+ {{ data - dropdownTotalError }}
+ <cd-icon type="success"></cd-icon>
</span>
<span>
- {{ dropdownTotalError }}
- <cd-icon
- type="danger"></cd-icon >
+ {{ dropdownTotalError }}
+ <cd-icon type="danger"></cd-icon>
</span>
</ng-template>
</ng-template>
</ng-template>
<ng-template #noLinkTitle>
-@if (data !== null || total) {
-<span *ngIf="total || total === 0"
- [ngPlural]="total">
- {{ total }}
- <ng-template ngPluralCase="=0">{{ title }}</ng-template>
- <ng-template ngPluralCase="=1">{{ title }}</ng-template>
- <ng-template ngPluralCase="other">{{ title }}s</ng-template>
-</span>
-} @else {
- <span>{{ title }}</span>
-}
+ @if (data !== null || total) {
+ <span
+ *ngIf="total || total === 0"
+ [ngPlural]="total"
+ >
+ {{ total }}
+ <ng-template ngPluralCase="=0">{{ title }}</ng-template>
+ <ng-template ngPluralCase="=1">{{ title }}</ng-template>
+ <ng-template ngPluralCase="other">{{ title }}s</ng-template>
+ </span>
+ } @else {
+ <span>{{ title }}</span>
+ }
</ng-template>
<ng-template #dropdownTemplate>
<li class="list-group-item">
<div class="d-flex pb-2 pt-2">
<div class="ms-5 me-auto">
- <span *ngIf="data.value.total"
- [ngPlural]="data.value.total"
- i18n>
- {{ data.value.total }}
+ <span
+ *ngIf="data.value.total"
+ [ngPlural]="data.value.total"
+ i18n
+ >
+ {{ data.value.total }}
<ng-template ngPluralCase="=0">{{ hwNames[data.key] }}</ng-template>
<ng-template ngPluralCase="=1">{{ hwNames[data.key] }}</ng-template>
<ng-template ngPluralCase="other">{{ hwNames[data.key] | pluralize }}</ng-template>
<span [ngClass]="data.value.error ? 'me-2' : 'me-4'">
{{ data.value.ok }}
<cd-icon
- *ngIf="data.value.ok"
- type="success">
- </cd-icon >
+ *ngIf="data.value.ok"
+ type="success"
+ >
+ </cd-icon>
</span>
- <span *ngIf="data.value.error"
- class="me-4 ms-2">
- {{ data.value.error }}
- <cd-icon
- type="danger">
- </cd-icon >
+ <span
+ *ngIf="data.value.error"
+ class="me-4 ms-2"
+ >
+ {{ data.value.error }}
+ <cd-icon type="danger"> </cd-icon>
</span>
</div>
</li>
-<div class="card flex-fill"
- [ngClass]="{'border-0': removeBorder, 'bg-color': cardType === 'Sync Status Card', 'shadow': shadow, 'shadow-sm': !shadow && cardType !== 'syncCards', 'h-100': fullHeight}">
- <h4 class="card-title mt-4 ms-4 mb-0"
- *ngIf="cardType !== 'zone'">
+<div
+ class="card flex-fill"
+ [ngClass]="{
+ 'border-0': removeBorder,
+ 'bg-color': cardType === 'Sync Status Card',
+ shadow: shadow,
+ 'shadow-sm': !shadow && cardType !== 'syncCards',
+ 'h-100': fullHeight
+ }"
+>
+ <h4
+ class="card-title mt-4 ms-4 mb-0"
+ *ngIf="cardType !== 'zone'"
+ >
<span *ngIf="cardType === ''">{{ cardTitle }}</span>
</h4>
- <h4 *ngIf="cardType === 'zone'"
- class="text-center mt-4 mb-0">
- <svg [cdsIcon]="icons.deploy"
- [size]="icons.size20"
- ></svg>
+ <h4
+ *ngIf="cardType === 'zone'"
+ class="text-center mt-4 mb-0"
+ >
+ <svg
+ [cdsIcon]="icons.deploy"
+ [size]="icons.size20"
+ ></svg>
<cds-tag class="tag-info">{{ cardTitle }}</cds-tag>
</h4>
- <h5 *ngIf="cardType === 'syncCards'"
- class="text-center card-title">
- {{ cardTitle }}
+ <h5
+ *ngIf="cardType === 'syncCards'"
+ class="text-center card-title"
+ >
+ {{ cardTitle }}
</h5>
- <div class="card-body ps-0 pe-0"
- [ngClass]="{'d-flex align-items-center': alignItemsCenter, 'justify-content-center': justifyContentCenter}">
+ <div
+ class="card-body ps-0 pe-0"
+ [ngClass]="{
+ 'd-flex align-items-center': alignItemsCenter,
+ 'justify-content-center': justifyContentCenter
+ }"
+ >
<ng-content></ng-content>
</div>
- <div class="card-footer p-0 bg-white"
- *ngIf="cardFooter">
+ <div
+ class="card-footer p-0 bg-white"
+ *ngIf="cardFooter"
+ >
<ng-content select=".footer"></ng-content>
</div>
</div>
-<cds-tag *ngIf="!key; else key_value"
- class="tags-{{value}}"
- ngClass="{{value | colorClassFromText}}"
- [ngbTooltip]="tooltipText">
+<cds-tag
+ *ngIf="!key; else key_value"
+ class="tags-{{ value }}"
+ ngClass="{{ value | colorClassFromText }}"
+ [ngbTooltip]="tooltipText"
+>
{{ value }}
</cds-tag>
<ng-template #key_value>
- <cds-tag class="tag-background-primary badge-{{key}}-{{value}}">
- {{ key }}: {{ value }}
+ <cds-tag class="tag-background-primary badge-{{ key }}-{{ value }}">
+ {{ key }}: {{ value }}
</cds-tag>
</ng-template>
</ng-container>
<ng-template #singleCodeBlock>
- <pre class="d-flex px-2 py-3 align-items-center justify-content-between text-dark"
- id="singleCodeBlock">
+ <pre
+ class="d-flex px-2 py-3 align-items-center justify-content-between text-dark"
+ id="singleCodeBlock"
+ >
<span [ngClass]="{'text-wrap': textWrap}">{{codes}}</span>
<cd-copy-2-clipboard-button
[source]="codes"
<div [formGroup]="optionsFormGroup">
<div *ngFor="let option of options; let last = last">
- <div class="form-group row pt-2"
- *ngIf="option.type === 'bool'">
- <label class="cd-col-form-label"
- [for]="option.name">
+ <div
+ class="form-group row pt-2"
+ *ngIf="option.type === 'bool'"
+ >
+ <label
+ class="cd-col-form-label"
+ [for]="option.name"
+ >
<b>{{ option.text }}</b>
- <br>
+ <br />
<span class="text-muted">
{{ option.desc }}
- <cd-helper *ngIf="option.long_desc">
- {{ option.long_desc }}</cd-helper>
+ <cd-helper *ngIf="option.long_desc"> {{ option.long_desc }}</cd-helper>
</span>
</label>
<div class="cd-col-form-input">
<div class="custom-control custom-checkbox">
- <input class="custom-control-input"
- type="checkbox"
- [id]="option.name"
- [formControlName]="option.name">
- <label class="custom-control-label"
- [for]="option.name"></label>
+ <input
+ class="custom-control-input"
+ type="checkbox"
+ [id]="option.name"
+ [formControlName]="option.name"
+ />
+ <label
+ class="custom-control-label"
+ [for]="option.name"
+ ></label>
</div>
</div>
</div>
- <div class="form-group row pt-2"
- *ngIf="option.type !== 'bool'">
- <label class="cd-col-form-label"
- [for]="option.name">{{ option.text }}
- <br>
+ <div
+ class="form-group row pt-2"
+ *ngIf="option.type !== 'bool'"
+ >
+ <label
+ class="cd-col-form-label"
+ [for]="option.name"
+ >{{ option.text }}
+ <br />
<span class="text-muted">
{{ option.desc }}
- <cd-helper *ngIf="option.long_desc">
- {{ option.long_desc }}</cd-helper>
+ <cd-helper *ngIf="option.long_desc"> {{ option.long_desc }}</cd-helper>
</span>
</label>
<div class="cd-col-form-input">
<div class="input-group">
- <input class="form-control"
- [type]="option.additionalTypeInfo.inputType"
- [id]="option.name"
- [placeholder]="option.additionalTypeInfo.humanReadable"
- [formControlName]="option.name"
- [step]="getStep(option.type, optionsForm.getValue(option.name))">
- <button class="btn btn-light"
- type="button"
- data-toggle="button"
- title="Remove the custom configuration value. The default configuration will be inherited and used instead."
- (click)="resetValue(option.name)"
- i18n-title
- *ngIf="optionsFormShowReset">
- <i [ngClass]="[icons.erase]"
- aria-hidden="true"></i>
+ <input
+ class="form-control"
+ [type]="option.additionalTypeInfo.inputType"
+ [id]="option.name"
+ [placeholder]="option.additionalTypeInfo.humanReadable"
+ [formControlName]="option.name"
+ [step]="getStep(option.type, optionsForm.getValue(option.name))"
+ />
+ <button
+ class="btn btn-light"
+ type="button"
+ data-toggle="button"
+ title="Remove the custom configuration value. The default configuration will be inherited and used instead."
+ (click)="resetValue(option.name)"
+ i18n-title
+ *ngIf="optionsFormShowReset"
+ >
+ <i
+ [ngClass]="[icons.erase]"
+ aria-hidden="true"
+ ></i>
</button>
</div>
- <span class="invalid-feedback"
- *ngIf="optionsForm.showError(option.name, optionsFormDir, 'pattern')">
- {{ option.additionalTypeInfo.patternHelpText }}</span>
- <span class="invalid-feedback"
- *ngIf="optionsForm.showError(option.name, optionsFormDir, 'invalidUuid')">
- {{ option.additionalTypeInfo.patternHelpText }}</span>
- <span class="invalid-feedback"
- *ngIf="optionsForm.showError(option.name, optionsFormDir, 'max')"
- i18n>The entered value is too high! It must not be greater than {{ option.maxValue }}.</span>
- <span class="invalid-feedback"
- *ngIf="optionsForm.showError(option.name, optionsFormDir, 'min')"
- i18n>The entered value is too low! It must not be lower than {{ option.minValue }}.</span>
+ <span
+ class="invalid-feedback"
+ *ngIf="optionsForm.showError(option.name, optionsFormDir, 'pattern')"
+ >
+ {{ option.additionalTypeInfo.patternHelpText }}</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="optionsForm.showError(option.name, optionsFormDir, 'invalidUuid')"
+ >
+ {{ option.additionalTypeInfo.patternHelpText }}</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="optionsForm.showError(option.name, optionsFormDir, 'max')"
+ i18n
+ >The entered value is too high! It must not be greater than {{ option.maxValue }}.</span
+ >
+ <span
+ class="invalid-feedback"
+ *ngIf="optionsForm.showError(option.name, optionsFormDir, 'min')"
+ i18n
+ >The entered value is too low! It must not be lower than {{ option.minValue }}.</span
+ >
</div>
</div>
- <hr *ngIf="!last"
- class="my-2">
+ <hr
+ *ngIf="!last"
+ class="my-2"
+ />
</div>
</div>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- i18n>{{ titleText }}</h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ titleText }}
+ </h3>
</cds-modal-header>
<section cdsModalContent>
- <form name="confirmationForm"
- #formDir="ngForm"
- [formGroup]="confirmationForm"
- novalidate>
+ <form
+ name="confirmationForm"
+ #formDir="ngForm"
+ [formGroup]="confirmationForm"
+ novalidate
+ >
<ng-container *ngTemplateOutlet="bodyTpl; context: bodyContext"></ng-container>
<p *ngIf="description">
- {{description}}
+ {{ description }}
</p>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="onSubmit(confirmationForm.value)"
- [form]="confirmationForm"
- [submitText]="buttonText"
- [cancelText]="cancelText"
- [showCancel]="showCancel"
- [showSubmit]="showSubmit"
- [submitBtnType]="submitBtnType"
- [modalForm]="true"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmit(confirmationForm.value)"
+ [form]="confirmationForm"
+ [submitText]="buttonText"
+ [cancelText]="cancelText"
+ [showCancel]="showCancel"
+ [showSubmit]="showSubmit"
+ [submitBtnType]="submitBtnType"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
-
-<button cdsButton="ghost"
- class="clipboard-btn"
- [ngClass]="{'clipboard-btn-with-text': text}"
- [size]="size"
- description="Copy to Clipboard"
- i18n-description
- type="button"
- (click)="onClick()">
- @if(text) {
- <span data-toggle="tooltip"
- [title]="text"
- class="cds--type-mono">{{text}}</span>
+<button
+ cdsButton="ghost"
+ class="clipboard-btn"
+ [ngClass]="{ 'clipboard-btn-with-text': text }"
+ [size]="size"
+ description="Copy to Clipboard"
+ i18n-description
+ type="button"
+ (click)="onClick()"
+>
+ @if (text) {
+ <span
+ data-toggle="tooltip"
+ [title]="text"
+ class="cds--type-mono"
+ >{{ text }}</span
+ >
}
<cd-icon type="copy"></cd-icon>
</button>
-<p class="login-text"
- *ngIf="bannerText$ | async as bannerText">{{ bannerText }}</p>
+<p
+ class="login-text"
+ *ngIf="bannerText$ | async as bannerText"
+>
+ {{ bannerText }}
+</p>
<div cdsCol>
- <div cdsRow
- class="form-item-append">
- <cds-text-label>{{name}}
- <cds-date-picker i18n-label
- [placeholder]="placeHolder"
- formControlname="expiresAt"
- dateFormat="Y/m/d"
- [value]="date"
- (valueChange)="onModelChange($event)"
- [helperText]="helperText"
- [disabled]="disabled"
- cdsTheme="theme"></cds-date-picker>
+ <div
+ cdsRow
+ class="form-item-append"
+ >
+ <cds-text-label
+ >{{ name }}
+ <cds-date-picker
+ i18n-label
+ [placeholder]="placeHolder"
+ formControlname="expiresAt"
+ dateFormat="Y/m/d"
+ [value]="date"
+ (valueChange)="onModelChange($event)"
+ [helperText]="helperText"
+ [disabled]="disabled"
+ cdsTheme="theme"
+ ></cds-date-picker>
</cds-text-label>
- <cds-text-label *ngIf="hasTime">Select a time
- <cds-timepicker (valueChange)="onModelChange($event)"
- [(ngModel)]="time"
- [disabled]="disabled"
- pattern="(1[012]|[0-9]):[0-5][0-9]"
- *ngIf="hasTime">
- <cds-timepicker-select [(ngModel)]="ampm"
- [disabled]="disabled"
- (valueChange)="onModelChange($event)">
- <option selected
- value="AM">AM</option>
- <option value="PM">PM</option>
- </cds-timepicker-select>
-</cds-timepicker>
-</cds-text-label>
-</div>
+ <cds-text-label *ngIf="hasTime"
+ >Select a time
+ <cds-timepicker
+ (valueChange)="onModelChange($event)"
+ [(ngModel)]="time"
+ [disabled]="disabled"
+ pattern="(1[012]|[0-9]):[0-5][0-9]"
+ *ngIf="hasTime"
+ >
+ <cds-timepicker-select
+ [(ngModel)]="ampm"
+ [disabled]="disabled"
+ (valueChange)="onModelChange($event)"
+ >
+ <option
+ selected
+ value="AM"
+ >
+ AM
+ </option>
+ <option value="PM">PM</option>
+ </cds-timepicker-select>
+ </cds-timepicker>
+ </cds-text-label>
+ </div>
</div>
-<cds-modal size="sm"
- [open]="open"
- (overlaySelected)="closeModal()">
+<cds-modal
+ size="sm"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+>
<cds-modal-header (closeSelect)="closeModal()">
<ng-container *ngTemplateOutlet="deletionHeading"></ng-container>
</cds-modal-header>
<section cdsModalContent>
- <form name="deletionForm"
- #formDir="ngForm"
- [formGroup]="deletionForm"
- novalidate>
- <cd-alert-panel *ngIf="infoMessage"
- type="info"
- spacingClass="cds-mb-3"
- i18n>
+ <form
+ name="deletionForm"
+ #formDir="ngForm"
+ [formGroup]="deletionForm"
+ novalidate
+ >
+ <cd-alert-panel
+ *ngIf="infoMessage"
+ type="info"
+ spacingClass="cds-mb-3"
+ i18n
+ >
<p>{{ infoMessage }}</p>
</cd-alert-panel>
<ng-container *ngTemplateOutlet="bodyTemplate; context: bodyContext"></ng-container>
<div class="question">
<span *ngIf="itemNames; else noNames">
<ng-container *ngIf="itemNames.length === 1; else manyNames">
- <p *ngIf="impact == impactEnum.medium"
- i18n>Are you sure that you want to {{ actionDescription | lowercase }} <strong>{{ itemNames[0] }}</strong>?</p>
+ <p
+ *ngIf="impact == impactEnum.medium"
+ i18n
+ >
+ Are you sure that you want to {{ actionDescription | lowercase }}
+ <strong>{{ itemNames[0] }}</strong
+ >?
+ </p>
</ng-container>
<ng-template #manyNames>
- <p i18n>Are you sure that you want to {{ actionDescription | lowercase }} the selected items?</p>
+ <p i18n>
+ Are you sure that you want to {{ actionDescription | lowercase }} the selected items?
+ </p>
<ul>
- <li *ngFor="let itemName of itemNames"><strong>{{ itemName }}</strong></li>
+ <li *ngFor="let itemName of itemNames">
+ <strong>{{ itemName }}</strong>
+ </li>
</ul>
</ng-template>
</span>
<ng-template #noNames>
- <p *ngIf="impact == impactEnum.medium"
- i18n>Are you sure that you want to {{ actionDescription | lowercase }} the selected {{ itemDescription }}?</p>
+ <p
+ *ngIf="impact == impactEnum.medium"
+ i18n
+ >
+ Are you sure that you want to {{ actionDescription | lowercase }} the selected
+ {{ itemDescription }}?
+ </p>
</ng-template>
- <ng-container *ngTemplateOutlet="childFormGroupTemplate; context:{form:deletionForm}"></ng-container>
+ <ng-container
+ *ngTemplateOutlet="childFormGroupTemplate; context: { form: deletionForm }"
+ ></ng-container>
<div class="form-item">
<ng-container *ngIf="impact == impactEnum.medium; else highImpactDeletion">
- <cds-checkbox id="confirmation"
- formControlName="confirmation"
- autofocus
- [required]="true"
- modal-primary-focus
- ariaLabel="confirmation"
- i18n>Yes, I am sure.</cds-checkbox>
+ <cds-checkbox
+ id="confirmation"
+ formControlName="confirmation"
+ autofocus
+ [required]="true"
+ modal-primary-focus
+ ariaLabel="confirmation"
+ i18n
+ >Yes, I am sure.</cds-checkbox
+ >
</ng-container>
<ng-template #highImpactDeletion>
<p class="cds--type-body-01">
- @if (bodyContext?.deletionMessage) {
- <span [innerHTML]="bodyContext.deletionMessage"></span>
- } @else {
- <ng-container i18n>Deleting <strong>{{ itemNames[0] }}</strong> will remove all associated {{itemDescription}}.This action cannot be undone.</ng-container>
- }
+ @if (bodyContext?.deletionMessage) {
+ <span [innerHTML]="bodyContext.deletionMessage"></span>
+ } @else {
+ <ng-container i18n
+ >Deleting <strong>{{ itemNames[0] }}</strong> will remove all associated
+ {{ itemDescription }}.This action cannot be undone.</ng-container
+ >
+ }
</p>
<ng-template #labelTemplate>
- <span i18n
- class="cds--type-label-01">Type <strong>{{ itemNames[0] }}</strong> to confirm (required)</span>
+ <span
+ i18n
+ class="cds--type-label-01"
+ >Type <strong>{{ itemNames[0] }}</strong> to confirm (required)</span
+ >
</ng-template>
- <cds-text-label [labelTemplate]="labelTemplate"
- labelInputID="resource_name"
- [cdRequiredField]="'Type ' + itemNames[0] + ' to confirm'"
- [invalid]="!deletionForm.controls.confirmInput.valid && deletionForm.controls.confirmInput.touched"
- [invalidText]="ResourceError"
- [disabled]="deletionForm.controls.confirmInput.disabled">
- <input cdsText
- type="text"
- [placeholder]="'Name of resource'"
- id="resource_name"
- formControlName="confirmInput"
- [attr.disabled]="deletionForm.controls.confirmInput.disabled ? true : null"
- i18n-placeholder
- autofocus/>
+ <cds-text-label
+ [labelTemplate]="labelTemplate"
+ labelInputID="resource_name"
+ [cdRequiredField]="'Type ' + itemNames[0] + ' to confirm'"
+ [invalid]="
+ !deletionForm.controls.confirmInput.valid &&
+ deletionForm.controls.confirmInput.touched
+ "
+ [invalidText]="ResourceError"
+ [disabled]="deletionForm.controls.confirmInput.disabled"
+ >
+ <input
+ cdsText
+ type="text"
+ [placeholder]="'Name of resource'"
+ id="resource_name"
+ formControlName="confirmInput"
+ [attr.disabled]="deletionForm.controls.confirmInput.disabled ? true : null"
+ i18n-placeholder
+ autofocus
+ />
</cds-text-label>
<ng-template #ResourceError>
- <span *ngIf="deletionForm.controls.confirmInput.hasError('required')"
- class="invalid-feedback">
+ <span
+ *ngIf="deletionForm.controls.confirmInput.hasError('required')"
+ class="invalid-feedback"
+ >
<ng-container i18n>This field is required.</ng-container>
</span>
- <span *ngIf="deletionForm.controls.confirmInput.hasError('matchResource')"
- class="invalid-feedback">
+ <span
+ *ngIf="deletionForm.controls.confirmInput.hasError('matchResource')"
+ class="invalid-feedback"
+ >
<ng-container i18n>Enter the correct resource name.</ng-container>
</span>
</ng-template>
@if (bodyContext?.forceDeleteAcknowledgementMessage) {
- <div class="form-item cds-mt-3">
- <cds-checkbox id="force_delete_ack"
- formControlName="forceDeleteAck"
- [required]="true"
- ariaLabel="Forced delete acknowledgement">
- {{ bodyContext.forceDeleteAcknowledgementMessage }}
- </cds-checkbox>
- </div>
+ <div class="form-item cds-mt-3">
+ <cds-checkbox
+ id="force_delete_ack"
+ formControlName="forceDeleteAck"
+ [required]="true"
+ ariaLabel="Forced delete acknowledgement"
+ >
+ {{ bodyContext.forceDeleteAcknowledgementMessage }}
+ </cds-checkbox>
+ </div>
}
</ng-template>
</div>
</div>
</form>
</section>
- <cd-form-button-panel (submitActionEvent)="callSubmitAction()"
- (backActionEvent)="backAction ? callBackAction() : hideModal()"
- [form]="deletionForm"
- [submitText]="(actionDescription | titlecase) + ' ' + itemDescription"
- [modalForm]="true"
- [disabled]="(submitDisabled$ | async) || deletionForm.disabled || (impact === impactEnum.high ? (!deletionForm.controls.confirmInput.value || !forceDeleteAckSatisfied) : !deletionForm.controls.confirmation.value)"
- [submitBtnType]="(actionDescription === 'delete' || actionDescription === 'remove') ? 'danger' : 'primary'"></cd-form-button-panel>
-
+ <cd-form-button-panel
+ (submitActionEvent)="callSubmitAction()"
+ (backActionEvent)="backAction ? callBackAction() : hideModal()"
+ [form]="deletionForm"
+ [submitText]="(actionDescription | titlecase) + ' ' + itemDescription"
+ [modalForm]="true"
+ [disabled]="
+ (submitDisabled$ | async) ||
+ deletionForm.disabled ||
+ (impact === impactEnum.high
+ ? !deletionForm.controls.confirmInput.value || !forceDeleteAckSatisfied
+ : !deletionForm.controls.confirmation.value)
+ "
+ [submitBtnType]="
+ actionDescription === 'delete' || actionDescription === 'remove' ? 'danger' : 'primary'
+ "
+ ></cd-form-button-panel>
</cds-modal>
<ng-template #deletionHeading>
@if (impact === impactEnum.high) {
- <h2 cdsModalHeaderLabel
- i18n>
- {{(actionDescription | titlecase) + ' ' + itemDescription}}
- </h2>
- <h2 class="cds--type-heading-03"
+ <h2
+ cdsModalHeaderLabel
+ i18n
+ >
+ {{ (actionDescription | titlecase) + ' ' + itemDescription }}
+ </h2>
+ <h2
+ class="cds--type-heading-03"
cdsModalHeaderHeading
- i18n>
- Confirm {{ actionDescription }}
- </h2>
+ i18n
+ >
+ Confirm {{ actionDescription }}
+ </h2>
} @else {
- <h3 cdsModalHeaderHeading
- i18n>
- {{(actionDescription | titlecase) + ' ' + itemDescription}}
- </h3>
+ <h3
+ cdsModalHeaderHeading
+ i18n
+ >
+ {{ (actionDescription | titlecase) + ' ' + itemDescription }}
+ </h3>
}
</ng-template>
<cd-productive-card>
<ng-template #header>
@if (cardTitle) {
- <h3 class="cds--type-heading-03" i18n>{{ cardTitle }}</h3>
+ <h3
+ class="cds--type-heading-03"
+ i18n
+ >
+ {{ cardTitle }}
+ </h3>
}
</ng-template>
- <div [cdsStack]="'vertical'"
- [gap]="0">
+ <div
+ [cdsStack]="'vertical'"
+ [gap]="0"
+ >
@if (details && details.length > 0) {
- <div [cdsStack]="'horizontal'"
- [gap]="5">
- @for (detail of getVisibleDetails(); track detail.label) {
- <div [cdsStack]="'vertical'"
- [gap]="2">
- <legend class="cds--type-label-01">{{ detail.label }}</legend>
- <div class="cds--type-body-01">
- @switch (detail.type) {
- @case ('status') {
- <div [cdsStack]="'horizontal'" [gap]="3">
- <cd-icon [type]="getStatusIcon(detail)"></cd-icon>
- <span>{{ getDisplayValue(detail.value) }}</span>
- </div>
- }
+ <div
+ [cdsStack]="'horizontal'"
+ [gap]="5"
+ >
+ @for (detail of getVisibleDetails(); track detail.label) {
+ <div
+ [cdsStack]="'vertical'"
+ [gap]="2"
+ >
+ <legend class="cds--type-label-01">{{ detail.label }}</legend>
+ <div class="cds--type-body-01">
+ @switch (detail.type) {
+ @case ('status') {
+ <div
+ [cdsStack]="'horizontal'"
+ [gap]="3"
+ >
+ <cd-icon [type]="getStatusIcon(detail)"></cd-icon>
+ <span>{{ getDisplayValue(detail.value) }}</span>
+ </div>
+ }
- @default {
- <span>{{ getDisplayValue(detail.value) }}</span>
- }
- }
- </div>
+ @default {
+ <span>{{ getDisplayValue(detail.value) }}</span>
+ }
+ }
+ </div>
+ </div>
+ }
</div>
- }
- </div>
}
<ng-content></ng-content>
</div>
-<a href="{{ docUrl }}"
- target="_blank"
- class="ps-1 pe-1">{{ docText }}</a>
+<a
+ href="{{ docUrl }}"
+ target="_blank"
+ class="ps-1 pe-1"
+ >{{ docText }}</a
+>
-<div ngbDropdown
- placement="bottom-right">
- <button type="button"
- [title]="title"
- class="btn btn-light dropdown-toggle-split"
- ngbDropdownToggle>
- <svg [cdsIcon]="icons.download"
- size="16"
- ></svg>
+<div
+ ngbDropdown
+ placement="bottom-right"
+>
+ <button
+ type="button"
+ [title]="title"
+ class="btn btn-light dropdown-toggle-split"
+ ngbDropdownToggle
+ >
+ <svg
+ [cdsIcon]="icons.download"
+ size="16"
+ ></svg
+ >
</button>
<div ngbDropdownMenu>
- <button ngbDropdownItem
- (click)="download('json')"
- type="button"
- *ngIf="objectItem">
- <svg [cdsIcon]="icons.code"
- size="16"
- ></svg>
+ <button
+ ngbDropdownItem
+ (click)="download('json')"
+ type="button"
+ *ngIf="objectItem"
+ >
+ <svg
+ [cdsIcon]="icons.code"
+ size="16"
+ ></svg>
<span> JSON</span>
</button>
- <button ngbDropdownItem
- (click)="download()"
- *ngIf="textItem"
- type="button">
- <svg [cdsIcon]="icons.document"
- size="16"
- ></svg>
+ <button
+ ngbDropdownItem
+ (click)="download()"
+ *ngIf="textItem"
+ type="button"
+ >
+ <svg
+ [cdsIcon]="icons.document"
+ size="16"
+ ></svg>
<span> Text</span>
</button>
</div>
<div
class="empty-state"
- [class.empty-state-title]="title">
+ [class.empty-state-title]="title"
+>
<img
src="{{ imgSrc }}"
- [alt]="text"/>
- @if(title) {
- <p class="cds--type-body-compact-02 cds-mb-0">{{title}}</p>
+ [alt]="text"
+ />
+ @if (title) {
+ <p class="cds--type-body-compact-02 cds-mb-0">{{ title }}</p>
}
- <p class="cds--type-label-01 empty-state-text"
- i18n>
+ <p
+ class="cds--type-label-01 empty-state-text"
+ i18n
+ >
{{ text }}
</p>
<ng-content></ng-content>
<fieldset>
- <cds-accordion size="lg"
- class="form-item">
- <cds-accordion-item [title]="titleTpl"
- i18n
- id="advanced-fieldset"
- (selected)="showAdvanced = !showAdvanced">
+ <cds-accordion
+ size="lg"
+ class="form-item"
+ >
+ <cds-accordion-item
+ [title]="titleTpl"
+ i18n
+ id="advanced-fieldset"
+ (selected)="showAdvanced = !showAdvanced"
+ >
<ng-content></ng-content>
</cds-accordion-item>
</cds-accordion>
<ng-template #titleTpl>
- <h5 class="cds--accordion__title cd-header"
- i18n>{{title}}</h5>
+ <h5
+ class="cds--accordion__title cd-header"
+ i18n
+ >
+ {{ title }}
+ </h5>
</ng-template>
</fieldset>
<ng-container *ngIf="!modalForm; else modalFooter">
<div [ngClass]="wrappingClass">
- <cd-back-button *ngIf="showCancel"
- (backAction)="backAction()"
- [name]="cancelText"></cd-back-button>
- <cd-submit-button *ngIf="showSubmit"
- (submitAction)="submitAction()"
- [disabled]="disabled"
- [form]="form"
- [ariaLabel]="submitText"
- data-testid="submitBtn"
- [buttonType]="submitBtnType">{{ submitText }}</cd-submit-button>
+ <cd-back-button
+ *ngIf="showCancel"
+ (backAction)="backAction()"
+ [name]="cancelText"
+ ></cd-back-button>
+ <cd-submit-button
+ *ngIf="showSubmit"
+ (submitAction)="submitAction()"
+ [disabled]="disabled"
+ [form]="form"
+ [ariaLabel]="submitText"
+ data-testid="submitBtn"
+ [buttonType]="submitBtnType"
+ >{{ submitText }}</cd-submit-button
+ >
</div>
</ng-container>
<ng-template #modalFooter>
<cds-modal-footer>
- <cd-back-button *ngIf="showCancel"
- (backAction)="backAction()"
- [name]="cancelText"
- [modalForm]="modalForm"
- [showSubmit]="showSubmit"
- class="w-100"></cd-back-button>
- <cd-submit-button *ngIf="showSubmit"
- (submitAction)="submitAction()"
- [disabled]="disabled"
- [form]="form"
- [ariaLabel]="submitText"
- data-testid="submitBtn"
- [modalForm]="modalForm"
- [buttonType]="submitBtnType"
- class="w-100">{{ submitText }}</cd-submit-button>
+ <cd-back-button
+ *ngIf="showCancel"
+ (backAction)="backAction()"
+ [name]="cancelText"
+ [modalForm]="modalForm"
+ [showSubmit]="showSubmit"
+ class="w-100"
+ ></cd-back-button>
+ <cd-submit-button
+ *ngIf="showSubmit"
+ (submitAction)="submitAction()"
+ [disabled]="disabled"
+ [form]="form"
+ [ariaLabel]="submitText"
+ data-testid="submitBtn"
+ [modalForm]="modalForm"
+ [buttonType]="submitBtnType"
+ class="w-100"
+ >{{ submitText }}</cd-submit-button
+ >
</cds-modal-footer>
</ng-template>
-<cds-modal size="md"
- [open]="open"
- (overlaySelected)="closeModal()"
- [hasScrollingContent]="true">
+<cds-modal
+ size="md"
+ [open]="open"
+ (overlaySelected)="closeModal()"
+ [hasScrollingContent]="true"
+>
<cds-modal-header (closeSelect)="closeModal()">
- <h3 cdsModalHeaderHeading
- *ngIf="titleText">
+ <h3
+ cdsModalHeaderHeading
+ *ngIf="titleText"
+ >
{{ titleText }}
</h3>
</cds-modal-header>
- <div cdsModalContent
- data-testid="modal-content">
- <form [formGroup]="formGroup"
- #formDir="ngForm"
- novalidate>
- <p *ngIf="message"
- id="description">{{ message }}</p>
+ <div
+ cdsModalContent
+ data-testid="modal-content"
+ >
+ <form
+ [formGroup]="formGroup"
+ #formDir="ngForm"
+ novalidate
+ >
+ <p
+ *ngIf="message"
+ id="description"
+ >
+ {{ message }}
+ </p>
<ng-container *ngFor="let field of fields">
<div class="form-item">
- <cds-text-label *ngIf="field.type === 'text'"
- [labelInputID]="field.name"
- [invalid]="getError(field)"
- [invalidText]="getError(field)"
- [cdRequiredField]="field?.required === true ? field.label : ''"
- i18n>
+ <cds-text-label
+ *ngIf="field.type === 'text'"
+ [labelInputID]="field.name"
+ [invalid]="getError(field)"
+ [invalidText]="getError(field)"
+ [cdRequiredField]="field?.required === true ? field.label : ''"
+ i18n
+ >
{{ field.label }}
- <input cdsText
- type="text"
- [id]="field.name"
- [name]="field.name"
- [formControlName]="field.name"
- [invalid]="getError(field)"
- autofocus>
+ <input
+ cdsText
+ type="text"
+ [id]="field.name"
+ [name]="field.name"
+ [formControlName]="field.name"
+ [invalid]="getError(field)"
+ autofocus
+ />
</cds-text-label>
- <cds-number *ngIf="field.type === 'number'"
- [invalid]="getError(field)"
- [invalidText]="getError(field)"
- [label]="field.label"
- [cdRequiredField]="field?.required === true ? field.label : ''"
- [formControlName]="field.name"
- [id]="field.name"
- i18n></cds-number>
- <cds-text-label *ngIf="field.type === 'binary'"
- [labelInputID]="field.name"
- [invalid]="getError(field)"
- [invalidText]="getError(field)"
- [cdRequiredField]="field?.required === true ? field.label : ''"
- i18n>
+ <cds-number
+ *ngIf="field.type === 'number'"
+ [invalid]="getError(field)"
+ [invalidText]="getError(field)"
+ [label]="field.label"
+ [cdRequiredField]="field?.required === true ? field.label : ''"
+ [formControlName]="field.name"
+ [id]="field.name"
+ i18n
+ ></cds-number>
+ <cds-text-label
+ *ngIf="field.type === 'binary'"
+ [labelInputID]="field.name"
+ [invalid]="getError(field)"
+ [invalidText]="getError(field)"
+ [cdRequiredField]="field?.required === true ? field.label : ''"
+ i18n
+ >
{{ field.label }}
- <input type="text"
- [id]="field.name"
- [name]="field.name"
- [formControlName]="field.name"
- cdsText
- cdDimlessBinary>
+ <input
+ type="text"
+ [id]="field.name"
+ [name]="field.name"
+ [formControlName]="field.name"
+ cdsText
+ cdDimlessBinary
+ />
</cds-text-label>
- <cds-select *ngIf="field.type === 'select'"
- [label]="field.label"
- [for]="field.name"
- [id]="field.name"
- [formControlName]="field.name"
- [options]="field?.typeConfig?.options"
- [placeholder]="field?.typeConfig?.placeholder"
- [invalid]="getError(field)"
- [invalidText]="getError(field)"
- [cdRequiredField]="field?.required === true ? field.label : ''"
- i18n>
- <option *ngIf="field?.typeConfig?.placeholder"
- [ngValue]="null">
+ <cds-select
+ *ngIf="field.type === 'select'"
+ [label]="field.label"
+ [for]="field.name"
+ [id]="field.name"
+ [formControlName]="field.name"
+ [options]="field?.typeConfig?.options"
+ [placeholder]="field?.typeConfig?.placeholder"
+ [invalid]="getError(field)"
+ [invalidText]="getError(field)"
+ [cdRequiredField]="field?.required === true ? field.label : ''"
+ i18n
+ >
+ <option
+ *ngIf="field?.typeConfig?.placeholder"
+ [ngValue]="null"
+ >
{{ field?.typeConfig?.placeholder }}
</option>
- <option *ngFor="let option of field?.typeConfig?.options"
- [value]="option.value">
+ <option
+ *ngFor="let option of field?.typeConfig?.options"
+ [value]="option.value"
+ >
{{ option.text }}
</option>
</cds-select>
- <cds-combo-box *ngIf="field.type === 'select-badges'"
- type="multi"
- selectionFeedback="top-after-reopen"
- [label]="field.label"
- [for]="field.name"
- [formControlName]="field.name"
- itemValueKey="content"
- [id]="field.name"
- [invalid]="getError(field)"
- [invalidText]="getError(field)"
- [appendInline]="false"
- cdDynamicInputCombobox
- (updatedItems)="onLabelsUpdated(field, $event)"
- [items]="field?.typeConfig?.options"
- [cdRequiredField]="field?.required === true ? field.label : ''"
- i18n>
+ <cds-combo-box
+ *ngIf="field.type === 'select-badges'"
+ type="multi"
+ selectionFeedback="top-after-reopen"
+ [label]="field.label"
+ [for]="field.name"
+ [formControlName]="field.name"
+ itemValueKey="content"
+ [id]="field.name"
+ [invalid]="getError(field)"
+ [invalidText]="getError(field)"
+ [appendInline]="false"
+ cdDynamicInputCombobox
+ (updatedItems)="onLabelsUpdated(field, $event)"
+ [items]="field?.typeConfig?.options"
+ [cdRequiredField]="field?.required === true ? field.label : ''"
+ i18n
+ >
<cds-dropdown-list></cds-dropdown-list>
</cds-combo-box>
</div>
</ng-container>
</form>
</div>
- <cd-form-button-panel (submitActionEvent)="onSubmitForm(formGroup.value)"
- [form]="formGroup"
- [submitText]="submitButtonText"
- [modalForm]="true"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="onSubmitForm(formGroup.value)"
+ [form]="formGroup"
+ [submitText]="submitButtonText"
+ [modalForm]="true"
+ ></cd-form-button-panel>
</cds-modal>
<!-- Embed dashboard -->
-<cd-loading-panel *ngIf="loading && grafanaExist"
- i18n>Loading panel data...</cd-loading-panel>
+<cd-loading-panel
+ *ngIf="loading && grafanaExist"
+ i18n
+ >Loading panel data...</cd-loading-panel
+>
-<cd-alert-panel type="info"
- *ngIf="!grafanaExist"
- i18n>Please consult the <cd-doc section="grafana"></cd-doc> on
- how to configure and enable the monitoring functionality.</cd-alert-panel>
+<cd-alert-panel
+ type="info"
+ *ngIf="!grafanaExist"
+ i18n
+ >Please consult the <cd-doc section="grafana"></cd-doc> on how to configure and enable
+ the monitoring functionality.</cd-alert-panel
+>
-<cd-alert-panel type="info"
- *ngIf="!dashboardExist"
- i18n>Grafana Dashboard doesn't exist. Please refer to
- <cd-doc section="grafana"></cd-doc> on how to add dashboards to Grafana.</cd-alert-panel>
+<cd-alert-panel
+ type="info"
+ *ngIf="!dashboardExist"
+ i18n
+ >Grafana Dashboard doesn't exist. Please refer to <cd-doc section="grafana"></cd-doc
+ > on how to add dashboards to Grafana.</cd-alert-panel
+>
<ng-container *ngIf="grafanaExist && dashboardExist">
<!--Start : UI row hidden intentionally; code retained as dead code for potential future use. -->
- <div class="row mb-3"
- *ngIf="showMessage">
- <div class="col-lg-5 d-flex" >
+ <div
+ class="row mb-3"
+ *ngIf="showMessage"
+ >
+ <div class="col-lg-5 d-flex">
<div class="col-sm-1">
- <button class="btn btn-light ms-3"
- i18n-title
- title="Reset Settings"
- type="button"
- (click)="reset()">
+ <button
+ class="btn btn-light ms-3"
+ i18n-title
+ title="Reset Settings"
+ type="button"
+ (click)="reset()"
+ >
<i [ngClass]="[icons.undo]"></i>
</button>
</div>
<div class="col-sm-1">
- <button class="btn btn-light ms-3"
- i18n-title
- title="Show hidden information"
- type="button"
- (click)="showMessage = !showMessage">
+ <button
+ class="btn btn-light ms-3"
+ i18n-title
+ title="Show hidden information"
+ type="button"
+ (click)="showMessage = !showMessage"
+ >
<i [ngClass]="[icons.infoCircle, icons.size24]"></i>
</button>
</div>
<!-- end -->
<div class="row">
- <div class="col my-2"
- *ngIf="showMessage">
- <cd-alert-panel type="info"
- class="mb-3"
- *ngIf="showMessage"
- dismissible="true"
- (dismissed)="showMessage = false"
- i18n>If no embedded Grafana Dashboard appeared below, please follow <a [href]="grafanaSrc"
- target="_blank"
- noopener
- noreferrer>this link </a> to check if Grafana is reachable and there are no HTTPS certificate issues. You may need to reload this page after accepting any Browser certificate exceptions</cd-alert-panel>
+ <div
+ class="col my-2"
+ *ngIf="showMessage"
+ >
+ <cd-alert-panel
+ type="info"
+ class="mb-3"
+ *ngIf="showMessage"
+ dismissible="true"
+ (dismissed)="showMessage = false"
+ i18n
+ >If no embedded Grafana Dashboard appeared below, please follow <a
+ [href]="grafanaSrc"
+ target="_blank"
+ noopener
+ noreferrer
+ >this link </a
+ > to check if Grafana is reachable and there are no HTTPS certificate issues. You may
+ need to reload this page after accepting any Browser certificate exceptions</cd-alert-panel
+ >
</div>
</div>
<div class="row">
<div class="col">
<div class="grafana-container">
- <iframe #iframe
- id="iframe"
- [src]="grafanaSrc"
- class="grafana"
- [ngClass]="panelStyle"
- frameborder="0"
- [(scrolling)]="scrollable"
- [title]="title"
- i18n-title>
+ <iframe
+ #iframe
+ id="iframe"
+ [src]="grafanaSrc"
+ class="grafana"
+ [ngClass]="panelStyle"
+ frameborder="0"
+ [(scrolling)]="scrollable"
+ [title]="title"
+ i18n-title
+ >
</iframe>
</div>
</div>
- <div class="form-text text-muted">
- <ng-container *ngIf="formAllFieldsRequired; else contentTpl"
- i18n>
- All fields are required, except where marked optional.
- </ng-container>
+<div class="form-text text-muted">
+ <ng-container
+ *ngIf="formAllFieldsRequired; else contentTpl"
+ i18n
+ >
+ All fields are required, except where marked optional.
+ </ng-container>
- <ng-template #contentTpl>
- <ng-content></ng-content>
- </ng-template>
- </div>
+ <ng-template #contentTpl>
+ <ng-content></ng-content>
+ </ng-template>
+</div>
<ng-template #tooltipTemplate>
<div class="cds--popover-scroll-container">
- <div [class]="class"
- [innerHtml]="html">
- </div>
+ <div
+ [class]="class"
+ [innerHtml]="html"
+ ></div>
<ng-container *ngTemplateOutlet="content"></ng-container>
</div>
</ng-template>
@if (type === helperType.tooltip) {
- <cds-tooltip [description]="tooltipTemplate"
- [autoAlign]="true"
- [id]="tooltipId">
- <svg [cdsIcon]="iconType"
- [size]="iconSize"></svg>
+ <cds-tooltip
+ [description]="tooltipTemplate"
+ [autoAlign]="true"
+ [id]="tooltipId"
+ >
+ <svg
+ [cdsIcon]="iconType"
+ [size]="iconSize"
+ ></svg>
</cds-tooltip>
} @else {
- <div class="inline-block"
- [ngClass]="class">
+ <div
+ class="inline-block"
+ [ngClass]="class"
+ >
<div
cdsPopover
[isOpen]="isPopoverOpen"
[autoAlign]="true"
(click)="togglePopover()"
(keydown.enter)="togglePopover()"
- tabindex="0">
+ tabindex="0"
+ >
<div class="popover-trigger">
<svg
[cdsIcon]="iconType"
- [size]="iconSize"></svg>
+ [size]="iconSize"
+ ></svg>
</div>
<cds-popover-content>
- <div class="cds--popover-scroll-container"
- (click)="$event.stopPropagation()"
- tabindex="0"
- (keydown.enter)="$event.stopPropagation()">
+ <div
+ class="cds--popover-scroll-container"
+ (click)="$event.stopPropagation()"
+ tabindex="0"
+ (keydown.enter)="$event.stopPropagation()"
+ >
<ng-container *ngTemplateOutlet="content"></ng-container>
</div>
</cds-popover-content>
-<svg [cdsIcon]="icon"
- [size]="size"
- [ngClass]="!useDefault ? [type + '-icon', customClass] : []">
-</svg>
+<svg
+ [cdsIcon]="icon"
+ [size]="size"
+ [ngClass]="!useDefault ? [type + '-icon', customClass] : []"
+></svg>
@if (!isDismissed) {
- <div class="inline-tip-container"
- [cdsStack]="'horizontal'"
- [gap]="4">
+ <div
+ class="inline-tip-container"
+ [cdsStack]="'horizontal'"
+ [gap]="4"
+ >
<div class="close-btn-position">
- <cds-icon-button class="close-btn inline-tip-bg-color"
- type="button"
- kind="ghost"
- size="sm"
- description="Close"
- i18n-description
- (click)="close()">
- <svg [size]="icons.size16"
- [cdsIcon]="icons.destroy"></svg>
+ <cds-icon-button
+ class="close-btn inline-tip-bg-color"
+ type="button"
+ kind="ghost"
+ size="sm"
+ description="Close"
+ i18n-description
+ (click)="close()"
+ >
+ <svg
+ [size]="icons.size16"
+ [cdsIcon]="icons.destroy"
+ ></svg>
</cds-icon-button>
</div>
- <div class="inline-tip-body"
- [cdsStack]="'horizontal'"
- [gap]="4">
- <svg [cdsIcon]="icons.idea"
- [size]="icons.size20"></svg>
+ <div
+ class="inline-tip-body"
+ [cdsStack]="'horizontal'"
+ [gap]="4"
+ >
+ <svg
+ [cdsIcon]="icons.idea"
+ [size]="icons.size20"
+ ></svg>
- <div [cdsStack]="'vertical'"
- [gap]="1"
- class="inline-tip-body-content">
- @if (title) {
- <h1 class="cds--type-heading-compact-01">{{ title }}</h1>
- }
+ <div
+ [cdsStack]="'vertical'"
+ [gap]="1"
+ class="inline-tip-body-content"
+ >
+ @if (title) {
+ <h1 class="cds--type-heading-compact-01">{{ title }}</h1>
+ }
- <div class="cds--type-body-01"
- [class.cds--text-truncate--end]="isTruncated">
+ <div
+ class="cds--type-body-01"
+ [class.cds--text-truncate--end]="isTruncated"
+ >
<ng-content></ng-content>
</div>
@if (collapsible) {
- <button class="inline-tip-bg-color btn-toggle"
- cdsButton="ghost"
- size="md"
- (click)="toggleContent()"
- type="button">
- <span i18n>{{ isTruncated ? 'Read more' : 'Read less' }}</span>
- </button>
- }
+ <button
+ class="inline-tip-bg-color btn-toggle"
+ cdsButton="ghost"
+ size="md"
+ (click)="toggleContent()"
+ type="button"
+ >
+ <span i18n>{{ isTruncated ? 'Read more' : 'Read less' }}</span>
+ </button>
+ }
</div>
</div>
</div>
<cds-header-item (click)="changeLanguage(lang.key)">{{ lang.value }}</cds-header-item>
</ng-container>
</cds-header-menu>
-
-<ngb-alert type="info"
- [dismissible]="false">
+<ngb-alert
+ type="info"
+ [dismissible]="false"
+>
<strong>
- <cds-inline-loading aria-hidden="true"
- class="me-2"></cds-inline-loading>
+ <cds-inline-loading
+ aria-hidden="true"
+ class="me-2"
+ ></cds-inline-loading>
</strong>
<ng-content></ng-content>
</ngb-alert>
<h4 class="modal-title float-start">
<ng-content select=".modal-title"></ng-content>
</h4>
- <button type="button"
- class="btn-close float-end"
- aria-label="Close"
- (click)="close()">
- </button>
+ <button
+ type="button"
+ class="btn-close float-end"
+ aria-label="Close"
+ (click)="close()"
+ ></button>
</div>
<ng-content select=".modal-content"></ng-content>
-<cd-alert-panel *ngIf="motd"
- size="slim"
- [showTitle]="false"
- [type]="motd.severity"
- [dismissible]="motd.severity !== 'danger'"
- (dismissed)="onDismissed()">
+<cd-alert-panel
+ *ngIf="motd"
+ size="slim"
+ [showTitle]="false"
+ [type]="motd.severity"
+ [dismissible]="motd.severity !== 'danger'"
+ (dismissed)="onDismissed()"
+>
<span [innerHTML]="motd.message | sanitizeHtml"></span>
</cd-alert-panel>
<div class="cds--toast-notification-container">
@for (toast of activeToasts$ | async; track $index) {
- <cds-toast
- [@toastAnimation]="'in'"
- [notificationObj]="{
- type: toast.type,
- title: toast.title,
- subtitle: toast.subtitle,
- caption: toast.caption,
- lowContrast: toast.lowContrast,
- showClose: toast.showClose
- }"
- (close)="onToastClose(toast)">
- </cds-toast>
+ <cds-toast
+ [@toastAnimation]="'in'"
+ [notificationObj]="{
+ type: toast.type,
+ title: toast.title,
+ subtitle: toast.subtitle,
+ caption: toast.caption,
+ lowContrast: toast.lowContrast,
+ showClose: toast.showClose
+ }"
+ (close)="onToastClose(toast)"
+ >
+ </cds-toast>
}
</div>
<ng-template #tasksTpl>
<!-- Executing -->
- <div *ngFor="let executingTask of executingTasks; trackBy:trackByFn">
+ <div *ngFor="let executingTask of executingTasks; trackBy: trackByFn">
<div class="card tc_task border-0">
<div class="row no-gutters">
<div class="col-md-2 text-center">
<span class="text-info">
- <svg [cdsIcon]="icons.circle"
- [size]="icons.size16"
- ></svg>
+ <svg
+ [cdsIcon]="icons.circle"
+ [size]="icons.size16"
+ ></svg>
</span>
</div>
<div class="col-md-9">
<div class="card-body p-1">
<h6 class="card-title bold">{{ executingTask.description }}</h6>
<div class="mb-1">
- <ngb-progressbar type="info"
- [value]="executingTask?.progress"
- [striped]="true"
- [animated]="true"></ngb-progressbar>
+ <ngb-progressbar
+ type="info"
+ [value]="executingTask?.progress"
+ [striped]="true"
+ [animated]="true"
+ ></ngb-progressbar>
</div>
<p class="card-text text-muted">
<small class="date float-start">
{{ executingTask.begin_time | cdDate }}
</small>
- <span class="float-end">
- {{ executingTask.progress || 0 }} %
- </span>
+ <span class="float-end"> {{ executingTask.progress || 0 }} % </span>
</p>
-
</div>
</div>
</div>
</div>
- <hr>
+ <hr />
</div>
</ng-template>
<ng-template #notificationsTpl>
<ng-container *ngIf="notifications.length > 0">
- <button type="button"
- class="btn btn-light btn-block"
- (click)="removeAll(); $event.stopPropagation()">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size16"
- ></svg>
+ <button
+ type="button"
+ class="btn btn-light btn-block"
+ (click)="removeAll(); $event.stopPropagation()"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size16"
+ ></svg>
<ng-container i18n>Clear notifications</ng-container>
</button>
- <hr>
+ <hr />
- <div *ngFor="let notification of notifications; let i = index"
- [ngClass]="notification.borderClass">
+ <div
+ *ngFor="let notification of notifications; let i = index"
+ [ngClass]="notification.borderClass"
+ >
<div class="card tc_notification border-0">
<div class="row no-gutters">
<div class="col-md-2 text-center">
- <cd-icon [type]="notification.iconClass"
- [size]="icons.size24"
- [customClass]="notification.textClass"></cd-icon>
+ <cd-icon
+ [type]="notification.iconClass"
+ [size]="icons.size24"
+ [customClass]="notification.textClass"
+ ></cd-icon>
</div>
<div class="col-md-10">
<div class="card-body p-1">
- <button class="btn btn-link float-end mt-0 pt-0"
- title="Remove notification"
- type="button"
- i18n-title
- (click)="remove(i); $event.stopPropagation()">
- <svg [cdsIcon]="icons.trash"
- [size]="icons.size16"
- ></svg>
+ <button
+ class="btn btn-link float-end mt-0 pt-0"
+ title="Remove notification"
+ type="button"
+ i18n-title
+ (click)="remove(i); $event.stopPropagation()"
+ >
+ <svg
+ [cdsIcon]="icons.trash"
+ [size]="icons.size16"
+ ></svg>
</button>
- <button *ngIf="notification.application === 'Prometheus' && notification.type !== 2 && !notification.alertSilenced"
- class="btn btn-link float-end text-muted mute m-0 p-0"
- title="Silence Alert"
- type="button"
- i18n-title
- (click)="silence(notification)">
- <svg [cdsIcon]="icons.mute"
- [size]="icons.size16"
- ></svg>
+ <button
+ *ngIf="
+ notification.application === 'Prometheus' &&
+ notification.type !== 2 &&
+ !notification.alertSilenced
+ "
+ class="btn btn-link float-end text-muted mute m-0 p-0"
+ title="Silence Alert"
+ type="button"
+ i18n-title
+ (click)="silence(notification)"
+ >
+ <svg
+ [cdsIcon]="icons.mute"
+ [size]="icons.size16"
+ ></svg>
</button>
- <button *ngIf="notification.application === 'Prometheus' && notification.type !== 2 && notification.alertSilenced"
- class="btn btn-link float-end text-muted mute m-0 p-0"
- title="Expire Silence"
- type="button"
- i18n-title
- (click)="expire(notification)">
- <svg [cdsIcon]="icons.bell"
- [size]="icons.size16"
- ></svg>
+ <button
+ *ngIf="
+ notification.application === 'Prometheus' &&
+ notification.type !== 2 &&
+ notification.alertSilenced
+ "
+ class="btn btn-link float-end text-muted mute m-0 p-0"
+ title="Expire Silence"
+ type="button"
+ i18n-title
+ (click)="expire(notification)"
+ >
+ <svg
+ [cdsIcon]="icons.bell"
+ [size]="icons.size16"
+ ></svg>
</button>
-
<h6 class="card-title bold">{{ notification.title }}</h6>
- <p class="card-text"
- [innerHtml]="notification.message"></p>
+ <p
+ class="card-text"
+ [innerHtml]="notification.message"
+ ></p>
<p class="card-text text-muted">
<ng-container *ngIf="notification.duration">
<small>
- <ng-container i18n>Duration:</ng-container> {{ notification.duration | duration }}
+ <ng-container i18n>Duration:</ng-container>
+ {{ notification.duration | duration }}
</small>
- <br>
+ <br />
</ng-container>
- <small class="date"
- [title]="notification.timestamp | cdDate">{{ notification.timestamp | relativeDate }}</small>
- <i class="float-end custom-icon"
- [ngClass]="[notification.applicationClass]"
- [title]="notification.application"></i>
+ <small
+ class="date"
+ [title]="notification.timestamp | cdDate"
+ >{{ notification.timestamp | relativeDate }}</small
+ >
+ <i
+ class="float-end custom-icon"
+ [ngClass]="[notification.applicationClass]"
+ [title]="notification.application"
+ ></i>
</p>
</div>
</div>
</div>
</div>
- <hr>
+ <hr />
</div>
</ng-container>
</ng-template>
<ng-template #emptyTpl>
<div *ngIf="notifications.length === 0 && executingTasks.length === 0">
- <div class="message text-center"
- i18n>There are no notifications.</div>
+ <div
+ class="message text-center"
+ i18n
+ >
+ There are no notifications.
+ </div>
</div>
</ng-template>
-<div class="card"
- (clickOutside)="closeSidebar()"
- [clickOutsideEnabled]="isSidebarOpened">
+<div
+ class="card"
+ (clickOutside)="closeSidebar()"
+ [clickOutsideEnabled]="isSidebarOpened"
+>
<div class="card-header">
<ng-container i18n>Tasks and Notifications</ng-container>
- <button class="btn-close float-end"
- tabindex="-1"
- type="button"
- title="close"
- (click)="closeSidebar()">
- </button>
+ <button
+ class="btn-close float-end"
+ tabindex="-1"
+ type="button"
+ title="close"
+ (click)="closeSidebar()"
+ ></button>
</div>
<ngx-simplebar [options]="simplebar">
[id]="unitControlName"
>
@for (unit of units; track unit) {
- <option [value]="unit">{{ unit }}</option>
+ <option [value]="unit">{{ unit }}</option>
}
</cds-select>
</div>
-<cd-alert-panel *ngIf="missingFeatures; else elseBlock"
- type="info"
- i18n>The feature is not supported in the current Orchestrator.</cd-alert-panel>
+<cd-alert-panel
+ *ngIf="missingFeatures; else elseBlock"
+ type="info"
+ i18n
+ >The feature is not supported in the current Orchestrator.</cd-alert-panel
+>
<ng-template #elseBlock>
- <cd-alert-panel type="info"
- i18n>Orchestrator is not available.
- Please consult the <cd-doc section="orch"></cd-doc> on how to configure and
- enable the functionality.</cd-alert-panel>
+ <cd-alert-panel
+ type="info"
+ i18n
+ >Orchestrator is not available. Please consult the <cd-doc section="orch"></cd-doc> on
+ how to configure and enable the functionality.</cd-alert-panel
+ >
</ng-template>
<div>
<cds-tile class="border-top padding-inline-0">
<p class="cds--type-heading-04">{{ title }}</p>
- @if(description) {
- <p class="cds--type-body-01">{{ description }}</p>
+ @if (description) {
+ <p class="cds--type-body-01">{{ description }}</p>
}
</cds-tile>
</div>
i18n-headerTitle
[applyShadow]="false"
>
- <ng-template #header>
- <h2 class="cds--type-heading-compact-02"
- i18n>Performance</h2>
- @if(!prometheusEmptyState && !storageEmptyState) {
- <div cdsStack="horizontal"
- gap="2">
- <cd-time-picker
- [dropdownSize]="'sm'"
- [label]="'Time Span'"
- (selectedTime)="loadCharts($event)"
- ></cd-time-picker>
- </div>
- }
- </ng-template>
- @if(storageEmptyState) {
- <cd-empty-state
- text="You must have storage configured to access this capability."
- i18n-text></cd-empty-state>
- }
- @else if(prometheusEmptyState) {
- <cd-empty-state
- text="You must have Prometheus configured to access this capability."
- i18n-text
- [imgSrc]="emptyState.locked"></cd-empty-state>
- }
- @else {
- <div cdsGrid
- [narrow]="true"
- [condensed]="false"
- [fullWidth]="true"
- class="cds-mt-5 cds-mb-5">
- <div cdsRow
- [narrow]="true">
- <div cdsCol
- class="cds-mb-5"
- [columnNumbers]="{lg: 5, md: 8, sm: 12}">
- <cd-area-chart
- chartTitle="IOPS"
- i18n-chartTitle
- [chartKey]="performanceTypes?.IOPS"
- [dataUnit]="metricUnitMap?.iops"
- [rawData]="chartDataSignal()?.iops">
- </cd-area-chart>
- </div>
- <div cdsCol
- [columnNumbers]="{lg: 5, md: 8, sm: 12}"
- class="cds-mb-5 performance-card-latency-chart">
- <cd-area-chart
- chartTitle="Latency"
- i18n-chartTitle
- [chartKey]="performanceTypes?.Latency"
- [dataUnit]="metricUnitMap?.latency"
- [rawData]="chartDataSignal()?.latency">
- </cd-area-chart>
+ <ng-template #header>
+ <h2
+ class="cds--type-heading-compact-02"
+ i18n
+ >
+ Performance
+ </h2>
+ @if (!prometheusEmptyState && !storageEmptyState) {
+ <div
+ cdsStack="horizontal"
+ gap="2"
+ >
+ <cd-time-picker
+ [dropdownSize]="'sm'"
+ [label]="'Time Span'"
+ (selectedTime)="loadCharts($event)"
+ ></cd-time-picker>
+ </div>
+ }
+ </ng-template>
+ @if (storageEmptyState) {
+ <cd-empty-state
+ text="You must have storage configured to access this capability."
+ i18n-text
+ ></cd-empty-state>
+ } @else if (prometheusEmptyState) {
+ <cd-empty-state
+ text="You must have Prometheus configured to access this capability."
+ i18n-text
+ [imgSrc]="emptyState.locked"
+ ></cd-empty-state>
+ } @else {
+ <div
+ cdsGrid
+ [narrow]="true"
+ [condensed]="false"
+ [fullWidth]="true"
+ class="cds-mt-5 cds-mb-5"
+ >
+ <div
+ cdsRow
+ [narrow]="true"
+ >
+ <div
+ cdsCol
+ class="cds-mb-5"
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ >
+ <cd-area-chart
+ chartTitle="IOPS"
+ i18n-chartTitle
+ [chartKey]="performanceTypes?.IOPS"
+ [dataUnit]="metricUnitMap?.iops"
+ [rawData]="chartDataSignal()?.iops"
+ >
+ </cd-area-chart>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ class="cds-mb-5 performance-card-latency-chart"
+ >
+ <cd-area-chart
+ chartTitle="Latency"
+ i18n-chartTitle
+ [chartKey]="performanceTypes?.Latency"
+ [dataUnit]="metricUnitMap?.latency"
+ [rawData]="chartDataSignal()?.latency"
+ >
+ </cd-area-chart>
+ </div>
+ <div
+ cdsCol
+ class="cds-mb-5"
+ [columnNumbers]="{ lg: 5, md: 8, sm: 12 }"
+ >
+ <cd-area-chart
+ chartTitle="Throughput"
+ i18n-chartTitle
+ [chartKey]="performanceTypes?.Throughput"
+ [dataUnit]="metricUnitMap?.throughput"
+ [rawData]="chartDataSignal()?.throughput"
+ >
+ </cd-area-chart>
+ </div>
+ </div>
</div>
- <div cdsCol
- class="cds-mb-5"
- [columnNumbers]="{lg: 5, md: 8, sm: 12}">
- <cd-area-chart
- chartTitle="Throughput"
- i18n-chartTitle
- [chartKey]="performanceTypes?.Throughput"
- [dataUnit]="metricUnitMap?.throughput"
- [rawData]="chartDataSignal()?.throughput">
- </cd-area-chart>
- </div>
- </div>
- </div>
- }
+ }
</cd-productive-card>
</div>
<ibm-pie-chart
*ngIf="chartData && chartOptions"
[data]="chartData"
- [options]="chartOptions">
+ [options]="chartOptions"
+>
</ibm-pie-chart>
-<cds-tile class="productive-card"
- [ngClass]="{'productive-card--shadow': applyShadow}"
- [cdsLayer]="0">
+<cds-tile
+ class="productive-card"
+ [ngClass]="{ 'productive-card--shadow': applyShadow }"
+ [cdsLayer]="0"
+>
<div class="productive-card-header">
<ng-container *ngTemplateOutlet="headerTemplate || null"></ng-container>
</div>
- <section class="productive-card-section cds--type-body-compact-01"
- [ngClass]="{'productive-card-section--footer': footerTemplate}">
+ <section
+ class="productive-card-section cds--type-body-compact-01"
+ [ngClass]="{ 'productive-card-section--footer': footerTemplate }"
+ >
<ng-content></ng-content>
</section>
- @if(!!footerTemplate) {
- <footer class="productive-card-footer">
- <ng-container *ngTemplateOutlet="footerTemplate || null"></ng-container>
- </footer>
+ @if (!!footerTemplate) {
+ <footer class="productive-card-footer">
+ <ng-container *ngTemplateOutlet="footerTemplate || null"></ng-container>
+ </footer>
}
</cds-tile>
<div class="d-flex flex-column justify-content-center align-items-center bold">
<ng-container>
- <h3 class="text-center"
- [ngClass]="{ 'mt-3': status === 'in-progress' && isPaused }"
- *ngIf="!value || actionName === 'upgrading'">
- <cds-loading *ngIf="status === 'in-progress' && isPaused; else spinningIcon"
- [isActive]="false"
- [overlay]="false"
- size="sm"></cds-loading>
+ <h3
+ class="text-center"
+ [ngClass]="{ 'mt-3': status === 'in-progress' && isPaused }"
+ *ngIf="!value || actionName === 'upgrading'"
+ >
+ <cds-loading
+ *ngIf="status === 'in-progress' && isPaused; else spinningIcon"
+ [isActive]="false"
+ [overlay]="false"
+ size="sm"
+ ></cds-loading>
<ng-template #spinningIcon>
- <cds-loading [isActive]="true"
- [overlay]="false"
- size="sm"></cds-loading>
+ <cds-loading
+ [isActive]="true"
+ [overlay]="false"
+ size="sm"
+ ></cds-loading>
</ng-template>
</h3>
- <h3 class="text-center"
- [ngClass]="status === 'in-progress' && isPaused ? ['mt-3', 'mb-4'] : 'mt-2'"
- *ngIf="label">
+ <h3
+ class="text-center"
+ [ngClass]="status === 'in-progress' && isPaused ? ['mt-3', 'mb-4'] : 'mt-2'"
+ *ngIf="label"
+ >
{{ label }}
</h3>
- <h5 class="text-center mt-3"
- *ngIf="subLabel && status === 'in-progress' && !isPaused">
+ <h5
+ class="text-center mt-3"
+ *ngIf="subLabel && status === 'in-progress' && !isPaused"
+ >
{{ subLabel }}
</h5>
- <h5 class="text-center mt-3"
- *ngIf="description">
+ <h5
+ class="text-center mt-3"
+ *ngIf="description"
+ >
{{ description }}
</h5>
- <p class="text-center text-muted mt-3"
- *ngIf="subDescription">
+ <p
+ class="text-center text-muted mt-3"
+ *ngIf="subDescription"
+ >
{{ subDescription }}
</p>
</ng-container>
<div class="w-50 row h-100 d-flex justify-content-center align-items-center mt-4">
<div class="text-center w-75">
- <ng-container *ngIf="completedItems && completedItems.length > 0"
- i18n>
+ <ng-container
+ *ngIf="completedItems && completedItems.length > 0"
+ i18n
+ >
Finished {{ actionName }}:
<span class="text-success">
{{ completedItems }}
<!-- Progress Bar -->
<div class="mt-2">
- <ngb-progressbar type="info"
- [value]="value"
- [striped]="true"
- [animated]="!isPaused"></ngb-progressbar>
+ <ngb-progressbar
+ type="info"
+ [value]="value"
+ [striped]="true"
+ [animated]="!isPaused"
+ ></ngb-progressbar>
</div>
<p class="card-text text-muted">
<span class="float-end">{{ value || 0 }} %</span>
</p>
</div>
- <h4 class="text-center m-2"
- *ngIf="helperText">
+ <h4
+ class="text-center m-2"
+ *ngIf="helperText"
+ >
{{ helperText }}
</h4>
- <h5 class="text-center mt-2"
- *ngIf="footerText">
+ <h5
+ class="text-center mt-2"
+ *ngIf="footerText"
+ >
{{ footerText }}
</h5>
</div>
-<cd-alert-panel class="no-margin-bottom"
- [type]="alertType"
- *ngIf="displayNotification"
- [showTitle]="false"
- size="slim"
- [dismissible]="alertType !== 'danger'"
- (dismissed)="onDismissed()">
- <div *ngIf="expirationDays === 0"
- i18n>Your password will expire in <strong>less than 1</strong> day. Click
- <a routerLink="/user-profile/edit"
- class="alert-link">here</a> to change it now.</div>
- <div *ngIf="expirationDays > 0"
- i18n>Your password will expire in <strong>{{ expirationDays }}</strong> day(s). Click
- <a routerLink="/user-profile/edit"
- class="alert-link">here</a> to change it now.</div>
+<cd-alert-panel
+ class="no-margin-bottom"
+ [type]="alertType"
+ *ngIf="displayNotification"
+ [showTitle]="false"
+ size="slim"
+ [dismissible]="alertType !== 'danger'"
+ (dismissed)="onDismissed()"
+>
+ <div
+ *ngIf="expirationDays === 0"
+ i18n
+ >
+ Your password will expire in <strong>less than 1</strong> day. Click
+ <a
+ routerLink="/user-profile/edit"
+ class="alert-link"
+ >here</a
+ >
+ to change it now.
+ </div>
+ <div
+ *ngIf="expirationDays > 0"
+ i18n
+ >
+ Your password will expire in <strong>{{ expirationDays }}</strong> day(s). Click
+ <a
+ routerLink="/user-profile/edit"
+ class="alert-link"
+ >here</a
+ >
+ to change it now.
+ </div>
</cd-alert-panel>
-<cd-select #cdSelect
- [data]="data"
- [options]="options"
- [messages]="messages"
- [selectionLimit]="selectionLimit"
- [customBadges]="customBadges"
- [customBadgeValidators]="customBadgeValidators"
- elemClass="me-2 select-menu-edit"
- (selection)="selection.emit($event)">
- <svg [cdsIcon]="icons.edit"
- [size]="icons.size20"
- class="cds-info-color"></svg>
+<cd-select
+ #cdSelect
+ [data]="data"
+ [options]="options"
+ [messages]="messages"
+ [selectionLimit]="selectionLimit"
+ [customBadges]="customBadges"
+ [customBadgeValidators]="customBadgeValidators"
+ elemClass="me-2 select-menu-edit"
+ (selection)="selection.emit($event)"
+>
+ <svg
+ [cdsIcon]="icons.edit"
+ [size]="icons.size20"
+ class="cds-info-color"
+ ></svg>
</cd-select>
<span *ngFor="let dataItem of data">
<cds-tag class="tag-dark me-2">
<span class="me-2">{{ dataItem }}</span>
- <a class="tags-remove"
- (click)="cdSelect.removeItem(dataItem)"
- tabindex="0"
- (keydown.enter)="cdSelect.removeItem(dataItem)">
- <svg [cdsIcon]="icons.destroy"
- [size]="icons.size20"
- class="cds-white"></svg>
+ <a
+ class="tags-remove"
+ (click)="cdSelect.removeItem(dataItem)"
+ tabindex="0"
+ (keydown.enter)="cdSelect.removeItem(dataItem)"
+ >
+ <svg
+ [cdsIcon]="icons.destroy"
+ [size]="icons.size20"
+ class="cds-white"
+ ></svg>
</a>
</cds-tag>
</span>
<ng-template #popTemplate>
- <form name="form"
- #formDir="ngForm"
- [formGroup]="form"
- novalidate>
+ <form
+ name="form"
+ #formDir="ngForm"
+ [formGroup]="form"
+ novalidate
+ >
<div>
- <input type="text"
- formControlName="filter"
- i18n-placeholder
- [placeholder]="messages.filter"
- (keyup)="$event.keyCode === 13 ? selectOption() : updateFilter()"
- class="form-control text-center" />
+ <input
+ type="text"
+ formControlName="filter"
+ i18n-placeholder
+ [placeholder]="messages.filter"
+ (keyup)="$event.keyCode === 13 ? selectOption() : updateFilter()"
+ class="form-control text-center"
+ />
<ng-container *ngFor="let error of Object.keys(messages.customValidations)">
- <span class="invalid-feedback text-center d-block"
- *ngIf="form.showError('filter', formDir) && filter.hasError(error)">
+ <span
+ class="invalid-feedback text-center d-block"
+ *ngIf="form.showError('filter', formDir) && filter.hasError(error)"
+ >
{{ messages.customValidations[error] }}
</span>
</ng-container>
</div>
</form>
- <div *ngFor="let option of filteredOptions"
- class="select-menu-item"
- [ngClass]="{'help-block disabled': (data.length === selectionLimit || !option.enabled) && !option.selected}"
- (click)="triggerSelection(option)"
- tabindex="0"
- (keydown.enter)="triggerSelection(option)">
+ <div
+ *ngFor="let option of filteredOptions"
+ class="select-menu-item"
+ [ngClass]="{
+ 'help-block disabled': (data.length === selectionLimit || !option.enabled) && !option.selected
+ }"
+ (click)="triggerSelection(option)"
+ tabindex="0"
+ (keydown.enter)="triggerSelection(option)"
+ >
<div class="select-menu-item-icon">
- <i [ngClass]="[icons.check]"
- aria-hidden="true"
- *ngIf="option.selected"></i>
+ <i
+ [ngClass]="[icons.check]"
+ aria-hidden="true"
+ *ngIf="option.selected"
+ ></i>
</div>
<div class="select-menu-item-content">
{{ option.name }}
<ng-container *ngIf="option.description">
- <br>
- <small class="form-text text-muted">
- {{ option.description }}
- </small>
+ <br />
+ <small class="form-text text-muted"> {{ option.description }} </small>
</ng-container>
</div>
</div>
- <div *ngIf="isCreatable()"
- class="select-menu-item"
- (click)="addCustomOption()"
- tabindex="0"
- (keydown.enter)="addCustomOption()">
+ <div
+ *ngIf="isCreatable()"
+ class="select-menu-item"
+ (click)="addCustomOption()"
+ tabindex="0"
+ (keydown.enter)="addCustomOption()"
+ >
<div class="select-menu-item-icon">
- <i [ngClass]="[icons.tag]"
- aria-hidden="true"></i>
+ <i
+ [ngClass]="[icons.tag]"
+ aria-hidden="true"
+ ></i>
</div>
- <div class="select-menu-item-content">
- {{ messages.add }} '{{ filter.value }}'
- </div>
+ <div class="select-menu-item-content">{{ messages.add }} '{{ filter.value }}'</div>
</div>
- <div class="is-invalid"
- *ngIf="data.length === selectionLimit">
- <span class="form-text text-muted text-center text-warning"
- [ngbTooltip]="messages.selectionLimit.tooltip"
- *ngIf="data.length === selectionLimit">
+ <div
+ class="is-invalid"
+ *ngIf="data.length === selectionLimit"
+ >
+ <span
+ class="form-text text-muted text-center text-warning"
+ [ngbTooltip]="messages.selectionLimit.tooltip"
+ *ngIf="data.length === selectionLimit"
+ >
{{ messages.selectionLimit.text }}
</span>
</div>
</ng-template>
-<a class="select-menu-edit float-start"
- [ngClass]="elemClass"
- [ngbPopover]="popTemplate"
- data-testid="select-menu-edit"
- *ngIf="customBadges || options.length > 0">
+<a
+ class="select-menu-edit float-start"
+ [ngClass]="elemClass"
+ [ngbPopover]="popTemplate"
+ data-testid="select-menu-edit"
+ *ngIf="customBadges || options.length > 0"
+>
<ng-content></ng-content>
</a>
-<span class="form-text text-muted float-start"
- *ngIf="data.length === 0 && !(!customBadges && options.length === 0)">
+<span
+ class="form-text text-muted float-start"
+ *ngIf="data.length === 0 && !(!customBadges && options.length === 0)"
+>
{{ messages.empty }}
</span>
-<span class="form-text text-muted float-start"
- *ngIf="!customBadges && options.length === 0">
+<span
+ class="form-text text-muted float-start"
+ *ngIf="!customBadges && options.length === 0"
+>
{{ messages.noOptions }}
</span>
-<div class="setup-step-card" [class.setup-step-card--loading]="isLoading">
+<div
+ class="setup-step-card"
+ [class.setup-step-card--loading]="isLoading"
+>
<div class="setup-step-card__step-row">
<span class="cds--type-heading-compact-01">{{ stepNumber }}.</span>
<span class="cds--type-heading-compact-01">{{ title }}</span>
</p>
<div class="setup-step-card__info">
@if (isLoading) {
- <cd-loading-panel></cd-loading-panel>
+ <cd-loading-panel></cd-loading-panel>
} @else if (isConfigured) {
- <cd-icon type="success"></cd-icon>
- <span class="cds--type-label-01">{{ statusMessage }}</span>
+ <cd-icon type="success"></cd-icon>
+ <span class="cds--type-label-01">{{ statusMessage }}</span>
} @else {
- <cd-icon type="infoCircle"></cd-icon>
- <span class="cds--type-label-01">{{ statusMessage }}</span>
+ <cd-icon type="infoCircle"></cd-icon>
+ <span class="cds--type-label-01">{{ statusMessage }}</span>
}
</div>
</div>
-<div class="overlay"
- (click)="close()"
- tabindex="0"
- (keydown.enter)="close()"
- *ngIf="expanded && overlay"></div>
+<div
+ class="overlay"
+ (click)="close()"
+ tabindex="0"
+ (keydown.enter)="close()"
+ *ngIf="expanded && overlay"
+></div>
-<cds-panel [expanded]="expanded"
- [attr.panel-size]="size"
- [cdsLayer]="layer"
- [cdsTheme]="theme">
+<cds-panel
+ [expanded]="expanded"
+ [attr.panel-size]="size"
+ [cdsLayer]="layer"
+ [cdsTheme]="theme"
+>
<div>
- <cds-icon-button kind="ghost"
- class="float-end"
- title="Close"
- i18n-title
- (click)="close()">
+ <cds-icon-button
+ kind="ghost"
+ class="float-end"
+ title="Close"
+ i18n-title
+ (click)="close()"
+ >
<svg cdsIcon="close"></svg>
</cds-icon-button>
- <div class="panel-header"
- *ngIf="headerText">
+ <div
+ class="panel-header"
+ *ngIf="headerText"
+ >
<p class="cds--type-heading-03">{{ headerText }}</p>
<ng-content select="[panel-header-description]"></ng-content>
</div>
@if (title) {
-<header class="sidebar-header">
- <h2 class="cds--type-heading-05">{{ title }}</h2>
-</header>
+ <header class="sidebar-header">
+ <h2 class="cds--type-heading-05">{{ title }}</h2>
+ </header>
}
<div class="sidebar-layout-container sidebar-layout--full">
<div class="sidebar-layout-shell">
<cds-sidenav
[expanded]="true"
- class="sidebar-layout-nav cds--side-nav--fixed">
+ class="sidebar-layout-nav cds--side-nav--fixed"
+ >
@for (item of items; track item.label) {
- <cds-sidenav-item
- [route]="item.route"
- [routeExtras]="item.routeExtras"
- [useRouter]="true"
- [routerLinkActiveOptions]="item.routerLinkActiveOptions || { exact: false }">
- <span class="cds--type-heading-compact-01">{{ item.label }}</span>
- </cds-sidenav-item>
+ <cds-sidenav-item
+ [route]="item.route"
+ [routeExtras]="item.routeExtras"
+ [useRouter]="true"
+ [routerLinkActiveOptions]="item.routerLinkActiveOptions || { exact: false }"
+ >
+ <span class="cds--type-heading-compact-01">{{ item.label }}</span>
+ </cds-sidenav-item>
}
</cds-sidenav>
-<div class="chart-container"
- [ngStyle]="style">
- <canvas baseChart
- #sparkCanvas
- [data]="chartData"
- [options]="options"
- [type]="'line'">
+<div
+ class="chart-container"
+ [ngStyle]="style"
+>
+ <canvas
+ baseChart
+ #sparkCanvas
+ [data]="chartData"
+ [options]="options"
+ [type]="'line'"
+ >
</canvas>
- <div class="chartjs-tooltip"
- #sparkTooltip>
+ <div
+ class="chartjs-tooltip"
+ #sparkTooltip
+ >
<table></table>
</div>
</div>
-<button [type]="type"
- class="tc_submitButton"
- [ngClass]="{'w-100': modalForm}"
- [disabled]="loading || disabled"
- (click)="submit($event)"
- [attr.aria-label]="ariaLabel"
- size="lg"
- [cdsButton]="buttonType"
- modal-primary-focus>
+<button
+ [type]="type"
+ class="tc_submitButton"
+ [ngClass]="{ 'w-100': modalForm }"
+ [disabled]="loading || disabled"
+ (click)="submit($event)"
+ [attr.aria-label]="ariaLabel"
+ size="lg"
+ [cdsButton]="buttonType"
+ modal-primary-focus
+>
<ng-content></ng-content>
- <cds-loading [isActive]="loading"
- [overlay]="false"
- size="sm"
- *ngIf="loading"></cds-loading>
+ <cds-loading
+ [isActive]="loading"
+ [overlay]="false"
+ size="sm"
+ *ngIf="loading"
+ ></cds-loading>
</button>
<!-- Full Tearsheet -->
- @if(type === 'full') {
-<div
- cdsGrid
- class="tearsheet--full"
- [useCssGrid]="true"
- [fullWidth]="true">
- <div cdsCol
- class="tearsheet-cols--full"
- [columnNumbers]="{'lg': 16, 'md': 16, 'sm': 16}">
- <!-- Tearsheet Header -->
- <header
- class="tearsheet-header tearsheet-header--full border-subtle-block-end">
- <h4 class="cds--type-heading-04 tearsheet-header-title">
- {{title}}
- </h4>
- <p class="cds--type-body-02 tearsheet-header-description">
- {{description}}
- </p>
- </header>
- <section cdsGrid
- class="tearsheet-body"
- [useCssGrid]="true"
- [fullWidth]="true">
- <!-- Tearsheet Influencer-->
- <div cdsCol
- [columnNumbers]="{'lg': 3, 'md': 3, 'sm': 3}"
- class="tearsheet-left-influencer border-subtle-inline-end">
- <cds-progress-indicator
- orientation="vertical"
- [steps]="steps"
- [current]="currentStep"
- spacing="equal"
- (stepSelected)="onStepSelect($event)">
- </cds-progress-indicator>
- </div>
- <div cdsCol
- [columnNumbers]="{'lg': 13, 'md': 13, 'sm': 13}"
- class="tearsheet-main">
- <!-- Tearsheet Content Area -->
- <div class="tearsheet-content tearsheet-content--full"
- [ngStyle]="contentOverflowStyle">
- <ng-container
- *ngTemplateOutlet="activeStepTemplate">
- </ng-container>
- </div>
- <!-- Tearsheet Footer -->
- <cds-modal-footer class="tearsheet-footer tearsheet-footer--full border-subtle-top">
- <button cdsButton="ghost"
- class="tearsheet-footer-cancel"
- (click)="closeTearsheet()"
- size="xl"
- type="button"
- i18n>Cancel</button>
- @if (steps.length > 1) {
- <button cdsButton="secondary"
- size="xl"
- [disabled]="currentStep === 0"
- (click)="onPrevious()"
- type="button"
- i18n>Previous</button>
- }
- @if (currentStep === lastStep) {
- <button cdsButton="primary"
- size="xl"
- class="tearsheet-footer-submit"
- [disabled]="isSubmitLoading"
- (click)="onSubmit()"
- type="button"
- i18n>
- @if (isSubmitLoading) {
- <cds-loading
- [isActive]="isSubmitLoading"
- [overlay]="false"
- size="sm">
- </cds-loading>
- {{submitButtonLoadingLabel}}...
- }
- @else {
- {{submitButtonLabel}}
- }
- </button>
- }
- @else {
- <button cdsButton="primary"
- size="xl"
- [disabled]="steps[currentStep]?.invalid"
- type="button"
- (click)="onNext()"
- i18n>Next</button>
- }
- </cds-modal-footer>
- </div>
- </section>
- </div>
-</div>
-}
-@else {
-<!-- Wide Tearsheet -->
-<cds-modal
- [size]="size"
- [open]="isOpen"
- (overlaySelected)="closeTearsheet()">
- <!-- Tearsheet Header -->
- <header
- class="tearsheet-header border-subtle-block-end">
- <h4 cdsModalHeaderHeading
- class="cds--type-heading-04 tearsheet-header-title">
- {{title}}
- </h4>
- <p class="cds--type-body-02 tearsheet-header-description">
- {{description}}
- </p>
- </header>
- <section cdsGrid
- class="tearsheet-body"
- [condensed]="true"
- [useCssGrid]="true"
- [fullWidth]="true">
- <!-- Tearsheet Left Influencer-->
- @if (steps.length > 1) {
- <div cdsCol
- [columnNumbers]="{lg: 3, md: 3, sm: 3}"
- class="tearsheet-left-influencer border-subtle-inline-end">
- <cds-progress-indicator
- orientation="vertical"
- [steps]="steps"
- [current]="currentStep"
- spacing="equal"
- (stepSelected)="onStepSelect($event)">
- </cds-progress-indicator>
- </div>
- }
- <div cdsCol
- [columnNumbers]="steps.length > 1 ? {lg: 13, md: 13, sm: 13} : {lg: 16, md: 16, sm: 16}"
- class="tearsheet-main">
- @if (showRightInfluencer) {
- <!-- Tearsheet content with right influencer -->
- <div
+@if (type === 'full') {
+ <div
+ cdsGrid
+ class="tearsheet--full"
+ [useCssGrid]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ class="tearsheet-cols--full"
+ [columnNumbers]="{ lg: 16, md: 16, sm: 16 }"
+ >
+ <!-- Tearsheet Header -->
+ <header class="tearsheet-header tearsheet-header--full border-subtle-block-end">
+ <h4 class="cds--type-heading-04 tearsheet-header-title">
+ {{ title }}
+ </h4>
+ <p class="cds--type-body-02 tearsheet-header-description">
+ {{ description }}
+ </p>
+ </header>
+ <section
cdsGrid
- [condensed]="true"
+ class="tearsheet-body"
[useCssGrid]="true"
- [fullWidth]="true">
+ [fullWidth]="true"
+ >
+ <!-- Tearsheet Influencer-->
<div
cdsCol
- class="tearsheet-content"
- [columnNumbers]="{ lg: 10 }"
- [ngStyle]="contentOverflowStyle">
- <ng-container *ngTemplateOutlet="activeStepTemplate"></ng-container>
+ [columnNumbers]="{ lg: 3, md: 3, sm: 3 }"
+ class="tearsheet-left-influencer border-subtle-inline-end"
+ >
+ <cds-progress-indicator
+ orientation="vertical"
+ [steps]="steps"
+ [current]="currentStep"
+ spacing="equal"
+ (stepSelected)="onStepSelect($event)"
+ >
+ </cds-progress-indicator>
</div>
- <aside
+ <div
cdsCol
- [columnNumbers]="{ lg: 3 }"
- class="tearsheet-right-influencer">
- <ng-container *ngTemplateOutlet="rightInfluencerTemplate"></ng-container>
- </aside>
- </div>
- }
- @else {
- <!-- Tearsheet content without right influencer -->
- <div class="tearsheet-content"
- [ngStyle]="contentOverflowStyle">
- <ng-container *ngTemplateOutlet="activeStepTemplate"></ng-container>
- </div>
- }
- <!-- Tearsheet Footer -->
- <cds-modal-footer class="tearsheet-footer border-subtle-top">
- <button cdsButton="ghost"
- (click)="closeTearsheet()"
- size="xl"
+ [columnNumbers]="{ lg: 13, md: 13, sm: 13 }"
+ class="tearsheet-main"
+ >
+ <!-- Tearsheet Content Area -->
+ <div
+ class="tearsheet-content tearsheet-content--full"
+ [ngStyle]="contentOverflowStyle"
+ >
+ <ng-container *ngTemplateOutlet="activeStepTemplate"> </ng-container>
+ </div>
+ <!-- Tearsheet Footer -->
+ <cds-modal-footer class="tearsheet-footer tearsheet-footer--full border-subtle-top">
+ <button
+ type="button"
+ cdsButton="ghost"
+ class="tearsheet-footer-cancel"
+ (click)="closeTearsheet()"
+ size="xl"
+ i18n
+ >
+ Cancel
+ </button>
+ @if (steps.length > 1) {
+ <button
type="button"
- i18n>Cancel</button>
- @if (steps.length > 1) {
- <button cdsButton="secondary"
+ cdsButton="secondary"
size="xl"
[disabled]="currentStep === 0"
(click)="onPrevious()"
+ i18n
+ >
+ Previous
+ </button>
+ }
+ @if (currentStep === lastStep) {
+ <button
type="button"
- i18n>Previous</button>
- }
- @if (currentStep === lastStep) {
- <button cdsButton="primary"
+ cdsButton="primary"
size="xl"
class="tearsheet-footer-submit"
[disabled]="isSubmitLoading"
(click)="onSubmit()"
+ i18n
+ >
+ @if (isSubmitLoading) {
+ <cds-loading
+ [isActive]="isSubmitLoading"
+ [overlay]="false"
+ size="sm"
+ >
+ </cds-loading>
+ {{ submitButtonLoadingLabel }}...
+ } @else {
+ {{ submitButtonLabel }}
+ }
+ </button>
+ } @else {
+ <button
type="button"
- i18n>
- @if (isSubmitLoading) {
- <cds-loading
- [isActive]="isSubmitLoading"
- [overlay]="false"
- size="sm">
- </cds-loading>
- {{submitButtonLoadingLabel}}...
- }
- @else {
- {{submitButtonLabel}}
- }
- </button>
- }
- @else {
- <button cdsButton="primary"
+ cdsButton="primary"
size="xl"
[disabled]="steps[currentStep]?.invalid"
(click)="onNext()"
- type="button"
- i18n>Next</button>
- }
- </cds-modal-footer>
+ i18n
+ >
+ Next
+ </button>
+ }
+ </cds-modal-footer>
+ </div>
+ </section>
</div>
- </section>
-</cds-modal>
+ </div>
+} @else {
+ <!-- Wide Tearsheet -->
+ <cds-modal
+ [size]="size"
+ [open]="isOpen"
+ (overlaySelected)="closeTearsheet()"
+ >
+ <!-- Tearsheet Header -->
+ <header class="tearsheet-header border-subtle-block-end">
+ <h4
+ cdsModalHeaderHeading
+ class="cds--type-heading-04 tearsheet-header-title"
+ >
+ {{ title }}
+ </h4>
+ <p class="cds--type-body-02 tearsheet-header-description">
+ {{ description }}
+ </p>
+ </header>
+ <section
+ cdsGrid
+ class="tearsheet-body"
+ [condensed]="true"
+ [useCssGrid]="true"
+ [fullWidth]="true"
+ >
+ <!-- Tearsheet Left Influencer-->
+ @if (steps.length > 1) {
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 3, md: 3, sm: 3 }"
+ class="tearsheet-left-influencer border-subtle-inline-end"
+ >
+ <cds-progress-indicator
+ orientation="vertical"
+ [steps]="steps"
+ [current]="currentStep"
+ spacing="equal"
+ (stepSelected)="onStepSelect($event)"
+ >
+ </cds-progress-indicator>
+ </div>
+ }
+ <div
+ cdsCol
+ [columnNumbers]="steps.length > 1 ? { lg: 13, md: 13, sm: 13 } : { lg: 16, md: 16, sm: 16 }"
+ class="tearsheet-main"
+ >
+ @if (showRightInfluencer) {
+ <!-- Tearsheet content with right influencer -->
+ <div
+ cdsGrid
+ [condensed]="true"
+ [useCssGrid]="true"
+ [fullWidth]="true"
+ >
+ <div
+ cdsCol
+ class="tearsheet-content"
+ [columnNumbers]="{ lg: 10 }"
+ [ngStyle]="contentOverflowStyle"
+ >
+ <ng-container *ngTemplateOutlet="activeStepTemplate"></ng-container>
+ </div>
+ <aside
+ cdsCol
+ [columnNumbers]="{ lg: 3 }"
+ class="tearsheet-right-influencer"
+ >
+ <ng-container *ngTemplateOutlet="rightInfluencerTemplate"></ng-container>
+ </aside>
+ </div>
+ } @else {
+ <!-- Tearsheet content without right influencer -->
+ <div
+ class="tearsheet-content"
+ [ngStyle]="contentOverflowStyle"
+ >
+ <ng-container *ngTemplateOutlet="activeStepTemplate"></ng-container>
+ </div>
+ }
+ <!-- Tearsheet Footer -->
+ <cds-modal-footer class="tearsheet-footer border-subtle-top">
+ <button
+ type="button"
+ cdsButton="ghost"
+ (click)="closeTearsheet()"
+ size="xl"
+ i18n
+ >
+ Cancel
+ </button>
+ @if (steps.length > 1) {
+ <button
+ type="button"
+ cdsButton="secondary"
+ size="xl"
+ [disabled]="currentStep === 0"
+ (click)="onPrevious()"
+ i18n
+ >
+ Previous
+ </button>
+ }
+ @if (currentStep === lastStep) {
+ <button
+ type="button"
+ cdsButton="primary"
+ size="xl"
+ class="tearsheet-footer-submit"
+ [disabled]="isSubmitLoading"
+ (click)="onSubmit()"
+ i18n
+ >
+ @if (isSubmitLoading) {
+ <cds-loading
+ [isActive]="isSubmitLoading"
+ [overlay]="false"
+ size="sm"
+ >
+ </cds-loading>
+ {{ submitButtonLoadingLabel }}...
+ } @else {
+ {{ submitButtonLabel }}
+ }
+ </button>
+ } @else {
+ <button
+ type="button"
+ cdsButton="primary"
+ size="xl"
+ [disabled]="steps[currentStep]?.invalid"
+ (click)="onNext()"
+ i18n
+ >
+ Next
+ </button>
+ }
+ </cds-modal-footer>
+ </div>
+ </section>
+ </cds-modal>
}
-<cd-alert-panel *ngIf="displayNotification"
- class="no-margin-bottom"
- [showTitle]="false"
- size="slim"
- [type]="notificationSeverity"
- [dismissible]="notificationSeverity !== 'danger'"
- [actionName]="'Configure Telemetry'"
- (action)="onConfigure()"
- (dismissed)="onDismissed()">
- <span i18n>Activate
- <a href="https://docs.ceph.com/en/latest/mgr/telemetry/"
- target="_blank"
- rel="noopener"> Telemetry
- </a>: The Ceph community welcomes your support in enhancing our efforts. Please activate the telemetry module.
+<cd-alert-panel
+ *ngIf="displayNotification"
+ class="no-margin-bottom"
+ [showTitle]="false"
+ size="slim"
+ [type]="notificationSeverity"
+ [dismissible]="notificationSeverity !== 'danger'"
+ [actionName]="'Configure Telemetry'"
+ (action)="onConfigure()"
+ (dismissed)="onDismissed()"
+>
+ <span i18n
+ >Activate
+ <a
+ href="https://docs.ceph.com/en/latest/mgr/telemetry/"
+ target="_blank"
+ rel="noopener"
+ >
+ Telemetry </a
+ >: The Ceph community welcomes your support in enhancing our efforts. Please activate the
+ telemetry module.
</span>
</cd-alert-panel>
@for (value of values; track $index) {
- <cds-text-label [helperText]="helperText && $index === values.length - 1 ? helperText : null"
- i18n-helperText
- i18n>
+ <cds-text-label
+ [helperText]="helperText && $index === values.length - 1 ? helperText : null"
+ i18n-helperText
+ i18n
+ >
<div class="cds-input-group">
- <input cdsText
- type="text"
- [placeholder]="placeholder"
- [value]="value"
- (input)="onInputChange($index, $event.target.value)" />
- @if ($index > 0 ) {
- <cds-icon-button kind="ghost"
- (click)="deleteInput($index)"
- size="md">
- <cd-icon type="trash"></cd-icon>
- </cds-icon-button>
+ <input
+ cdsText
+ type="text"
+ [placeholder]="placeholder"
+ [value]="value"
+ (input)="onInputChange($index, $event.target.value)"
+ />
+ @if ($index > 0) {
+ <cds-icon-button
+ kind="ghost"
+ (click)="deleteInput($index)"
+ size="md"
+ >
+ <cd-icon type="trash"></cd-icon>
+ </cds-icon-button>
}
</div>
- {{$index === 0 ? label : ''}}
+ {{ $index === 0 ? label : '' }}
</cds-text-label>
}
[inline]="true"
class="timepicker-dropdown"
[label]="label"
- i18n>
+ i18n
+>
<cds-dropdown-list [items]="timeOptions"></cds-dropdown-list>
</cds-dropdown>
<div *ngIf="upgradeStatus$ | async as status; else isUpgradable">
<ng-container *ngIf="status.is_paused || status.in_progress; else isUpgradable">
- <h5 *ngIf="status.is_paused; else inProgress"
- i18n>
+ <h5
+ *ngIf="status.is_paused; else inProgress"
+ i18n
+ >
Upgrade is paused
</h5>
<ng-template #inProgress>
- <a href="#/upgrade/progress"
- i18n>
+ <a
+ href="#/upgrade/progress"
+ i18n
+ >
<cds-inline-loading></cds-inline-loading>
- Upgrading {{executingTask?.progress}}%
+ Upgrading {{ executingTask?.progress }}%
</a>
</ng-template>
</ng-container>
</div>
<ng-template #isUpgradable>
- <div *ngIf="upgradeInfo$ | async as info"
- i18n>
- <h5 *ngIf="info.versions.length > 0"
- (click)="upgradeModal()"
- tabindex="0"
- (keydown.enter)="upgradeModal()">
+ <div
+ *ngIf="upgradeInfo$ | async as info"
+ i18n
+ >
+ <h5
+ *ngIf="info.versions.length > 0"
+ (click)="upgradeModal()"
+ tabindex="0"
+ (keydown.enter)="upgradeModal()"
+ >
<i [ngClass]="icons.up"></i>
Upgrade available
</h5>
<ng-container i18n>{{ customLabel }}</ng-container>
</ng-template>
</ng-container>
-<ibm-meter-chart *ngIf="used >=0 && total > 0; else noDataFound"
- [data]="data"
- [options]="options">
+<ibm-meter-chart
+ *ngIf="used >= 0 && total > 0; else noDataFound"
+ [data]="data"
+ [options]="options"
+>
</ibm-meter-chart>
<ng-template #noDataFound>
- <span i18n>{{noDataText}}</span>
+ <span i18n>{{ noDataText }}</span>
</ng-template>
<ng-container *ngIf="items.length">
- <h3 i18n
- *ngIf="title">{{title}}</h3>
- <input type="text"
- placeholder="Filter by name..."
- (keyup)="updateFilter()"
- [id]="inputIdentifier"
- class="form-control text-center mb-2">
+ <h3
+ i18n
+ *ngIf="title"
+ >
+ {{ title }}
+ </h3>
+ <input
+ type="text"
+ placeholder="Filter by name..."
+ (keyup)="updateFilter()"
+ [id]="inputIdentifier"
+ class="form-control text-center mb-2"
+ />
<div class="overflow-auto">
<ul class="nav flex-column nav-pills">
- <li class="nav-item"
- *ngFor="let item of filteredItems; trackBy: trackByFn">
- <a class="nav-link"
- [class.active]="!activeItem"
- (click)="selectItem()"
- tabindex="0"
- (keydown.enter)="selectItem()"
- *ngIf="item === ''">_nogroup</a>
- <a class="nav-link text-decoration-none text-break"
- [class.active]="item === activeItem"
- (click)="selectItem(item)"
- tabindex="0"
- (keydown.enter)="selectItem(item)"
- *ngIf="item !== ''">{{item}}</a>
+ <li
+ class="nav-item"
+ *ngFor="let item of filteredItems; trackBy: trackByFn"
+ >
+ <a
+ class="nav-link"
+ [class.active]="!activeItem"
+ (click)="selectItem()"
+ tabindex="0"
+ (keydown.enter)="selectItem()"
+ *ngIf="item === ''"
+ >_nogroup</a
+ >
+ <a
+ class="nav-link text-decoration-none text-break"
+ [class.active]="item === activeItem"
+ (click)="selectItem(item)"
+ tabindex="0"
+ (keydown.enter)="selectItem(item)"
+ *ngIf="item !== ''"
+ >{{ item }}</a
+ >
</li>
</ul>
</div>
<cds-progress-indicator
orientation="vertical"
[steps]="stepsTitle"
- [current]="currentStep?.stepIndex">
+ [current]="currentStep?.stepIndex"
+ >
</cds-progress-indicator>
</div>
-<cd-table [data]="data"
- [columns]="columns"
- columnMode="flex"
- [toolHeader]="false"
- [autoReload]="false"
- [autoSave]="false"
- [footer]="false"
- size="xs"
- [layer]="0"
- [limit]="0">
+<cd-table
+ [data]="data"
+ [columns]="columns"
+ columnMode="flex"
+ [toolHeader]="false"
+ [autoReload]="false"
+ [autoSave]="false"
+ [footer]="false"
+ size="xs"
+ [layer]="0"
+ [limit]="0"
+>
</cd-table>
-<ng-template #cellScopeCheckboxTpl
- let-column="data.column"
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #cellScopeCheckboxTpl
+ let-column="data.column"
+ let-row="data.row"
+ let-value="data.value"
+>
<div class="m-2">
- <cds-checkbox id="scope_{{ row.scope }}"
- [checked]="isRowChecked(row.scope)"
- [disabled]="isDisabled"
- (checkedChange)="onClickCellCheckbox(row.scope, column.prop, $event)"
- i18n>
- <span class="datatable-permissions-scope-cell-label custom-control-label"
- for="scope_{{ row.scope }}">{{ value }}</span>
+ <cds-checkbox
+ id="scope_{{ row.scope }}"
+ [checked]="isRowChecked(row.scope)"
+ [disabled]="isDisabled"
+ (checkedChange)="onClickCellCheckbox(row.scope, column.prop, $event)"
+ i18n
+ >
+ <span
+ class="datatable-permissions-scope-cell-label custom-control-label"
+ for="scope_{{ row.scope }}"
+ >{{ value }}</span
+ >
</cds-checkbox>
</div>
</ng-template>
-<ng-template #cellPermissionCheckboxTpl
- let-column="data.column"
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #cellPermissionCheckboxTpl
+ let-column="data.column"
+ let-row="data.row"
+ let-value="data.value"
+>
<div class="m-2">
- <cds-checkbox [id]="row.scope + '-' + column.prop"
- [checked]="value"
- [disabled]="isDisabled"
- (checkedChange)="onClickCellCheckbox(row.scope, column.prop, $event)"
- i18n>
- <span class="custom-control-label"
- [for]="row.scope + '-' + column.prop"></span>
+ <cds-checkbox
+ [id]="row.scope + '-' + column.prop"
+ [checked]="value"
+ [disabled]="isDisabled"
+ (checkedChange)="onClickCellCheckbox(row.scope, column.prop, $event)"
+ i18n
+ >
+ <span
+ class="custom-control-label"
+ [for]="row.scope + '-' + column.prop"
+ ></span>
</cds-checkbox>
</div>
</ng-template>
-<ng-template #headerPermissionCheckboxTpl
- let-column="data">
+<ng-template
+ #headerPermissionCheckboxTpl
+ let-column="data"
+>
<div class="m-2">
- <cds-checkbox id="header_{{ column.prop }}"
- [disabled]="isDisabled"
- [checked]="isHeaderChecked(column.prop)"
- (checkedChange)="onClickHeaderCheckbox(column.prop, $event)"
- i18n>
- <span class="datatable-permissions-header-cell-label custom-control-label"
- for="header_{{ column.prop }}">{{ column.name }}</span>
+ <cds-checkbox
+ id="header_{{ column.prop }}"
+ [disabled]="isDisabled"
+ [checked]="isHeaderChecked(column.prop)"
+ (checkedChange)="onClickHeaderCheckbox(column.prop, $event)"
+ i18n
+ >
+ <span
+ class="datatable-permissions-header-cell-label custom-control-label"
+ for="header_{{ column.prop }}"
+ >{{ column.name }}</span
+ >
</cds-checkbox>
</div>
</ng-template>
-<ul class="nav nav-tabs"
- *ngIf="tabs">
- <li class="nav-item"
- *ngFor="let tab of tabs; keyvalue">
- <a class="nav-link"
- [routerLink]="tab.url"
- routerLinkActive="active"
- ariaCurrentWhenActive="page"
- [routerLinkActiveOptions]="{exact: true}"
- i18n>{{tab.name}}</a>
+<ul
+ class="nav nav-tabs"
+ *ngIf="tabs"
+>
+ <li
+ class="nav-item"
+ *ngFor="let tab of tabs; keyvalue"
+ >
+ <a
+ class="nav-link"
+ [routerLink]="tab.url"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ [routerLinkActiveOptions]="{ exact: true }"
+ i18n
+ >{{ tab.name }}</a
+ >
</li>
</ul>
<ng-container *ngIf="meta">
<cd-table
- [data]="data$ | async"
- [columns]="meta.table.columns"
- [columnMode]="meta.table.columnMode"
- (setExpandedRow)="setExpandedRow($event)"
- [hasDetails]="meta.detail_columns.length > 0"
- [selectionType]="meta.table.selectionType"
- (updateSelection)="updateSelection($event)"
- [toolHeader]="meta.table.toolHeader">
+ [data]="data$ | async"
+ [columns]="meta.table.columns"
+ [columnMode]="meta.table.columnMode"
+ (setExpandedRow)="setExpandedRow($event)"
+ [hasDetails]="meta.detail_columns.length > 0"
+ [selectionType]="meta.table.selectionType"
+ (updateSelection)="updateSelection($event)"
+ [toolHeader]="meta.table.toolHeader"
+ >
<div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- id="crud-table-actions"
- [tableActions]="meta.actions">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ id="crud-table-actions"
+ [tableActions]="meta.actions"
+ >
</cd-table-actions>
</div>
<ng-container *ngIf="expandedRow && meta.detail_columns.length > 0">
- <table *cdTableDetail
- class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
+ <table
+ *cdTableDetail
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ >
<tbody>
<tr *ngFor="let column of meta.detail_columns">
- <td i18n
- class="bold">{{ column }}</td>
- <td><pre>{{ expandedRow[column] }}</pre></td>
+ <td
+ i18n
+ class="bold"
+ >
+ {{ column }}
+ </td>
+ <td>
+ <pre>{{ expandedRow[column] }}</pre>
+ </td>
</tr>
</tbody>
</table>
</ng-container>
-
</cd-table>
</ng-container>
-<ng-template #tagDictTpl
- let-value="data.value">
+<ng-template
+ #tagDictTpl
+ let-value="data.value"
+>
<span *ngFor="let instance of value | keyvalue; last as isLast">
- <cds-tag class="tag-background-primary" >{{ instance.key }}: {{ instance.value }}</cds-tag>
+ <cds-tag class="tag-background-primary">{{ instance.key }}: {{ instance.value }}</cds-tag>
<ng-container *ngIf="!isLast"> </ng-container>
</span>
</ng-template>
-<ng-template #dateTpl
- let-value="data.value">
+<ng-template
+ #dateTpl
+ let-value="data.value"
+>
<span>{{ value | cdDate }}</span>
</ng-template>
-<ng-template #durationTpl
- let-value="data.value">
+<ng-template
+ #durationTpl
+ let-value="data.value"
+>
<span>{{ value | duration }}</span>
</ng-template>
<ng-template #exportDataModalTpl>
<div class="d-flex flex-column align-items-center w-100 gap-3">
- <textarea readonly
- class="form-control w-100 bg-light height-400"
- id="authExportArea">{{ modalState.authExportData }}</textarea>
- <cd-copy-2-clipboard-button class="align-self-end"
- source="authExportArea">
-
+ <textarea
+ readonly
+ class="form-control w-100 bg-light height-400"
+ id="authExportArea"
+ >{{ modalState.authExportData }}</textarea>
+ <cd-copy-2-clipboard-button
+ class="align-self-end"
+ source="authExportArea"
+ >
</cd-copy-2-clipboard-button>
</div>
</ng-template>
<ng-container *ngIf="!dropDownOnly; else dropDownOnlyTpl">
- <button *ngIf="currentAction && tableActions.length > 0"
- type="button"
- [cdsButton]="currentAction.buttonKind"
- title="{{ useDisableDesc(currentAction) }}"
- (click)="useClickAction(currentAction)"
- [disabled]="disableSelectionAction(currentAction)"
- [routerLink]="useRouterLink(currentAction)"
- [attr.aria-label]="currentAction.name"
- [preserveFragment]="currentAction.preserveFragment ? '' : null"
- data-testid="primary-action">
+ <button
+ *ngIf="currentAction && tableActions.length > 0"
+ type="button"
+ [cdsButton]="currentAction.buttonKind"
+ title="{{ useDisableDesc(currentAction) }}"
+ (click)="useClickAction(currentAction)"
+ [disabled]="disableSelectionAction(currentAction)"
+ [routerLink]="useRouterLink(currentAction)"
+ [attr.aria-label]="currentAction.name"
+ [preserveFragment]="currentAction.preserveFragment ? '' : null"
+ data-testid="primary-action"
+ >
<span i18n>{{ currentAction.name }}</span>
- <svg class="cds--btn__icon"
- cdsIcon="add"
- size="16"></svg>
+ <svg
+ class="cds--btn__icon"
+ cdsIcon="add"
+ size="16"
+ ></svg>
</button>
<ng-container *ngIf="primaryDropDown">
- <button class="primary-dropdown-btn"
- [attr.aria-label]="dropDownOnly"
- [offset]="{ x: -210, y: 65 }"
- [cdsOverflowMenu]="overflowMenuTpl"
- data-testid="table-action-btn"
- type="button">
- <svg
- [cdsIcon]="icons.chevronDown"></svg>
+ <button
+ class="primary-dropdown-btn"
+ [attr.aria-label]="dropDownOnly"
+ [offset]="{ x: -210, y: 65 }"
+ [cdsOverflowMenu]="overflowMenuTpl"
+ data-testid="table-action-btn"
+ type="button"
+ >
+ <svg [cdsIcon]="icons.chevronDown"></svg>
</button>
<ng-template #overflowMenuTpl>
<ng-container *ngFor="let action of dropDownActions">
- <cds-overflow-menu-option *ngIf="currentAction !== action"
- class="{{ toClassName(action) }}"
- title="{{ useDisableDesc(action) }}"
- (click)="useClickAction(action)"
- [routerLink]="useRouterLink(action)"
- [preserveFragment]="action.preserveFragment ? '' : null"
- [disabled]="disableSelectionAction(action)"
- [attr.aria-label]="action.name"
- data-testid="table-action-option-btn"
- i18n>
- {{ action.name }}
+ <cds-overflow-menu-option
+ *ngIf="currentAction !== action"
+ class="{{ toClassName(action) }}"
+ title="{{ useDisableDesc(action) }}"
+ (click)="useClickAction(action)"
+ [routerLink]="useRouterLink(action)"
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ [disabled]="disableSelectionAction(action)"
+ [attr.aria-label]="action.name"
+ data-testid="table-action-option-btn"
+ i18n
+ >
+ {{ action.name }}
</cds-overflow-menu-option>
</ng-container>
</ng-template>
</ng-container>
<ng-template #caret>
- <button [cdsButton]="currentAction.buttonKind"
- class="caret-btn"
- type="button">
- <svg class="cds--btn__icon"
- [cdsIcon]="icons.chevronDown"></svg>
+ <button
+ [cdsButton]="currentAction.buttonKind"
+ class="caret-btn"
+ type="button"
+ >
+ <svg
+ class="cds--btn__icon"
+ [cdsIcon]="icons.chevronDown"
+ ></svg>
</button>
</ng-template>
<ng-template #dropDownOnlyTpl>
- <cds-overflow-menu [customTrigger]="customTrigger"
- [flip]="true"
- [offset]="dropDownOnlyOffset"
- data-testid="table-action-btn"
- class="d-flex justify-content-end">
+ <cds-overflow-menu
+ [customTrigger]="customTrigger"
+ [flip]="true"
+ [offset]="dropDownOnlyOffset"
+ data-testid="table-action-btn"
+ class="d-flex justify-content-end"
+ >
<ng-container *ngFor="let action of dropDownActions">
- <cds-overflow-menu-option *ngIf="currentAction !== action"
- class="{{ toClassName(action) }}"
- title="{{ useDisableDesc(action) }}"
- (click)="useClickAction(action)"
- [routerLink]="useRouterLink(action)"
- [preserveFragment]="action.preserveFragment ? '' : null"
- [disabled]="disableSelectionAction(action)"
- [attr.aria-label]="action.name"
- data-testid="table-action-option-btn"
- i18n>
- {{ action.name }}
+ <cds-overflow-menu-option
+ *ngIf="currentAction !== action"
+ class="{{ toClassName(action) }}"
+ title="{{ useDisableDesc(action) }}"
+ (click)="useClickAction(action)"
+ [routerLink]="useRouterLink(action)"
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ [disabled]="disableSelectionAction(action)"
+ [attr.aria-label]="action.name"
+ data-testid="table-action-option-btn"
+ i18n
+ >
+ {{ action.name }}
</cds-overflow-menu-option>
</ng-container>
</cds-overflow-menu>
</ng-template>
<ng-template #customTrigger>
- <button [cdsButton]="dropDownOnlyBtnColor"
- type="button">
+ <button
+ [cdsButton]="dropDownOnlyBtnColor"
+ type="button"
+ >
<span i18n>{{ dropDownOnly }}</span>
- <svg class="override-position-static cds--btn__icon"
- [cdsIcon]="icons.chevronDown"></svg>
+ <svg
+ class="override-position-static cds--btn__icon"
+ [cdsIcon]="icons.chevronDown"
+ ></svg>
</button>
</ng-template>
<div class="key-value-table">
- <cd-table #table
- [data]="tableData || []"
- [columns]="columns"
- columnMode="flex"
- [toolHeader]="false"
- [autoReload]="autoReload"
- [customCss]="customCss"
- [autoSave]="false"
- [header]="false"
- [footer]="false"
- [limit]="0">
+ <cd-table
+ #table
+ [data]="tableData || []"
+ [columns]="columns"
+ columnMode="flex"
+ [toolHeader]="false"
+ [autoReload]="autoReload"
+ [customCss]="customCss"
+ [autoSave]="false"
+ [header]="false"
+ [footer]="false"
+ [limit]="0"
+ >
</cd-table>
</div>
-<ng-template #valueCellTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #valueCellTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<span
class="pre-wrap"
*ngIf="row.key in multilineTextKeys; else normalText"
- >{{ value }}</span>
+ >{{ value }}</span
+ >
<ng-template #normalText>
<span>{{ value }}</span>
</ng-template>
-<nav class="pagination"
- aria-label="Pagination"
- i18n-aria-label>
+<nav
+ class="pagination"
+ aria-label="Pagination"
+ i18n-aria-label
+>
<button
class="pagination__btn pagination__btn_first"
aria-label="Go to first page"
-<cds-table-container [cdsLayer]="layer"
- [cdsTheme]="theme"
- class="content-theme">
+<cds-table-container
+ [cdsLayer]="layer"
+ [cdsTheme]="theme"
+ class="content-theme"
+>
<cds-table-header *ngIf="headerTitle">
- <h4 cdsTableHeaderTitle
- i18n>
+ <h4
+ cdsTableHeaderTitle
+ i18n
+ >
@if (isHeaderTitleString) {
{{ headerTitle }}
- } @else {
- <ng-container *ngTemplateOutlet="headerTitle"></ng-container>
- }
+ } @else {
+ <ng-container *ngTemplateOutlet="headerTitle"></ng-container>
+ }
</h4>
- <p cdsTableHeaderDescription
- i18n
- *ngIf="headerDescription">
- {{headerDescription}}
+ <p
+ cdsTableHeaderDescription
+ i18n
+ *ngIf="headerDescription"
+ >
+ {{ headerDescription }}
</p>
</cds-table-header>
- <cds-table-toolbar #toolbar
- *ngIf="toolHeader"
- (cancel)="onBatchActionsCancel()"
- [model]="selectionType === 'multiClick' ? model : []"
- [batchText]="{ SINGLE: '1 item selected', MULTIPLE: '{{count}} items selected' }">
+ <cds-table-toolbar
+ #toolbar
+ *ngIf="toolHeader"
+ (cancel)="onBatchActionsCancel()"
+ [model]="selectionType === 'multiClick' ? model : []"
+ [batchText]="{ SINGLE: '1 item selected', MULTIPLE: '{{count}} items selected' }"
+ >
<!-- batch actions -->
<cds-table-toolbar-actions *ngIf="tableActions?.dropDownActions.length > 0">
<ng-container *ngFor="let action of tableActions?.dropDownActions">
- <button *ngIf="tableActions.currentAction !== action"
- cdsButton="primary"
- [tabindex]="toolbar.selected ? 0 : -1"
- class="{{ tableActions.toClassName(action) }}"
- title="{{ tableActions.useDisableDesc(action) }}"
- (click)="tableActions.useClickAction(action)"
- [routerLink]="tableActions.useRouterLink(action)"
- [preserveFragment]="action.preserveFragment ? '' : null"
- [disabled]="tableActions.disableSelectionAction(action)"
- [attr.aria-label]="action.name"
- type="button"
- i18n>
+ <button
+ *ngIf="tableActions.currentAction !== action"
+ cdsButton="primary"
+ [tabindex]="toolbar.selected ? 0 : -1"
+ class="{{ tableActions.toClassName(action) }}"
+ title="{{ tableActions.useDisableDesc(action) }}"
+ (click)="tableActions.useClickAction(action)"
+ [routerLink]="tableActions.useRouterLink(action)"
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ [disabled]="tableActions.disableSelectionAction(action)"
+ [attr.aria-label]="action.name"
+ type="button"
+ i18n
+ >
{{ action.name }}
</button>
</ng-container>
<ng-content select=".table-filter"></ng-content>
<!-- end custom filter slot -->
<!-- search -->
- <cds-table-toolbar-search *ngIf="searchField"
- [expandable]="false"
- [(ngModel)]="search"
- aria-label="search"
- (valueChange)="updateFilter($event)"
- (clear)="onClearSearch()">
+ <cds-table-toolbar-search
+ *ngIf="searchField"
+ [expandable]="false"
+ [(ngModel)]="search"
+ aria-label="search"
+ (valueChange)="updateFilter($event)"
+ (clear)="onClearSearch()"
+ >
</cds-table-toolbar-search>
<!-- end search -->
<!-- column filters -->
- @if (columnFilters.length !== 0 || customFilter) {
- <div cdsPopover
- [isOpen]="openFilterPopover"
- [autoAlign]="true"
- [caret]="false">
+ @if (columnFilters.length !== 0 || customFilter) {
+ <div
+ cdsPopover
+ [isOpen]="openFilterPopover"
+ [autoAlign]="true"
+ [caret]="false"
+ >
<cds-icon-button
kind="ghost"
class="toolbar-action"
(click)="toggleFilterPopover()"
- data-testid="filter-button">
- <svg [cdsIcon]="icons.filter"
- [size]="icons.size16"
- class="cds--toolbar-action__icon"></svg>
+ data-testid="filter-button"
+ >
+ <svg
+ [cdsIcon]="icons.filter"
+ [size]="icons.size16"
+ class="cds--toolbar-action__icon"
+ ></svg>
</cds-icon-button>
<cds-popover-content [cdsLayer]="0">
- <div cdsStack="horizontal" class="filter--header">
- <span class="cds--type-heading-03" i18n>Filters</span>
- <cds-icon-button kind="ghost"
- size="sm"
- (click)="toggleFilterPopover()">
+ <div
+ cdsStack="horizontal"
+ class="filter--header"
+ >
+ <span
+ class="cds--type-heading-03"
+ i18n
+ >Filters</span
+ >
+ <cds-icon-button
+ kind="ghost"
+ size="sm"
+ (click)="toggleFilterPopover()"
+ >
<cd-icon type="destroy"></cd-icon>
</cds-icon-button>
</div>
cdsGrid
[fullWidth]="true"
[condensed]="true"
- [narrow]="true">
- @if (columnFilters.length !== 0) {
- @for (filter of columnFilters; track filter.column.name; let i = $index) {
- <div
- cdsRow
- [cdsLayer]="2"
- class="cds-mt-4">
-
- <!-- filter names column -->
- <div
- cdsCol
- [columnNumbers]="{sm: 4, md: 4}">
- <cds-text-label>Filter
- <input cdsText
- readonly
- size="md"
- [id]="'filter_key_' + i"
- [name]="'filter_key_' + i"
- [value]="filter.column.name">
- </cds-text-label>
- </div>
+ [narrow]="true"
+ >
+ @if (columnFilters.length !== 0) {
+ @for (filter of columnFilters; track filter.column.name; let i = $index) {
+ <div
+ cdsRow
+ [cdsLayer]="2"
+ class="cds-mt-4"
+ >
+ <!-- filter names column -->
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4 }"
+ >
+ <cds-text-label
+ >Filter
+ <input
+ cdsText
+ readonly
+ size="md"
+ [id]="'filter_key_' + i"
+ [name]="'filter_key_' + i"
+ [value]="filter.column.name"
+ />
+ </cds-text-label>
+ </div>
- <!-- filter values column -->
- <div
- cdsCol
- [columnNumbers]="{sm: 4, md: 4}">
- <cds-select (valueChange)="onChangeFilter($event, filter)"
- [id]="'filter_value_' + i"
- label="Value"
- size="md"
- [attr.data-testid]="'filter-select-' + filter.column.name"
- i18n-label>
- <option i18n>Any</option>
- @for (option of filter.options; track option.raw) {
- <option [value]="option.raw"
- [selected]="option.raw === selectedFilters[filter.column.name]">
- {{ option.formatted }}
- </option>
+ <!-- filter values column -->
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 4 }"
+ >
+ <cds-select
+ (valueChange)="onChangeFilter($event, filter)"
+ [id]="'filter_value_' + i"
+ label="Value"
+ size="md"
+ [attr.data-testid]="'filter-select-' + filter.column.name"
+ i18n-label
+ >
+ <option i18n>Any</option>
+ @for (option of filter.options; track option.raw) {
+ <option
+ [value]="option.raw"
+ [selected]="option.raw === selectedFilters[filter.column.name]"
+ >
+ {{ option.formatted }}
+ </option>
+ }
+ </cds-select>
+ </div>
+ </div>
+ }
+ }
+ @if (customFilter) {
+ @for (filter of stagedCustomFilters; track filter.id; let i = $index) {
+ @if (isCustomFilterString) {
+ <div
+ cdsRow
+ class="cds-mt-4 cds--type-body-02"
+ >
+ Filter {{ customFilter }}:
+ </div>
}
+ <div
+ cdsRow
+ [cdsLayer]="1"
+ class="cds-mt-4"
+ >
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 3, lg: 7 }"
+ >
+ <cds-text-label
+ >Key
+ <input
+ cdsText
+ size="md"
+ [id]="'filter_key_' + i"
+ [value]="filter.key"
+ (input)="filter.key = $any($event.target).value"
+ />
+ </cds-text-label>
+ </div>
- </cds-select>
- </div>
- </div>
- }}
- @if (customFilter) {
- @for (filter of stagedCustomFilters; track filter.id; let i = $index) {
- @if (isCustomFilterString) {
- <div cdsRow
- class="cds-mt-4 cds--type-body-02">
- Filter {{ customFilter }}:
- </div>
- }
- <div cdsRow
- [cdsLayer]="1"
- class="cds-mt-4">
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 3, lg: 7}">
- <cds-text-label>Key
- <input cdsText
- size="md"
- [id]="'filter_key_' + i"
- [value]="filter.key"
- (input)="filter.key = $any($event.target).value">
- </cds-text-label>
- </div>
-
- <div cdsCol
- [columnNumbers]="{sm: 4, md: 3, lg: 7}">
- <cds-text-label>Value
- <input cdsText
- size="md"
- [id]="'filter_value_' + i"
- [value]="filter.value"
- (input)="filter.value = $any($event.target).value">
- </cds-text-label>
- </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 4, md: 3, lg: 7 }"
+ >
+ <cds-text-label
+ >Value
+ <input
+ cdsText
+ size="md"
+ [id]="'filter_value_' + i"
+ [value]="filter.value"
+ (input)="filter.value = $any($event.target).value"
+ />
+ </cds-text-label>
+ </div>
- @if (i !== 0) {
- <div cdsCol
- [columnNumbers]="{sm: 2, md: 2, lg: 2}"
- class="cds-mt-6">
- <cds-icon-button kind="ghost"
- size="sm"
- (click)="removeCustomFilter(filter.id)">
- <cd-icon type="trash"></cd-icon>
- </cds-icon-button>
- </div>
- }
- </div>
- }
- @if (stagedCustomFilters.length < 5) {
- <div cdsRow
- class="cds-mt-4">
- <div cdsCol>
- <button
- cdsButton="tertiary"
- size="md"
- type="button"
- (click)="addCustomFilter()">Add new filter rule +</button>
- </div>
+ @if (i !== 0) {
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 2, md: 2, lg: 2 }"
+ class="cds-mt-6"
+ >
+ <cds-icon-button
+ kind="ghost"
+ size="sm"
+ (click)="removeCustomFilter(filter.id)"
+ >
+ <cd-icon type="trash"></cd-icon>
+ </cds-icon-button>
+ </div>
+ }
+ </div>
+ }
+ @if (stagedCustomFilters.length < 5) {
+ <div
+ cdsRow
+ class="cds-mt-4"
+ >
+ <div cdsCol>
+ <button
+ cdsButton="tertiary"
+ size="md"
+ type="button"
+ (click)="addCustomFilter()"
+ >
+ Add new filter rule +
+ </button>
+ </div>
+ </div>
+ }
+ }
</div>
- }
- }
- </div>
- <div class="filter--footer">
- <button cdsButton="secondary"
- size="lg"
- data-testid="clear-filters"
- type="button"
- (click)="onClearFilters()">
- <ng-container i18n>Clear all</ng-container>
- </button>
+ <div class="filter--footer">
+ <button
+ cdsButton="secondary"
+ size="lg"
+ data-testid="clear-filters"
+ type="button"
+ (click)="onClearFilters()"
+ >
+ <ng-container i18n>Clear all</ng-container>
+ </button>
- <button cdsButton="primary"
- size="lg"
- data-testid="apply-filters"
- [disabled]="isApplyFilterDisabled"
- type="button"
- (click)="onSubmitFilter()">
- <ng-container i18n>Apply</ng-container>
- </button>
- </div>
+ <button
+ cdsButton="primary"
+ size="lg"
+ data-testid="apply-filters"
+ [disabled]="isApplyFilterDisabled"
+ type="button"
+ (click)="onSubmitFilter()"
+ >
+ <ng-container i18n>Apply</ng-container>
+ </button>
+ </div>
</cds-popover-content>
</div>
}
<!-- end column filters -->
<!-- refresh button -->
<cds-icon-button
- [kind]="status.type"
- [disabled]="!fetchData?.observers?.length"
- (click)="refreshBtn()"
- [title]="status.msg"
- [description]="status.msg"
- i18n-title
- i18n-description
- class="toolbar-action"
- placement="bottom"
- *ngIf="fetchData?.observers?.length > 0">
- <svg [cdsIcon]="icons.refresh"
- [size]="icons.size16"
- [ngClass]="{ 'cds--toolbar-action__icon': true, 'reload': loadingIndicator }"></svg>
+ [kind]="status.type"
+ [disabled]="!fetchData?.observers?.length"
+ (click)="refreshBtn()"
+ [title]="status.msg"
+ [description]="status.msg"
+ i18n-title
+ i18n-description
+ class="toolbar-action"
+ placement="bottom"
+ *ngIf="fetchData?.observers?.length > 0"
+ >
+ <svg
+ [cdsIcon]="icons.refresh"
+ [size]="icons.size16"
+ [ngClass]="{ 'cds--toolbar-action__icon': true, reload: loadingIndicator }"
+ ></svg>
</cds-icon-button>
<!-- end refresh button -->
<!-- show hide columns -->
- <button cdsButton="ghost"
- class="toolbar-action"
- type="button"
- [cdsOverflowMenu]="showHideColumnsRef"
- placement="bottom"
- [flip]="true"
- [offset]="{ x: 3, y: 0 }">
- <svg [cdsIcon]="icons.dataTable"
- [size]="icons.size16"
- class="cds--toolbar-action__icon"></svg>
+ <button
+ cdsButton="ghost"
+ class="toolbar-action"
+ type="button"
+ [cdsOverflowMenu]="showHideColumnsRef"
+ placement="bottom"
+ [flip]="true"
+ [offset]="{ x: 3, y: 0 }"
+ >
+ <svg
+ [cdsIcon]="icons.dataTable"
+ [size]="icons.size16"
+ class="cds--toolbar-action__icon"
+ ></svg>
</button>
<ng-template #showHideColumnsRef>
- <div class="vstack gap-3 p-3"
- (click)="$event.stopPropagation()"
- tabindex="0"
- (keydown.enter)="$event.stopPropagation()"
- [cdsTheme]="theme">
+ <div
+ class="vstack gap-3 p-3"
+ (click)="$event.stopPropagation()"
+ tabindex="0"
+ (keydown.enter)="$event.stopPropagation()"
+ [cdsTheme]="theme"
+ >
<ng-container *ngFor="let column of localColumns">
- <cds-checkbox *ngIf="!column?.isInvisible"
- id="{{ column.prop }}{{ tableName }}"
- name="{{ column.prop }}{{ tableName }}"
- [checked]="!column?.isHidden"
- (checkedChange)="toggleColumn(column);">{{ column.name }}
- </cds-checkbox>
+ <cds-checkbox
+ *ngIf="!column?.isInvisible"
+ id="{{ column.prop }}{{ tableName }}"
+ name="{{ column.prop }}{{ tableName }}"
+ [checked]="!column?.isHidden"
+ (checkedChange)="toggleColumn(column)"
+ >{{ column.name }}
+ </cds-checkbox>
</ng-container>
</div>
</ng-template>
</cds-table-toolbar-content>
</cds-table-toolbar>
<!-- filter chips for column filters -->
- @if (toolHeader && columnFiltered) {
+ @if (toolHeader && columnFiltered) {
<div class="filter-tags">
<div
class="align-items-center"
cdsStack="horizontal"
- [gap]="2">
- @for (filter of activeFilters | slice:0:3; track filter.id) {
+ [gap]="2"
+ >
+ @for (filter of activeFilters | slice: 0 : 3; track filter.id) {
@if (filter.value) {
<cds-tag-filter
closeButtonLabel="Clear"
i18n-closeButtonLabel
- (close)="onRemoveFilter(filter)">
+ (close)="onRemoveFilter(filter)"
+ >
{{ filter.name }}={{ filter.value }}
</cds-tag-filter>
}
}
@if (activeFilters.length > 3) {
<cds-tooltip [description]="remainingFiltersTpl">
- <cds-tag>
- +{{ activeFilters.length - 3 }}
- </cds-tag>
+ <cds-tag> +{{ activeFilters.length - 3 }} </cds-tag>
<ng-template #remainingFiltersTpl>
<div
cdsStack="vertical"
- [gap]="2">
- @for (filter of activeFilters | slice:3; track filter.id) {
- <cds-tag-filter
- closeButtonLabel="Clear"
- i18n-closeButtonLabel
- (close)="onRemoveFilter(filter)">
- {{ filter.name }}={{ filter.value }}
- </cds-tag-filter>
- }
+ [gap]="2"
+ >
+ @for (filter of activeFilters | slice: 3; track filter.id) {
+ <cds-tag-filter
+ closeButtonLabel="Clear"
+ i18n-closeButtonLabel
+ (close)="onRemoveFilter(filter)"
+ >
+ {{ filter.name }}={{ filter.value }}
+ </cds-tag-filter>
+ }
</div>
</ng-template>
</cds-tooltip>
}
- <button cdsButton="ghost"
- (click)="onClearFilters($event)"
- type="button">
+ <button
+ cdsButton="ghost"
+ (click)="onClearFilters($event)"
+ type="button"
+ >
<ng-container i18n>Clear filters</ng-container>
</button>
</div>
</div>
}
<!-- end filter chips for column filters -->
- <table cdsTable
- [sortable]="sortable"
- [noBorder]="false"
- [size]="size"
- [striped]="false"
- [skeleton]="loadingIndicator">
- <thead cdsTableHead
- [sortable]="sortable"
- (deselectAll)="onDeselectAll()"
- (selectAll)="onSelectAll()"
- (sort)="changeSorting($event)"
- [model]="model"
- [selectAllCheckbox]="selectAllCheckbox"
- [selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
- [showSelectionColumn]="showSelectionColumn"
- [enableSingleSelect]="enableSingleSelect"
- [skeleton]="loadingIndicator"
- [stickyHeader]="false">
- </thead>
- <tbody cdsTableBody
- *ngIf="!noData; else noDataTemplate"
- [enableSingleSelect]="enableSingleSelect"
- [skeleton]="loadingIndicator">
- <ng-container *ngFor="let row of model.data; let i = index; trackBy: trackByFn.bind(this, identifier)">
- <tr cdsTableRow
+ <table
+ cdsTable
+ [sortable]="sortable"
+ [noBorder]="false"
+ [size]="size"
+ [striped]="false"
+ [skeleton]="loadingIndicator"
+ >
+ <thead
+ cdsTableHead
+ [sortable]="sortable"
+ (deselectAll)="onDeselectAll()"
+ (selectAll)="onSelectAll()"
+ (sort)="changeSorting($event)"
+ [model]="model"
+ [selectAllCheckbox]="selectAllCheckbox"
+ [selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected"
+ [showSelectionColumn]="showSelectionColumn"
+ [enableSingleSelect]="enableSingleSelect"
+ [skeleton]="loadingIndicator"
+ [stickyHeader]="false"
+ ></thead>
+ <tbody
+ cdsTableBody
+ *ngIf="!noData; else noDataTemplate"
+ [enableSingleSelect]="enableSingleSelect"
+ [skeleton]="loadingIndicator"
+ >
+ <ng-container
+ *ngFor="let row of model.data; let i = index; trackBy: trackByFn.bind(this, identifier)"
+ >
+ <tr
+ cdsTableRow
+ [model]="model"
+ [row]="row"
+ [size]="size"
+ [selected]="model.isRowSelected(i)"
+ [expandable]="model.isRowExpandable(i)"
+ [expanded]="model.isRowExpanded(i)"
+ [showSelectionColumn]="showSelectionColumn"
+ [enableSingleSelect]="enableSingleSelect"
+ [skeleton]="loadingIndicator"
+ (selectRow)="onSelect(i)"
+ (deselectRow)="onDeselect(i)"
+ (expandRow)="model.expandRow(i, !model.isRowExpanded(i))"
+ (rowClick)="onSelect(i)"
+ *ngIf="!model.isRowFiltered(i)"
+ ></tr>
+ <tr
+ cdsTableExpandedRow
+ cdsExpandedRowHover
+ *ngIf="model.isRowExpandable(i) && !shouldExpandAsTable(row) && !model.isRowFiltered(i)"
+ [row]="row"
+ [expanded]="model.isRowExpanded(i)"
+ [skeleton]="loadingIndicator"
+ ></tr>
+ <ng-container
+ *ngIf="
+ model.isRowExpandable(i) &&
+ shouldExpandAsTable(row) &&
+ model.isRowExpanded(i) &&
+ !model.isRowFiltered(i)
+ "
+ >
+ <tr
+ cdsTableRow
+ *ngFor="let expandedDataRow of firstExpandedDataInRow(row)"
[model]="model"
- [row]="row"
+ [showSelectionColumnCheckbox]="false"
+ [showSelectionColumn]="showSelectionColumn"
+ [row]="expandedDataRow"
[size]="size"
[selected]="model.isRowSelected(i)"
- [expandable]="model.isRowExpandable(i)"
- [expanded]="model.isRowExpanded(i)"
- [showSelectionColumn]="showSelectionColumn"
- [enableSingleSelect]="enableSingleSelect"
[skeleton]="loadingIndicator"
- (selectRow)="onSelect(i)"
- (deselectRow)="onDeselect(i)"
- (expandRow)="model.expandRow(i, !model.isRowExpanded(i))"
- (rowClick)="onSelect(i)"
- *ngIf="!model.isRowFiltered(i)">
- </tr>
- <tr cdsTableExpandedRow
- cdsExpandedRowHover
- *ngIf="model.isRowExpandable(i) && !shouldExpandAsTable(row) && !model.isRowFiltered(i)"
- [row]="row"
- [expanded]="model.isRowExpanded(i)"
- [skeleton]="loadingIndicator">
- </tr>
- <ng-container *ngIf="model.isRowExpandable(i) && shouldExpandAsTable(row) && model.isRowExpanded(i) && !model.isRowFiltered(i)">
- <tr cdsTableRow
- *ngFor="let expandedDataRow of firstExpandedDataInRow(row)"
- [model]="model"
- [showSelectionColumnCheckbox]="false"
- [showSelectionColumn]="showSelectionColumn"
- [row]="expandedDataRow"
- [size]="size"
- [selected]="model.isRowSelected(i)"
- [skeleton]="loadingIndicator">
- </tr>
+ ></tr>
</ng-container>
</ng-container>
</tbody>
</table>
- <cds-pagination [model]="model"
- (selectPage)="onPageChange($event)"
- [disabled]="limit === 0"
- [skeleton]="loadingIndicator"
- [pageInputDisabled]="limit === 0">
+ <cds-pagination
+ [model]="model"
+ (selectPage)="onPageChange($event)"
+ [disabled]="limit === 0"
+ [skeleton]="loadingIndicator"
+ [pageInputDisabled]="limit === 0"
+ >
</cds-pagination>
</cds-table-container>
<ng-template #noDataTemplate>
<tbody>
<tr cdstablerow>
- <td *ngIf="!rows?.length && !loadingIndicator"
- class="no-data"
- cdstabledata
- [attr.colspan]="visibleColumns.length + 2">
- <div class="empty-state cds-ml-3"
- cdsStack="vertical"
- gap="11">
+ <td
+ *ngIf="!rows?.length && !loadingIndicator"
+ class="no-data"
+ cdstabledata
+ [attr.colspan]="visibleColumns.length + 2"
+ >
+ <div
+ class="empty-state cds-ml-3"
+ cdsStack="vertical"
+ gap="11"
+ >
<div></div>
- <div cdsStack="vertical"
- gap="1">
+ <div
+ cdsStack="vertical"
+ gap="1"
+ >
<div>
- <img src="{{ emptyStateImage }}"
- alt="No data available" />
+ <img
+ src="{{ emptyStateImage }}"
+ alt="No data available"
+ />
</div>
<legend class="cds--type-body-compact-02">
<ng-container>{{ emptyStateTitle }}</ng-container>
</tbody>
</ng-template>
-<ng-template #rowDetailTpl
- let-row="data">
+<ng-template
+ #rowDetailTpl
+ let-row="data"
+>
@if (row[identifier] === expanded?.[identifier] && !scrollable) {
- <div
- (mouseenter)="onRowDetailHover($event)"
- data-testid="datatable-row-detail">
- <ng-template [ngTemplateOutlet]="rowDetail.template"></ng-template>
- </div>
+ <div
+ (mouseenter)="onRowDetailHover($event)"
+ data-testid="datatable-row-detail"
+ >
+ <ng-template [ngTemplateOutlet]="rowDetail.template"></ng-template>
+ </div>
} @else if (row[identifier] === expanded?.[identifier] && scrollable) {
- <div
- (mouseenter)="onRowDetailHover($event)"
- data-testid="datatable-row-detail"
- class="scrollable-expanded-row">
- <ng-template [ngTemplateOutlet]="rowDetail.template"></ng-template>
- </div>
+ <div
+ (mouseenter)="onRowDetailHover($event)"
+ data-testid="datatable-row-detail"
+ class="scrollable-expanded-row"
+ >
+ <ng-template [ngTemplateOutlet]="rowDetail.template"></ng-template>
+ </div>
}
</ng-template>
-<ng-template #defaultValueTpl
- let-value="data.value"
- let-expanded="expanded"
- let-column="data.column">
+<ng-template
+ #defaultValueTpl
+ let-value="data.value"
+ let-expanded="expanded"
+ let-column="data.column"
+>
<span [ngClass]="column?.cellClass">{{ value }}</span>
</ng-template>
<ng-template #tableActionTpl>
- <cds-overflow-menu *ngIf="tableActions?.dropDownActions.length > 1 && selectionType !== 'multiClick'"
- [flip]="true"
- data-testid="table-action-btn"
- class="d-flex justify-content-end">
+ <cds-overflow-menu
+ *ngIf="tableActions?.dropDownActions.length > 1 && selectionType !== 'multiClick'"
+ [flip]="true"
+ data-testid="table-action-btn"
+ class="d-flex justify-content-end"
+ >
<ng-container *ngFor="let action of tableActions?.dropDownActions">
- <cds-overflow-menu-option *ngIf="tableActions.currentAction !== action"
- class="{{ tableActions.toClassName(action) }}"
- title="{{ tableActions.useDisableDesc(action) }}"
- (click)="tableActions.useClickAction(action)"
- [routerLink]="tableActions.useRouterLink(action)"
- [preserveFragment]="action.preserveFragment ? '' : null"
- [disabled]="tableActions.disableSelectionAction(action)"
- [attr.aria-label]="action.name"
- data-testid="table-action-option-btn"
- i18n>
+ <cds-overflow-menu-option
+ *ngIf="tableActions.currentAction !== action"
+ class="{{ tableActions.toClassName(action) }}"
+ title="{{ tableActions.useDisableDesc(action) }}"
+ (click)="tableActions.useClickAction(action)"
+ [routerLink]="tableActions.useRouterLink(action)"
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ [disabled]="tableActions.disableSelectionAction(action)"
+ [attr.aria-label]="action.name"
+ data-testid="table-action-option-btn"
+ i18n
+ >
{{ action.name }}
</cds-overflow-menu-option>
</ng-container>
</cds-overflow-menu>
</ng-template>
-
<!-- cell templates that can be accessed from outside -->
-<ng-template #tableCellBoldTpl
- let-value="data.value">
+<ng-template
+ #tableCellBoldTpl
+ let-value="data.value"
+>
<strong>{{ value }}</strong>
</ng-template>
-<ng-template #sparklineTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #sparklineTpl
+ let-row="data.row"
+ let-value="data.value"
+>
<div class="position-relative">
- <cd-sparkline [data]="value"
- [isBinary]="row.cdIsBinary"></cd-sparkline>
+ <cd-sparkline
+ [data]="value"
+ [isBinary]="row.cdIsBinary"
+ ></cd-sparkline>
</div>
</ng-template>
-<ng-template #routerLinkTpl
- let-row="data.row"
- let-value="data.value">
- <a [routerLink]="[row.cdLink]"
- [queryParams]="row.cdParams">{{ value }}</a>
+<ng-template
+ #routerLinkTpl
+ let-row="data.row"
+ let-value="data.value"
+>
+ <a
+ [routerLink]="[row.cdLink]"
+ [queryParams]="row.cdParams"
+ >{{ value }}</a
+ >
</ng-template>
-<ng-template #checkIconTpl
- let-value="data.value">
+<ng-template
+ #checkIconTpl
+ let-value="data.value"
+>
@if (value | boolean) {
- <cd-icon type="check"></cd-icon>
-}
+ <cd-icon type="check"></cd-icon>
+ }
</ng-template>
-<ng-template #perSecondTpl
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #perSecondTpl
+ let-row="data.row"
+ let-value="data.value"
+>
{{ value | dimless }} /s
</ng-template>
-<ng-template #executingTpl
- let-column="data.column"
- let-row="data.row"
- let-value="data.value">
+<ng-template
+ #executingTpl
+ let-column="data.column"
+ let-row="data.row"
+ let-value="data.value"
+>
@if (row.cdExecuting) {
<cds-inline-loading></cds-inline-loading>
}
{{ value }}
</span>
@if (row.cdExecuting) {
- <span [ngClass]="column?.customTemplateConfig?.executingClass ? column?.customTemplateConfig.executingClass : 'text-muted italic'">({{ row.cdExecuting }})</span>
+ <span
+ [ngClass]="
+ column?.customTemplateConfig?.executingClass
+ ? column?.customTemplateConfig.executingClass
+ : 'text-muted italic'
+ "
+ >({{ row.cdExecuting }})</span
+ >
}
</ng-template>
-<ng-template #classAddingTpl
- let-value="data.value">
+<ng-template
+ #classAddingTpl
+ let-value="data.value"
+>
<span *ngIf="value">
- <span *ngIf="!(value=='active')||(value=='expired')||(value=='pending')">
+ <span *ngIf="!(value == 'active') || value == 'expired' || value == 'pending'">
{{ value }}
</span>
- <cds-tag *ngIf="(value==='active')||(value=== 'expired')||(value=== 'pending')"
- class="{{ value | pipeFunction:useCustomClass:this }}">
- {{value}}
+ <cds-tag
+ *ngIf="value === 'active' || value === 'expired' || value === 'pending'"
+ class="{{ value | pipeFunction: useCustomClass : this }}"
+ >
+ {{ value }}
</cds-tag>
</span>
</ng-template>
-<ng-template #tagTpl
- let-column="data.column"
- let-value="data.value">
- <span *ngFor="let item of (value | array); last as last">
- <cds-tag [size]="'md'"
- [class]="'table-tag ' + ((column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.class) ? column.customTemplateConfig.map[item].class : (column?.customTemplateConfig?.class ? column.customTemplateConfig.class : 'tag-primary'))"
- *ngIf="(column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.value) ? column.customTemplateConfig.map[item].value : column?.customTemplateConfig?.prefix ? column.customTemplateConfig.prefix + item : item">
- {{(column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.value) ? column.customTemplateConfig.map[item].value : column?.customTemplateConfig?.prefix ? column.customTemplateConfig.prefix + item : item }}
+<ng-template
+ #tagTpl
+ let-column="data.column"
+ let-value="data.value"
+>
+ <span *ngFor="let item of value | array; last as last">
+ <cds-tag
+ [size]="'md'"
+ [class]="
+ 'table-tag ' +
+ (column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.class
+ ? column.customTemplateConfig.map[item].class
+ : column?.customTemplateConfig?.class
+ ? column.customTemplateConfig.class
+ : 'tag-primary')
+ "
+ *ngIf="
+ column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.value
+ ? column.customTemplateConfig.map[item].value
+ : column?.customTemplateConfig?.prefix
+ ? column.customTemplateConfig.prefix + item
+ : item
+ "
+ >
+ {{
+ column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.value
+ ? column.customTemplateConfig.map[item].value
+ : column?.customTemplateConfig?.prefix
+ ? column.customTemplateConfig.prefix + item
+ : item
+ }}
</cds-tag>
<span *ngIf="!last"> </span>
</span>
</ng-template>
-<ng-template #mapTpl
- let-column="data.column"
- let-value="data.value">
- <span>{{ value | map:column?.customTemplateConfig }}</span>
+<ng-template
+ #mapTpl
+ let-column="data.column"
+ let-value="data.value"
+>
+ <span>{{ value | map: column?.customTemplateConfig }}</span>
</ng-template>
-<ng-template #tooltipTpl
- let-column="data.column"
- let-value="data.value">
- <span *ngFor="let item of (value | array);">
+<ng-template
+ #tooltipTpl
+ let-column="data.column"
+ let-value="data.value"
+>
+ <span *ngFor="let item of value | array">
<cds-tag
i18n
i18n-ngbTooltip
- class="{{(column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.class) ? column.customTemplateConfig.map[item].class : ''}}"
- ngbTooltip="{{(column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.tooltip) ? column.customTemplateConfig.map[item].tooltip : ''}}">
- {{value}}
- </cds-tag>
+ class="{{
+ column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.class
+ ? column.customTemplateConfig.map[item].class
+ : ''
+ }}"
+ ngbTooltip="{{
+ column?.customTemplateConfig?.map && column?.customTemplateConfig?.map[item]?.tooltip
+ ? column.customTemplateConfig.map[item].tooltip
+ : ''
+ }}"
+ >
+ {{ value }}
+ </cds-tag>
</span>
</ng-template>
-<ng-template #truncateTpl
- let-column="data.column"
- let-value="data.value">
- <span data-toggle="tooltip"
- [title]="value">{{ value | truncate:column?.customTemplateConfig?.length:column?.customTemplateConfig?.omission }}</span>
+<ng-template
+ #truncateTpl
+ let-column="data.column"
+ let-value="data.value"
+>
+ <span
+ data-toggle="tooltip"
+ [title]="value"
+ >{{
+ value
+ | truncate: column?.customTemplateConfig?.length : column?.customTemplateConfig?.omission
+ }}</span
+ >
</ng-template>
-<ng-template #rowDetailsTpl
- let-row="data.row"
- let-isExpanded="data.expanded"
- ngx-datatable-cell-template>
- <a href="javascript:void(0)"
- [class.expand-collapse-icon-right]="!isExpanded"
- [class.expand-collapse-icon-down]="isExpanded"
- class="expand-collapse-icon tc_expand-collapse"
- title="Expand/Collapse Row"
- i18n-title
- (click)="toggleExpandRow(row, isExpanded, $event)">
+<ng-template
+ #rowDetailsTpl
+ let-row="data.row"
+ let-isExpanded="data.expanded"
+ ngx-datatable-cell-template
+>
+ <a
+ href="javascript:void(0)"
+ [class.expand-collapse-icon-right]="!isExpanded"
+ [class.expand-collapse-icon-down]="isExpanded"
+ class="expand-collapse-icon tc_expand-collapse"
+ title="Expand/Collapse Row"
+ i18n-title
+ (click)="toggleExpandRow(row, isExpanded, $event)"
+ >
</a>
</ng-template>
-<ng-template #timeAgoTpl
- let-value="data.value">
- <span data-toggle="tooltip"
- [title]="value | cdDate">{{ value | relativeDate }}</span>
+<ng-template
+ #timeAgoTpl
+ let-value="data.value"
+>
+ <span
+ data-toggle="tooltip"
+ [title]="value | cdDate"
+ >{{ value | relativeDate }}</span
+ >
</ng-template>
-<ng-template #pathTpl
- let-value="data.value">
- <cd-copy-2-clipboard-button *ngIf="value"
- [source]="value"
- [byId]="false"
- size="lg"
- text="{{ value | path }}">
+<ng-template
+ #pathTpl
+ let-value="data.value"
+>
+ <cd-copy-2-clipboard-button
+ *ngIf="value"
+ [source]="value"
+ [byId]="false"
+ size="lg"
+ text="{{ value | path }}"
+ >
</cd-copy-2-clipboard-button>
</ng-template>
-<ng-template #copyTpl
- let-value="data.value">
- <cd-copy-2-clipboard-button *ngIf="value"
- [source]="value"
- [byId]="false"
- [size]="lg"
- [text]="value">
+<ng-template
+ #copyTpl
+ let-value="data.value"
+>
+ <cd-copy-2-clipboard-button
+ *ngIf="value"
+ [source]="value"
+ [byId]="false"
+ [size]="lg"
+ [text]="value"
+ >
</cd-copy-2-clipboard-button>
</ng-template>
-<ng-template #editingTpl
- let-value="data.value"
- let-row="data.row"
- let-column="data.column">
+<ng-template
+ #editingTpl
+ let-value="data.value"
+ let-row="data.row"
+ let-column="data.column"
+>
@if (isCellEditing(row?.[identifier], column?.prop)) {
- <form [formGroup]="formGroup"
- #formDir="ngForm">
+ <form
+ [formGroup]="formGroup"
+ #formDir="ngForm"
+ >
+ <div cdsRow>
+ <div cdsCol>
+ <cds-text-label
+ [invalid]="
+ formGroup.controls[row?.[identifier] + '-' + column?.prop]?.invalid &&
+ formGroup.controls[row?.[identifier] + '-' + column?.prop]?.dirty
+ "
+ [invalidText]="errorTpl"
+ >
+ <input
+ type="text"
+ cdsText
+ size="sm"
+ [id]="row?.[identifier] + '-' + column?.prop"
+ [formControlName]="row?.[identifier] + '-' + column?.prop"
+ (input)="valueChange(row?.[identifier], column?.prop, $event.target.value)"
+ [invalid]="
+ formGroup.controls[row?.[identifier] + '-' + column?.prop]?.invalid &&
+ formGroup.controls[row?.[identifier] + '-' + column?.prop]?.dirty
+ "
+ />
+ </cds-text-label>
+ <ng-template #errorTpl>
+ @for (
+ errorKey of formGroup?.get(row?.[identifier] + '-' + column?.prop)?.errors | keyvalue;
+ track $index
+ ) {
+ @if (
+ formGroup?.showError(row?.[identifier] + '-' + column?.prop, formDir, errorKey.key)
+ ) {
+ <ng-container i18n>
+ {{
+ column.customTemplateConfig?.errorMessages?.[errorKey.key] ||
+ 'Invalid ' + column.name
+ }}
+ </ng-container>
+ }
+ }
+ </ng-template>
+ </div>
+ <div
+ cdsCol
+ [columnNumbers]="{ sm: 1 }"
+ class="cds-p-0 cds-pt-3"
+ >
+ <div cdsRow>
+ <cds-icon-button
+ kind="tertiary"
+ size="sm"
+ id="cell-inline-save-btn"
+ type="button"
+ (click)="saveCellItem(row, column?.prop)"
+ >
+ <cd-icon type="check"></cd-icon>
+ </cds-icon-button>
+ <cds-icon-button
+ kind="ghost"
+ size="sm"
+ id="cell-inline-cancel-btn"
+ type="button"
+ (click)="cancelCellEdit(row[identifier], column?.prop)"
+ >
+ <cd-icon type="destroy"></cd-icon>
+ </cds-icon-button>
+ </div>
+ </div>
+ </div>
+ </form>
+ } @else {
<div cdsRow>
- <div cdsCol>
- <cds-text-label [invalid]="formGroup.controls[row?.[identifier] + '-' + column?.prop]?.invalid && formGroup.controls[row?.[identifier] + '-' + column?.prop]?.dirty"
- [invalidText]="errorTpl">
- <input type="text"
- cdsText
- size="sm"
- [id]="row?.[identifier] + '-' + column?.prop"
- [formControlName]="row?.[identifier] + '-' + column?.prop"
- (input)="valueChange(row?.[identifier], column?.prop, $event.target.value)"
- [invalid]="formGroup.controls[row?.[identifier] + '-' + column?.prop]?.invalid && formGroup.controls[row?.[identifier] + '-' + column?.prop]?.dirty">
- </cds-text-label>
- <ng-template #errorTpl>
- @for (errorKey of formGroup?.get(row?.[identifier] + '-' + column?.prop)?.errors | keyvalue; track $index) {
- @if (formGroup?.showError(row?.[identifier] + '-' + column?.prop, formDir, errorKey.key)) {
- <ng-container i18n>
- {{ column.customTemplateConfig?.errorMessages?.[errorKey.key] || ('Invalid ' + column.name) }}
- </ng-container>
- }}
- </ng-template>
+ <div
+ cdsCol
+ class="cds-pt-3"
+ >
+ {{ value }}
</div>
- <div cdsCol
- [columnNumbers]="{sm:1}"
- class="cds-p-0 cds-pt-3">
- <div cdsRow>
- <cds-icon-button kind="tertiary"
- size="sm"
- id="cell-inline-save-btn"
- type="button"
- (click)="saveCellItem(row, column?.prop)">
- <cd-icon type="check"></cd-icon>
- </cds-icon-button>
- <cds-icon-button kind="ghost"
- size="sm"
- id="cell-inline-cancel-btn"
- type="button"
- (click)="cancelCellEdit(row[identifier], column?.prop)">
- <cd-icon type="destroy"></cd-icon>
+ <div
+ cdsCol
+ [columnNumbers]="{ lg: 5 }"
+ class="edit-btn"
+ >
+ <cds-icon-button
+ kind="ghost"
+ size="sm"
+ id="cell-inline-edit-btn"
+ (click)="editCellItem(row[identifier], column, value)"
+ >
+ <cd-icon type="edit"></cd-icon>
</cds-icon-button>
- </div>
</div>
</div>
- </form>
- } @else {
- <div cdsRow>
- <div cdsCol
- class="cds-pt-3">
- {{ value }}
- </div>
- <div cdsCol
- [columnNumbers]="{lg: 5}"
- class="edit-btn">
- <cds-icon-button kind="ghost"
- size="sm"
- id="cell-inline-edit-btn"
- (click)="editCellItem(row[identifier], column, value)">
- <cd-icon type="edit"></cd-icon>
- </cds-icon-button>
- </div>
- </div>
}
</ng-template>
-<ng-template #redirectTpl
- let-value="data.value"
- let-row="data.row"
- let-column="data.column">
-@if (column.customTemplateConfig?.customRowProperty && row[column.customTemplateConfig?.customRowProperty]) {
- <a [routerLink]="row[column.customTemplateConfig?.customRowProperty]">{{value}}</a>
-} @else if (column.customTemplateConfig?.redirectLink) {
- <a [routerLink]="column.customTemplateConfig?.redirectLink | redirectLinkResolver:value">{{value}}</a>
-} @else {
- {{ value }}
-}
+<ng-template
+ #redirectTpl
+ let-value="data.value"
+ let-row="data.row"
+ let-column="data.column"
+>
+ @if (
+ column.customTemplateConfig?.customRowProperty &&
+ row[column.customTemplateConfig?.customRowProperty]
+ ) {
+ <a [routerLink]="row[column.customTemplateConfig?.customRowProperty]">{{ value }}</a>
+ } @else if (column.customTemplateConfig?.redirectLink) {
+ <a [routerLink]="column.customTemplateConfig?.redirectLink | redirectLinkResolver: value">{{
+ value
+ }}</a>
+ } @else {
+ {{ value }}
+ }
</ng-template>
<div class="cd-col-form">
- <div class="card pb-0"
- *ngIf="formUISchema$ | async as formUISchema">
- <div i18n="form title"
- class="card-header">{{ formUISchema.title }}</div>
- <form *ngIf="formUISchema.uiSchema"
- [formGroup]="form"
- (ngSubmit)="submit(model, formUISchema.taskInfo)">
-
+ <div
+ class="card pb-0"
+ *ngIf="formUISchema$ | async as formUISchema"
+ >
+ <div
+ i18n="form title"
+ class="card-header"
+ >
+ {{ formUISchema.title }}
+ </div>
+ <form
+ *ngIf="formUISchema.uiSchema"
+ [formGroup]="form"
+ (ngSubmit)="submit(model, formUISchema.taskInfo)"
+ >
<div class="card-body position-relative">
- <formly-form [form]="form"
- [fields]="formUISchema.controlSchema"
- [model]="model"
- [options]="{formState: formUISchema.uiSchema}"></formly-form>
+ <formly-form
+ [form]="form"
+ [fields]="formUISchema.controlSchema"
+ [model]="model"
+ [options]="{ formState: formUISchema.uiSchema }"
+ ></formly-form>
</div>
<div class="card-footer">
- <cd-form-button-panel (submitActionEvent)="submit(model, formUISchema.taskInfo)"
- [form]="formDir"
- [submitText]="formUISchema.title"
- [disabled]="!form.valid"
- wrappingClass="text-right"></cd-form-button-panel>
+ <cd-form-button-panel
+ (submitActionEvent)="submit(model, formUISchema.taskInfo)"
+ [form]="formDir"
+ [submitText]="formUISchema.title"
+ [disabled]="!form.valid"
+ wrappingClass="text-right"
+ ></cd-form-button-panel>
</div>
</form>
</div>
<div class="mb-3">
- <legend *ngIf="props.label"
- class="cd-header mt-1"
- i18n>{{ props.label }}</legend>
- <p *ngIf="props.description"
- i18n>{{ props.description }}</p>
+ <legend
+ *ngIf="props.label"
+ class="cd-header mt-1"
+ i18n
+ >
+ {{ props.label }}
+ </legend>
+ <p
+ *ngIf="props.description"
+ i18n
+ >
+ {{ props.description }}
+ </p>
- <div *ngFor="let field of field.fieldGroup; let i = index"
- class="d-flex">
- <formly-field class="col"
- [field]="field"></formly-field>
+ <div
+ *ngFor="let field of field.fieldGroup; let i = index"
+ class="d-flex"
+ >
+ <formly-field
+ class="col"
+ [field]="field"
+ ></formly-field>
<div class="action-btn">
- <button class="btn btn-light ms-1"
- type="button"
- (click)="addWrapper()">
+ <button
+ class="btn btn-light ms-1"
+ type="button"
+ (click)="addWrapper()"
+ >
<i [ngClass]="icons.add"></i>
</button>
- <button class="btn btn-light ms-1"
- type="button"
- (click)="remove(i)"
- *ngIf="field.props.removable !== false">
+ <button
+ class="btn btn-light ms-1"
+ type="button"
+ (click)="remove(i)"
+ *ngIf="field.props.removable !== false"
+ >
<i [ngClass]="icons.trash"></i>
</button>
</div>
</div>
- <div *ngIf="field.fieldGroup.length === 0"
- class="text-right">
- <button class="btn btn-light"
- type="button"
- (click)="addWrapper()"
- i18n>
+ <div
+ *ngIf="field.fieldGroup.length === 0"
+ class="text-right"
+ >
+ <button
+ class="btn btn-light"
+ type="button"
+ (click)="addWrapper()"
+ i18n
+ >
<i [ngClass]="icons.add"></i>
Add {{ props.label }}
</button>
</div>
- <span class="invalid-feedback"
- role="alert"
- *ngIf="showError && formControl.errors">
+ <span
+ class="invalid-feedback"
+ role="alert"
+ *ngIf="showError && formControl.errors"
+ >
<formly-validation-message [field]="field"></formly-validation-message>
</span>
</div>
-<input type="file"
- [formControl]="formControl"
- [formlyAttributes]="field"
- />
+<input
+ type="file"
+ [formControl]="formControl"
+ [formlyAttributes]="field"
+/>
-<input [formControl]="formControl"
- [formlyAttributes]="field"
- class="form-control col-form-input"/>
+<input
+ [formControl]="formControl"
+ [formlyAttributes]="field"
+ class="form-control col-form-input"
+/>
<ng-template #labelTemplate>
<div class="d-flex align-items-center">
- <label *ngIf="props.label && props.hideLabel !== true"
- [attr.for]="id"
- class="form-label">
+ <label
+ *ngIf="props.label && props.hideLabel !== true"
+ [attr.for]="id"
+ class="form-label"
+ >
{{ props.label }}
- <span *ngIf="props.required && props.hideRequiredMarker !== true"
- aria-hidden="true">*</span>
+ <span
+ *ngIf="props.required && props.hideRequiredMarker !== true"
+ aria-hidden="true"
+ >*</span
+ >
<cd-helper *ngIf="helper">
<span [innerHTML]="helper"></span>
</cd-helper>
</div>
</ng-template>
-<div class="mb-3"
- [class.form-floating]="props.labelPosition === 'floating'"
- [class.has-error]="showError">
+<div
+ class="mb-3"
+ [class.form-floating]="props.labelPosition === 'floating'"
+ [class.has-error]="showError"
+>
<ng-container *ngIf="props.labelPosition !== 'floating'">
<ng-container [ngTemplateOutlet]="labelTemplate"></ng-container>
</ng-container>
<ng-container [ngTemplateOutlet]="labelTemplate"></ng-container>
</ng-container>
- <div *ngIf="showError"
- class="invalid-feedback"
- [style.display]="'block'">
+ <div
+ *ngIf="showError"
+ class="invalid-feedback"
+ [style.display]="'block'"
+ >
<formly-validation-message [field]="field"></formly-validation-message>
</div>
- <small *ngIf="props.description"
- class="form-text text-muted">{{ props.description }}</small>
+ <small
+ *ngIf="props.description"
+ class="form-text text-muted"
+ >{{ props.description }}</small
+ >
</div>
<div class="mb-3">
- <legend *ngIf="props.label"
- class="cd-col-form-label"
- i18n>{{ props.label }}</legend>
- <p *ngIf="props.description"
- i18n>{{ props.description }}</p>
- <div class="alert alert-danger"
- role="alert"
- *ngIf="showError && formControl.errors">
+ <legend
+ *ngIf="props.label"
+ class="cd-col-form-label"
+ i18n
+ >
+ {{ props.label }}
+ </legend>
+ <p
+ *ngIf="props.description"
+ i18n
+ >
+ {{ props.description }}
+ </p>
+ <div
+ class="alert alert-danger"
+ role="alert"
+ *ngIf="showError && formControl.errors"
+ >
<formly-validation-message [field]="field"></formly-validation-message>
</div>
<div [ngClass]="inputClass">
- <formly-field *ngFor="let f of field.fieldGroup"
- [field]="f"
- class="flex-grow-1"></formly-field>
+ <formly-field
+ *ngFor="let f of field.fieldGroup"
+ [field]="f"
+ class="flex-grow-1"
+ ></formly-field>
</div>
</div>
-<textarea #textArea
- [formControl]="formControl"
- [cols]="props.cols"
- [rows]="props.rows"
- class="form-control"
- [class.is-invalid]="showError"
- [formlyAttributes]="field"
- (change)="onChange()">
-</textarea>
+<textarea
+ #textArea
+ [formControl]="formControl"
+ [cols]="props.cols"
+ [rows]="props.rows"
+ class="form-control"
+ [class.is-invalid]="showError"
+ [formlyAttributes]="field"
+ (change)="onChange()"
+></textarea>
<!doctype html>
<html lang="en">
-<head>
- <meta charset="utf-8">
- <title>Ceph</title>
+ <head>
+ <meta charset="utf-8" />
+ <title>Ceph</title>
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- <link rel="icon" type="image/x-icon" id="cdFavicon" href="favicon.ico">
-</head>
-<body>
- <noscript>
- <div class="noscript container"
- ng-if="false">
- <div class="jumbotron alert alert-danger">
- <h2 i18n>JavaScript required!</h2>
- <p i18n>A browser with JavaScript enabled is required in order to use this service.</p>
- <p i18n>When using Internet Explorer, please check your security settings and add this address to your trusted sites.</p>
+ <meta
+ name="viewport"
+ content="width=device-width, initial-scale=1, shrink-to-fit=no"
+ />
+ <link
+ rel="icon"
+ type="image/x-icon"
+ id="cdFavicon"
+ href="favicon.ico"
+ />
+ </head>
+ <body>
+ <noscript>
+ <div
+ class="noscript container"
+ ng-if="false"
+ >
+ <div class="jumbotron alert alert-danger">
+ <h2 i18n>JavaScript required!</h2>
+ <p i18n>A browser with JavaScript enabled is required in order to use this service.</p>
+ <p i18n>
+ When using Internet Explorer, please check your security settings and add this address
+ to your trusted sites.
+ </p>
+ </div>
</div>
- </div>
- </noscript>
+ </noscript>
- <cd-root></cd-root>
-</body>
+ <cd-root></cd-root>
+ </body>
</html>