<option *ngIf="allsubvolgrps === null"
value=""
i18n>Loading...</option>
- <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length === 0"
- value=""
- i18n>-- No CephFS subvolume group available --</option>
- <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length > 0"
+ <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length >= 0"
value=""
i18n>-- Select the CephFS subvolume group --</option>
<option *ngFor="let subvol_grp of allsubvolgrps"
- [value]="subvol_grp.name">{{ subvol_grp.name }}</option>
+ [value]="subvol_grp.name"
+ [selected]="subvol_grp.name === nfsForm.get('subvolume_group').value">{{ subvol_grp.name }}</option>
<option [value]="defaultSubVolGroup">{{ defaultSubVolGroup }}</option>
</select>
</div>
formControlName="subvolume"
name="subvolume"
id="subvolume"
- (change)="setSubVolPath()">
+ (change)="setSubVolPath()"
+ [invalid]="nfsForm.controls.subvolume.invalid && (nfsForm.controls.subvolume.dirty)"
+ [invalidText]="subvolumeError">
<option *ngIf="allsubvols === null"
value=""
i18n>Loading...</option>
value=""
i18n>-- Select the CephFS subvolume --</option>
<option *ngFor="let subvolume of allsubvols"
- [value]="subvolume.name">{{ subvolume.name }}</option>
+ [value]="subvolume.name"
+ [selected]="subvolume.name === nfsForm.get('subvolume').value">{{ subvolume.name }}</option>
</select>
+ <span class="invalid-feedback"
+ *ngIf="nfsForm.getValue('subvolume_group') === defaultSubVolGroup && !nfsForm.getValue('subvolume')"
+ i18n>This field is required.</span>
</div>
</div>
<span class="invalid-feedback"
*ngIf="nfsForm.showError('path', formDir, 'required')"
i18n>This field is required.</span>
-
+ <span class="invalid-feedback"
+ *ngIf="nfsForm.get('path').hasError('isIsolatedSlash') && nfsForm.get('path').touched"
+ i18n>Export on CephFS volume "<code>/</code>" not allowed.</span>
<span class="invalid-feedback"
*ngIf="nfsForm.showError('path', formDir, 'pattern')"
i18n>Path need to start with a '/' and can be followed by a word</span>
import { getFsalFromRoute, getPathfromFsal } from '../utils';
import { CephfsSubvolumeService } from '~/app/shared/api/cephfs-subvolume.service';
import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service';
+import { DEFAULT_SUBVOLUME_GROUP } from '~/app/shared/constants/cephfs.constant';
@Component({
selector: 'cd-nfs-form',
selectedFsName: string = '';
selectedSubvolGroup: string = '';
selectedSubvol: string = '';
- defaultSubVolGroup = '_nogroup';
+ defaultSubVolGroup = DEFAULT_SUBVOLUME_GROUP;
pathDataSource = (text$: Observable<string>) => {
return text$.pipe(
}
volumeChangeHandler() {
- this.pathChangeHandler();
- const fs_name = this.nfsForm.getValue('fsal').fs_name;
- this.getSubVolGrp(fs_name);
+ this.isDefaultSubvolumeGroup();
}
async getSubVol() {
).subscribe((data: any) => {
this.allsubvols = data;
});
+ this.setUpVolumeValidation();
}
getSubVolGrp(fs_name: string) {
}
setSubVolGrpPath(): Promise<void> {
- return new Promise<void>((resolve, reject) => {
- const subvolGroup = this.nfsForm.getValue('subvolume_group');
- const fs_name = this.nfsForm.getValue('fsal').fs_name;
+ const fsName = this.nfsForm.getValue('fsal').fs_name;
+ const subvolGroup = this.nfsForm.getValue('subvolume_group');
- if (subvolGroup === this.defaultSubVolGroup) {
+ return new Promise<void>((resolve, reject) => {
+ if (subvolGroup == this.defaultSubVolGroup) {
this.updatePath('/volumes/' + this.defaultSubVolGroup);
- resolve();
- } else {
+ } else if (subvolGroup != '') {
this.subvolgrpService
- .info(fs_name, subvolGroup)
+ .info(fsName, subvolGroup)
.pipe(map((data) => data['path']))
.subscribe(
(path) => {
},
(error) => reject(error)
);
+ } else {
+ this.updatePath('');
+ this.setUpVolumeValidation();
}
+ resolve();
});
}
+ // Checking if subVolGroup is "_nogroup" and updating path to default as "/volumes/_nogroup else blank."
+ isDefaultSubvolumeGroup() {
+ const fsName = this.nfsForm.getValue('fsal').fs_name;
+ this.getSubVolGrp(fsName);
+ this.getSubVol();
+ this.updatePath('/volumes/' + this.defaultSubVolGroup);
+ this.setUpVolumeValidation();
+ }
+
setSubVolPath(): Promise<void> {
return new Promise<void>((resolve, reject) => {
const subvol = this.nfsForm.getValue('subvolume');
});
}
+ setUpVolumeValidation() {
+ const subvolumeGroup = this.nfsForm.get('subvolume_group').value;
+ const subVolumeControl = this.nfsForm.get('subvolume');
+
+ // SubVolume is required if SubVolume Group is "_nogroup".
+ if (subvolumeGroup == this.defaultSubVolGroup) {
+ subVolumeControl?.setValidators([Validators.required]);
+ } else {
+ subVolumeControl?.clearValidators();
+ }
+ subVolumeControl?.updateValueAndValidity();
+ }
+
updatePath(path: string) {
this.nfsForm.patchValue({ path: path });
- this.pathChangeHandler();
}
createForm() {
]
})
}),
- subvolume_group: new UntypedFormControl(''),
+ subvolume_group: new UntypedFormControl(this.defaultSubVolGroup),
subvolume: new UntypedFormControl(''),
- path: new UntypedFormControl('/', {
- validators: [Validators.required]
+ path: new UntypedFormControl('', {
+ validators: [
+ Validators.required,
+ CdValidators.custom('isIsolatedSlash', this.isolatedSlashCondition) // Path can never be single "/".
+ ]
}),
protocolNfsv3: new UntypedFormControl(true, {
validators: [
this.defaultAccessType[name] = accessType;
}
+ isolatedSlashCondition(value: string): boolean {
+ return value === '/';
+ }
+
setPathValidation() {
const path = this.nfsForm.get('path');
if (this.storageBackend === SUPPORTED_FSAL.RGW) {
);
}
- pathChangeHandler() {
- if (!this.isEdit) {
- this.nfsForm.patchValue({
- pseudo: this.generatePseudo()
- });
- }
- }
-
private getBucketTypeahead(path: string): Observable<any> {
if (_.isString(path) && path !== '/' && path !== '') {
return this.rgwBucketService.list().pipe(
}
}
- private generatePseudo() {
- let newPseudo = this.nfsForm.getValue('pseudo');
- if (this.nfsForm.get('pseudo') && !this.nfsForm.get('pseudo').dirty) {
- newPseudo = undefined;
- if (this.storageBackend === 'CEPH') {
- newPseudo = '/cephfs';
- if (_.isString(this.nfsForm.getValue('path'))) {
- newPseudo += this.nfsForm.getValue('path');
- }
- }
- }
- return newPseudo;
- }
-
submitAction() {
let action: Observable<any>;
const requestModel = this.buildRequest();