mirror of
https://github.com/ceph/ceph
synced 2025-04-01 23:02:17 +00:00
mgr/dashboard: Update bootstrap (#25188)
mgr/dashboard: Update bootstrap Reviewed-by: Ricardo Marques <rimarques@suse.com> Reviewed-by: Tatjana Dehler <tdehler@suse.com>
This commit is contained in:
commit
c58ca8ea5a
src/pybind/mgr/dashboard
HACKING.rst
frontend
angular.jsonpackage-lock.jsonpackage.json
src/app
app.component.scssapp.component.spec.tsapp.component.tsapp.module.ts
ceph
block
block.module.ts
iscsi-tabs
iscsi-target-details
iscsi-target-details.component.htmliscsi-target-details.component.spec.tsiscsi-target-details.component.ts
iscsi-target-discovery-modal
iscsi-target-form
iscsi-target-image-settings-modal
iscsi-target-iqn-settings-modal
iscsi-target-list
iscsi
mirroring
image-list
mirror-health-color.pipe.spec.tsmirror-health-color.pipe.tsmirroring.module.tsoverview
pool-edit-mode-modal
pool-edit-peer-modal
pool-list
rbd-configuration-form
rbd-configuration-list
rbd-details
rbd-form
rbd-images
rbd-list
rbd-snapshot-form
rbd-snapshot-list
rbd-trash-list
rbd-trash-move-modal
rbd-trash-purge-modal
rbd-trash-restore-modal
cephfs/cephfs-detail
cluster
cluster.module.ts
configuration
crushmap
logs
mgr-modules
monitor
osd
osd-flags-modal
osd-list
osd-pg-scrub-modal
osd-recv-speed-modal
osd-reweight-modal
osd-scrub-modal
prometheus
alert-list
prometheus-tabs
silence-form
silence-list
silence-matcher-modal
dashboard
health
info-card
info-group
nfs
pool/erasure-code-profile-form
@ -252,7 +252,7 @@ Example:
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ToastsManager } from 'ng2-toastr';
|
||||
import { ToastrManager } from 'ngx-toastr';
|
||||
|
||||
import { Credentials } from '../../../shared/models/credentials.model';
|
||||
import { HostService } from './services/host.service';
|
||||
@ -295,7 +295,7 @@ or removed to/from a set of items (e.g.: 'Add permission' to a user vs. 'Create
|
||||
|
||||
In order to enforce the use of this wording, a service ``ActionLabelsI18n`` has
|
||||
been created, which provides translated labels for use in UI elements.
|
||||
|
||||
|
||||
Frontend branding
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1500,7 +1500,7 @@ decorators that can be used to add more information:
|
||||
|
||||
* ``@EndpointDoc()`` for documentation of endpoints. It has four optional arguments
|
||||
(explained below): ``description``, ``group``, ``parameters`` and``responses``.
|
||||
* ``@ControllerDoc()`` for documentation of controller or group associated with
|
||||
* ``@ControllerDoc()`` for documentation of controller or group associated with
|
||||
the endpoints. It only takes the two first arguments: ``description`` and``group``.
|
||||
|
||||
|
||||
@ -1509,7 +1509,7 @@ decorators that can be used to add more information:
|
||||
|
||||
``group``: By default, an endpoint is grouped together with other endpoints
|
||||
within the same controller class. ``group`` is a string that can be used to
|
||||
assign an endpoint or all endpoints in a class to another controller or a
|
||||
assign an endpoint or all endpoints in a class to another controller or a
|
||||
conceived group name.
|
||||
|
||||
|
||||
@ -1543,7 +1543,7 @@ for nested parameters).
|
||||
'item2': (str, 'Description of item2', True), # item2 is optional
|
||||
'item3': (str, 'Description of item3', True, 'foo'), # item3 is optional with 'foo' as default value
|
||||
}, 'Description of my_dictionary')})
|
||||
|
||||
|
||||
If the parameter is a ``list`` of primitive types, the type should be
|
||||
surrounded with square brackets.
|
||||
|
||||
|
@ -21,18 +21,21 @@
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"node_modules/bootstrap/dist/css/bootstrap.css",
|
||||
"node_modules/ng2-toastr/bundles/ng2-toastr.min.css",
|
||||
"node_modules/fork-awesome/css/fork-awesome.css",
|
||||
"node_modules/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css",
|
||||
"node_modules/ngx-toastr/toastr.css",
|
||||
"node_modules/ngx-bootstrap/datepicker/bs-datepicker.css",
|
||||
"src/styles.scss",
|
||||
"src/vendor.overrides.scss",
|
||||
"src/styles/vendor.overrides.scss",
|
||||
"node_modules/ng2-tree/styles.css"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/chart.js/dist/Chart.bundle.js"
|
||||
]
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": [
|
||||
"src/styles",
|
||||
"src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
1816
src/pybind/mgr/dashboard/frontend/package-lock.json
generated
1816
src/pybind/mgr/dashboard/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -67,8 +67,7 @@
|
||||
"@auth0/angular-jwt": "2.1.0",
|
||||
"@ngx-translate/i18n-polyfill": "1.0.0",
|
||||
"@swimlane/ngx-datatable": "14.0.0",
|
||||
"awesome-bootstrap-checkbox": "0.3.7",
|
||||
"bootstrap": "3.4.1",
|
||||
"bootstrap": "4.3.1",
|
||||
"chart.js": "2.7.3",
|
||||
"core-js": "2.6.5",
|
||||
"detect-browser": "4.1.0",
|
||||
@ -76,10 +75,11 @@
|
||||
"lodash": "4.17.11",
|
||||
"moment": "2.24.0",
|
||||
"ng-block-ui": "2.1.1",
|
||||
"ng-bootstrap-form-validation": "4.0.0",
|
||||
"ng2-charts": "1.6.0",
|
||||
"ng2-toastr": "zzakir/ng2-toastr#0eafd72",
|
||||
"ng2-tree": "2.0.0-rc.11",
|
||||
"ngx-bootstrap": "3.2.0",
|
||||
"ngx-bootstrap": "4.3.0",
|
||||
"ngx-toastr": "10.0.2",
|
||||
"rxjs": "6.4.0",
|
||||
"rxjs-compat": "6.4.0",
|
||||
"tslib": "1.9.3",
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../defaults';
|
||||
@import 'defaults';
|
||||
|
||||
.dashboard {
|
||||
background-color: $color-whitesmoke-gray;
|
||||
@ -13,7 +13,7 @@
|
||||
margin-top: 2.5vw;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) {
|
||||
@media (max-width: $screen-md-max) {
|
||||
margin-top: 9vw;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
|
||||
import { configureTestBed } from '../testing/unit-test-helper';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AuthStorageService } from './shared/services/auth-storage.service';
|
||||
@ -13,7 +11,7 @@ describe('AppComponent', () => {
|
||||
let fixture: ComponentFixture<AppComponent>;
|
||||
|
||||
configureTestBed({
|
||||
imports: [RouterTestingModule, ToastModule.forRoot()],
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [AppComponent],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
providers: [AuthStorageService]
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Component, ViewContainerRef } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ToastsManager } from 'ng2-toastr';
|
||||
import { TooltipConfig } from 'ngx-bootstrap/tooltip';
|
||||
|
||||
import { AuthStorageService } from './shared/services/auth-storage.service';
|
||||
@ -23,14 +22,7 @@ import { AuthStorageService } from './shared/services/auth-storage.service';
|
||||
export class AppComponent {
|
||||
title = 'cd';
|
||||
|
||||
constructor(
|
||||
private authStorageService: AuthStorageService,
|
||||
private router: Router,
|
||||
public toastr: ToastsManager,
|
||||
private vcr: ViewContainerRef
|
||||
) {
|
||||
this.toastr.setRootViewContainerRef(this.vcr);
|
||||
}
|
||||
constructor(private authStorageService: AuthStorageService, private router: Router) {}
|
||||
|
||||
isLoginActive() {
|
||||
return this.router.url === '/login' || !this.authStorageService.isLoggedIn();
|
||||
|
@ -7,10 +7,11 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { JwtModule } from '@auth0/angular-jwt';
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill';
|
||||
import { BlockUIModule } from 'ng-block-ui';
|
||||
import { ToastModule, ToastOptions } from 'ng2-toastr/ng2-toastr';
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { AccordionModule } from 'ngx-bootstrap/accordion';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
@ -21,13 +22,6 @@ import { ApiInterceptorService } from './shared/services/api-interceptor.service
|
||||
import { JsErrorHandler } from './shared/services/js-error-handler.service';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
|
||||
export class CustomOption extends ToastOptions {
|
||||
animate = 'flyRight';
|
||||
newestOnTop = true;
|
||||
showCloseButton = true;
|
||||
enableHTML = true;
|
||||
}
|
||||
|
||||
export function jwtTokenGetter() {
|
||||
return localStorage.getItem('access_token');
|
||||
}
|
||||
@ -41,7 +35,11 @@ registerLocaleData(LocaleHelper.getLocaleData(), LocaleHelper.getLocale());
|
||||
BlockUIModule.forRoot(),
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot({
|
||||
positionClass: 'toast-top-right',
|
||||
preventDuplicates: true,
|
||||
enableHtml: true
|
||||
}),
|
||||
AppRoutingModule,
|
||||
CoreModule,
|
||||
SharedModule,
|
||||
@ -53,7 +51,8 @@ registerLocaleData(LocaleHelper.getLocaleData(), LocaleHelper.getLocale());
|
||||
config: {
|
||||
tokenGetter: jwtTokenGetter
|
||||
}
|
||||
})
|
||||
}),
|
||||
NgBootstrapFormValidationModule.forRoot()
|
||||
],
|
||||
exports: [SharedModule],
|
||||
providers: [
|
||||
@ -66,10 +65,6 @@ registerLocaleData(LocaleHelper.getLocaleData(), LocaleHelper.getLocale());
|
||||
useClass: ApiInterceptorService,
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: ToastOptions,
|
||||
useClass: CustomOption
|
||||
},
|
||||
i18nProviders,
|
||||
I18n
|
||||
],
|
||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { TreeModule } from 'ng2-tree';
|
||||
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
@ -62,7 +63,8 @@ import { RbdTrashRestoreModalComponent } from './rbd-trash-restore-modal/rbd-tra
|
||||
ModalModule.forRoot(),
|
||||
SharedModule,
|
||||
RouterModule,
|
||||
TreeModule
|
||||
TreeModule,
|
||||
NgBootstrapFormValidationModule
|
||||
],
|
||||
declarations: [
|
||||
RbdListComponent,
|
||||
|
@ -2,11 +2,11 @@
|
||||
<tab heading="Overview"
|
||||
i18n-heading
|
||||
[active]="url === '/block/iscsi/overview'"
|
||||
(select)="navigateTo('/block/iscsi/overview')">
|
||||
(selectTab)="navigateTo('/block/iscsi/overview')">
|
||||
</tab>
|
||||
<tab heading="Targets"
|
||||
i18n-heading
|
||||
[active]="url === '/block/iscsi/targets'"
|
||||
(select)="navigateTo('/block/iscsi/targets')">
|
||||
(selectTab)="navigateTo('/block/iscsi/targets')">
|
||||
</tab>
|
||||
</tabset>
|
||||
|
@ -1,30 +1,32 @@
|
||||
<div class="col-sm-6 col-lg-6">
|
||||
<legend i18n>iSCSI Topology</legend>
|
||||
<tree [tree]="tree"
|
||||
(nodeSelected)="onNodeSelected($event)">
|
||||
<ng-template let-node>
|
||||
<span class="node-name"
|
||||
[innerHTML]="node.value"></span>
|
||||
<span> </span>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<legend i18n>iSCSI Topology</legend>
|
||||
<tree [tree]="tree"
|
||||
(nodeSelected)="onNodeSelected($event)">
|
||||
<ng-template let-node>
|
||||
<span class="node-name"
|
||||
[innerHTML]="node.value"></span>
|
||||
<span> </span>
|
||||
|
||||
<span class="label"
|
||||
[ngClass]="{'label-success': ['logged_in'].includes(node.status), 'label-danger': ['logged_out'].includes(node.status)}">
|
||||
{{ node.status }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</tree>
|
||||
</div>
|
||||
<span class="badge"
|
||||
[ngClass]="{'badge-success': ['logged_in'].includes(node.status), 'badge-danger': ['logged_out'].includes(node.status)}">
|
||||
{{ node.status }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</tree>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 col-lg-6 metadata"
|
||||
*ngIf="data">
|
||||
<legend>{{ title }}</legend>
|
||||
<div class="col-6 metadata"
|
||||
*ngIf="data">
|
||||
<legend>{{ title }}</legend>
|
||||
|
||||
<cd-table #detailTable
|
||||
[data]="data"
|
||||
columnMode="flex"
|
||||
[columns]="columns"
|
||||
[limit]="0">
|
||||
</cd-table>
|
||||
<cd-table #detailTable
|
||||
[data]="data"
|
||||
columnMode="flex"
|
||||
[columns]="columns"
|
||||
[limit]="0">
|
||||
</cd-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #highlightTpl
|
||||
|
@ -111,8 +111,8 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
children: [{ id: 'disk_rbd_disk_1', value: 'rbd/disk_1' }],
|
||||
settings: {
|
||||
cssClasses: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.width, Icons.disk], ' ')
|
||||
expanded: _.join([Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.disk], ' ')
|
||||
},
|
||||
selectionAllowed: false
|
||||
},
|
||||
@ -122,8 +122,8 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
children: [{ value: 'node1:192.168.100.201' }],
|
||||
settings: {
|
||||
cssClasses: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.server], ' '),
|
||||
leaf: _.join([Icons.width, Icons.large, Icons.server], ' ')
|
||||
expanded: _.join([Icons.large, Icons.server], ' '),
|
||||
leaf: _.join([Icons.large, Icons.server], ' ')
|
||||
},
|
||||
selectionAllowed: false
|
||||
},
|
||||
@ -137,8 +137,8 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
id: 'disk_rbd_disk_1',
|
||||
settings: {
|
||||
cssClasses: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.width, Icons.disk], ' ')
|
||||
expanded: _.join([Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.disk], ' ')
|
||||
}
|
||||
},
|
||||
value: 'rbd/disk_1'
|
||||
@ -151,8 +151,8 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
],
|
||||
settings: {
|
||||
cssClasses: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.width, Icons.user], ' ')
|
||||
expanded: _.join([Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.user], ' ')
|
||||
},
|
||||
selectionAllowed: false
|
||||
},
|
||||
@ -162,8 +162,8 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
children: [],
|
||||
settings: {
|
||||
cssClasses: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.width, Icons.user], ' ')
|
||||
expanded: _.join([Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.user], ' ')
|
||||
},
|
||||
selectionAllowed: false
|
||||
},
|
||||
@ -172,7 +172,7 @@ describe('IscsiTargetDetailsComponent', () => {
|
||||
],
|
||||
id: 'root',
|
||||
settings: {
|
||||
cssClasses: { expanded: _.join([Icons.width, Icons.large, Icons.bullseye], ' ') },
|
||||
cssClasses: { expanded: _.join([Icons.large, Icons.bullseye], ' ') },
|
||||
static: true
|
||||
},
|
||||
value: 'iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw'
|
||||
|
@ -78,23 +78,23 @@ export class IscsiTargetDetailsComponent implements OnChanges, OnInit {
|
||||
this.metadata = { root: this.selectedItem.target_controls };
|
||||
const cssClasses = {
|
||||
target: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.bullseye], ' ')
|
||||
expanded: _.join([Icons.large, Icons.bullseye], ' ')
|
||||
},
|
||||
initiators: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.width, Icons.user], ' ')
|
||||
expanded: _.join([Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.user], ' ')
|
||||
},
|
||||
groups: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.width, Icons.user], ' ')
|
||||
expanded: _.join([Icons.large, Icons.user], ' '),
|
||||
leaf: _.join([Icons.user], ' ')
|
||||
},
|
||||
disks: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.width, Icons.disk], ' ')
|
||||
expanded: _.join([Icons.large, Icons.disk], ' '),
|
||||
leaf: _.join([Icons.disk], ' ')
|
||||
},
|
||||
portals: {
|
||||
expanded: _.join([Icons.width, Icons.large, Icons.server], ' '),
|
||||
leaf: _.join([Icons.width, Icons.large, Icons.server], ' ')
|
||||
expanded: _.join([Icons.large, Icons.server], ' '),
|
||||
leaf: _.join([Icons.large, Icons.server], ' ')
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,15 +4,13 @@
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form name="discoveryForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="discoveryForm"
|
||||
novalidate>
|
||||
<div class="modal-body">
|
||||
<!-- User -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': discoveryForm.showError('user', formDir)}">
|
||||
<label class="control-label col-sm-4"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4"
|
||||
for="user"
|
||||
i18n>User</label>
|
||||
<div class="col-sm-8">
|
||||
@ -20,11 +18,11 @@
|
||||
class="form-control"
|
||||
formControlName="user"
|
||||
type="text">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('user', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('user', formDir, 'pattern')"
|
||||
i18n>Usernames must have a length of 8 to 64 characters and
|
||||
can only contain letters, '.', '@', '-', '_' or ':'.</span>
|
||||
@ -32,9 +30,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': discoveryForm.showError('password', formDir)}">
|
||||
<label class="control-label col-sm-4"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4"
|
||||
for="password"
|
||||
i18n>Password</label>
|
||||
<div class="col-sm-8">
|
||||
@ -44,22 +41,22 @@
|
||||
formControlName="password"
|
||||
type="password">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
cdPasswordButton="password">
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
cdCopy2ClipboardButton="password">
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('password', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('password', formDir, 'pattern')"
|
||||
i18n>Passwords must have a length of 12 to 16 characters
|
||||
and can only contain letters, '@', '-', '_' or '/'.</span>
|
||||
@ -67,9 +64,8 @@
|
||||
</div>
|
||||
|
||||
<!-- mutual_user -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': discoveryForm.showError('mutual_user', formDir)}">
|
||||
<label class="control-label col-sm-4"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4"
|
||||
for="mutual_user">
|
||||
<ng-container i18n>Mutual User</ng-container>
|
||||
</label>
|
||||
@ -79,11 +75,11 @@
|
||||
formControlName="mutual_user"
|
||||
type="text">
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('mutual_user', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('mutual_user', formDir, 'pattern')"
|
||||
i18n>Usernames must have a length of 8 to 64 characters and
|
||||
can only contain letters, '.', '@', '-', '_' or ':'.</span>
|
||||
@ -91,9 +87,8 @@
|
||||
</div>
|
||||
|
||||
<!-- mutual_password -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': discoveryForm.showError('mutual_password', formDir)}">
|
||||
<label class="control-label col-sm-4"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-4"
|
||||
for="mutual_password"
|
||||
i18n>Mutual Password</label>
|
||||
<div class="col-sm-8">
|
||||
@ -103,22 +98,22 @@
|
||||
formControlName="mutual_password"
|
||||
type="password">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
cdPasswordButton="mutual_password">
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
cdCopy2ClipboardButton="mutual_password">
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('mutual_password', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="discoveryForm.showError('mutual_password', formDir, 'pattern')"
|
||||
i18n>Passwords must have a length of 12 to 16 characters and
|
||||
can only contain letters, '@', '-', '_' or '/'.</span>
|
||||
|
@ -8,8 +8,8 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { Permission } from '../../../shared/models/permissions';
|
||||
@ -31,7 +31,7 @@ describe('IscsiTargetDiscoveryModalComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
RouterTestingModule
|
||||
],
|
||||
providers: [i18nProviders, BsModalRef]
|
||||
|
@ -1,21 +1,17 @@
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<form name="targetForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="targetForm"
|
||||
novalidate
|
||||
*ngIf="targetForm">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="card-body">
|
||||
<!-- Target IQN -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': targetForm.showError('target_iqn', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="target_iqn">
|
||||
<ng-container i18n>Target IQN</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -27,28 +23,29 @@
|
||||
id="target_iqn"
|
||||
name="target_iqn"
|
||||
formControlName="target_iqn" />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
id="ecp-info-button"
|
||||
type="button"
|
||||
(click)="targetSettingsModal()">
|
||||
<i [ngClass]="[icons.deepCheck, icons.width]"
|
||||
<i [ngClass]="[icons.deepCheck]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="targetForm.showError('target_iqn', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="targetForm.showError('target_iqn', formDir, 'pattern')"
|
||||
i18n>IQN has wrong pattern.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<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>
|
||||
<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>
|
||||
@ -57,7 +54,7 @@
|
||||
i18n>More information</a>
|
||||
</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="hasAdvancedSettings(targetForm.getValue('target_controls'))"
|
||||
i18n>This target has modified advanced settings.</span>
|
||||
<hr />
|
||||
@ -65,9 +62,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Portals -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': targetForm.showError('portals', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="portals">
|
||||
<ng-container i18n>Portals</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -76,22 +72,22 @@
|
||||
|
||||
<ng-container *ngFor="let portal of portals.value; let i = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="portal"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removePortal(i, portal)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="targetForm.showError('portals', formDir, 'minGateways')"
|
||||
i18n>At least {{ minimum_gateways }} gateways are required.</span>
|
||||
|
||||
@ -101,8 +97,8 @@
|
||||
[options]="portalsSelections"
|
||||
[messages]="messages.portals"
|
||||
(selection)="onPortalSelection($event)"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add portal</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -113,36 +109,35 @@
|
||||
</div>
|
||||
|
||||
<!-- Images -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': targetForm.showError('disks', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="disks"
|
||||
i18n>Images</label>
|
||||
<div class="col-sm-9">
|
||||
<ng-container *ngFor="let image of targetForm.getValue('disks'); let i = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="image"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="imageSettingsModal(image)">
|
||||
<i [ngClass]="[icons.deepCheck, icons.width]"
|
||||
<i [ngClass]="[icons.deepCheck]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="btn btn-default"
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removeImage(i, image)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<span class="help-block">
|
||||
<span class="form-text text-muted">
|
||||
<ng-container *ngIf="backstores.length > 1"
|
||||
i18n>Backstore: {{ imagesSettings[image].backstore | iscsiBackstore }}. </ng-container>
|
||||
|
||||
@ -151,7 +146,7 @@
|
||||
</span>
|
||||
</ng-container>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="targetForm.showError('disks', formDir, 'required')"
|
||||
i18n>At least 1 image is required.</span>
|
||||
|
||||
@ -161,8 +156,8 @@
|
||||
[options]="imagesSelections"
|
||||
[messages]="messages.images"
|
||||
(selection)="onImageSelection($event)"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add image</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -173,14 +168,16 @@
|
||||
</div>
|
||||
|
||||
<!-- acl_enabled -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@ -189,29 +186,28 @@
|
||||
</div>
|
||||
|
||||
<!-- Initiators -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="targetForm.getValue('acl_enabled')">
|
||||
<label class="control-label col-sm-3"
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="initiators"
|
||||
i18n>Initiators</label>
|
||||
<div class="col-sm-9"
|
||||
formArrayName="initiators">
|
||||
<div class="panel panel-default"
|
||||
<div class="card mb-2"
|
||||
*ngFor="let initiator of initiators.controls; let ii = index"
|
||||
[formGroupName]="ii">
|
||||
<div class="panel-heading">
|
||||
<div class="card-header">
|
||||
<ng-container i18n>Initiator</ng-container>: {{ initiator.getValue('client_iqn') }}
|
||||
<button type="button"
|
||||
class="close"
|
||||
(click)="removeInitiator(ii)">
|
||||
<i [ngClass]="[icons.deepCheck, icons.width]"></i>
|
||||
<i [ngClass]="[icons.deepCheck]"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="card-body">
|
||||
<!-- Initiator: Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('client_iqn', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="client_iqn">
|
||||
<ng-container i18n>Client IQN</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -222,15 +218,15 @@
|
||||
formControlName="client_iqn"
|
||||
(blur)="updatedInitiatorSelector()">
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('client_iqn', formDir, 'notUnique')"
|
||||
i18n>Initiator IQN needs to be unique.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('client_iqn', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('client_iqn', formDir, 'pattern')"
|
||||
i18n>IQN has wrong pattern.</span>
|
||||
</div>
|
||||
@ -238,9 +234,8 @@
|
||||
|
||||
<ng-container formGroupName="auth">
|
||||
<!-- Initiator: User -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('user', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="user"
|
||||
i18n>User</label>
|
||||
<div class="col-sm-9">
|
||||
@ -248,11 +243,11 @@
|
||||
class="form-control"
|
||||
formControlName="user"
|
||||
type="text">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('user', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('user', formDir, 'pattern')"
|
||||
i18n>Usernames must have a length of 8 to 64 characters and
|
||||
can only contain letters, '.', '@', '-', '_' or ':'.</span>
|
||||
@ -260,9 +255,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Initiator: Password -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('password', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="password"
|
||||
i18n>Password</label>
|
||||
<div class="col-sm-9">
|
||||
@ -272,22 +266,22 @@
|
||||
formControlName="password"
|
||||
type="password">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
[cdPasswordButton]="'password' + ii">
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
[cdCopy2ClipboardButton]="'password' + ii">
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('password', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('password', formDir, 'pattern')"
|
||||
i18n>Passwords must have a length of 12 to 16 characters
|
||||
and can only contain letters, '@', '-', '_' or '/'.</span>
|
||||
@ -296,9 +290,8 @@
|
||||
|
||||
|
||||
<!-- Initiator: mutual_user -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('mutual_user', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="mutual_user">
|
||||
<ng-container i18n>Mutual User</ng-container>
|
||||
</label>
|
||||
@ -308,11 +301,11 @@
|
||||
formControlName="mutual_user"
|
||||
type="text">
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('mutual_user', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('mutual_user', formDir, 'pattern')"
|
||||
i18n>Usernames must have a length of 8 to 64 characters and
|
||||
can only contain letters, '.', '@', '-', '_' or ':'.</span>
|
||||
@ -320,9 +313,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Initiator: mutual_password -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('mutual_password', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="mutual_password"
|
||||
i18n>Mutual Password</label>
|
||||
<div class="col-sm-9">
|
||||
@ -332,22 +324,22 @@
|
||||
formControlName="mutual_password"
|
||||
type="password">
|
||||
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
[cdPasswordButton]="'mutual_password' + ii">
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
[cdCopy2ClipboardButton]="'mutual_password' + ii">
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('mutual_password', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="initiator.showError('mutual_password', formDir, 'pattern')"
|
||||
i18n>Passwords must have a length of 12 to 16 characters and
|
||||
can only contain letters, '@', '-', '_' or '/'.</span>
|
||||
@ -356,23 +348,22 @@
|
||||
</ng-container>
|
||||
|
||||
<!-- Initiator: Images -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': initiator.showError('luns', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="luns"
|
||||
i18n>Images</label>
|
||||
<div class="col-sm-9">
|
||||
<ng-container *ngFor="let image of initiator.getValue('luns'); let li = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="image"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removeInitiatorImage(initiator, li, ii, image)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
@ -388,8 +379,8 @@
|
||||
<cd-select [data]="initiator.getValue('luns')"
|
||||
[options]="imagesInitiatorSelections[ii]"
|
||||
[messages]="messages.initiatorImage"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add image</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -401,13 +392,13 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<span class="text-muted"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="initiators.controls.length === 0"
|
||||
i18n>No items added.</span>
|
||||
|
||||
<button (click)="addInitiator(); false"
|
||||
class="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
class="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add initiator</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
@ -418,29 +409,28 @@
|
||||
</div>
|
||||
|
||||
<!-- Groups -->
|
||||
<div class="form-group"
|
||||
*ngIf="targetForm.getValue('acl_enabled')"
|
||||
[ngClass]="{'has-error': targetForm.showError('groups', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row"
|
||||
*ngIf="targetForm.getValue('acl_enabled')">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="initiators"
|
||||
i18n>Groups</label>
|
||||
<div class="col-sm-9"
|
||||
formArrayName="groups">
|
||||
<div class="panel panel-default"
|
||||
<div class="card mb-2"
|
||||
*ngFor="let group of groups.controls; let gi = index"
|
||||
[formGroupName]="gi">
|
||||
<div class="panel-heading">
|
||||
<div class="card-header">
|
||||
<ng-container i18n>Group</ng-container>: {{ group.getValue('group_id') }}
|
||||
<button type="button"
|
||||
class="close"
|
||||
(click)="groups.removeAt(gi)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"></i>
|
||||
<i [ngClass]="[icons.destroy]"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="card-body">
|
||||
<!-- Group: group_id -->
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="group_id">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -453,24 +443,23 @@
|
||||
</div>
|
||||
|
||||
<!-- Group: members -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': group.showError('members', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="members">
|
||||
<ng-container i18n>Initiators</ng-container>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<ng-container *ngFor="let member of group.getValue('members'); let i = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="member"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removeGroupInitiator(group, i, gi)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
@ -483,8 +472,8 @@
|
||||
[options]="groupMembersSelections[gi]"
|
||||
[messages]="messages.groupInitiator"
|
||||
(selection)="onGroupMemberSelection($event)"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add initiator</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -495,24 +484,23 @@
|
||||
</div>
|
||||
|
||||
<!-- Group: disks -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': group.showError('disks', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="disks">
|
||||
<ng-container i18n>Images</ng-container>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<ng-container *ngFor="let disk of group.getValue('disks'); let i = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="disk"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removeGroupDisk(group, i, gi)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
@ -524,8 +512,8 @@
|
||||
<cd-select [data]="group.getValue('disks')"
|
||||
[options]="groupDiskSelections[gi]"
|
||||
[messages]="messages.initiatorImage"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add image</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -539,13 +527,13 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<span class="text-muted"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="groups.controls.length === 0"
|
||||
i18n>No items added.</span>
|
||||
|
||||
<button (click)="addGroup(); false"
|
||||
class="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
class="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add group</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
@ -554,13 +542,11 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button
|
||||
[form]="formDir"
|
||||
(submitAction)="submit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-submit-button (submitAction)="submit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
[form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-back-button></cd-back-button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
@ -130,7 +130,7 @@ describe('IscsiTargetFormComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
i18nProviders,
|
||||
|
@ -12,11 +12,11 @@
|
||||
<!-- BACKSTORE -->
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-12">
|
||||
<label class="control-label"
|
||||
<label class="col-form-label"
|
||||
i18n>Backstore</label>
|
||||
<select id="backstore"
|
||||
name="backstore"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
[(ngModel)]="model.backstore"
|
||||
[disabled]="backstores.length == 1">
|
||||
<option *ngFor="let bs of backstores"
|
||||
@ -31,12 +31,12 @@
|
||||
<div class="form-group row"
|
||||
*ngFor="let setting of disk_default_controls[bs] | keyvalue">
|
||||
<div class="col-sm-12">
|
||||
<label class="control-label"
|
||||
<label class="col-form-label"
|
||||
for="{{ setting.key }}">{{ setting.key }}</label>
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
[(ngModel)]="model[bs][setting.key]">
|
||||
<span class="help-block">{{ helpText[setting.key]?.help }}</span>
|
||||
<span class="form-text text-muted">{{ helpText[setting.key]?.help }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
<div class="modal-footer">
|
||||
<div class="button-group text-right">
|
||||
<button class="btn btn-sm btn-primary"
|
||||
<button class="btn btn-secondary"
|
||||
(click)="save()"
|
||||
i18n>Confirm</button>
|
||||
<cd-back-button [back]="modalRef.hide"
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form name="settingsForm"
|
||||
class="form"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="settingsForm"
|
||||
novalidate>
|
||||
@ -13,10 +12,9 @@
|
||||
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"
|
||||
[ngClass]="{'has-error': settingsForm.showError(setting.key, formDir)}">
|
||||
*ngFor="let setting of settingsForm.controls | keyvalue">
|
||||
<div class="col-sm-12">
|
||||
<label class="control-label"
|
||||
<label class="col-form-label"
|
||||
for="{{ setting.key }}">{{ setting.key }}</label>
|
||||
<input class="form-control"
|
||||
*ngIf="!isRadio(setting.key)"
|
||||
@ -25,23 +23,27 @@
|
||||
|
||||
<ng-container *ngIf="isRadio(setting.key)">
|
||||
<br>
|
||||
<div class="radio radio-inline">
|
||||
<div class="custom-control custom-radio custom-control-inline">
|
||||
<input type="radio"
|
||||
[id]="setting.key + 'Yes'"
|
||||
value="Yes"
|
||||
[formControlName]="setting.key">
|
||||
<label [for]="setting.key + 'Yes'">Yes</label>
|
||||
[formControlName]="setting.key"
|
||||
class="custom-control-input">
|
||||
<label class="custom-col-form-label"
|
||||
[for]="setting.key + 'Yes'">Yes</label>
|
||||
</div>
|
||||
<div class="radio radio-inline">
|
||||
<div class="custom-control custom-radio custom-control-inline">
|
||||
<input type="radio"
|
||||
[id]="setting.key + 'No'"
|
||||
value="No"
|
||||
class="custom-control-input"
|
||||
[formControlName]="setting.key">
|
||||
<label [for]="setting.key + 'No'">No</label>
|
||||
<label class="custom-col-form-label"
|
||||
[for]="setting.key + 'No'">No</label>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<span class="help-block">{{ helpText[setting.key]?.help }}</span>
|
||||
<span class="form-text text-muted">{{ helpText[setting.key]?.help }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,10 +30,10 @@
|
||||
[tableActions]="tableActions">
|
||||
</cd-table-actions>
|
||||
|
||||
<button class="btn btn-sm btn-default btn-label"
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="configureDiscoveryAuth()">
|
||||
<i [ngClass]="[icons.key, icons.width]"
|
||||
<i [ngClass]="[icons.key]"
|
||||
aria-hidden="true">
|
||||
</i>
|
||||
<ng-container i18n>Discovery authentication</ng-container>
|
||||
|
@ -3,9 +3,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TreeModule } from 'ng2-tree';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { BehaviorSubject, of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -40,7 +40,7 @@ describe('IscsiTargetListComponent', () => {
|
||||
SharedModule,
|
||||
TabsModule.forRoot(),
|
||||
TreeModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
declarations: [IscsiTargetListComponent, IscsiTabsComponent, IscsiTargetDetailsComponent],
|
||||
providers: [TaskListService, i18nProviders]
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
<ng-template #statusColorTpl
|
||||
let-value="value">
|
||||
<span class="label"
|
||||
[ngClass]="{'label-success': 'up' == value, 'label-danger': 'down' == value}">{{ value }}</span>
|
||||
<span class="badge"
|
||||
[ngClass]="{'badge-success': 'up' == value, 'badge-danger': 'down' == value}">{{ value }}</span>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #iscsiSparklineTpl
|
||||
|
@ -35,7 +35,7 @@
|
||||
</ng-template>
|
||||
|
||||
<ng-template #syncTmpl>
|
||||
<span class="label label-info" i18n>Syncing</span>
|
||||
<span class="badge badge-info" i18n>Syncing</span>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #progressTmpl
|
||||
|
@ -8,18 +8,18 @@ describe('MirrorHealthColorPipe', () => {
|
||||
});
|
||||
|
||||
it('transforms "warning"', () => {
|
||||
expect(pipe.transform('warning')).toBe('label label-warning');
|
||||
expect(pipe.transform('warning')).toBe('badge badge-warning');
|
||||
});
|
||||
|
||||
it('transforms "error"', () => {
|
||||
expect(pipe.transform('error')).toBe('label label-danger');
|
||||
expect(pipe.transform('error')).toBe('badge badge-danger');
|
||||
});
|
||||
|
||||
it('transforms "success"', () => {
|
||||
expect(pipe.transform('success')).toBe('label label-success');
|
||||
expect(pipe.transform('success')).toBe('badge badge-success');
|
||||
});
|
||||
|
||||
it('transforms others', () => {
|
||||
expect(pipe.transform('abc')).toBe('label label-info');
|
||||
expect(pipe.transform('abc')).toBe('badge badge-info');
|
||||
});
|
||||
});
|
||||
|
@ -6,12 +6,12 @@ import { Pipe, PipeTransform } from '@angular/core';
|
||||
export class MirrorHealthColorPipe implements PipeTransform {
|
||||
transform(value: any): any {
|
||||
if (value === 'warning') {
|
||||
return 'label label-warning';
|
||||
return 'badge badge-warning';
|
||||
} else if (value === 'error') {
|
||||
return 'label label-danger';
|
||||
return 'badge badge-danger';
|
||||
} else if (value === 'success') {
|
||||
return 'label label-success';
|
||||
return 'badge badge-success';
|
||||
}
|
||||
return 'label label-info';
|
||||
return 'badge badge-info';
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { TreeModule } from 'ng2-tree';
|
||||
import { AlertModule } from 'ngx-bootstrap/alert';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
@ -35,7 +36,8 @@ import { PoolListComponent } from './pool-list/pool-list.component';
|
||||
ModalModule.forRoot(),
|
||||
AlertModule.forRoot(),
|
||||
TooltipModule.forRoot(),
|
||||
TreeModule
|
||||
TreeModule,
|
||||
NgBootstrapFormValidationModule
|
||||
],
|
||||
declarations: [
|
||||
DaemonListComponent,
|
||||
|
@ -2,10 +2,10 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
@ -34,7 +34,7 @@ describe('OverviewComponent', () => {
|
||||
ProgressbarModule.forRoot(),
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: i18nProviders
|
||||
});
|
||||
|
@ -15,20 +15,19 @@
|
||||
<kbd>Update</kbd>.</ng-container>
|
||||
</p>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': editModeForm.showError('mirrorMode', formDir)}">
|
||||
<label class="control-label"
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"
|
||||
for="mirrorMode">
|
||||
<span i18n>Mode</span>
|
||||
</label>
|
||||
<select id="mirrorMode"
|
||||
name="mirrorMode"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="mirrorMode">
|
||||
<option *ngFor="let mirrorMode of mirrorModes"
|
||||
[value]="mirrorMode.id">{{ mirrorMode.name }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editModeForm.showError('mirrorMode', formDir, 'cannotDisable')"
|
||||
i18n>Peer clusters must be removed prior to disabling mirror.</span>
|
||||
</div>
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -31,7 +31,7 @@ describe('PoolEditModeModalComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: [BsModalRef, BsModalService, i18nProviders]
|
||||
});
|
||||
|
@ -12,13 +12,12 @@
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
<ng-container i18n>{mode, select, edit {Edit} other {Add}} the pool
|
||||
mirror peer attributes for pool <kbd>{{ poolName }}</kbd> and click
|
||||
mirror peer attributes for pool <kbd>{{ poolName }}</kbd> and click
|
||||
<kbd>Submit</kbd>.</ng-container>
|
||||
</p>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': editPeerForm.showError('clusterName', formDir)}">
|
||||
<label class="control-label"
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"
|
||||
for="clusterName">
|
||||
<span i18n>Cluster Name</span>
|
||||
<span class="required"></span>
|
||||
@ -31,17 +30,16 @@
|
||||
name="clusterName"
|
||||
formControlName="clusterName"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('clusterName', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('clusterName', formDir, 'invalidClusterName')"
|
||||
i18n>The cluster name is not valid.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': editPeerForm.showError('clientID', formDir)}">
|
||||
<label class="control-label"
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"
|
||||
for="clientID">
|
||||
<span i18n>CephX ID</span>
|
||||
<span class="required"></span>
|
||||
@ -53,17 +51,16 @@
|
||||
id="clientID"
|
||||
name="clientID"
|
||||
formControlName="clientID">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('clientID', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('clientID', formDir, 'invalidClientID')"
|
||||
i18n>The CephX ID is not valid.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': editPeerForm.showError('monAddr', formDir)}">
|
||||
<label class="control-label"
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"
|
||||
for="monAddr">
|
||||
<span i18n>Monitor Addresses</span>
|
||||
</label>
|
||||
@ -74,14 +71,13 @@
|
||||
id="monAddr"
|
||||
name="monAddr"
|
||||
formControlName="monAddr">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('monAddr', formDir, 'invalidMonAddr')"
|
||||
i18n>The monitory address is not valid.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': editPeerForm.showError('key', formDir)}">
|
||||
<label class="control-label"
|
||||
<div class="form-group">
|
||||
<label class="col-form-label"
|
||||
for="key">
|
||||
<span i18n>CephX Key</span>
|
||||
</label>
|
||||
@ -92,7 +88,7 @@
|
||||
id="key"
|
||||
name="key"
|
||||
formControlName="key">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="editPeerForm.showError('key', formDir, 'invalidKey')"
|
||||
i18n>CephX key must be base64 encoded.</span>
|
||||
</div>
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -32,7 +32,7 @@ describe('PoolEditPeerModalComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: [BsModalRef, BsModalService, i18nProviders]
|
||||
});
|
||||
|
@ -2,10 +2,10 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
@ -25,7 +25,7 @@ describe('PoolListComponent', () => {
|
||||
ProgressbarModule.forRoot(),
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: i18nProviders
|
||||
});
|
||||
|
@ -1,74 +1,68 @@
|
||||
<fieldset #cfgFormGroup [formGroup]="form.get('configuration')">
|
||||
<fieldset #cfgFormGroup
|
||||
[formGroup]="form.get('configuration')">
|
||||
<legend i18n>RBD Configuration</legend>
|
||||
|
||||
<div *ngFor="let section of rbdConfigurationService.sections">
|
||||
<h3 class="page-header">
|
||||
<span
|
||||
(click)="toggleSectionVisibility(section.class)"
|
||||
<div *ngFor="let section of rbdConfigurationService.sections"
|
||||
class="col-12">
|
||||
<h3 class="cd-header">
|
||||
<span (click)="toggleSectionVisibility(section.class)"
|
||||
class="collapsible">{{ section.heading }} <i [ngClass]="!sectionVisibility[section.class] ? icons.addCircle : icons.minusCircle" aria-hidden="true"></i></span>
|
||||
</h3>
|
||||
<div class="{{ section.class }}" [hidden]="!sectionVisibility[section.class]">
|
||||
<div
|
||||
class="form-group"
|
||||
*ngFor="let option of section.options"
|
||||
[ngClass]="{'has-error': form.showError('configuration.' + option.name, cfgFormGroup)}">
|
||||
<label
|
||||
class="control-label col-sm-3"
|
||||
[for]="option.name">{{ option.displayName }}<cd-helper>{{ option.description }}</cd-helper></label>
|
||||
<div class="{{ section.class }}"
|
||||
[hidden]="!sectionVisibility[section.class]">
|
||||
<div class="form-group row"
|
||||
*ngFor="let option of section.options">
|
||||
<label class="col-form-label col-sm-3"
|
||||
[for]="option.name">{{ option.displayName }}<cd-helper>{{ option.description }}</cd-helper></label>
|
||||
|
||||
<div class="col-sm-9 {{ section.heading }}">
|
||||
<div class="input-group">
|
||||
<ng-container [ngSwitch]="option.type">
|
||||
<ng-container *ngSwitchCase="configurationType.milliseconds">
|
||||
<input
|
||||
[id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdMilliseconds>
|
||||
<input [id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdMilliseconds>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="configurationType.bps">
|
||||
<input
|
||||
[id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
defaultUnit="b"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdDimlessBinaryPerSecond>
|
||||
<input [id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
defaultUnit="b"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdDimlessBinaryPerSecond>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="configurationType.iops">
|
||||
<input
|
||||
[id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdIops>
|
||||
<input [id]="option.name"
|
||||
[name]="option.name"
|
||||
[formControlName]="option.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
[ngDataReady]="ngDataReady"
|
||||
cdIops>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<span class="input-group-btn">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
type="button"
|
||||
data-toggle="button"
|
||||
[ngClass]="{'active': isDisabled(option.name)}"
|
||||
title="Remove the local configuration value. The parent configuration value will be inherited and used instead."
|
||||
i18n-title
|
||||
(click)="reset(option.name)">
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
data-toggle="button"
|
||||
[ngClass]="{'active': isDisabled(option.name)}"
|
||||
title="Remove the local configuration value. The parent configuration value will be inherited and used instead."
|
||||
i18n-title
|
||||
(click)="reset(option.name)">
|
||||
<i [ngClass]="[icons.erase]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
i18n
|
||||
class="help-block"
|
||||
*ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')">The mininum value is 0</span>
|
||||
<span i18n
|
||||
class="invalid-feedback"
|
||||
*ngIf="form.showError('configuration.' + option.name, cfgFormGroup, 'min')">The mininum value is 0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@ import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { NgxDatatableModule } from '@swimlane/ngx-datatable';
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
import { AlertModule } from 'ngx-bootstrap/alert';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { ErrorPanelComponent } from '../../../shared/components/error-panel/error-panel.component';
|
||||
@ -26,6 +27,7 @@ describe('RbdConfigurationListComponent', () => {
|
||||
NgxDatatableModule,
|
||||
RouterTestingModule,
|
||||
AlertModule,
|
||||
BsDropdownModule.forRoot(),
|
||||
ChartsModule,
|
||||
PipesModule
|
||||
],
|
||||
|
@ -10,54 +10,54 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Name</td>
|
||||
<td class="col-sm-3">{{ selectedItem.name }}</td>
|
||||
class="bold w-25">Name</td>
|
||||
<td class="w-75">{{ selectedItem.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Pool</td>
|
||||
<td class="col-sm-3">{{ selectedItem.pool_name }}</td>
|
||||
class="bold">Pool</td>
|
||||
<td>{{ selectedItem.pool_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Data Pool</td>
|
||||
<td class="col-sm-3">{{ selectedItem.data_pool | empty }}</td>
|
||||
class="bold">Data Pool</td>
|
||||
<td>{{ selectedItem.data_pool | empty }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Created</td>
|
||||
<td class="col-sm-3">{{ selectedItem.timestamp | cdDate }}</td>
|
||||
class="bold">Created</td>
|
||||
<td>{{ selectedItem.timestamp | cdDate }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Size</td>
|
||||
<td class="col-sm-3">{{ selectedItem.size | dimlessBinary }}</td>
|
||||
class="bold">Size</td>
|
||||
<td>{{ selectedItem.size | dimlessBinary }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Objects</td>
|
||||
<td class="col-sm-3">{{ selectedItem.num_objs | dimless }}</td>
|
||||
class="bold">Objects</td>
|
||||
<td>{{ selectedItem.num_objs | dimless }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Object size</td>
|
||||
<td class="col-sm-3">{{ selectedItem.obj_size | dimlessBinary }}</td>
|
||||
class="bold">Object size</td>
|
||||
<td>{{ selectedItem.obj_size | dimlessBinary }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Features</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Features</td>
|
||||
<td>
|
||||
<span *ngFor="let feature of selectedItem.features_name">
|
||||
<span class="badge badge-pill badge-primary margin-right-sm">{{ feature }}</span>
|
||||
<span class="badge badge-pill badge-dark mr-2">{{ feature }}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Provisioned</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Provisioned</td>
|
||||
<td>
|
||||
<span *ngIf="selectedItem.features_name?.indexOf('fast-diff') === -1">
|
||||
<span class="text-muted"
|
||||
<span class="form-text text-muted"
|
||||
[tooltip]="usageNotAvailableTooltipTpl"
|
||||
placement="right"
|
||||
i18n>N/A</span>
|
||||
@ -69,10 +69,10 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Total provisioned</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Total provisioned</td>
|
||||
<td>
|
||||
<span *ngIf="selectedItem.features_name?.indexOf('fast-diff') === -1">
|
||||
<span class="text-muted"
|
||||
<span class="form-text text-muted"
|
||||
[tooltip]="usageNotAvailableTooltipTpl"
|
||||
placement="right"
|
||||
i18n>N/A</span>
|
||||
@ -84,18 +84,18 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Striping unit</td>
|
||||
<td class="col-sm-3">{{ selectedItem.stripe_unit | dimlessBinary }}</td>
|
||||
class="bold">Striping unit</td>
|
||||
<td>{{ selectedItem.stripe_unit | dimlessBinary }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Striping count</td>
|
||||
<td class="col-sm-3">{{ selectedItem.stripe_count }}</td>
|
||||
class="bold">Striping count</td>
|
||||
<td>{{ selectedItem.stripe_count }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Parent</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Parent</td>
|
||||
<td>
|
||||
<span *ngIf="selectedItem.parent">{{ selectedItem.parent.pool_name }}
|
||||
/{{ selectedItem.parent.image_name }}
|
||||
@{{ selectedItem.parent.snap_name }}</span>
|
||||
@ -104,13 +104,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Block name prefix</td>
|
||||
<td class="col-sm-3">{{ selectedItem.block_name_prefix }}</td>
|
||||
class="bold">Block name prefix</td>
|
||||
<td>{{ selectedItem.block_name_prefix }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Order</td>
|
||||
<td class="col-sm-3">{{ selectedItem.order }}</td>
|
||||
class="bold">Order</td>
|
||||
<td>{{ selectedItem.order }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -1,21 +1,18 @@
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<form name="rbdForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="rbdForm"
|
||||
novalidate>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="card">
|
||||
<div i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Parent -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="rbdForm.getValue('parent')">
|
||||
<label i18n
|
||||
class="control-label col-sm-3"
|
||||
class="col-form-label col-sm-3"
|
||||
for="name">{{ action | titlecase }} from</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control"
|
||||
@ -28,9 +25,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('name', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="name">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -43,11 +39,11 @@
|
||||
name="name"
|
||||
formControlName="name"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('name', formDir, 'required')">
|
||||
<ng-container i18n>This field is required.</ng-container>
|
||||
</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('name', formDir, 'pattern')">
|
||||
<ng-container i18n>'/' and '@' are not allowed.</ng-container>
|
||||
</span>
|
||||
@ -55,10 +51,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Pool -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('pool', formDir)}"
|
||||
<div class="form-group row"
|
||||
(change)="onPoolChange($event.target.value)">
|
||||
<label class="control-label col-sm-3"
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="pool">
|
||||
Pool
|
||||
<span class="required"
|
||||
@ -74,7 +69,7 @@
|
||||
*ngIf="mode === 'editing' || !poolPermission.read">
|
||||
<select id="pool"
|
||||
name="pool"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="pool"
|
||||
*ngIf="mode !== 'editing' && poolPermission.read">
|
||||
<option *ngIf="pools === null"
|
||||
@ -90,31 +85,32 @@
|
||||
[value]="pool.pool_name">{{ pool.pool_name }}</option>
|
||||
</select>
|
||||
<span *ngIf="rbdForm.showError('pool', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Use a dedicated pool -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
id="useDataPool"
|
||||
name="useDataPool"
|
||||
formControlName="useDataPool"
|
||||
(change)="onUseDataPoolChange()">
|
||||
<label i18n
|
||||
for="useDataPool">Use a dedicated data pool</label>
|
||||
<label class="custom-control-label"
|
||||
for="useDataPool"
|
||||
i18n>Use a dedicated data pool</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Pool -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('dataPool', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="rbdForm.getValue('useDataPool')">
|
||||
<label class="control-label col-sm-3"
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="dataPool">
|
||||
<ng-container i18n>Data pool</ng-container>
|
||||
<span class="required"
|
||||
@ -133,7 +129,7 @@
|
||||
*ngIf="mode === 'editing' || !poolPermission.read">
|
||||
<select id="dataPool"
|
||||
name="dataPool"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="dataPool"
|
||||
(change)="onDataPoolChange($event.target.value)"
|
||||
*ngIf="mode !== 'editing' && poolPermission.read">
|
||||
@ -149,16 +145,15 @@
|
||||
<option *ngFor="let dataPool of dataPools"
|
||||
[value]="dataPool.pool_name">{{ dataPool.pool_name }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('dataPool', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Size -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('size', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="size">
|
||||
<ng-container i18n>Size</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -173,30 +168,31 @@
|
||||
placeholder="e.g., 10GiB"
|
||||
defaultUnit="GiB"
|
||||
cdDimlessBinary>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('size', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('size', formDir, 'invalidSizeObject')"
|
||||
i18n>You have to increase the size.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': (formDir.submitted || rbdForm.get('features').dirty) && rbdForm.get('features').invalid}"
|
||||
<div class="form-group row"
|
||||
formGroupName="features">
|
||||
<label i18n
|
||||
class="col-sm-3 control-label"
|
||||
class="col-sm-3 col-form-label"
|
||||
for="features">Features</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox checkbox-primary"
|
||||
<div class="custom-control custom-checkbox"
|
||||
*ngFor="let feature of featuresList">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
id="{{ feature.key }}"
|
||||
name="{{ feature.key }}"
|
||||
formControlName="{{ feature.key }}">
|
||||
<label for="{{ feature.key }}">{{ feature.desc }}</label>
|
||||
<label class="custom-control-label"
|
||||
for="{{ feature.key }}">{{ feature.desc }}</label>
|
||||
<cd-helper *ngIf="feature.helperHtml"
|
||||
html="{{ feature.helperHtml }}">
|
||||
</cd-helper>
|
||||
@ -207,30 +203,32 @@
|
||||
<!-- Advanced -->
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<a class="pull-right margin-right-md"
|
||||
(click)="advancedEnabled = true"
|
||||
<a class="float-right margin-right-md"
|
||||
(click)="advancedEnabled = true; false"
|
||||
*ngIf="!advancedEnabled"
|
||||
href=""
|
||||
i18n>Advanced...</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div [hidden]="!advancedEnabled">
|
||||
|
||||
<h2 i18n
|
||||
class="page-header">Advanced</h2>
|
||||
<legend class="cd-header"
|
||||
i18n>Advanced</legend>
|
||||
|
||||
<div class="section">
|
||||
<h3 class="page-header" i18n>Striping</h3>
|
||||
<div class="col-md-12">
|
||||
<h3 class="cd-header"
|
||||
i18n>Striping</h3>
|
||||
|
||||
<!-- Object Size -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('obj_size', formDir)}">
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="control-label col-sm-3"
|
||||
class="col-form-label col-sm-3"
|
||||
for="size">Object size</label>
|
||||
<div class="col-sm-9">
|
||||
<select id="obj_size"
|
||||
name="obj_size"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="obj_size">
|
||||
<option *ngFor="let objectSize of objectSizes"
|
||||
[value]="objectSize">{{ objectSize }}</option>
|
||||
@ -238,44 +236,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Unit -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('stripingUnit', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<!-- stripingUnit -->
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="stripingUnit">
|
||||
<span i18n>Stripe unit</span>
|
||||
<span class="required"
|
||||
*ngIf="rbdForm.getValue('stripingCount')">
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select id="stripingUnit"
|
||||
name="stripingUnit"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="stripingUnit">
|
||||
<option i18n
|
||||
[ngValue]="null">-- Select stripe unit --</option>
|
||||
<option *ngFor="let objectSize of objectSizes"
|
||||
[value]="objectSize">{{ objectSize }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('stripingUnit', formDir, 'required')"
|
||||
i18n>This field is required because stripe count is defined!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('stripingUnit', formDir, 'invalidStripingUnit')"
|
||||
i18n>Stripe unit is greater than object size.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stripe Count -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': rbdForm.showError('stripingCount', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="stripingCount">
|
||||
<span i18n>Stripe count</span>
|
||||
<span class="required"
|
||||
*ngIf="rbdForm.getValue('stripingUnit')">
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input id="stripingCount"
|
||||
@ -283,32 +279,27 @@
|
||||
formControlName="stripingCount"
|
||||
class="form-control"
|
||||
type="number">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('stripingCount', formDir, 'required')"
|
||||
i18n>This field is required because stripe unit is defined!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="rbdForm.showError('stripingCount', formDir, 'min')"
|
||||
i18n>Stripe count must be greater than 0.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<cd-rbd-configuration-form [form]="rbdForm"
|
||||
[initializeData]="initializeConfigData"
|
||||
(changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
|
||||
</div>
|
||||
|
||||
<cd-rbd-configuration-form [form]="rbdForm"
|
||||
[initializeData]="initializeConfigData"
|
||||
(changes)="getDirtyConfigurationValues = $event"></cd-rbd-configuration-form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button
|
||||
[form]="formDir"
|
||||
(submitAction)="submit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-submit-button (submitAction)="submit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
[form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-back-button></cd-back-button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { TooltipModule } from 'ngx-bootstrap/tooltip';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of } from 'rxjs';
|
||||
@ -30,7 +30,7 @@ describe('RbdFormComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
SharedModule,
|
||||
TooltipModule
|
||||
],
|
||||
@ -83,7 +83,10 @@ describe('RbdFormComponent', () => {
|
||||
describe('test image configuration component', () => {
|
||||
it('is visible', () => {
|
||||
fixture.detectChanges();
|
||||
expect(queryNativeElement('cd-rbd-configuration-form').parentElement.hidden).toBe(false);
|
||||
expect(
|
||||
fixture.debugElement.query(By.css('cd-rbd-configuration-form')).nativeElement.parentElement
|
||||
.hidden
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2,9 +2,9 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { TooltipModule } from 'ngx-bootstrap/tooltip';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { TaskListService } from '../../../shared/services/task-list.service';
|
||||
@ -34,7 +34,7 @@ describe('RbdImagesComponent', () => {
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
TabsModule.forRoot(),
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
TooltipModule.forRoot()
|
||||
],
|
||||
providers: [TaskListService, i18nProviders]
|
||||
|
@ -3,12 +3,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { AlertModule } from 'ngx-bootstrap/alert';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { TooltipModule } from 'ngx-bootstrap/tooltip';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { BehaviorSubject, of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -47,7 +47,7 @@ describe('RbdListComponent', () => {
|
||||
TabsModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
TooltipModule.forRoot(),
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
AlertModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
HttpClientTestingModule
|
||||
|
@ -1,24 +1,22 @@
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title pull-left"
|
||||
<h4 class="modal-title float-left"
|
||||
i18n>{ editing, select, true {Rename} other {Create}} RBD Snapshot</h4>
|
||||
<button type="button"
|
||||
class="close pull-right"
|
||||
class="close float-right"
|
||||
aria-label="Close"
|
||||
(click)="modalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form name="snapshotForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="snapshotForm"
|
||||
novalidate>
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': snapshotForm.showError('snapshotName', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="snapshotName">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -31,7 +29,7 @@
|
||||
name="snapshotName"
|
||||
formControlName="snapshotName"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="snapshotForm.showError('snapshotName', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
</div>
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { ApiModule } from '../../../shared/api/api.module';
|
||||
@ -22,7 +22,7 @@ describe('RbdSnapshotFormComponent', () => {
|
||||
ComponentsModule,
|
||||
HttpClientTestingModule,
|
||||
ApiModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [RbdSnapshotFormComponent],
|
||||
|
@ -13,10 +13,10 @@
|
||||
<ng-template #protectTpl
|
||||
let-value="value">
|
||||
<span *ngIf="value"
|
||||
class="label label-success"
|
||||
class="badge badge-success">
|
||||
i18n>PROTECTED</span>
|
||||
<span *ngIf="!value"
|
||||
class="label label-info"
|
||||
class="badge badge-info"
|
||||
i18n>UNPROTECTED</span>
|
||||
</ng-template>
|
||||
|
||||
|
@ -4,8 +4,8 @@ import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { Subject, throwError as observableThrowError } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -48,7 +48,7 @@ describe('RbdSnapshotListComponent', () => {
|
||||
imports: [
|
||||
DataTableModule,
|
||||
ComponentsModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
ApiModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
|
@ -16,11 +16,11 @@
|
||||
[tableActions]="tableActions">
|
||||
</cd-table-actions>
|
||||
|
||||
<button class="btn btn-sm btn-default btn-label"
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="purgeModal()"
|
||||
*ngIf="permission.delete">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
<ng-container i18n>Purge Trash</ng-container>
|
||||
</button>
|
||||
|
@ -2,7 +2,7 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { By } from '@angular/platform-browser';
|
||||
@ -23,7 +23,7 @@ describe('RbdTrashListComponent', () => {
|
||||
|
||||
configureTestBed({
|
||||
declarations: [RbdTrashListComponent],
|
||||
imports: [SharedModule, HttpClientTestingModule, RouterTestingModule, ToastModule.forRoot()],
|
||||
imports: [SharedModule, HttpClientTestingModule, RouterTestingModule, ToastrModule.forRoot()],
|
||||
providers: [TaskListService, i18nProviders]
|
||||
});
|
||||
|
||||
|
@ -12,8 +12,7 @@
|
||||
<p i18n>To move <kbd>{{ poolName }}/{{ imageName }}</kbd> to trash,
|
||||
click <kbd>Move Image</kbd>. Optionally, you can pick an expiration date.</p>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': moveForm.showError('expiresAt', formDir)}">
|
||||
<div class="form-group">
|
||||
<label for="expires"
|
||||
i18n>Protection expires at</label>
|
||||
<input type="text"
|
||||
@ -24,10 +23,10 @@
|
||||
[bsConfig]="bsConfig"
|
||||
formControlName="expiresAt"
|
||||
bsDatepicker>
|
||||
<span class="help-block"
|
||||
<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="help-block"
|
||||
<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>
|
||||
|
@ -4,9 +4,9 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import * as moment from 'moment';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { NotificationService } from '../../../shared/services/notification.service';
|
||||
@ -24,7 +24,7 @@ describe('RbdTrashMoveModalComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
BsDatepickerModule.forRoot()
|
||||
],
|
||||
declarations: [RbdTrashMoveModalComponent],
|
||||
|
@ -15,7 +15,7 @@
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="center-block"
|
||||
<label class="mx-auto"
|
||||
i18n>Pool:</label>
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
@ -23,7 +23,7 @@
|
||||
i18n-placeholder
|
||||
formControlName="poolName"
|
||||
*ngIf="!poolPermission.read">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="poolName"
|
||||
*ngIf="poolPermission.read">
|
||||
<option value=""
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { Permission } from '../../../shared/models/permissions';
|
||||
@ -22,7 +22,7 @@ describe('RbdTrashPurgeModalComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [RbdTrashPurgeModalComponent],
|
||||
|
@ -16,8 +16,7 @@
|
||||
<kbd i18n>Restore Image</kbd>.
|
||||
</p>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': restoreForm.showError('name', formDir)}">
|
||||
<div class="form-group">
|
||||
<label for="name"
|
||||
i18n>New Name</label>
|
||||
<input type="text"
|
||||
@ -27,7 +26,7 @@
|
||||
autocomplete="off"
|
||||
formControlName="name"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="restoreForm.showError('name', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
</div>
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
import { NotificationService } from '../../../shared/services/notification.service';
|
||||
@ -20,7 +20,7 @@ describe('RbdTrashRestoreModalComponent', () => {
|
||||
imports: [
|
||||
ReactiveFormsModule,
|
||||
HttpClientTestingModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
SharedModule,
|
||||
RouterTestingModule
|
||||
],
|
||||
|
@ -35,7 +35,7 @@
|
||||
</tab>
|
||||
<tab i18n-heading
|
||||
heading="Clients: {{ clientCount }}"
|
||||
(select)="clientsSelect=true"
|
||||
(selectTab)="clientsSelect=true"
|
||||
(deselect)="clientsSelect=false">
|
||||
<cd-cephfs-clients [id]="id"
|
||||
*ngIf="clientsSelect">
|
||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { TreeModule } from 'ng2-tree';
|
||||
import { AlertModule } from 'ngx-bootstrap/alert';
|
||||
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||
@ -66,7 +67,8 @@ import { SilenceMatcherModalComponent } from './prometheus/silence-matcher-modal
|
||||
MgrModulesModule,
|
||||
TypeaheadModule.forRoot(),
|
||||
TimepickerModule.forRoot(),
|
||||
BsDatepickerModule.forRoot()
|
||||
BsDatepickerModule.forRoot(),
|
||||
NgBootstrapFormValidationModule
|
||||
],
|
||||
declarations: [
|
||||
HostsComponent,
|
||||
|
@ -5,102 +5,102 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Name</td>
|
||||
<td class="col-sm-3">{{ selectedItem.name }}</td>
|
||||
class="bold w-25">Name</td>
|
||||
<td class="w-75">{{ selectedItem.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Description</td>
|
||||
<td class="col-sm-3">{{ selectedItem.desc }}</td>
|
||||
class="bold">Description</td>
|
||||
<td>{{ selectedItem.desc }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Long description</td>
|
||||
<td class="col-sm-3">{{ selectedItem.long_desc }}</td>
|
||||
class="bold">Long description</td>
|
||||
<td>{{ selectedItem.long_desc }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Current values</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Current values</td>
|
||||
<td>
|
||||
<span *ngFor="let conf of selectedItem.value; last as isLast">
|
||||
{{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br/>
|
||||
{{ conf.section }}: {{ conf.value }}{{ !isLast ? "," : "" }}<br />
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Default</td>
|
||||
<td class="col-sm-3">{{ selectedItem.default }}</td>
|
||||
class="bold">Default</td>
|
||||
<td>{{ selectedItem.default }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Daemon default</td>
|
||||
<td class="col-sm-3">{{ selectedItem.daemon_default }}</td>
|
||||
class="bold">Daemon default</td>
|
||||
<td>{{ selectedItem.daemon_default }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Type</td>
|
||||
<td class="col-sm-3">{{ selectedItem.type }}</td>
|
||||
class="bold">Type</td>
|
||||
<td>{{ selectedItem.type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Min</td>
|
||||
<td class="col-sm-3">{{ selectedItem.min }}</td>
|
||||
class="bold">Min</td>
|
||||
<td>{{ selectedItem.min }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Max</td>
|
||||
<td class="col-sm-3">{{ selectedItem.max }}</td>
|
||||
class="bold">Max</td>
|
||||
<td>{{ selectedItem.max }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Flags</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Flags</td>
|
||||
<td>
|
||||
<span *ngFor="let flag of selectedItem.flags">
|
||||
<span title="{{ flags[flag] }}">
|
||||
<span class="badge badge-pill badge-primary margin-right-sm">{{ flag | uppercase }}</span>
|
||||
<span class="badge badge-pill badge-dark mr-2">{{ flag | uppercase }}</span>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Services</td>
|
||||
<td class="col-sm-3">
|
||||
class="bold">Services</td>
|
||||
<td>
|
||||
<span *ngFor="let service of selectedItem.services">
|
||||
<span class="badge badge-pill badge-primary margin-right-sm">{{ service }}</span>
|
||||
<span class="badge badge-pill badge-dark mr-2">{{ service }}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Source</td>
|
||||
<td class="col-sm-3">{{ selectedItem.source }}</td>
|
||||
class="bold">Source</td>
|
||||
<td>{{ selectedItem.source }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Level</td>
|
||||
<td class="col-sm-3">{{ selectedItem.level }}</td>
|
||||
class="bold">Level</td>
|
||||
<td>{{ selectedItem.level }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Can be updated at runtime (editable)</td>
|
||||
<td class="col-sm-3">{{ selectedItem.can_update_at_runtime | booleanText }}</td>
|
||||
class="bold">Can be updated at runtime (editable)</td>
|
||||
<td>{{ selectedItem.can_update_at_runtime | booleanText }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Tags</td>
|
||||
<td class="col-sm-3">{{ selectedItem.tags }}</td>
|
||||
class="bold">Tags</td>
|
||||
<td>{{ selectedItem.tags }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">Enum values</td>
|
||||
<td class="col-sm-3">{{ selectedItem.enum_values }}</td>
|
||||
class="bold">Enum values</td>
|
||||
<td>{{ selectedItem.enum_values }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td i18n
|
||||
class="bold col-sm-1">See also</td>
|
||||
<td class="col-sm-3">{{ selectedItem.see_also }}</td>
|
||||
class="bold">See also</td>
|
||||
<td>{{ selectedItem.see_also }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -1,21 +1,18 @@
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
||||
<form name="configForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="configForm"
|
||||
novalidate>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<ng-container i18n>Edit</ng-container> {{ configForm.getValue('name') }}
|
||||
</h3>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<ng-container i18>Edit</ng-container> {{ configForm.getValue('name') }}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="card-body">
|
||||
<!-- Name -->
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Name</label>
|
||||
class="col-form-label col-sm-3">Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
@ -26,10 +23,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="configForm.getValue('desc')">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Description</label>
|
||||
class="col-form-label col-sm-3">Description</label>
|
||||
<div class="col-sm-9">
|
||||
<textarea class="form-control resize-vertical"
|
||||
id="desc"
|
||||
@ -40,10 +37,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Long description -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="configForm.getValue('long_desc')">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Long description</label>
|
||||
class="col-form-label col-sm-3">Long description</label>
|
||||
<div class="col-sm-9">
|
||||
<textarea class="form-control resize-vertical"
|
||||
id="long_desc"
|
||||
@ -54,10 +51,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Default -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="configForm.getValue('default') !== ''">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Default</label>
|
||||
class="col-form-label col-sm-3">Default</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
@ -68,10 +65,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Daemon default -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="configForm.getValue('daemon_default') !== ''">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Daemon default</label>
|
||||
class="col-form-label col-sm-3">Daemon default</label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
@ -82,41 +79,41 @@
|
||||
</div>
|
||||
|
||||
<!-- Services -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="configForm.getValue('services').length > 0">
|
||||
<label i18n
|
||||
class="control-label col-sm-3">Services</label>
|
||||
class="col-form-label col-sm-3">Services</label>
|
||||
<div class="col-sm-9">
|
||||
<span *ngFor="let service of configForm.getValue('services')"
|
||||
class="form-component-badge">
|
||||
<span class="badge badge-pill badge-primary">{{ service }}</span>
|
||||
<span class="badge badge-pill badge-dark">{{ service }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Values -->
|
||||
<div class="col-sm-12"
|
||||
formGroupName="values">
|
||||
<div formGroupName="values">
|
||||
<h2 i18n
|
||||
class="page-header">Values</h2>
|
||||
<div class="row"
|
||||
*ngFor="let section of availSections">
|
||||
<div class="form-group"
|
||||
class="cd-header">Values</h2>
|
||||
<ng-container *ngFor="let section of availSections">
|
||||
<div class="form-group row"
|
||||
*ngIf="type === 'bool'">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input [id]="section"
|
||||
type="checkbox"
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
[id]="section"
|
||||
[formControlName]="section">
|
||||
<label [for]="section">{{ section }}
|
||||
<label class="custom-control-label"
|
||||
[for]="section">{{ section }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': configForm.showError(section, formDir)}"
|
||||
|
||||
<div class="form-group row"
|
||||
*ngIf="type !== 'bool'">
|
||||
<label class="control-label col-sm-3"
|
||||
<label class="col-form-label col-sm-3"
|
||||
[for]="section">{{ section }}
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
@ -126,30 +123,29 @@
|
||||
[placeholder]="humanReadableType"
|
||||
[formControlName]="section"
|
||||
[step]="getStep(type, this.configForm.getValue(section))">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="configForm.showError(section, formDir, 'pattern')">
|
||||
{{ patternHelpText }}
|
||||
</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="configForm.showError(section, formDir, 'invalidUuid')">
|
||||
{{ patternHelpText }}
|
||||
</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="configForm.showError(section, formDir, 'max')"
|
||||
i18n>The entered value is too high! It must not be greater than {{ maxValue }}.</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="configForm.showError(section, formDir, 'min')"
|
||||
i18n>The entered value is too low! It must not be lower than {{ minValue }}.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<div class="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button [form]="formDir"
|
||||
type="button"
|
||||
(submitAction)="submit()">
|
||||
<span i18n>Save</span>
|
||||
</cd-submit-button>
|
||||
|
@ -4,7 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
import { ConfigFormModel } from '../../../../shared/components/config-option/config-option.model';
|
||||
@ -20,7 +20,7 @@ describe('ConfigurationFormComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
SharedModule
|
||||
],
|
||||
declarations: [ConfigurationFormComponent],
|
||||
|
@ -8,32 +8,40 @@
|
||||
[selection]="selection"
|
||||
[tableActions]="tableActions">
|
||||
</cd-table-actions>
|
||||
<div class="table-filters">
|
||||
<div class="table-filters form-inline">
|
||||
<div class="form-group filter"
|
||||
*ngFor="let filter of filters">
|
||||
<label>{{ filter.label }}: </label>
|
||||
<select class="form-control input-sm"
|
||||
<select class="form-control custom-select"
|
||||
[(ngModel)]="filter.value"
|
||||
(ngModelChange)="updateFilter()">
|
||||
<option *ngFor="let opt of filter.options">{{ opt }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<a [ngClass]="[icons.stack]"
|
||||
title="Reset filters"
|
||||
(click)="resetFilter()">
|
||||
<i [ngClass]="[icons.filter, icons.stack2x]"></i>
|
||||
<i [ngClass]="[icons.destroy, icons.stack1x]" style="margin-left: 8px; margin-top: 5px;"></i>
|
||||
</a>
|
||||
|
||||
<div class="widget-toolbar tc_refreshBtn">
|
||||
<button type="button"
|
||||
title="Reset filters"
|
||||
class="btn btn-light"
|
||||
(click)="resetFilter()">
|
||||
<span [ngClass]="[icons.stack]">
|
||||
<i [ngClass]="[icons.filter, icons.stack2x]"></i>
|
||||
<i [ngClass]="[icons.destroy, icons.stack1x]"
|
||||
style="margin-left: 8px; margin-top: 5px;"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<cd-configuration-details cdTableDetail
|
||||
[selection]="selection">
|
||||
</cd-configuration-details>
|
||||
</cd-table>
|
||||
|
||||
<ng-template #confValTpl let-value="value">
|
||||
<ng-template #confValTpl
|
||||
let-value="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>
|
||||
|
@ -2,6 +2,10 @@
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.fa-stack {
|
||||
font-size: 0.79rem;
|
||||
}
|
||||
|
||||
::ng-deep datatable-body-cell.wrap {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
@ -1,29 +1,31 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<span i18n>CRUSH map viewer</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-sm-6 col-lg-6">
|
||||
<tree [tree]="tree"
|
||||
[settings]="{rootIsVisible: false}"
|
||||
(nodeSelected)="onNodeSelected($event)">
|
||||
<ng-template let-node>
|
||||
<span class="label"
|
||||
[ngClass]="{'label-success': ['in', 'up'].includes(node.status), 'label-danger': ['down', 'out'].includes(node.status)}">{{ node.status }}</span>
|
||||
<span> </span>
|
||||
<span class="node-name" [innerHTML]="node.value"></span>
|
||||
</ng-template>
|
||||
</tree>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-6 metadata" *ngIf="metadata">
|
||||
<legend>{{ metadataTitle }}</legend>
|
||||
<cd-table-key-value [data]="metadata"></cd-table-key-value>
|
||||
<div class="card">
|
||||
<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 [tree]="tree"
|
||||
[settings]="{rootIsVisible: false}"
|
||||
(nodeSelected)="onNodeSelected($event)">
|
||||
<ng-template let-node>
|
||||
<span class="badge"
|
||||
[ngClass]="{'badge-success': ['in', 'up'].includes(node.status), 'badge-danger': ['down', 'out'].includes(node.status)}">
|
||||
{{ node.status }}
|
||||
</span>
|
||||
<span> </span>
|
||||
<span class="node-name"
|
||||
[innerHTML]="node.value"></span>
|
||||
</ng-template>
|
||||
</tree>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-6 metadata"
|
||||
*ngIf="metadata">
|
||||
<legend>{{ metadataTitle }}</legend>
|
||||
<cd-table-key-value [data]="metadata"></cd-table-key-value>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@ describe('CrushmapComponent', () => {
|
||||
|
||||
it('should display right title', () => {
|
||||
fixture.detectChanges();
|
||||
const span = debugElement.nativeElement.querySelector('span');
|
||||
const span = debugElement.nativeElement.querySelector('.card-header');
|
||||
expect(span.textContent).toBe('CRUSH map viewer');
|
||||
});
|
||||
|
||||
|
@ -1,72 +1,80 @@
|
||||
<div *ngIf="contentData">
|
||||
<ng-container *ngTemplateOutlet="logFiltersTpl"></ng-container>
|
||||
<tabset>
|
||||
<tab i18n-heading
|
||||
heading="Cluster Logs">
|
||||
<div class="well">
|
||||
<div *ngIf="clog">
|
||||
<p *ngFor="let line of clog">
|
||||
<span class="timestamp">{{ line.stamp | cdDate }}</span>
|
||||
<span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
|
||||
<span class="message">{{ line.message }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div *ngIf="contentData.clog.length === 0">
|
||||
<p i18n>No entries found</p>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
<ng-container *ngTemplateOutlet="logFiltersTpl"></ng-container>
|
||||
|
||||
<tab i18n-heading
|
||||
heading="Audit Logs">
|
||||
<div class="well">
|
||||
<div *ngIf="audit_log">
|
||||
<p *ngFor="let line of audit_log">
|
||||
<span class="timestamp">{{ line.stamp | cdDate }}</span>
|
||||
<span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
|
||||
<span class="message">{{ line.message }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div *ngIf="contentData.audit_log.length === 0">
|
||||
<p i18n>No entries found</p>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
</tabset>
|
||||
<tabset>
|
||||
<tab i18n-heading
|
||||
heading="Cluster Logs">
|
||||
<div class="card bg-light mb-3"
|
||||
*ngIf="clog">
|
||||
<div class="card-body">
|
||||
<p *ngFor="let line of clog">
|
||||
<span class="timestamp">{{ line.stamp | cdDate }}</span>
|
||||
<span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
|
||||
<span class="message">{{ line.message }}</span>
|
||||
</p>
|
||||
|
||||
<span *ngIf="contentData.clog.length === 0"
|
||||
i18n>No entries found</span>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
|
||||
<tab i18n-heading
|
||||
heading="Audit Logs">
|
||||
<div class="card bg-light mb-3"
|
||||
*ngIf="audit_log">
|
||||
<div class="card-body">
|
||||
<p *ngFor="let line of audit_log">
|
||||
<span class="timestamp">{{ line.stamp | cdDate }}</span>
|
||||
<span class="priority {{ line.priority | logPriority }}">{{ line.priority }}</span>
|
||||
<span class="message">{{ line.message }}</span>
|
||||
</p>
|
||||
|
||||
<span *ngIf="contentData.audit_log.length === 0"
|
||||
i18n>No entries found</span>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
</tabset>
|
||||
</div>
|
||||
|
||||
<ng-template #logFiltersTpl>
|
||||
<div class="row log-filters">
|
||||
<div class="col-xs-4 col-md-2 cd-col-1 filter-box">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<label i18n>Priority:</label>
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
[(ngModel)]="priority"
|
||||
(ngModelChange)="filterLogs()">
|
||||
<option class="form-control"
|
||||
*ngFor="let prio of prioritys"
|
||||
<option *ngFor="let prio of prioritys"
|
||||
[value]="prio.value">{{ prio.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-4 col-md-3 cd-col-3 filter-box">
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n>Keyword:</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">
|
||||
<i [ngClass]="[icons.search]"></i>
|
||||
</span>
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
<i [ngClass]="[icons.search]"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<input class="form-control"
|
||||
type="text"
|
||||
[(ngModel)]="search"
|
||||
(keyup)="filterLogs()">
|
||||
<span class="input-group-btn">
|
||||
|
||||
<div class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default clear-input tc_clearInputBtn"
|
||||
class="btn btn-light"
|
||||
(click)="clearSearchKey()">
|
||||
<i class="icon-prepend {{ icons.destroy }}"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-4 col-md-3 cd-col-2 filter-box">
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n>Date:</label>
|
||||
<div class="input-group">
|
||||
<input type="text"
|
||||
@ -77,31 +85,33 @@
|
||||
bsDatepicker
|
||||
[(ngModel)]="selectedDate"
|
||||
(ngModelChange)="filterLogs()">
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default clear-input tc_clearInputBtn"
|
||||
class="btn btn-light"
|
||||
(click)="clearDate()">
|
||||
<i class="icon-prepend {{ icons.destroy }}"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix visible-xs-block"></div>
|
||||
<div class="col-xs-8 col-md-4 cd-col-4 filter-box time-box">
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n>Time range:</label>
|
||||
<timepicker [showMeridian]="false"
|
||||
[showSpinners]="showSpinners"
|
||||
[minuteStep]="1"
|
||||
[(ngModel)]="startTime"
|
||||
(ngModelChange)="filterLogs()">
|
||||
</timepicker>
|
||||
<span> — </span>
|
||||
<timepicker [showMeridian]="false"
|
||||
[showSpinners]="showSpinners"
|
||||
[minuteStep]="1"
|
||||
[(ngModel)]="endTime"
|
||||
(ngModelChange)="filterLogs()">
|
||||
</timepicker>
|
||||
<div class="d-inline-flex">
|
||||
<timepicker [showMeridian]="false"
|
||||
[showSpinners]="false"
|
||||
[minuteStep]="1"
|
||||
[(ngModel)]="startTime"
|
||||
(ngModelChange)="filterLogs()">
|
||||
</timepicker>
|
||||
<span class="middle"> — </span>
|
||||
<timepicker [showMeridian]="false"
|
||||
[showSpinners]="false"
|
||||
[minuteStep]="1"
|
||||
[(ngModel)]="endTime"
|
||||
(ngModelChange)="filterLogs()">
|
||||
</timepicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -1,11 +1,10 @@
|
||||
@import '../../../../defaults';
|
||||
@import 'styles';
|
||||
|
||||
p {
|
||||
font-family: monospace;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.well {
|
||||
.card {
|
||||
div p {
|
||||
display: flex;
|
||||
|
||||
@ -41,103 +40,22 @@ p {
|
||||
}
|
||||
|
||||
::ng-deep timepicker table tbody tr td {
|
||||
.bs-timepicker-field {
|
||||
width: 3.5rem;
|
||||
input.bs-timepicker-field {
|
||||
width: 3.5rem !important;
|
||||
font-size: 1rem;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
.btn {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.log-filters {
|
||||
margin-bottom: 5px;
|
||||
padding: 0 30px;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.filter-box {
|
||||
margin: 0;
|
||||
padding: 0 15px 5px 0;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
label {
|
||||
padding-top: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.time-box {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.cd-col-4 {
|
||||
width: 28vw;
|
||||
}
|
||||
|
||||
.cd-col-3 {
|
||||
width: 20vw;
|
||||
}
|
||||
|
||||
.cd-col-2 {
|
||||
width: 16vw;
|
||||
}
|
||||
.cd-col-1 {
|
||||
width: 14vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.cd-col-4 {
|
||||
width: 24vw;
|
||||
}
|
||||
|
||||
.cd-col-3 {
|
||||
width: 18vw;
|
||||
}
|
||||
|
||||
.cd-col-2 {
|
||||
width: 14vw;
|
||||
}
|
||||
.cd-col-1 {
|
||||
width: 12vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1600px) {
|
||||
.cd-col-4 {
|
||||
width: 22vw;
|
||||
}
|
||||
|
||||
.cd-col-3 {
|
||||
width: 16vw;
|
||||
}
|
||||
|
||||
.cd-col-2 {
|
||||
width: 12vw;
|
||||
}
|
||||
.cd-col-1 {
|
||||
width: 10vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1800px) {
|
||||
.cd-col-3 {
|
||||
width: 14vw;
|
||||
}
|
||||
|
||||
.cd-col-2 {
|
||||
width: 11vw;
|
||||
}
|
||||
.cd-col-1 {
|
||||
width: 9vw;
|
||||
}
|
||||
}
|
||||
label {
|
||||
@extend .mr-2;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
@extend .mr-3;
|
||||
@extend .mb-3;
|
||||
}
|
||||
|
||||
.middle {
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
@ -6,21 +6,18 @@
|
||||
<div class="col-sm-12 col-lg-6"
|
||||
*ngIf="!loading && !error">
|
||||
<form name="mgrModuleForm"
|
||||
class="form-horizontal"
|
||||
#frm="ngForm"
|
||||
[formGroup]="mgrModuleForm"
|
||||
novalidate>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title" i18n>Edit Manager module</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': mgrModuleForm.showError(moduleOption.value.name, frm)}"
|
||||
<div class="card">
|
||||
<div class="card-header"
|
||||
i18n>Edit Manager module</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group row"
|
||||
*ngFor="let moduleOption of moduleOptions | keyvalue">
|
||||
|
||||
<!-- Field label -->
|
||||
<label class="control-label col-sm-3"
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="{{ moduleOption.value.name }}">
|
||||
{{ moduleOption.value.name }}
|
||||
<cd-helper *ngIf="moduleOption.value.long_desc || moduleOption.value.desc">
|
||||
@ -32,11 +29,13 @@
|
||||
<!-- bool -->
|
||||
<div class="col-sm-7"
|
||||
*ngIf="moduleOption.value.type === 'bool'">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input id="{{ moduleOption.value.name }}"
|
||||
type="checkbox"
|
||||
class="custom-control-input"
|
||||
formControlName="{{ moduleOption.value.name }}">
|
||||
<label for="{{ moduleOption.value.name }}"></label>
|
||||
<label class="custom-control-label"
|
||||
for="{{ moduleOption.value.name }}"></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,7 +48,7 @@
|
||||
formControlName="{{ moduleOption.value.name }}"
|
||||
*ngIf="moduleOption.value.enum_allowed.length === 0">
|
||||
<select id="{{ moduleOption.value.name }}"
|
||||
class="form-control"
|
||||
class="form-control custom-select"
|
||||
formControlName="{{ moduleOption.value.name }}"
|
||||
*ngIf="moduleOption.value.enum_allowed.length > 0">
|
||||
<option *ngFor="let value of moduleOption.value.enum_allowed"
|
||||
@ -57,10 +56,10 @@
|
||||
{{ value }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<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="help-block"
|
||||
<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>
|
||||
@ -74,16 +73,16 @@
|
||||
formControlName="{{ moduleOption.value.name }}"
|
||||
min="{{ moduleOption.value.min }}"
|
||||
max="{{ moduleOption.value.max }}">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
<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="help-block"
|
||||
<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="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'pattern')"
|
||||
i18n>The entered value needs to be a number.</span>
|
||||
</div>
|
||||
@ -95,25 +94,24 @@
|
||||
class="form-control"
|
||||
type="number"
|
||||
formControlName="{{ moduleOption.value.name }}">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="mgrModuleForm.showError(moduleOption.value.name, frm, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
<span class="help-block"
|
||||
<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="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button type="button"
|
||||
(submitAction)="onSubmit()"
|
||||
<cd-submit-button (submitAction)="onSubmit()"
|
||||
[form]="mgrModuleForm">
|
||||
<ng-container i18n>Update</ng-container>
|
||||
</cd-submit-button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-default"
|
||||
class="btn btn-light"
|
||||
routerLink="/mgr-modules"
|
||||
i18n>Back</button>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
@ -20,7 +20,7 @@ describe('MgrModuleFormComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: i18nProviders
|
||||
});
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of as observableOf, throwError as observableThrowError } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -33,7 +33,7 @@ describe('MgrModuleListComponent', () => {
|
||||
SharedModule,
|
||||
HttpClientTestingModule,
|
||||
TabsModule.forRoot(),
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
providers: [MgrModuleService, NotificationService, i18nProviders]
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
|
||||
import { AppRoutingModule } from '../../../app-routing.module';
|
||||
@ -16,7 +17,8 @@ import { MgrModuleListComponent } from './mgr-module-list/mgr-module-list.compon
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
TabsModule.forRoot()
|
||||
TabsModule.forRoot(),
|
||||
NgBootstrapFormValidationModule
|
||||
],
|
||||
declarations: [MgrModuleListComponent, MgrModuleFormComponent, MgrModuleDetailsComponent]
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="col-lg-4">
|
||||
<fieldset>
|
||||
<legend i18n>Status</legend>
|
||||
<legend class="cd-header" i18n>Status</legend>
|
||||
<table class="table table-striped"
|
||||
*ngIf="mon_status">
|
||||
<tr>
|
||||
@ -43,15 +43,15 @@
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="col-lg-8">
|
||||
<legend i18n
|
||||
class="in-quorum">In Quorum</legend>
|
||||
class="in-quorum cd-header">In Quorum</legend>
|
||||
<cd-table [data]="inQuorum.data"
|
||||
[columns]="inQuorum.columns">
|
||||
</cd-table>
|
||||
|
||||
<legend i18n
|
||||
class="in-quorum">Not In Quorum</legend>
|
||||
class="in-quorum cd-header">Not In Quorum</legend>
|
||||
<cd-table [data]="notInQuorum.data"
|
||||
(fetchData)="refresh()"
|
||||
[columns]="notInQuorum.columns">
|
||||
|
@ -8,19 +8,21 @@
|
||||
[formGroup]="osdFlagsForm"
|
||||
novalidate>
|
||||
<div class="modal-body osd-modal">
|
||||
<div class="checkbox checkbox-primary"
|
||||
<div class="custom-control custom-checkbox"
|
||||
*ngFor="let flag of flags; let last = last">
|
||||
<input type="checkbox"
|
||||
<input class="custom-control-input"
|
||||
type="checkbox"
|
||||
[checked]="flag.value"
|
||||
(change)="flag.value = !flag.value"
|
||||
[name]="flag.code"
|
||||
[id]="flag.code"
|
||||
[disabled]="flag.disabled">
|
||||
<label [for]="flag.code"
|
||||
<label class="custom-control-label"
|
||||
[for]="flag.code"
|
||||
ng-class="['tc_' + key]">
|
||||
<strong>{{ flag.name }}</strong>
|
||||
<br>
|
||||
<span class="text-muted">{{ flag.description }}</span>
|
||||
<span class="form-text text-muted">{{ flag.description }}</span>
|
||||
</label>
|
||||
<hr class="oa-hr-small"
|
||||
*ngIf="!last">
|
||||
|
@ -4,8 +4,8 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
import { NotificationType } from '../../../../shared/enum/notification-type.enum';
|
||||
@ -32,7 +32,7 @@ describe('OsdFlagsModalComponent', () => {
|
||||
SharedModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
declarations: [OsdFlagsModalComponent],
|
||||
providers: [BsModalRef, i18nProviders]
|
||||
|
@ -17,7 +17,7 @@
|
||||
<cd-table-actions [permission]="{read: true}"
|
||||
[selection]="selection"
|
||||
dropDownOnly="Cluster-wide configuration"
|
||||
btnColor="default"
|
||||
btnColor="light"
|
||||
class="btn-group"
|
||||
id="cluster-wide-actions"
|
||||
[tableActions]="clusterWideActions">
|
||||
@ -32,8 +32,8 @@
|
||||
<ng-template #statusColor
|
||||
let-value="value">
|
||||
<span *ngFor="let state of value; last as last">
|
||||
<span class="label"
|
||||
[ngClass]="{'label-success': ['in', 'up'].includes(state), 'label-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
|
||||
<span class="badge"
|
||||
[ngClass]="{'badge-success': ['in', 'up'].includes(state), 'badge-danger': ['down', 'out'].includes(state)}">{{ state }}</span>
|
||||
<span *ngIf="!last"> </span>
|
||||
</span>
|
||||
</ng-template>
|
||||
@ -58,7 +58,7 @@
|
||||
<ng-template #markOsdConfirmationTpl
|
||||
let-markActionDescription="markActionDescription">
|
||||
<ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be marked
|
||||
<strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
|
||||
<strong>{{ markActionDescription }}</strong> if you proceed.</ng-container>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #criticalConfirmationTpl
|
||||
@ -69,5 +69,5 @@
|
||||
<cd-warning-panel i18n>The OSD is not safe to destroy!</cd-warning-panel>
|
||||
</div>
|
||||
<ng-container i18n><strong>OSD {{ selection.first().id }}</strong> will be
|
||||
<strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
|
||||
<strong>{{ actionDescription }}</strong> if you proceed.</ng-container>
|
||||
</ng-template>
|
||||
|
@ -263,7 +263,7 @@ describe('OsdListComponent', () => {
|
||||
const tableActionElement = fixture.debugElement.query(By.directive(TableActionsComponent));
|
||||
const toClassName = TestBed.get(TableActionsComponent).toClassName;
|
||||
const getActionClasses = (action: CdTableAction) =>
|
||||
tableActionElement.query(By.css('.' + toClassName(action.name))).classes;
|
||||
tableActionElement.query(By.css(`.${toClassName(action.name)} .dropdown-item`)).classes;
|
||||
|
||||
component.tableActions.forEach((action) => {
|
||||
expect(getActionClasses(action).disabled).toBe(true);
|
||||
|
@ -3,8 +3,7 @@
|
||||
class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
<form #formDir="ngForm"
|
||||
[formGroup]="osdPgScrubForm"
|
||||
novalidate>
|
||||
<div class="modal-body osd-modal">
|
||||
@ -37,9 +36,8 @@
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button *ngIf="permissions.configOpt.update"
|
||||
(submitAction)="submitAction()"
|
||||
[form]="osdPgScrubForm"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
[form]="osdPgScrubForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-back-button [back]="bsModalRef.hide">
|
||||
</cd-back-button>
|
||||
</div>
|
||||
|
@ -4,8 +4,8 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
@ -27,7 +27,7 @@ describe('OsdPgScrubModalComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
declarations: [OsdPgScrubModalComponent],
|
||||
providers: [BsModalRef, i18nProviders]
|
||||
|
@ -3,21 +3,19 @@
|
||||
i18n>OSD Recovery Priority</ng-container>
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
<form #formDir="ngForm"
|
||||
[formGroup]="osdRecvSpeedForm"
|
||||
novalidate>
|
||||
<div class="modal-body">
|
||||
<!-- Priority -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': osdRecvSpeedForm.showError('priority', formDir)}">
|
||||
<label class="control-label col-sm-6"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-6"
|
||||
for="priority">
|
||||
<ng-container i18n>Priority</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="priority"
|
||||
id="priority"
|
||||
(change)="onPriorityChange($event.target.value)">
|
||||
@ -26,34 +24,37 @@
|
||||
{{ priority.text }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="osdRecvSpeedForm.showError('priority', formDir, 'required')"
|
||||
i18n>This field is required.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customize priority -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-6 col-sm-6">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-6 col-sm-6">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input formControlName="customizePriority"
|
||||
class="custom-control-input"
|
||||
id="customizePriority"
|
||||
name="customizePriority"
|
||||
type="checkbox"
|
||||
(change)="onCustomizePriorityChange()">
|
||||
<label i18n
|
||||
for="customizePriority">Customize priority values</label>
|
||||
<label class="custom-control-label"
|
||||
for="customizePriority"
|
||||
i18n>Customize priority values</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Priority values -->
|
||||
<div class="form-group" *ngFor="let attr of priorityAttrs | keyvalue"
|
||||
[ngClass]="{'has-error': osdRecvSpeedForm.getValue('customizePriority') &&
|
||||
osdRecvSpeedForm.showError(attr.key, formDir)}">
|
||||
<label class="control-label col-sm-6"
|
||||
<div class="form-group row"
|
||||
*ngFor="let attr of priorityAttrs | keyvalue">
|
||||
<label class="col-form-label col-sm-6"
|
||||
[for]="attr.key">{{ attr.value.text }}
|
||||
<cd-helper *ngIf="attr.value.desc">{{ attr.value.desc }}</cd-helper>
|
||||
<span class="required" *ngIf="osdRecvSpeedForm.getValue('customizePriority')"></span>
|
||||
<span class="required"
|
||||
*ngIf="osdRecvSpeedForm.getValue('customizePriority')"></span>
|
||||
</label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control"
|
||||
@ -61,19 +62,19 @@
|
||||
[id]="attr.key"
|
||||
[formControlName]="attr.key"
|
||||
[readonly]="!osdRecvSpeedForm.getValue('customizePriority')">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
|
||||
osdRecvSpeedForm.showError(attr.key, formDir, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="osdRecvSpeedForm.getValue('customizePriority') &&
|
||||
osdRecvSpeedForm.showError(attr.key, formDir, 'pattern')"
|
||||
i18n>{{ attr.value.patternHelpText }}</span>
|
||||
<span class="help-block"
|
||||
<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="help-block"
|
||||
<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>
|
||||
|
@ -4,8 +4,8 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsModalRef, ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { configureTestBed, i18nProviders } from '../../../../../testing/unit-test-helper';
|
||||
@ -25,7 +25,7 @@ describe('OsdRecvSpeedModalComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot()
|
||||
ToastrModule.forRoot()
|
||||
],
|
||||
declarations: [OsdRecvSpeedModalComponent],
|
||||
providers: [BsModalRef, i18nProviders]
|
||||
|
@ -3,16 +3,15 @@
|
||||
i18n>Reweight OSD</ng-container>
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form class="form-horizontal"
|
||||
[formGroup]="reweightForm">
|
||||
<div class="modal-body" [ngClass]="{'has-error': weight.errors}">
|
||||
<form [formGroup]="reweightForm">
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<label for="weight" class="col-sm-2 control-label">Weight</label>
|
||||
<label for="weight" class="col-sm-2 col-form-label">Weight</label>
|
||||
<div class="col-sm-10">
|
||||
<input id="weight" class="form-control" type="number"
|
||||
step="0.1" formControlName="weight" min="0" max="1"
|
||||
[value]="currentWeight">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="weight.errors">
|
||||
<span *ngIf="weight.errors?.required"
|
||||
i18n>This field is required.</span>
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
<ng-container class="modal-content">
|
||||
<form name="scrubForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="scrubForm"
|
||||
novalidate>
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import {
|
||||
configureTestBed,
|
||||
@ -25,7 +25,7 @@ describe('PrometheusListComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
TabsModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
SharedModule
|
||||
],
|
||||
declarations: [AlertListComponent, PrometheusTabsComponent],
|
||||
|
@ -28,9 +28,9 @@ export class AlertListComponent implements OnInit {
|
||||
selection = new CdTableSelection();
|
||||
icons = Icons;
|
||||
customCss = {
|
||||
'label label-danger': 'active',
|
||||
'label label-warning': 'unprocessed',
|
||||
'label label-info': 'suppressed'
|
||||
'badge badge-danger': 'active',
|
||||
'badge badge-warning': 'unprocessed',
|
||||
'badge badge-info': 'suppressed'
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
@ -2,12 +2,12 @@
|
||||
<tab heading="Alerts"
|
||||
i18n-heading
|
||||
[active]="url === '/alerts'"
|
||||
(select)="navigateTo('/alerts')">
|
||||
(selectTab)="navigateTo('/alerts')">
|
||||
</tab>
|
||||
<tab heading="Silences"
|
||||
i18n-heading
|
||||
[active]="url === '/silence'"
|
||||
(select)="navigateTo('/silence')">
|
||||
(selectTab)="navigateTo('/silence')">
|
||||
</tab>
|
||||
</tabset>
|
||||
|
||||
|
@ -15,7 +15,7 @@ describe('PrometheusTabsComponent', () => {
|
||||
let router: Router;
|
||||
|
||||
const selectTab = (index) => {
|
||||
fixture.debugElement.queryAll(By.css('tab'))[index].triggerEventHandler('select', null);
|
||||
fixture.debugElement.queryAll(By.css('tab'))[index].triggerEventHandler('selectTab', null);
|
||||
};
|
||||
|
||||
configureTestBed({
|
||||
|
@ -1,10 +1,15 @@
|
||||
<ng-template #matcherTpl let-matcher="matcher" let-index="index">
|
||||
<div class="input-group">
|
||||
<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-addon"
|
||||
[tooltip]=config.tooltip>
|
||||
<i class="icon-prepend" [ngClass]="[config.icon]"></i>
|
||||
</span>
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"
|
||||
[tooltip]=config.tooltip>
|
||||
<i [ngClass]="[config.icon]"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="config.attribute !== 'isRegex'">
|
||||
<input type="text"
|
||||
id="matcher-{{config.attribute}}-{{index}}"
|
||||
@ -13,20 +18,24 @@
|
||||
disabled
|
||||
readonly>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="config.attribute === 'isRegex'">
|
||||
<span class="input-group-addon">
|
||||
<input type="checkbox"
|
||||
id="matcher-{{config.attribute}}-{{index}}"
|
||||
[checked]="matcher[config.attribute]"
|
||||
disabled
|
||||
readonly>
|
||||
</span>
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">
|
||||
<input type="checkbox"
|
||||
id="matcher-{{config.attribute}}-{{index}}"
|
||||
[checked]="matcher[config.attribute]"
|
||||
disabled
|
||||
readonly>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<!-- Matcher actions -->
|
||||
<span class="input-group-btn">
|
||||
<span class="input-group-append">
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
id="matcher-edit-{{index}}"
|
||||
i18n-tooltip
|
||||
tooltip="Edit"
|
||||
@ -34,7 +43,7 @@
|
||||
<i [ngClass]="[icons.edit]"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
class="btn btn-light"
|
||||
id="matcher-delete-{{index}}"
|
||||
i18n-tooltip
|
||||
tooltip="Delete"
|
||||
@ -49,25 +58,22 @@
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<form #formDir="ngForm"
|
||||
[formGroup]="form"
|
||||
class="form-horizontal"
|
||||
class="form"
|
||||
name="form"
|
||||
novalidate>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<span i18n="@@formTitle">
|
||||
{{ 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>
|
||||
</h3>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<span i18n="@@formTitle">
|
||||
{{ 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>
|
||||
</div>
|
||||
|
||||
<!-- Creator -->
|
||||
<div class="panel-body">
|
||||
<div [ngClass]="{'has-error': form.showError('createdBy', formDir)}"
|
||||
class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="created-by">
|
||||
<ng-container i18n>Creator</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -79,15 +85,14 @@
|
||||
name="created-by"
|
||||
type="text">
|
||||
<span *ngIf="form.showError('createdBy', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Comment -->
|
||||
<div [ngClass]="{'has-error': form.showError('comment', formDir)}"
|
||||
class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="comment">
|
||||
<ng-container i18n>Comment</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -100,15 +105,14 @@
|
||||
type="text">
|
||||
</textarea>
|
||||
<span *ngIf="form.showError('comment', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Start time -->
|
||||
<div [ngClass]="{'has-error': form.showError('startsAt', formDir)}"
|
||||
class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="starts-at">
|
||||
<ng-container i18n>Start time</ng-container>
|
||||
<cd-helper i18n>If the start time lies in the past the creation time will be used</cd-helper>
|
||||
@ -122,15 +126,14 @@
|
||||
id="starts-at"
|
||||
name="starts-at">
|
||||
<span *ngIf="form.showError('startsAt', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Duration -->
|
||||
<div [ngClass]="{'has-error': form.showError('duration', formDir)}"
|
||||
class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="duration">
|
||||
<ng-container i18n>Duration</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -142,15 +145,14 @@
|
||||
name="duration"
|
||||
type="text">
|
||||
<span *ngIf="form.showError('duration', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- End time -->
|
||||
<div [ngClass]="{'has-error': form.showError('endsAt', formDir)}"
|
||||
class="form-group">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="ends-at">
|
||||
<ng-container i18n>End time</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -163,7 +165,7 @@
|
||||
id="ends-at"
|
||||
name="ends-at">
|
||||
<span *ngIf="form.showError('endsAt', formDir, 'required')"
|
||||
class="help-block"
|
||||
class="invalid-feedback"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -171,7 +173,8 @@
|
||||
<!-- Matchers -->
|
||||
<fieldset>
|
||||
<legend i18n>Matchers<span class="required">*</span></legend>
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<h5 *ngIf="matchers.length === 0"
|
||||
[ngClass]="{'text-warning': !formDir.submitted, 'text-danger': formDir.submitted}">
|
||||
<strong i18n>A silence requires at least one matcher</strong>
|
||||
@ -181,34 +184,35 @@
|
||||
<ng-container *ngTemplateOutlet="matcherTpl; context:{index: i, matcher: matcher}"></ng-container>
|
||||
</span>
|
||||
|
||||
<span class="form-control no-border">
|
||||
<button type="button"
|
||||
id="add-matcher"
|
||||
class="btn btn-sm btn-default btn-label pull-right"
|
||||
[ngClass]="{'btn-warning': formDir.submitted && matchers.length === 0 }"
|
||||
(click)="showMatcherModal()">
|
||||
<i [ngClass]="[icons.width, icons.add]"></i>
|
||||
<ng-container i18n>Add matcher</ng-container>
|
||||
</button>
|
||||
</span>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button type="button"
|
||||
id="add-matcher"
|
||||
class="btn btn-light float-right my-3"
|
||||
[ngClass]="{'btn-warning': formDir.submitted && matchers.length === 0 }"
|
||||
(click)="showMatcherModal()">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add matcher</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="matchers.length && matcherMatch"
|
||||
class="col-sm-offset-3 col-sm-9 {{matcherMatch.cssClass}}"
|
||||
class="offset-sm-3 col-sm-9 {{matcherMatch.cssClass}}"
|
||||
id="match-state">
|
||||
<span class="help-block {{matcherMatch.cssClass}}">
|
||||
<span class="text-muted {{matcherMatch.cssClass}}">
|
||||
{{ matcherMatch.status }}
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button (submitAction)="submit()"
|
||||
[form]="formDir"
|
||||
id="submit"
|
||||
i18n="@@formTitle"
|
||||
type="button">
|
||||
i18n="@@formTitle">
|
||||
{{ action | titlecase }} {{ resource | upperFirst }}
|
||||
</cd-submit-button>
|
||||
<cd-back-button></cd-back-button>
|
||||
|
@ -6,10 +6,10 @@ import { ActivatedRoute, Router, Routes } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsDatepickerDirective, BsDatepickerModule } from 'ngx-bootstrap/datepicker';
|
||||
import { BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { TooltipModule } from 'ngx-bootstrap/tooltip';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of, throwError } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -61,7 +61,7 @@ describe('SilenceFormComponent', () => {
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
BsDatepickerModule.forRoot(),
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
TooltipModule.forRoot(),
|
||||
ReactiveFormsModule
|
||||
],
|
||||
|
@ -3,10 +3,10 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { BsModalRef, BsModalService, ModalModule } from 'ngx-bootstrap/modal';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -34,7 +34,7 @@ describe('SilenceListComponent', () => {
|
||||
BsDropdownModule.forRoot(),
|
||||
TabsModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
HttpClientTestingModule
|
||||
],
|
||||
|
@ -40,9 +40,9 @@ export class SilenceListComponent implements OnInit {
|
||||
selection = new CdTableSelection();
|
||||
modalRef: BsModalRef;
|
||||
customCss = {
|
||||
'label label-danger': 'active',
|
||||
'label label-warning': 'pending',
|
||||
'label label-default': 'expired'
|
||||
'badge badge-danger': 'active',
|
||||
'badge badge-warning': 'pending',
|
||||
'badge badge-default': 'expired'
|
||||
};
|
||||
sorts: SortPropDir[] = [{ prop: 'endsAt', dir: SortDirection.desc }];
|
||||
|
||||
|
@ -9,15 +9,14 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal"
|
||||
<form class="form"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="form"
|
||||
novalidate>
|
||||
<div class="modal-body">
|
||||
<!-- Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('name', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="name">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -41,9 +40,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Value -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('value', formDir)}">
|
||||
<label class="control-label col-sm-3"
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3"
|
||||
for="value">
|
||||
<ng-container i18n>Value</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -60,25 +58,26 @@
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
<div *ngIf="form.getValue('value') && !form.getValue('isRegex') && matcherMatch"
|
||||
class="col-sm-offset-3 col-sm-9 {{matcherMatch.cssClass}}"
|
||||
class="offset-sm-3 col-sm-9 {{matcherMatch.cssClass}}"
|
||||
id="match-state">
|
||||
<span class="help-block {{matcherMatch.cssClass}}">
|
||||
<span class="text-muted {{matcherMatch.cssClass}}">
|
||||
{{matcherMatch.status}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- isRegex -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-3 col-sm-9">
|
||||
<div class="input-group">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<input id="is-regex"
|
||||
type="checkbox"
|
||||
formControlName="isRegex">
|
||||
<label for="is-regex"
|
||||
i18n>Use regular expression</label>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,4 +94,3 @@
|
||||
</cd-back-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
class="container-fluid">
|
||||
<cd-info-group groupTitle="Status"
|
||||
i18n-groupTitle
|
||||
class="row info-group"
|
||||
*ngIf="healthData.health?.status
|
||||
|| healthData.mon_status
|
||||
|| healthData.osd_map
|
||||
@ -14,8 +13,8 @@
|
||||
|
||||
<cd-info-card cardTitle="Cluster Status"
|
||||
i18n-cardTitle
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
[contentClass]="healthData.health?.checks?.length > 0 ? 'content-highlight text-area-size-2' : 'content-highlight'"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.health?.status">
|
||||
<ng-container *ngIf="healthData.health?.checks?.length > 0">
|
||||
<ng-template #healthChecks>
|
||||
@ -48,7 +47,7 @@
|
||||
<cd-info-card cardTitle="Monitors"
|
||||
i18n-cardTitle
|
||||
link="/monitor"
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.mon_status">
|
||||
{{ healthData.mon_status | monSummary }}
|
||||
@ -57,9 +56,9 @@
|
||||
<cd-info-card cardTitle="OSDs"
|
||||
i18n-cardTitle
|
||||
link="/osd"
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
class="cd-status-card"
|
||||
*ngIf="(healthData.osd_map | osdSummary) as transformedResult"
|
||||
[contentClass]="(transformedResult.length == 5 ? 'text-area-size-3' : 'text-area-size-2') + ' content-highlight'">
|
||||
contentClass="content-highlight">
|
||||
<span *ngFor="let result of transformedResult"
|
||||
[ngClass]="result.class">
|
||||
{{ result.content }}
|
||||
@ -68,8 +67,8 @@
|
||||
|
||||
<cd-info-card cardTitle="Manager Daemons"
|
||||
i18n-cardTitle
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
contentClass="content-highlight text-area-size-2"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.mgr_map">
|
||||
<span *ngFor="let result of (healthData.mgr_map | mgrSummary)"
|
||||
[ngClass]="result.class"
|
||||
@ -81,8 +80,8 @@
|
||||
<cd-info-card cardTitle="Hosts"
|
||||
i18n-cardTitle
|
||||
link="/hosts"
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
contentClass="content-medium content-highlight"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.hosts != null">
|
||||
{{ healthData.hosts }} total
|
||||
</cd-info-card>
|
||||
@ -90,16 +89,18 @@
|
||||
<cd-info-card cardTitle="Object Gateways"
|
||||
i18n-cardTitle
|
||||
link="/rgw/daemon"
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
contentClass="content-medium content-highlight"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="enabledFeature.rgw && healthData.rgw != null">
|
||||
{{ healthData.rgw }} total
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Metadata Servers"
|
||||
i18n-cardTitle
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
class="cd-status-card"
|
||||
*ngIf="(enabledFeature.cephfs && healthData.fs_map | mdsSummary) as transformedResult"
|
||||
[contentClass]="(transformedResult.length > 1 ? 'text-area-size-2' : '') + ' content-highlight'">
|
||||
<!-- TODO: check text-area-size-2 -->
|
||||
<span *ngFor="let result of transformedResult"
|
||||
[ngClass]="result.class">
|
||||
{{ result.content }}
|
||||
@ -109,8 +110,8 @@
|
||||
<cd-info-card cardTitle="iSCSI Gateways"
|
||||
i18n-cardTitle
|
||||
link="/block/iscsi"
|
||||
class="col-sm-6 col-md-4 col-lg-3"
|
||||
contentClass="content-medium content-highlight"
|
||||
class="cd-status-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="enabledFeature.iscsi && healthData.iscsi_daemons != null">
|
||||
{{ healthData.iscsi_daemons }} total
|
||||
</cd-info-card>
|
||||
@ -118,143 +119,126 @@
|
||||
|
||||
<cd-info-group groupTitle="Performance"
|
||||
i18n-groupTitle
|
||||
class="row info-group"
|
||||
*ngIf="healthData.client_perf || healthData.scrub_status">
|
||||
|
||||
<div class="cd-container-flex">
|
||||
<cd-info-card cardTitle="Client IOPS"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ (healthData.client_perf.read_op_per_sec + healthData.client_perf.write_op_per_sec) | round:1 }}
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Client IOPS"
|
||||
i18n-cardTitle
|
||||
class="cd-performance-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ (healthData.client_perf.read_op_per_sec + healthData.client_perf.write_op_per_sec) | round:1 }}
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Client Throughput"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ ((healthData.client_perf.read_bytes_sec + healthData.client_perf.write_bytes_sec) | dimlessBinary) + '/s' }}
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Client Throughput"
|
||||
i18n-cardTitle
|
||||
class="cd-performance-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ ((healthData.client_perf.read_bytes_sec + healthData.client_perf.write_bytes_sec) | dimlessBinary) + '/s' }}
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Client Read/Write"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
[contentClass]="isClientReadWriteChartShowable() ? 'content-chart': 'content-medium content-highlight'"
|
||||
*ngIf="healthData.client_perf">
|
||||
<cd-health-pie *ngIf="isClientReadWriteChartShowable()"
|
||||
[data]="healthData"
|
||||
(prepareFn)="prepareReadWriteRatio($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
<span *ngIf="!isClientReadWriteChartShowable()">
|
||||
N/A
|
||||
</span>
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Client Read/Write"
|
||||
i18n-cardTitle
|
||||
class="cd-performance-card"
|
||||
[contentClass]="isClientReadWriteChartShowable() ? 'content-chart': 'content-highlight'"
|
||||
*ngIf="healthData.client_perf">
|
||||
<cd-health-pie *ngIf="isClientReadWriteChartShowable()"
|
||||
[data]="healthData"
|
||||
(prepareFn)="prepareReadWriteRatio($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
<span *ngIf="!isClientReadWriteChartShowable()">
|
||||
N/A
|
||||
</span>
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Recovery Throughput"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ (healthData.client_perf.recovering_bytes_per_sec | dimlessBinary) + '/s' }}
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Recovery Throughput"
|
||||
i18n-cardTitle
|
||||
class="cd-performance-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.client_perf">
|
||||
{{ (healthData.client_perf.recovering_bytes_per_sec | dimlessBinary) + '/s' }}
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Scrub"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.scrub_status">
|
||||
{{ healthData.scrub_status }}
|
||||
</cd-info-card>
|
||||
</div>
|
||||
<cd-info-card cardTitle="Scrub"
|
||||
i18n-cardTitle
|
||||
class="cd-performance-card"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.scrub_status">
|
||||
{{ healthData.scrub_status }}
|
||||
</cd-info-card>
|
||||
</cd-info-group>
|
||||
|
||||
<cd-info-group groupTitle="Capacity"
|
||||
i18n-groupTitle
|
||||
class="row info-group"
|
||||
*ngIf="healthData.pools
|
||||
|| healthData.df
|
||||
|| healthData.pg_info">
|
||||
<cd-info-card cardTitle="Pools"
|
||||
i18n-cardTitle
|
||||
link="/pool"
|
||||
class="cd-capacity-card order-md-1 order-lg-4 order-xl-1"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.pools">
|
||||
{{ healthData.pools.length }}
|
||||
</cd-info-card>
|
||||
|
||||
<div class="cd-container-flex">
|
||||
<cd-info-card cardTitle="Pools"
|
||||
i18n-cardTitle
|
||||
link="/pool"
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.pools">
|
||||
{{ healthData.pools.length }}
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Raw Capacity"
|
||||
i18n-cardTitle
|
||||
class="cd-capacity-card order-md-3 order-lg-1 order-xl-2"
|
||||
contentClass="content-chart"
|
||||
*ngIf="healthData.df">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="rawCapacityChartConfig"
|
||||
[isBytesData]="true"
|
||||
(prepareFn)="prepareRawUsage($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Raw Capacity"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-chart"
|
||||
*ngIf="healthData.df">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="rawCapacityChartConfig"
|
||||
[showLabelAsTooltip]="true"
|
||||
(prepareFn)="prepareRawUsage($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="Objects"
|
||||
i18n-cardTitle
|
||||
class="cd-capacity-card order-md-4 order-lg-2 order-xl-3"
|
||||
contentClass="content-chart"
|
||||
*ngIf="healthData.pg_info?.object_stats?.num_objects != null">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="objectsChartConfig"
|
||||
(prepareFn)="prepareObjects($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="Objects"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-chart"
|
||||
*ngIf="healthData.pg_info?.object_stats?.num_objects != null">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="objectsChartConfig"
|
||||
(prepareFn)="prepareObjects($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</cd-info-card>
|
||||
<cd-info-card cardTitle="PGs per OSD"
|
||||
i18n-cardTitle
|
||||
class="cd-capacity-card order-md-2 order-lg-5 order-xl-4"
|
||||
contentClass="content-highlight"
|
||||
*ngIf="healthData.pg_info">
|
||||
{{ healthData.pg_info.pgs_per_osd | dimless }}
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="PGs per OSD"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-medium content-highlight"
|
||||
*ngIf="healthData.pg_info">
|
||||
{{ healthData.pg_info.pgs_per_osd | dimless }}
|
||||
</cd-info-card>
|
||||
|
||||
<cd-info-card cardTitle="PG Status"
|
||||
i18n-cardTitle
|
||||
class="cd-col-5"
|
||||
cardClass="card-medium"
|
||||
contentClass="content-chart"
|
||||
(click)="pgStatusTarget.toggle()"
|
||||
*ngIf="healthData.pg_info">
|
||||
<ng-template #pgStatus>
|
||||
<ng-container *ngTemplateOutlet="logsLink"></ng-container>
|
||||
<ul>
|
||||
<li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
|
||||
{{ pgStatesText.key }}: {{ pgStatesText.value }}
|
||||
</li>
|
||||
</ul>
|
||||
</ng-template>
|
||||
<div class="pg-status-popover-wrapper">
|
||||
<div [popover]="pgStatus"
|
||||
triggers=""
|
||||
#pgStatusTarget="bs-popover"
|
||||
placement="bottom">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="pgStatusChartConfig"
|
||||
(prepareFn)="preparePgStatus($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</div>
|
||||
<cd-info-card cardTitle="PG Status"
|
||||
i18n-cardTitle
|
||||
class="cd-capacity-card order-md-5 order-lg-3 order-xl-5"
|
||||
contentClass="content-chart"
|
||||
(click)="pgStatusTarget.toggle()"
|
||||
*ngIf="healthData.pg_info">
|
||||
<ng-template #pgStatus>
|
||||
<ng-container *ngTemplateOutlet="logsLink"></ng-container>
|
||||
<ul>
|
||||
<li *ngFor="let pgStatesText of healthData.pg_info.statuses | keyvalue">
|
||||
{{ pgStatesText.key }}: {{ pgStatesText.value }}
|
||||
</li>
|
||||
</ul>
|
||||
</ng-template>
|
||||
<div class="pg-status-popover-wrapper">
|
||||
<div [popover]="pgStatus"
|
||||
triggers=""
|
||||
#pgStatusTarget="bs-popover"
|
||||
placement="bottom">
|
||||
<cd-health-pie [data]="healthData"
|
||||
[config]="pgStatusChartConfig"
|
||||
(prepareFn)="preparePgStatus($event[0], $event[1])">
|
||||
</cd-health-pie>
|
||||
</div>
|
||||
</cd-info-card>
|
||||
</div>
|
||||
</div>
|
||||
</cd-info-card>
|
||||
</cd-info-group>
|
||||
|
||||
<ng-template #logsLink>
|
||||
|
@ -1,55 +1,9 @@
|
||||
@import '../../../../defaults';
|
||||
@import 'styles';
|
||||
|
||||
cd-info-card {
|
||||
padding: 0 0.5vw 0 0.5vw;
|
||||
}
|
||||
|
||||
.cd-container-flex {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.cd-col-5 {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
@media (max-width: 1599px) {
|
||||
.cd-col-5 {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
.cd-col-5 {
|
||||
width: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) {
|
||||
.cd-col-5 {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
cd-info-card {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cd-col-5 {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.info-group {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@extend .d-flex;
|
||||
@extend .flex-column;
|
||||
}
|
||||
|
||||
::ng-deep .pg-status-popover-wrapper {
|
||||
@ -87,3 +41,19 @@ cd-info-card {
|
||||
.mgr-active-name:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::ng-deep cd-info-card {
|
||||
@extend .col-12;
|
||||
@extend .col-sm-12;
|
||||
@extend .col-md-6;
|
||||
@extend .col-lg-4;
|
||||
|
||||
&.cd-status-card {
|
||||
@extend .col-xl-3;
|
||||
}
|
||||
|
||||
&.cd-performance-card,
|
||||
&.cd-capacity-card {
|
||||
@extend .col-xl;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../../../../defaults';
|
||||
@import 'defaults';
|
||||
|
||||
.info-card-popover-cluster-status {
|
||||
max-width: 23vw;
|
||||
@ -11,18 +11,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
@media (max-width: $screen-lg-max) {
|
||||
.info-card-popover-cluster-status {
|
||||
max-width: 31vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) {
|
||||
@media (max-width: $screen-md-max) {
|
||||
.info-card-popover-cluster-status {
|
||||
max-width: 46vw;
|
||||
}
|
||||
}
|
||||
@media (max-width: $screen-xs-max) {
|
||||
@media (max-width: $screen-sm-max) {
|
||||
.info-card-popover-cluster-status {
|
||||
max-width: 83vw;
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
<div class="card"
|
||||
<div class="card mb-4"
|
||||
[ngClass]="cardClass">
|
||||
<div class="card-title">
|
||||
<a *ngIf="link; else noLinkTitle"
|
||||
[routerLink]="link">{{ cardTitle }}</a>
|
||||
<ng-template #noLinkTitle>
|
||||
{{ cardTitle }}
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="card-body"
|
||||
[ngClass]="contentClass">
|
||||
<ng-content></ng-content>
|
||||
<div class="card-body d-flex align-items-center justify-content-center">
|
||||
<h5 class="card-title m-4">
|
||||
<a *ngIf="link; else noLinkTitle"
|
||||
[routerLink]="link">{{ cardTitle }}</a>
|
||||
|
||||
<ng-template #noLinkTitle>
|
||||
{{ cardTitle }}
|
||||
</ng-template>
|
||||
</h5>
|
||||
|
||||
<div class="card-text text-center"
|
||||
[ngClass]="contentClass">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,53 +1,36 @@
|
||||
@import '../../../../defaults';
|
||||
@import 'styles';
|
||||
|
||||
$card-height: 6vw;
|
||||
$card-medium-height: 12vw;
|
||||
$card-font-min-width: 320px;
|
||||
$card-font-max-width: 2048px;
|
||||
$card-font-min-size: 12px;
|
||||
$card-font-max-size: 21px;
|
||||
$logs-text-font-size: $card-font-min-size;
|
||||
|
||||
.card {
|
||||
height: 100%;
|
||||
@extend .pb-2;
|
||||
border: 0.5px solid $color-info-card-border;
|
||||
border-radius: 3px;
|
||||
background-color: $color-solid-white;
|
||||
box-shadow: 0 1px 1px $color-shadow-gray;
|
||||
margin: 0 -10px 20px;
|
||||
padding: 0 20px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
min-height: $card-height;
|
||||
@include fluid-font-size(
|
||||
$card-font-min-width,
|
||||
$card-font-max-width,
|
||||
$card-font-min-size,
|
||||
$card-font-max-size
|
||||
);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin: 1.1vw 0;
|
||||
padding: 0;
|
||||
}
|
||||
.card-body {
|
||||
padding-top: 40px !important;
|
||||
|
||||
.card-body {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
}
|
||||
.card-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.content-chart {
|
||||
margin-top: -0.7vw;
|
||||
position: unset;
|
||||
top: unset;
|
||||
left: unset;
|
||||
transform: unset;
|
||||
.card-text {
|
||||
@extend .pt-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-center {
|
||||
@ -57,79 +40,6 @@ $logs-text-font-size: $card-font-min-size;
|
||||
transform: unset;
|
||||
}
|
||||
|
||||
.text-area-size-2 {
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, -20%);
|
||||
}
|
||||
|
||||
.text-area-size-3 {
|
||||
margin-right: -50%;
|
||||
transform: translate(-50%, -40%);
|
||||
}
|
||||
|
||||
.content-highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-medium {
|
||||
min-height: $card-medium-height;
|
||||
}
|
||||
|
||||
.scroll {
|
||||
max-height: ($card-medium-height * 1.5);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.text-monospace {
|
||||
font-size: $logs-text-font-size;
|
||||
font-family: monospace;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media (max-width: 1599px) {
|
||||
.card {
|
||||
min-height: $card-height * 1.3;
|
||||
}
|
||||
|
||||
.card-medium {
|
||||
min-height: $card-medium-height * 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
.card-medium {
|
||||
min-height: $card-medium-height * 1.5;
|
||||
}
|
||||
|
||||
.content-chart {
|
||||
margin-top: -0.6vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) {
|
||||
.card {
|
||||
min-height: $card-height * 2;
|
||||
}
|
||||
|
||||
.content-chart {
|
||||
margin-top: -0.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-sm-max) and (min-width: $screen-sm-min) {
|
||||
.card-medium {
|
||||
min-height: $card-medium-height * 2.2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 599px) {
|
||||
.card {
|
||||
min-height: $card-height * 3;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 319px) {
|
||||
.card {
|
||||
min-height: $card-height * 4;
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ describe('InfoCardComponent', () => {
|
||||
const contentClass = 'my-css-content-class';
|
||||
component.contentClass = contentClass;
|
||||
fixture.detectChanges();
|
||||
const card = fixture.debugElement.nativeElement.querySelector(`.card-body.${contentClass}`);
|
||||
const card = fixture.debugElement.nativeElement.querySelector(`.card-body .${contentClass}`);
|
||||
|
||||
expect(card).toBeTruthy();
|
||||
});
|
||||
|
@ -1,4 +1,6 @@
|
||||
<div class="info-group-title">
|
||||
{{ groupTitle }}
|
||||
<div class="row">
|
||||
<span class="info-group-title">{{ groupTitle }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
<ng-content></ng-content>
|
||||
|
@ -1,7 +1,4 @@
|
||||
@import '../../../../defaults';
|
||||
|
||||
.info-group-title {
|
||||
margin: 0 0 0.5vw 0.5vw;
|
||||
padding: 0;
|
||||
font-size: 21px;
|
||||
}
|
||||
|
@ -1,34 +1,32 @@
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
i18n>Clients</label>
|
||||
|
||||
<div class="col-sm-9"
|
||||
[formGroup]="form"
|
||||
#formDir="ngForm">
|
||||
<span *ngIf="form.get('clients').value.length === 0"
|
||||
class="form-control no-border text-muted">
|
||||
<span class="text-muted"
|
||||
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 form.get('clients').value; let index = index; trackBy: trackByFn">
|
||||
<div class="panel panel-default"
|
||||
<div class="card"
|
||||
[formGroupName]="index">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ (index + 1) | ordinal }}
|
||||
<span class="pull-right clickable"
|
||||
(click)="removeClient(index)"
|
||||
tooltip="Remove">×</span>
|
||||
</h3>
|
||||
<div class="card-header">
|
||||
{{ (index + 1) | ordinal }}
|
||||
<span class="float-right clickable"
|
||||
(click)="removeClient(index)"
|
||||
tooltip="Remove">×</span>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="card-body">
|
||||
<!-- Addresses -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{ 'has-error': showError(index, 'addresses', formDir) }">
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="col-sm-3 control-label"
|
||||
class="col-sm-3 col-form-label"
|
||||
for="addresses">Addresses</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text"
|
||||
@ -37,7 +35,7 @@
|
||||
id="addresses"
|
||||
formControlName="addresses"
|
||||
placeholder="192.168.0.10, 192.168.1.0/8">
|
||||
<span class="help-block">
|
||||
<span class="invalid-feedback">
|
||||
<span *ngIf="showError(index, 'addresses', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
|
||||
@ -51,12 +49,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Access Type-->
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="col-sm-3 control-label"
|
||||
class="col-sm-3 col-form-label"
|
||||
for="access_type">Access Type</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
name="access_type"
|
||||
id="access_type"
|
||||
formControlName="access_type">
|
||||
@ -64,7 +62,7 @@
|
||||
<option *ngFor="let item of nfsAccessType"
|
||||
[value]="item.value">{{ item.value }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="getValue(index, 'access_type')">
|
||||
{{ getAccessTypeHelp(index) }}
|
||||
</span>
|
||||
@ -72,12 +70,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Squash -->
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label i18n
|
||||
class="col-sm-3 control-label"
|
||||
class="col-sm-3 col-form-label"
|
||||
for="squash">Squash</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
name="squash"
|
||||
id="squash"
|
||||
formControlName="squash">
|
||||
@ -92,13 +90,16 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<span class="form-control no-border">
|
||||
<button class="btn btn-default btn-label pull-right"
|
||||
(click)="addClient()">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
<ng-container i18n>Add clients</ng-container>
|
||||
</button>
|
||||
</span>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="float-right">
|
||||
<button class="btn btn-light "
|
||||
(click)="addClient()">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add clients</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,28 +1,23 @@
|
||||
<div class="col-sm-12 col-lg-6">
|
||||
<form name="nfsForm"
|
||||
class="form-horizontal"
|
||||
#formDir="ngForm"
|
||||
[formGroup]="nfsForm"
|
||||
novalidate>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="panel-title">{{ action | titlecase }} {{ resource | upperFirst }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="card">
|
||||
<div i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<!-- cluster_id -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('cluster_id', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="!isDefaultCluster">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="cluster_id">
|
||||
<ng-container i18n>Cluster</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="cluster_id"
|
||||
name="cluster_id"
|
||||
id="cluster_id"
|
||||
@ -39,31 +34,30 @@
|
||||
<option *ngFor="let cluster of allClusters"
|
||||
[value]="cluster">{{ cluster }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('cluster_id', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- daemons -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('daemons', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="daemons">
|
||||
<ng-container i18n>Daemons</ng-container>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<ng-container *ngFor="let daemon of nfsForm.getValue('daemons'); let i = index">
|
||||
<div class="input-group cd-mb">
|
||||
<input class="form-control"
|
||||
<input class="cd-form-control"
|
||||
type="text"
|
||||
[value]="daemon"
|
||||
disabled />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default"
|
||||
<span class="input-group-append">
|
||||
<button class="btn btn-light"
|
||||
type="button"
|
||||
(click)="removeDaemon(i, daemon)">
|
||||
<i [ngClass]="[icons.destroy, icons.width]"
|
||||
<i [ngClass]="[icons.destroy]"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</span>
|
||||
@ -76,8 +70,8 @@
|
||||
[options]="daemonsSelections"
|
||||
[messages]="daemonsMessages"
|
||||
(selection)="onDaemonSelection()"
|
||||
elemClass="btn btn-default pull-right">
|
||||
<i [ngClass]="[icons.add, icons.width]"></i>
|
||||
elemClass="btn btn-light float-right">
|
||||
<i [ngClass]="[icons.add]"></i>
|
||||
<ng-container i18n>Add daemon</ng-container>
|
||||
</cd-select>
|
||||
</div>
|
||||
@ -88,15 +82,14 @@
|
||||
<!-- FSAL -->
|
||||
<div formGroupName="fsal">
|
||||
<!-- Name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('name', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="name">
|
||||
<ng-container i18n>Storage Backend</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="name"
|
||||
name="name"
|
||||
id="name"
|
||||
@ -113,23 +106,22 @@
|
||||
<option *ngFor="let fsal of allFsals"
|
||||
[value]="fsal.value">{{ fsal.descr }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('name', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RGW user -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('rgw_user_id', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'RGW'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="rgw_user_id">
|
||||
<ng-container i18n>Object Gateway User</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="rgw_user_id"
|
||||
name="rgw_user_id"
|
||||
id="rgw_user_id"
|
||||
@ -146,23 +138,22 @@
|
||||
<option *ngFor="let rgwUserId of allRgwUsers"
|
||||
[value]="rgwUserId">{{ rgwUserId }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('rgw_user_id', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CephFS user_id -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('user_id', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'CEPH'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="user_id">
|
||||
<ng-container i18n>CephFS User ID</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="user_id"
|
||||
name="user_id"
|
||||
id="user_id">
|
||||
@ -178,23 +169,22 @@
|
||||
<option *ngFor="let client of allCephxClients"
|
||||
[value]="client">{{ client }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('user_id', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CephFS fs_name -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('fs_name', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'CEPH'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="fs_name">
|
||||
<ng-container i18n>CephFS Name</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="fs_name"
|
||||
name="fs_name"
|
||||
id="fs_name"
|
||||
@ -211,7 +201,7 @@
|
||||
<option *ngFor="let filesystem of allFsNames"
|
||||
[value]="filesystem.name">{{ filesystem.name }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('fs_name', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
@ -219,10 +209,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Secutiry Label -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('security_label', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'CEPH'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="security_label">
|
||||
<ng-container i18n>Security Label</ng-container>
|
||||
<span class="required"
|
||||
@ -230,12 +219,14 @@
|
||||
</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
formControlName="security_label"
|
||||
name="security_label"
|
||||
id="security_label">
|
||||
<label for="security_label"
|
||||
class="custom-control-label"
|
||||
i18n>Enable security label</label>
|
||||
</div>
|
||||
|
||||
@ -248,17 +239,16 @@
|
||||
id="sec_label_xattr"
|
||||
formControlName="sec_label_xattr">
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('sec_label_xattr', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Path -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('path', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'CEPH'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="path">
|
||||
<ng-container i18n>CephFS Path</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -272,24 +262,23 @@
|
||||
[typeahead]="pathDataSource"
|
||||
(typeaheadOnSelect)="pathChangeHandler()"
|
||||
(blur)="pathChangeHandler()">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('path', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
|
||||
<span class="help-block"
|
||||
<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="help-block"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="isNewDirectory && !nfsForm.showError('path', formDir)"
|
||||
i18n>New directory will be created</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bucket -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('path', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('name') === 'RGW'">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="path">
|
||||
<ng-container i18n>Path</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -304,46 +293,49 @@
|
||||
(typeaheadOnSelect)="bucketChangeHandler()"
|
||||
(blur)="bucketChangeHandler()">
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('path', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('path', formDir, 'pattern')"
|
||||
i18n>Path can only be a single '/' or a word</span>
|
||||
|
||||
<span class="help-block"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="isNewBucket && !nfsForm.showError('path', formDir)"
|
||||
i18n>New bucket will be created</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NFS Protocol -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('protocolNfsv3', formDir) || nfsForm.showError('protocolNfsv4', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="protocols">
|
||||
<ng-container i18n>NFS Protocol</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
id="protocolNfsv3"
|
||||
name="protocolNfsv3"
|
||||
formControlName="protocolNfsv3">
|
||||
<label i18n
|
||||
class="custom-control-label"
|
||||
for="protocolNfsv3">NFSv3</label>
|
||||
</div>
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
formControlName="protocolNfsv4"
|
||||
name="protocolNfsv4"
|
||||
id="protocolNfsv4">
|
||||
<label i18n
|
||||
class="custom-control-label"
|
||||
for="protocolNfsv4">NFSv4</label>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('protocolNfsv3', formDir, 'required') ||
|
||||
nfsForm.showError('protocolNfsv4', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
@ -351,9 +343,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Tag -->
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('protocolNfsv3')">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="tag">
|
||||
<ng-container i18n>NFS Tag</ng-container>
|
||||
<cd-helper>
|
||||
@ -372,10 +364,9 @@
|
||||
</div>
|
||||
|
||||
<!-- Pseudo -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('pseudo', formDir)}"
|
||||
<div class="form-group row"
|
||||
*ngIf="nfsForm.getValue('protocolNfsv4')">
|
||||
<label class="col-sm-3 control-label"
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="pseudo">
|
||||
<ng-container i18n>Pseudo</ng-container>
|
||||
<span class="required"></span>
|
||||
@ -391,25 +382,24 @@
|
||||
name="pseudo"
|
||||
id="pseudo"
|
||||
formControlName="pseudo">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('pseudo', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
<span class="help-block"
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Access Type -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('access_type', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="access_type">
|
||||
<ng-container i18n>Access Type</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
formControlName="access_type"
|
||||
name="access_type"
|
||||
id="access_type">
|
||||
@ -425,26 +415,25 @@
|
||||
<option *ngFor="let accessType of nfsAccessType"
|
||||
[value]="accessType.value">{{ accessType.value }}</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="form-text text-muted"
|
||||
*ngIf="nfsForm.getValue('access_type')">
|
||||
{{ getAccessTypeHelp(nfsForm.getValue('access_type')) }}
|
||||
</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('access_type', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Squash -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('squash', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="squash">
|
||||
<ng-container i18n>Squash</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
name="squash"
|
||||
formControlName="squash"
|
||||
id="squash">
|
||||
@ -461,38 +450,41 @@
|
||||
[value]="squash">{{ squash }}</option>
|
||||
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('squash', formDir,'required')"
|
||||
i18n>Required field</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transport Protocol -->
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': nfsForm.showError('transportUDP', formDir) || nfsForm.showError('transportTCP', formDir)}">
|
||||
<label class="col-sm-3 control-label"
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"
|
||||
for="transports">
|
||||
<ng-container i18n>Transport Protocol</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
formControlName="transportUDP"
|
||||
name="transportUDP"
|
||||
id="transportUDP">
|
||||
<label for="transportUDP"
|
||||
class="custom-control-label"
|
||||
i18n>UDP</label>
|
||||
</div>
|
||||
<div class="checkbox checkbox-primary">
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox"
|
||||
class="custom-control-input"
|
||||
formControlName="transportTCP"
|
||||
name="transportTCP"
|
||||
id="transportTCP">
|
||||
<label for="transportTCP"
|
||||
class="custom-control-label"
|
||||
i18n>TCP</label>
|
||||
</div>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="nfsForm.showError('transportUDP', formDir, 'required') ||
|
||||
nfsForm.showError('transportTCP', formDir, 'required')"
|
||||
i18n>Required field</span>
|
||||
@ -507,13 +499,12 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel-footer">
|
||||
<div class="card-footer">
|
||||
<div class="button-group text-right">
|
||||
<cd-submit-button
|
||||
[form]="formDir"
|
||||
(submitAction)="submitAction()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
type="button">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
[form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-back-button></cd-back-button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,8 +4,8 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
|
||||
import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
|
||||
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
|
||||
@ -28,7 +28,7 @@ describe('NfsFormComponent', () => {
|
||||
ReactiveFormsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
TypeaheadModule.forRoot()
|
||||
],
|
||||
providers: [
|
||||
|
@ -3,8 +3,8 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { ToastModule } from 'ng2-toastr';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { BehaviorSubject, of } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -39,7 +39,7 @@ describe('NfsListComponent', () => {
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
ToastModule.forRoot(),
|
||||
ToastrModule.forRoot(),
|
||||
TabsModule.forRoot()
|
||||
],
|
||||
providers: [TaskListService, i18nProviders]
|
||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { NgBootstrapFormValidationModule } from 'ng-bootstrap-form-validation';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
|
||||
|
||||
@ -20,7 +21,8 @@ import { NfsListComponent } from './nfs-list/nfs-list.component';
|
||||
SharedModule,
|
||||
TabsModule.forRoot(),
|
||||
CommonModule,
|
||||
TypeaheadModule.forRoot()
|
||||
TypeaheadModule.forRoot(),
|
||||
NgBootstrapFormValidationModule
|
||||
],
|
||||
declarations: [
|
||||
NfsListComponent,
|
||||
|
@ -1,23 +1,22 @@
|
||||
<div class="modal-header">
|
||||
<h4 i18n="form title|Example: Create Pool@@formTitle"
|
||||
class="modal-title pull-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
|
||||
class="modal-title float-left">{{ action | titlecase }} {{ resource | upperFirst }}</h4>
|
||||
|
||||
<button type="button"
|
||||
class="close pull-right"
|
||||
class="close float-right"
|
||||
aria-label="Close"
|
||||
(click)="bsModalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal"
|
||||
#frm="ngForm"
|
||||
<form #frm="ngForm"
|
||||
[formGroup]="form"
|
||||
novalidate>
|
||||
<div class="modal-body">
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('name', frm)}">
|
||||
<div class="form-group row">
|
||||
<label for="name"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Name</ng-container>
|
||||
<span class="required"></span>
|
||||
</label>
|
||||
@ -29,28 +28,28 @@
|
||||
placeholder="Name..."
|
||||
formControlName="name"
|
||||
autofocus>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('name', frm, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('name', frm, 'pattern')"
|
||||
i18n>The name can only consist of alphanumeric characters, dashes and underscores.</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('name', frm, 'uniqueName')"
|
||||
i18n>The chosen erasure code profile name is already in use.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label for="plugin"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Plugin</ng-container>
|
||||
<span class="required"></span>
|
||||
<cd-helper [html]="tooltips.plugins[plugin].description">
|
||||
</cd-helper>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
id="plugin"
|
||||
name="plugin"
|
||||
formControlName="plugin">
|
||||
@ -62,16 +61,15 @@
|
||||
{{ plugin }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('name', frm, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('k', frm)}">
|
||||
<div class="form-group row">
|
||||
<label for="k"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Data chunks (k)</ng-container>
|
||||
<span class="required"
|
||||
*ngIf="requiredControls.includes('k')"></span>
|
||||
@ -86,19 +84,18 @@
|
||||
ng-model="$ctrl.erasureCodeProfile.k"
|
||||
placeholder="Data chunks..."
|
||||
formControlName="k">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('k', frm, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('k', frm, 'min')"
|
||||
i18n>Must be equal to or greater than 2.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('m', frm)}">
|
||||
<div class="form-group row">
|
||||
<label for="m"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Coding chunks (m)</ng-container>
|
||||
<span class="required"
|
||||
*ngIf="requiredControls.includes('m')"></span>
|
||||
@ -112,20 +109,19 @@
|
||||
class="form-control"
|
||||
placeholder="Coding chunks..."
|
||||
formControlName="m">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('m', frm, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('m', frm, 'min')"
|
||||
i18n>Must be equal to or greater than 1.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
*ngIf="plugin === 'shec'"
|
||||
[ngClass]="{'has-error': form.showError('c', frm)}">
|
||||
<div class="form-group row"
|
||||
*ngIf="plugin === 'shec'">
|
||||
<label for="c"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Durability estimator (c)</ng-container>
|
||||
<cd-helper [html]="tooltips.plugins.shec.c">
|
||||
</cd-helper>
|
||||
@ -137,17 +133,16 @@
|
||||
class="form-control"
|
||||
placeholder="Coding chunks..."
|
||||
formControlName="c">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('c', frm, 'min')"
|
||||
i18n>Must be equal to or greater than 1.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
*ngIf="plugin === PLUGIN.LRC"
|
||||
[ngClass]="{'has-error': form.showError('l', frm)}">
|
||||
<div class="form-group row"
|
||||
*ngIf="plugin === PLUGIN.LRC">
|
||||
<label for="l"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Locality (l)</ng-container>
|
||||
<span class="required"></span>
|
||||
<cd-helper [html]="tooltips.plugins.lrc.l">
|
||||
@ -160,24 +155,24 @@
|
||||
class="form-control"
|
||||
placeholder="Coding chunks..."
|
||||
formControlName="l">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('l', frm, 'required')"
|
||||
i18n>This field is required!</span>
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('l', frm, 'min')"
|
||||
i18n>Must be equal to or greater than 1.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label for="crushFailureDomain"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Crush failure domain</ng-container>
|
||||
<cd-helper [html]="tooltips.crushFailureDomain">
|
||||
</cd-helper>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
id="crushFailureDomain"
|
||||
name="crushFailureDomain"
|
||||
formControlName="crushFailureDomain">
|
||||
@ -192,16 +187,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="plugin === PLUGIN.LRC">
|
||||
<label for="crushLocality"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Crush Locality</ng-container>
|
||||
<cd-helper [html]="tooltips.plugins.lrc.crushLocality">
|
||||
</cd-helper>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
id="crushLocality"
|
||||
name="crushLocality"
|
||||
formControlName="crushLocality">
|
||||
@ -219,16 +214,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
<div class="form-group row"
|
||||
*ngIf="[PLUGIN.JERASURE, PLUGIN.ISA].includes(plugin)">
|
||||
<label for="technique"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Technique</ng-container>
|
||||
<cd-helper [html]="tooltips.plugins[plugin].technique">
|
||||
</cd-helper>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
id="technique"
|
||||
name="technique"
|
||||
formControlName="technique">
|
||||
@ -240,11 +235,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
*ngIf="plugin === PLUGIN.JERASURE"
|
||||
[ngClass]="{'has-error': form.showError('packetSize', frm)}">
|
||||
<div class="form-group row"
|
||||
*ngIf="plugin === PLUGIN.JERASURE">
|
||||
<label for="packetSize"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Packetsize</ng-container>
|
||||
<cd-helper [html]="tooltips.plugins.jerasure.packetSize">
|
||||
</cd-helper>
|
||||
@ -256,16 +250,15 @@
|
||||
class="form-control"
|
||||
placeholder="Packetsize..."
|
||||
formControlName="packetSize">
|
||||
<span class="help-block"
|
||||
<span class="invalid-feedback"
|
||||
*ngIf="form.showError('packetSize', frm, 'min')"
|
||||
i18n>Must be equal to or greater than 1.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group"
|
||||
[ngClass]="{'has-error': form.showError('crushRoot', frm)}">
|
||||
<div class="form-group row">
|
||||
<label for="crushRoot"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Crush root</ng-container>
|
||||
<cd-helper [html]="tooltips.crushRoot">
|
||||
</cd-helper>
|
||||
@ -280,15 +273,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label for="crushDeviceClass"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Crush device class</ng-container>
|
||||
<cd-helper [html]="tooltips.crushDeviceClass">
|
||||
</cd-helper>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control"
|
||||
<select class="form-control custom-select"
|
||||
id="crushDeviceClass"
|
||||
name="crushDeviceClass"
|
||||
formControlName="crushDeviceClass">
|
||||
@ -302,9 +295,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-group row">
|
||||
<label for="directory"
|
||||
class="control-label col-sm-3">
|
||||
class="col-form-label col-sm-3">
|
||||
<ng-container i18n>Directory</ng-container>
|
||||
<cd-helper [html]="tooltips.directory">
|
||||
</cd-helper>
|
||||
@ -321,10 +314,9 @@
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<cd-submit-button
|
||||
(submitAction)="onSubmit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
[form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-submit-button (submitAction)="onSubmit()"
|
||||
i18n="form action button|Example: Create Pool@@formActionButton"
|
||||
[form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
|
||||
<cd-back-button [back]="bsModalRef.hide"></cd-back-button>
|
||||
</div>
|
||||
</form>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user