File
Implements
Metadata
selector |
cd-nfs-form |
styleUrls |
./nfs-form.component.scss |
templateUrl |
./nfs-form.component.html |
Methods
_buildRequest
|
_buildRequest()
|
|
|
_generatePseudo
|
_generatePseudo()
|
|
|
_generateTag
|
_generateTag()
|
|
|
bucketChangeHandler
|
bucketChangeHandler()
|
|
|
fsalChangeHandler
|
fsalChangeHandler()
|
|
|
getAccessTypeHelp
|
getAccessTypeHelp(accessType)
|
|
Parameters :
Name |
Optional |
accessType |
No
|
|
getBucketTypeahead
|
getBucketTypeahead(path: string)
|
|
Parameters :
Name |
Type |
Optional |
path |
string
|
No
|
Returns : Observable<any>
|
getData
|
getData(promises)
|
|
Parameters :
Name |
Optional |
promises |
No
|
|
getPathTypeahead
|
getPathTypeahead(path)
|
|
|
onClusterChange
|
onClusterChange()
|
|
|
onDaemonSelection
|
onDaemonSelection()
|
|
|
pathChangeHandler
|
pathChangeHandler()
|
|
|
removeDaemon
|
removeDaemon(index, daemon)
|
|
Parameters :
Name |
Optional |
index |
No
|
daemon |
No
|
|
resolveClients
|
resolveClients(clients)
|
|
|
resolveDaemons
|
resolveDaemons(daemons)
|
|
|
resolveFilesystems
|
resolveFilesystems(filesystems)
|
|
Parameters :
Name |
Optional |
filesystems |
No
|
|
resolvefsals
|
resolvefsals(res: string[])
|
|
Parameters :
Name |
Type |
Optional |
res |
string[]
|
No
|
|
resolveModel
|
resolveModel(res)
|
|
|
rgwUserIdChangeHandler
|
rgwUserIdChangeHandler()
|
|
|
setPathValidation
|
setPathValidation()
|
|
|
submitAction
|
submitAction()
|
|
|
allCephxClients
|
Type : any[]
|
Default value : null
|
|
allClusters
|
Type : string[]
|
Default value : null
|
|
allDaemons
|
Type : object
|
Default value : {}
|
|
allFsals
|
Type : any[]
|
Default value : []
|
|
allFsNames
|
Type : any[]
|
Default value : null
|
|
allRgwUsers
|
Type : any[]
|
Default value : []
|
|
bucketDataSource
|
Type : Observable<any>
|
Default value : Observable.create((observer: any) => {
observer.next(this.nfsForm.getValue('path'));
}).pipe(mergeMap((token: string) => this.getBucketTypeahead(token)))
|
|
cluster_id
|
Type : null
|
Default value : null
|
|
daemonsMessages
|
Default value : new SelectMessages(
{ noOptions: this.i18n('There are no daemons available.') },
this.i18n
)
|
|
export_id
|
Type : null
|
Default value : null
|
|
isDefaultCluster
|
Default value : false
|
|
isEdit
|
Default value : false
|
|
isNewBucket
|
Default value : false
|
|
isNewDirectory
|
Default value : false
|
|
nfsAccessType
|
Type : any[]
|
Default value : this.nfsService.nfsAccessType
|
|
nfsSquash
|
Type : any[]
|
Default value : this.nfsService.nfsSquash
|
|
pathDataSource
|
Type : Observable<any>
|
Default value : Observable.create((observer: any) => {
observer.next(this.nfsForm.getValue('path'));
}).pipe(
mergeMap((token: string) => this.getPathTypeahead(token)),
map((val: any) => val.paths)
)
|
|
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { I18n } from '@ngx-translate/i18n-polyfill';
import * as _ from 'lodash';
import { forkJoin, Observable, of } from 'rxjs';
import { map, mergeMap } from 'rxjs/operators';
import { NfsService } from '../../../shared/api/nfs.service';
import { RgwUserService } from '../../../shared/api/rgw-user.service';
import { SelectMessages } from '../../../shared/components/select/select-messages.model';
import { SelectOption } from '../../../shared/components/select/select-option.model';
import { CdFormBuilder } from '../../../shared/forms/cd-form-builder';
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import { CdValidators } from '../../../shared/forms/cd-validators';
import { FinishedTask } from '../../../shared/models/finished-task';
import { Permission } from '../../../shared/models/permissions';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
import { NfsFormClientComponent } from '../nfs-form-client/nfs-form-client.component';
@Component({
selector: 'cd-nfs-form',
templateUrl: './nfs-form.component.html',
styleUrls: ['./nfs-form.component.scss']
})
export class NfsFormComponent implements OnInit {
@ViewChild('nfsClients')
nfsClients: NfsFormClientComponent;
permission: Permission;
nfsForm: CdFormGroup;
isEdit = false;
cluster_id = null;
export_id = null;
isNewDirectory = false;
isNewBucket = false;
isDefaultCluster = false;
allClusters: string[] = null;
allDaemons = {};
allFsals: any[] = [];
allRgwUsers: any[] = [];
allCephxClients: any[] = null;
allFsNames: any[] = null;
nfsAccessType: any[] = this.nfsService.nfsAccessType;
nfsSquash: any[] = this.nfsService.nfsSquash;
daemonsSelections: SelectOption[] = [];
daemonsMessages = new SelectMessages(
{ noOptions: this.i18n('There are no daemons available.') },
this.i18n
);
pathDataSource: Observable<any> = Observable.create((observer: any) => {
observer.next(this.nfsForm.getValue('path'));
}).pipe(
mergeMap((token: string) => this.getPathTypeahead(token)),
map((val: any) => val.paths)
);
bucketDataSource: Observable<any> = Observable.create((observer: any) => {
observer.next(this.nfsForm.getValue('path'));
}).pipe(mergeMap((token: string) => this.getBucketTypeahead(token)));
constructor(
private authStorageService: AuthStorageService,
private nfsService: NfsService,
private route: ActivatedRoute,
private router: Router,
private rgwUserService: RgwUserService,
private formBuilder: CdFormBuilder,
private taskWrapper: TaskWrapperService,
private cdRef: ChangeDetectorRef,
private i18n: I18n
) {
this.permission = this.authStorageService.getPermissions().pool;
this.createForm();
}
ngOnInit() {
const promises: any[] = [
this.nfsService.daemon(),
this.nfsService.fsals(),
this.nfsService.clients(),
this.nfsService.filesystems()
];
if (this.router.url.startsWith('/nfs/edit')) {
this.isEdit = true;
}
if (this.isEdit) {
this.route.params.subscribe((params: { cluster_id: string; export_id: string }) => {
this.cluster_id = decodeURIComponent(params.cluster_id);
this.export_id = decodeURIComponent(params.export_id);
promises.push(this.nfsService.get(this.cluster_id, this.export_id));
this.getData(promises);
});
} else {
this.getData(promises);
}
}
getData(promises) {
forkJoin(promises).subscribe((data: any[]) => {
this.resolveDaemons(data[0]);
this.resolvefsals(data[1]);
this.resolveClients(data[2]);
this.resolveFilesystems(data[3]);
if (data[4]) {
this.resolveModel(data[4]);
}
});
}
createForm() {
this.nfsForm = new CdFormGroup({
cluster_id: new FormControl('', {
validators: [Validators.required]
}),
daemons: new FormControl([]),
fsal: new CdFormGroup({
name: new FormControl('', {
validators: [Validators.required]
}),
user_id: new FormControl('', {
validators: [
CdValidators.requiredIf({
name: 'CEPH'
})
]
}),
fs_name: new FormControl('', {
validators: [
CdValidators.requiredIf({
name: 'CEPH'
})
]
}),
rgw_user_id: new FormControl('', {
validators: [
CdValidators.requiredIf({
name: 'RGW'
})
]
})
}),
path: new FormControl(''),
protocolNfsv3: new FormControl(true, {
validators: [
CdValidators.requiredIf({ protocolNfsv4: false }, (value) => {
return !value;
})
]
}),
protocolNfsv4: new FormControl(true, {
validators: [
CdValidators.requiredIf({ protocolNfsv3: false }, (value) => {
return !value;
})
]
}),
tag: new FormControl(''),
pseudo: new FormControl('', {
validators: [
CdValidators.requiredIf({ protocolNfsv4: true }),
Validators.pattern('^/[^><|&()]*$')
]
}),
access_type: new FormControl('RW', {
validators: [Validators.required]
}),
squash: new FormControl('', {
validators: [Validators.required]
}),
transportUDP: new FormControl(true, {
validators: [
CdValidators.requiredIf({ transportTCP: false }, (value) => {
return !value;
})
]
}),
transportTCP: new FormControl(true, {
validators: [
CdValidators.requiredIf({ transportUDP: false }, (value) => {
return !value;
})
]
}),
clients: this.formBuilder.array([]),
security_label: new FormControl(false),
sec_label_xattr: new FormControl(
'security.selinux',
CdValidators.requiredIf({ security_label: true, 'fsal.name': 'CEPH' })
)
});
this.nfsForm.get('protocolNfsv4').valueChanges.subscribe(() => {
this.nfsForm.get('pseudo').updateValueAndValidity({ emitEvent: false });
});
}
resolveModel(res) {
if (res.fsal.name === 'CEPH') {
res.sec_label_xattr = res.fsal.sec_label_xattr;
}
this.daemonsSelections = _.map(
this.allDaemons[res.cluster_id],
(daemon) => new SelectOption(res.daemons.indexOf(daemon) !== -1, daemon, '')
);
this.daemonsSelections = [...this.daemonsSelections];
res.protocolNfsv3 = res.protocols.indexOf(3) !== -1;
res.protocolNfsv4 = res.protocols.indexOf(4) !== -1;
delete res.protocols;
res.transportTCP = res.transports.indexOf('TCP') !== -1;
res.transportUDP = res.transports.indexOf('UDP') !== -1;
delete res.transports;
res.clients.forEach((client) => {
let addressStr = '';
client.addresses.forEach((address) => {
addressStr += address + ', ';
});
if (addressStr.length >= 2) {
addressStr = addressStr.substring(0, addressStr.length - 2);
}
client.addresses = addressStr;
});
this.nfsForm.patchValue(res);
this.setPathValidation();
this.nfsClients.resolveModel(res.clients);
}
resolveDaemons(daemons) {
daemons = _.sortBy(daemons, ['daemon_id']);
this.allClusters = _(daemons)
.map((daemon) => daemon.cluster_id)
.sortedUniq()
.value();
_.forEach(this.allClusters, (cluster) => {
this.allDaemons[cluster] = [];
});
_.forEach(daemons, (daemon) => {
this.allDaemons[daemon.cluster_id].push(daemon.daemon_id);
});
const hasOneCluster = _.isArray(this.allClusters) && this.allClusters.length === 1;
this.isDefaultCluster = hasOneCluster && this.allClusters[0] === '_default_';
if (hasOneCluster) {
this.nfsForm.patchValue({
cluster_id: this.allClusters[0]
});
this.onClusterChange();
}
}
resolvefsals(res: string[]) {
res.forEach((fsal) => {
const fsalItem = this.nfsService.nfsFsal.find((currentFsalItem) => {
return fsal === currentFsalItem.value;
});
if (_.isObjectLike(fsalItem)) {
this.allFsals.push(fsalItem);
if (fsalItem.value === 'RGW') {
this.rgwUserService.list().subscribe((result: any) => {
result.forEach((user) => {
if (user.suspended === 0 && user.keys.length > 0) {
this.allRgwUsers.push(user.user_id);
}
});
});
}
}
});
if (this.allFsals.length === 1 && _.isUndefined(this.nfsForm.getValue('fsal'))) {
this.nfsForm.patchValue({
fsal: this.allFsals[0]
});
}
}
resolveClients(clients) {
this.allCephxClients = clients;
}
resolveFilesystems(filesystems) {
this.allFsNames = filesystems;
if (filesystems.length === 1) {
this.nfsForm.patchValue({
fsal: {
fs_name: filesystems[0].name
}
});
}
}
fsalChangeHandler() {
this.nfsForm.patchValue({
tag: this._generateTag(),
pseudo: this._generatePseudo()
});
this.setPathValidation();
this.cdRef.detectChanges();
}
setPathValidation() {
if (this.nfsForm.getValue('name') === 'RGW') {
this.nfsForm
.get('path')
.setValidators([Validators.required, Validators.pattern('^(/|[^/><|&()#?]+)$')]);
} else {
this.nfsForm
.get('path')
.setValidators([Validators.required, Validators.pattern('^/[^><|&()?]*$')]);
}
}
rgwUserIdChangeHandler() {
this.nfsForm.patchValue({
pseudo: this._generatePseudo()
});
}
getAccessTypeHelp(accessType) {
const accessTypeItem = this.nfsAccessType.find((currentAccessTypeItem) => {
if (accessType === currentAccessTypeItem.value) {
return currentAccessTypeItem;
}
});
return _.isObjectLike(accessTypeItem) ? accessTypeItem.help : '';
}
getId() {
if (
_.isString(this.nfsForm.getValue('cluster_id')) &&
_.isString(this.nfsForm.getValue('path'))
) {
return this.nfsForm.getValue('cluster_id') + ':' + this.nfsForm.getValue('path');
}
return '';
}
getPathTypeahead(path) {
if (!_.isString(path) || path === '/') {
return of([]);
}
return this.nfsService.lsDir(path);
}
pathChangeHandler() {
this.nfsForm.patchValue({
pseudo: this._generatePseudo()
});
const path = this.nfsForm.getValue('path');
this.getPathTypeahead(path).subscribe((res: any) => {
this.isNewDirectory = path !== '/' && res.paths.indexOf(path) === -1;
});
}
bucketChangeHandler() {
this.nfsForm.patchValue({
tag: this._generateTag(),
pseudo: this._generatePseudo()
});
const bucket = this.nfsForm.getValue('path');
this.getBucketTypeahead(bucket).subscribe((res: any) => {
this.isNewBucket = bucket !== '' && res.indexOf(bucket) === -1;
});
}
getBucketTypeahead(path: string): Observable<any> {
const rgwUserId = this.nfsForm.getValue('rgw_user_id');
if (_.isString(rgwUserId) && _.isString(path) && path !== '/' && path !== '') {
return this.nfsService.buckets(rgwUserId);
} else {
return of([]);
}
}
_generateTag() {
let newTag = this.nfsForm.getValue('tag');
if (!this.nfsForm.get('tag').dirty) {
newTag = undefined;
if (this.nfsForm.getValue('fsal') === 'RGW') {
newTag = this.nfsForm.getValue('path');
}
}
return newTag;
}
_generatePseudo() {
let newPseudo = this.nfsForm.getValue('pseudo');
if (this.nfsForm.get('pseudo') && !this.nfsForm.get('pseudo').dirty) {
newPseudo = undefined;
if (this.nfsForm.getValue('fsal') === 'CEPH') {
newPseudo = '/cephfs';
if (_.isString(this.nfsForm.getValue('path'))) {
newPseudo += this.nfsForm.getValue('path');
}
} else if (this.nfsForm.getValue('fsal') === 'RGW') {
if (_.isString(this.nfsForm.getValue('rgw_user_id'))) {
newPseudo = '/' + this.nfsForm.getValue('rgw_user_id');
if (_.isString(this.nfsForm.getValue('path'))) {
newPseudo += '/' + this.nfsForm.getValue('path');
}
}
}
}
return newPseudo;
}
onClusterChange() {
const cluster_id = this.nfsForm.getValue('cluster_id');
this.daemonsSelections = _.map(
this.allDaemons[cluster_id],
(daemon) => new SelectOption(false, daemon, '')
);
this.daemonsSelections = [...this.daemonsSelections];
this.nfsForm.patchValue({ daemons: [] });
}
removeDaemon(index, daemon) {
this.daemonsSelections.forEach((value) => {
if (value.name === daemon) {
value.selected = false;
}
});
const daemons = this.nfsForm.get('daemons');
daemons.value.splice(index, 1);
daemons.setValue(daemons.value);
return false;
}
onDaemonSelection() {
this.nfsForm.get('daemons').setValue(this.nfsForm.getValue('daemons'));
}
submitAction() {
let action: Observable<any>;
const requestModel = this._buildRequest();
if (this.isEdit) {
action = this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('nfs/edit', {
cluster_id: this.cluster_id,
export_id: this.export_id
}),
call: this.nfsService.update(this.cluster_id, this.export_id, requestModel)
});
} else {
// Create
action = this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('nfs/create', {
path: requestModel.path,
fsal: requestModel.fsal,
cluster_id: requestModel.cluster_id
}),
call: this.nfsService.create(requestModel)
});
}
action.subscribe(
undefined,
() => this.nfsForm.setErrors({ cdSubmitButton: true }),
() => this.router.navigate(['/nfs'])
);
}
_buildRequest() {
const requestModel: any = _.cloneDeep(this.nfsForm.value);
if (_.isUndefined(requestModel.tag) || requestModel.tag === '') {
requestModel.tag = null;
}
if (this.isEdit) {
requestModel.export_id = this.export_id;
}
if (requestModel.fsal.name === 'CEPH') {
delete requestModel.fsal.rgw_user_id;
} else {
delete requestModel.fsal.fs_name;
delete requestModel.fsal.user_id;
}
requestModel.protocols = [];
if (requestModel.protocolNfsv3) {
requestModel.protocols.push(3);
} else {
requestModel.tag = null;
}
delete requestModel.protocolNfsv3;
if (requestModel.protocolNfsv4) {
requestModel.protocols.push(4);
} else {
requestModel.pseudo = null;
}
delete requestModel.protocolNfsv4;
requestModel.transports = [];
if (requestModel.transportTCP) {
requestModel.transports.push('TCP');
}
delete requestModel.transportTCP;
if (requestModel.transportUDP) {
requestModel.transports.push('UDP');
}
delete requestModel.transportUDP;
requestModel.clients.forEach((client) => {
if (_.isString(client.addresses)) {
client.addresses = _(client.addresses)
.split(/[ ,]+/)
.uniq()
.filter((address) => address !== '')
.value();
} else {
client.addresses = [];
}
});
if (requestModel.security_label === false || requestModel.fsal.name === 'RGW') {
requestModel.fsal.sec_label_xattr = null;
} else {
requestModel.fsal.sec_label_xattr = requestModel.sec_label_xattr;
}
delete requestModel.sec_label_xattr;
return requestModel;
}
}
<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 class="panel-title"
i18n>NFS export {{ export_id ? cluster_id + ':' + export_id : '' }}</h3>
</div>
<div class="panel-body">
<!-- cluster_id -->
<div class="form-group"
[ngClass]="{'has-error': nfsForm.showError('cluster_id', formDir)}"
*ngIf="!isDefaultCluster">
<label class="col-sm-3 control-label"
for="cluster_id">
<ng-container i18n>Cluster</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<select class="form-control"
formControlName="cluster_id"
name="cluster_id"
id="cluster_id"
(change)="onClusterChange()">
<option *ngIf="allClusters === null"
value=""
i18n>Loading...</option>
<option *ngIf="allClusters !== null && allClusters.length === 0"
value=""
i18n>-- No cluster available --</option>
<option *ngIf="allClusters !== null && allClusters.length > 0"
value=""
i18n>-- Select the cluster --</option>
<option *ngFor="let cluster of allClusters"
[value]="cluster">{{ cluster }}</option>
</select>
<span class="help-block"
*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"
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"
type="text"
[value]="daemon"
disabled />
<span class="input-group-btn">
<button class="btn btn-default"
type="button"
(click)="removeDaemon(i, daemon)">
<i class="fa fa-remove fa-fw"
aria-hidden="true"></i>
</button>
</span>
</div>
</ng-container>
<div class="row">
<div class="col-md-12">
<cd-select [data]="nfsForm.get('daemons').value"
[options]="daemonsSelections"
[messages]="daemonsMessages"
(selection)="onDaemonSelection()"
elemClass="btn btn-default pull-right">
<i class="fa fa-fw fa-plus"></i>
<ng-container i18n>Add daemon</ng-container>
</cd-select>
</div>
</div>
</div>
</div>
<!-- FSAL -->
<div formGroupName="fsal">
<!-- Name -->
<div class="form-group"
[ngClass]="{'has-error': nfsForm.showError('name', formDir)}">
<label class="col-sm-3 control-label"
for="name">
<ng-container i18n>Storage Backend</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<select class="form-control"
formControlName="name"
name="name"
id="name"
(change)="fsalChangeHandler()">
<option *ngIf="allFsals === null"
value=""
i18n>Loading...</option>
<option *ngIf="allFsals !== null && allFsals.length === 0"
value=""
i18n>-- No data pools available --</option>
<option *ngIf="allFsals !== null && allFsals.length > 0"
value=""
i18n>-- Select the storage backend --</option>
<option *ngFor="let fsal of allFsals"
[value]="fsal.value">{{ fsal.descr }}</option>
</select>
<span class="help-block"
*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)}"
*ngIf="nfsForm.getValue('name') === 'RGW'">
<label class="col-sm-3 control-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"
formControlName="rgw_user_id"
name="rgw_user_id"
id="rgw_user_id"
(change)="rgwUserIdChangeHandler()">
<option *ngIf="allRgwUsers === null"
value=""
i18n>Loading...</option>
<option *ngIf="allRgwUsers !== null && allRgwUsers.length === 0"
value=""
i18n>-- No users available --</option>
<option *ngIf="allRgwUsers !== null && allRgwUsers.length > 0"
value=""
i18n>-- Select the object gateway user --</option>
<option *ngFor="let rgwUserId of allRgwUsers"
[value]="rgwUserId">{{ rgwUserId }}</option>
</select>
<span class="help-block"
*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)}"
*ngIf="nfsForm.getValue('name') === 'CEPH'">
<label class="col-sm-3 control-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"
formControlName="user_id"
name="user_id"
id="user_id">
<option *ngIf="allCephxClients === null"
value=""
i18n>Loading...</option>
<option *ngIf="allCephxClients !== null && allCephxClients.length === 0"
value=""
i18n>-- No clients available --</option>
<option *ngIf="allCephxClients !== null && allCephxClients.length > 0"
value=""
i18n>-- Select the cephx client --</option>
<option *ngFor="let client of allCephxClients"
[value]="client">{{ client }}</option>
</select>
<span class="help-block"
*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)}"
*ngIf="nfsForm.getValue('name') === 'CEPH'">
<label class="col-sm-3 control-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"
formControlName="fs_name"
name="fs_name"
id="fs_name"
(change)="rgwUserIdChangeHandler()">
<option *ngIf="allFsNames === null"
value=""
i18n>Loading...</option>
<option *ngIf="allFsNames !== null && allFsNames.length === 0"
value=""
i18n>-- No CephFS filesystem available --</option>
<option *ngIf="allFsNames !== null && allFsNames.length > 0"
value=""
i18n>-- Select the CephFS filesystem --</option>
<option *ngFor="let filesystem of allFsNames"
[value]="filesystem.name">{{ filesystem.name }}</option>
</select>
<span class="help-block"
*ngIf="nfsForm.showError('fs_name', formDir, 'required')"
i18n>Required field</span>
</div>
</div>
</div>
<!-- Secutiry Label -->
<div class="form-group"
[ngClass]="{'has-error': nfsForm.showError('security_label', formDir)}"
*ngIf="nfsForm.getValue('name') === 'CEPH'">
<label class="col-sm-3 control-label"
for="security_label">
<ng-container i18n>Security Label</ng-container>
<span class="required"
*ngIf="nfsForm.getValue('security_label')"></span>
</label>
<div class="col-sm-9">
<div class="checkbox checkbox-primary">
<input type="checkbox"
formControlName="security_label"
name="security_label"
id="security_label">
<label for="security_label"
i18n>Enable security label</label>
</div>
<br>
<input type="text"
*ngIf="nfsForm.getValue('security_label')"
class="form-control"
name="sec_label_xattr"
id="sec_label_xattr"
formControlName="sec_label_xattr">
<span class="help-block"
*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)}"
*ngIf="nfsForm.getValue('name') === 'CEPH'">
<label class="col-sm-3 control-label"
for="path">
<ng-container i18n>CephFS Path</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<input type="text"
class="form-control"
name="path"
id="path"
formControlName="path"
[typeahead]="pathDataSource"
(typeaheadOnSelect)="pathChangeHandler()"
(blur)="pathChangeHandler()">
<span class="help-block"
*ngIf="nfsForm.showError('path', formDir, 'required')"
i18n>Required field</span>
<span class="help-block"
*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"
*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)}"
*ngIf="nfsForm.getValue('name') === 'RGW'">
<label class="col-sm-3 control-label"
for="path">
<ng-container i18n>Path</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<input type="text"
class="form-control"
name="path"
id="path"
formControlName="path"
[typeahead]="bucketDataSource"
(typeaheadOnSelect)="bucketChangeHandler()"
(blur)="bucketChangeHandler()">
<span class="help-block"
*ngIf="nfsForm.showError('path', formDir, 'required')"
i18n>Required field</span>
<span class="help-block"
*ngIf="nfsForm.showError('path', formDir, 'pattern')"
i18n>Path can only be a single '/' or a word</span>
<span class="help-block"
*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"
for="protocols">
<ng-container i18n>NFS Protocol</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<div class="checkbox checkbox-primary">
<input type="checkbox"
id="protocolNfsv3"
name="protocolNfsv3"
formControlName="protocolNfsv3">
<label i18n
for="protocolNfsv3">NFSv3</label>
</div>
<div class="checkbox checkbox-primary">
<input type="checkbox"
formControlName="protocolNfsv4"
name="protocolNfsv4"
id="protocolNfsv4">
<label i18n
for="protocolNfsv4">NFSv4</label>
</div>
<span class="help-block"
*ngIf="nfsForm.showError('protocolNfsv3', formDir, 'required') ||
nfsForm.showError('protocolNfsv4', formDir, 'required')"
i18n>Required field</span>
</div>
</div>
<!-- Tag -->
<div class="form-group"
*ngIf="nfsForm.getValue('protocolNfsv3')">
<label class="col-sm-3 control-label"
for="tag">
<ng-container i18n>NFS Tag</ng-container>
<cd-helper>
<p i18n>Alternative access for <strong>NFS v3</strong> mounts (it must not have a leading /).</p>
<p i18n>Clients may not mount subdirectories (i.e. if Tag = foo, the client may not mount foo/baz).</p>
<p i18n>By using different Tag options, the same Path may be exported multiple times.</p>
</cd-helper>
</label>
<div class="col-sm-9">
<input type="text"
class="form-control"
name="tag"
id="tag"
formControlName="tag">
</div>
</div>
<!-- Pseudo -->
<div class="form-group"
[ngClass]="{'has-error': nfsForm.showError('pseudo', formDir)}"
*ngIf="nfsForm.getValue('protocolNfsv4')">
<label class="col-sm-3 control-label"
for="pseudo">
<ng-container i18n>Pseudo</ng-container>
<span class="required"></span>
<cd-helper>
<p i18n>The position that this <strong>NFS v4</strong> export occupies
in the <strong>Pseudo FS</strong> (it must be unique).</p>
<p i18n>By using different Pseudo options, the same Path may be exported multiple times.</p>
</cd-helper>
</label>
<div class="col-sm-9">
<input type="text"
class="form-control"
name="pseudo"
id="pseudo"
formControlName="pseudo">
<span class="help-block"
*ngIf="nfsForm.showError('pseudo', formDir, 'required')"
i18n>Required field</span>
<span class="help-block"
*ngIf="nfsForm.showError('pseudo', formDir, 'pattern')"
i18n>Wrong format</span>
</div>
</div>
<!-- Access Type -->
<div class="form-group"
[ngClass]="{'has-error': nfsForm.showError('access_type', formDir)}">
<label class="col-sm-3 control-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"
formControlName="access_type"
name="access_type"
id="access_type">
<option *ngIf="nfsAccessType === null"
value=""
i18n>Loading...</option>
<option *ngIf="nfsAccessType !== null && nfsAccessType.length === 0"
value=""
i18n>-- No access type available --</option>
<option *ngIf="nfsAccessType !== null && nfsAccessType.length > 0"
value=""
i18n>-- Select the access type --</option>
<option *ngFor="let accessType of nfsAccessType"
[value]="accessType.value">{{ accessType.value }}</option>
</select>
<span class="help-block"
*ngIf="nfsForm.getValue('access_type')">
{{ getAccessTypeHelp(nfsForm.getValue('access_type')) }}
</span>
<span class="help-block"
*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"
for="squash">
<ng-container i18n>Squash</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<select class="form-control"
name="squash"
formControlName="squash"
id="squash">
<option *ngIf="nfsSquash === null"
value=""
i18n>Loading...</option>
<option *ngIf="nfsSquash !== null && nfsSquash.length === 0"
value=""
i18n>-- No squash available --</option>
<option *ngIf="nfsSquash !== null && nfsSquash.length > 0"
value=""
i18n>--Select what kind of user id squashing is performed --</option>
<option *ngFor="let squash of nfsSquash"
[value]="squash">{{ squash }}</option>
</select>
<span class="help-block"
*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"
for="transports">
<ng-container i18n>Transport Protocol</ng-container>
<span class="required"></span>
</label>
<div class="col-sm-9">
<div class="checkbox checkbox-primary">
<input type="checkbox"
formControlName="transportUDP"
name="transportUDP"
id="transportUDP">
<label for="transportUDP"
i18n>UDP</label>
</div>
<div class="checkbox checkbox-primary">
<input type="checkbox"
formControlName="transportTCP"
name="transportTCP"
id="transportTCP">
<label for="transportTCP"
i18n>TCP</label>
</div>
<span class="help-block"
*ngIf="nfsForm.showError('transportUDP', formDir, 'required') ||
nfsForm.showError('transportTCP', formDir, 'required')"
i18n>Required field</span>
<hr>
</div>
</div>
<!-- Clients -->
<cd-nfs-form-client [form]="nfsForm"
#nfsClients>
</cd-nfs-form-client>
</div>
<div class="panel-footer">
<div class="button-group text-right">
<cd-submit-button [form]="formDir"
type="button"
(submitAction)="submitAction()">
<ng-container i18n>Submit</ng-container>
</cd-submit-button>
<cd-back-button></cd-back-button>
</div>
</div>
</div>
</form>
</div>
.cd-mb {
margin-bottom: 10px;
}
Legend
Html element with directive