Advanced Cluster Management - NGUI
- Added new OKA packages module under packages
- Added Profiless, KSU under k8s section
- Feature 11020. 11022, 11023, 11024, 11025, 11026
Change-Id: Ibddeb4d5693ce24d80e378277693405c810f6e04
Signed-off-by: SANDHYA.JS <sandhya.j@tataelxsi.co.in>
diff --git a/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.html b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.html
new file mode 100644
index 0000000..e75cc7e
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.html
@@ -0,0 +1,126 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+-->
+<form [formGroup]="KsuForm" (ngSubmit)="KSUAddSubmit();">
+ <div class="modal-header">
+ <h4 *ngIf="profileType === 'add'" class="modal-title" id="modal-basic-title">{{'PAGE.K8S.ADDKSU' | translate}}</h4>
+ <h4 *ngIf="profileType === 'edit'"class="modal-title" id="modal-basic-title">{{'PAGE.K8S.EDITKSU' | translate}}</h4>
+ <h4 *ngIf="profileType === 'move'"class="modal-title" id="modal-basic-title">{{'PAGE.K8S.MOVE' | translate}}</h4>
+ <h4 *ngIf="profileType === 'clone'"class="modal-title" id="modal-basic-title">{{'PAGE.K8S.CLONE' | translate}}</h4>
+ <button class="button-xs" type="button" class="close" aria-label="Close" (click)="activeModal.close()">
+ <i class="fas fa-times-circle text-danger"></i>
+ </button>
+ </div>
+ <div class="modal-body modal-body-custom-height">
+ <div class="form-group row mb-3" *ngIf="isClone || isKsu">
+ <label class="col-sm-12 col-form-label mandatory-label"
+ [ngClass]="{'text-danger': KsuForm.invalid === true && submitted === true}">{{'MANDATORYCHECK' |
+ translate}}</label>
+ <label class="col-sm-4 col-form-label" for="name">{{'PAGE.K8S.NAME' | translate}}*</label>
+ <div class="col-sm-8">
+ <input autocomplete="off" class="form-control" placeholder="{{'PAGE.K8S.NAME' | translate}}" type="text"
+ formControlName="name" id="name" [ngClass]="{ 'is-invalid': submitted && f.name.errors }" required>
+ </div>
+ </div>
+ <div class="form-group row mb-3"*ngIf="isKsu">
+ <label class="col-sm-4 col-form-label" for="description">{{'PAGE.K8S.DESCRIPTION' | translate}}*</label>
+ <div class="col-sm-8">
+ <textarea class="form-control" placeholder="{{'PAGE.K8S.DESCRIPTION' | translate}}" type="text"
+ formControlName="description" id="description"
+ [ngClass]="{ 'is-invalid': submitted && f.description.errors }" required></textarea>
+ </div>
+ </div>
+ <div class="form-group row mb-3" *ngIf="isClone || isMove || isKsu">
+ <label class="col-sm-4 col-form-label" for="profile_type">{{'PAGE.K8S.PROFILETYPE' | translate}}*</label>
+ <div class="col-sm-8">
+ <ng-select (change)="getprofileDetails($event.value)"
+ placeholder="{{'SELECT' | translate}} {{'TYPE' | translate}}" [items]="profileSelect"
+ bindLabel="title" bindValue="value" formControlName="profile_type" id="profile_type"
+ [ngClass]="{ 'is-invalid': submitted && f.profile_type.errors }" required>
+ </ng-select>
+ </div>
+ </div>
+ <div class="form-group row mb-3" *ngIf="isClone || isMove || isKsu">
+ <label class="col-sm-4 col-form-label" for="id">{{'PAGE.K8S.PROFILENAME' | translate}}*</label>
+ <div class="col-sm-8">
+ <ng-select placeholder=" {{'SELECT' | translate}} {{'NAME' |
+ translate}}" [items]="profileDetails" bindLabel="name" bindValue="id" formControlName="id" id="id"
+ [ngClass]="{ 'is-invalid': submitted && f.id.errors }" required>
+ </ng-select>
+ </div>
+ </div>
+ <div class="form-group row p-2 bg-light text-white justify-content-end mb-3"*ngIf="isKsu">
+ <div class="col-4">
+ <button class="button-xs" type="button" class="btn btn-primary" (click)="addOka()">
+ <i class="fas fa-plus-circle"></i>{{'PAGE.K8S.SELECTOKA' | translate}}</button>
+ </div>
+ </div>
+ <ng-container *ngIf="isKsu">
+ <div formArrayName="oka" *ngFor="let params of getControls(); let i = index;">
+ <div class="form-group row" [formGroupName]="i">
+ <div class="card bg-light">
+ <div class="card-body">
+ <div class="form-group row">
+ <label class="col-sm-3 col-md-3 col-form-label" for="_id{{i}}">{{'PAGE.K8S.OKA' |
+ translate}}</label>
+ <div class="col-sm-8 col-md-8">
+ <ng-select
+ placeholder="{{'SELECT' | translate}} {{'PAGE.K8S.OKANAME' | translate}}" [items]="okaDetail" bindLabel="name"
+ bindValue="id" formControlName="_id" id="_id{{i}}"
+ [ngClass]="{ 'is-invalid': submitted && params.controls._id.errors }">
+ </ng-select>
+ <div class="fileupload-text mt-1 mb-1">or {{'PAGE.K8S.PATH' | translate}}</div>
+ <div class="col-sm-8 col-md-8">
+ <input autocomplete="off" class="form-control"
+ placeholder="{{'PAGE.K8S.PATH' | translate}}" type="text" formControlName="sw_catalog_path"
+ id="sw_catalog_path" [ngClass]="{ 'is-invalid': submitted && params.controls.sw_catalog_path.errors }">
+ </div>
+ </div>
+ <label class="col-sm-3 col-md-3 col-form-label"
+ for="transformation{{i}}">{{'PAGE.K8S.TRANSFORMFILE' |
+ translate}}</label>
+ <div class="col-sm-8 col-md-8">
+ <textarea rows="5" cols="50" class="form-control" placeholder="{{'YAMLCONFIG' | translate}}"
+ formControlName="transformation" id="transformation"></textarea>
+ <div class="fileupload-text mt-1 mb-1">{{'FILEUPLOADLABEL' | translate}}</div>
+ <div class="custom-file">
+ <input type="file" #fileInputConfig class="fileupload custom-file-input"
+ (change)="configFile($event.target.files)" id="customConfigFile">
+ </div>
+ </div>
+ <div class="col-sm-1">
+ <button class="button-xs" type="button" class="close" (click)="removeMapping(i)"
+ placement="right" ngbTooltip="{{ 'CANCEL' | translate }}">
+ <i class="fas fa-minus-circle text-danger"></i>
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </ng-container>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-danger" (click)="activeModal.close()">{{'CANCEL' | translate}}</button>
+ <button *ngIf="profileType === 'add'" type="submit" class="btn btn-primary">{{'CREATE' | translate}}</button>
+ <button *ngIf="profileType === 'edit'" type="submit" class="btn btn-primary">{{'Edit' | translate}}</button>
+ <button *ngIf="profileType === 'move'" type="submit" class="btn btn-primary">{{'Move' | translate}}</button>
+ <button *ngIf="profileType === 'clone'" type="submit" class="btn btn-primary">{{'Clone' | translate}}</button>
+ </div>
+</form>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.scss b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.scss
new file mode 100644
index 0000000..c55461a
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.scss
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.ts b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.ts
new file mode 100644
index 0000000..26f86f1
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-add/KSUAddComponent.ts
@@ -0,0 +1,481 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
+/**
+ * @file KSUAddComponent.ts.
+ */
+import { HttpHeaders } from '@angular/common/http';
+import { Component, ElementRef, Injector, Input, OnInit, ViewChild } from '@angular/core';
+import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { NotifierService } from 'angular-notifier';
+import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, TYPESECTION, URLPARAMS } from 'CommonModel';
+import { environment } from 'environment';
+import * as jsyaml from 'js-yaml';
+import { INFRACONFIGPAYLOAD, KSU, OKA } from 'K8sModel';
+import { RestService } from 'RestService';
+import { isNullOrUndefined, SharedService } from 'SharedService';
+/**
+ * Creating Component
+ * @Component takes KSUAddComponent.html as template url
+ */
+@Component({
+ selector: 'app-ksu-add',
+ templateUrl: './KSUAddComponent.html',
+ styleUrls: ['./KSUAddComponent.scss']
+})
+/** Exporting a class @exports KSUAddComponent */
+export class KSUAddComponent implements OnInit {
+ /** To inject services @public */
+ public injector: Injector;
+
+ /** FormGroup instance added to the form @ html @public */
+ public KsuForm: FormGroup;
+
+ /** Contains all deployment methods */
+ public profileSelect: TYPESECTION[] = [];
+
+ /** Instance for active modal service @public */
+ public activeModal: NgbActiveModal;
+
+ /** Form submission Add */
+ public submitted: boolean = false;
+
+ /** check move action */
+ public isMove: boolean = false;
+
+ /** check clone action */
+ public isClone: boolean = false;
+
+ /** check KSU */
+ public isKsu: boolean = false;
+
+ /** Check the loading results @public */
+ public isLoadingResults: boolean = false;
+
+ /** Give the message for the loading @public */
+ public message: string = 'PLEASEWAIT';
+
+ /** contains url @public */
+ public profileUrl: string;
+
+ /** contains profileData @public */
+ public profileData: {}[] = [];
+
+ /** OKA array @private */
+ private okaArray: FormArray;
+
+ /** contains profile details @public */
+ public profileDetails: {}[];
+
+ /** contains Oka Data @public */
+ public okaData: {}[] = [];
+
+ /** contains OKA details @public */
+ public okaDetail: {}[];
+
+ /** contains payload @public */
+ public payload: INFRACONFIGPAYLOAD | KSU;
+
+ /** oka Form array @private */
+ private okaFormArray: FormArray;
+
+ /** Input contains Modal dialog component Instance @public */
+ @Input() public profileType: string;
+
+ /** Input contains Modal dialog component Instance @public */
+ @Input() public profileID: string;
+
+ /** Element ref for fileInputConfig @public */
+ @ViewChild('fileInputConfig') fileInputConfig: ElementRef<HTMLInputElement>;
+
+ /** Element ref for fileInputConfigLabel @public */
+ @ViewChild('fileInputConfigLabel') fileInputConfigLabel: ElementRef<HTMLLabelElement>;
+
+ /** FormBuilder instance added to the formBuilder @private */
+ private formBuilder: FormBuilder;
+
+ /** Utilizes rest service for any CRUD operations @private */
+ private restService: RestService;
+
+ /** Notifier service to popup notification @private */
+ private notifierService: NotifierService;
+
+ /** Contains tranlsate instance @private */
+ private translateService: TranslateService;
+
+ /** Controls the header form @private */
+ private headers: HttpHeaders;
+
+ /** Contains all methods related to shared @private */
+ private sharedService: SharedService;
+
+ constructor(injector: Injector) {
+ this.injector = injector;
+ this.restService = this.injector.get(RestService);
+ this.activeModal = this.injector.get(NgbActiveModal);
+ this.formBuilder = this.injector.get(FormBuilder);
+ this.notifierService = this.injector.get(NotifierService);
+ this.translateService = this.injector.get(TranslateService);
+ this.sharedService = this.injector.get(SharedService);
+ this.profileSelect = [
+ {
+ title: 'Infra Config Profile',
+ value: 'infra_config_profiles'
+ },
+ {
+ title: 'Infra Controller Profile',
+ value: 'infra_controller_profiles'
+ }, {
+ title: 'App Profile',
+ value: 'app_profiles'
+ }, {
+ title: 'Resource Profile',
+ value: 'resource_profiles'
+ }
+ ];
+ }
+
+ public ngOnInit(): void {
+ /** On Initializing call the methods */
+ this.KsuFormAction();
+ this.headers = new HttpHeaders({
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
+ });
+ this.okaDetails();
+ if (this.profileType === 'clone') {
+ this.isClone = true;
+ } else if (this.profileType === 'move') {
+ this.isMove = true;
+ } else if (this.profileType === 'edit') {
+ this.isKsu = true;
+ this.getksuDetails();
+ } else {
+ this.isKsu = true;
+ }
+ }
+
+ /** Generate primitive params @public */
+ get okaParamsBuilder(): FormGroup {
+ return this.formBuilder.group({
+ _id: [null],
+ sw_catalog_path: [null],
+ transformation: [null]
+ });
+ }
+
+
+ /** On modal initializing forms @public */
+ public KsuFormAction(): void {
+ this.KsuForm = this.formBuilder.group({
+ name: ['', [Validators.required]],
+ description: ['', [Validators.required]],
+ profile_type: [null, [Validators.required]],
+ id: [null, [Validators.required]],
+ oka: this.formBuilder.array([])
+ });
+ }
+
+ /** Handle FormArray Controls @public */
+ public getControls(): AbstractControl[] {
+ return (this.KsuForm.get('oka') as FormArray).controls;
+ }
+
+ /** convenience getter for easy access to form fields */
+ get f(): FormGroup['controls'] { return this.KsuForm.controls; }
+
+ /** Get OKA details @public */
+ public okaDetails(): void {
+ this.isLoadingResults = true;
+ this.restService.getResource(environment.OKAPACKAGES_URL)
+ .subscribe((okaData: []): void => {
+ okaData.forEach((okaDetail: INFRACONFIGPAYLOAD): void => {
+ const oka: {} = {
+ name: okaDetail.name,
+ id: okaDetail._id
+ };
+ this.okaData.push(oka);
+ });
+ this.okaDetail = this.okaData;
+ this.isLoadingResults = false;
+ }, (error: ERRORDATA): void => {
+ this.isLoadingResults = false;
+ this.restService.handleError(error, 'get');
+ });
+ }
+
+ /** Get KSU details @public */
+ public getksuDetails(): void {
+ this.restService.getResource(environment.KSU_URL + '/' + this.profileID)
+ .subscribe((ksuData: KSU): void => {
+ this.KsuForm.patchValue({ id: ksuData.profile._id, name: ksuData.name, description: ksuData.description, profile_type: ksuData.profile.profile_type });
+ this.getprofileDetails(this.KsuForm.value.profile_type, ksuData.profile.name);
+ ksuData.oka.forEach((data: OKA): void => {
+ this.okaArray = this.KsuForm.get('oka') as FormArray;
+ const transformations: string = JSON.stringify(data.transformation);
+ if (!isNullOrUndefined(data._id)) {
+ data.sw_catalog_path = null;
+ } else if (!isNullOrUndefined(data.sw_catalog_path)) {
+ data._id = null;
+ }
+ const okaFormGroup = this.formBuilder.group({
+ _id: data._id,
+ sw_catalog_path: data.sw_catalog_path,
+ transformation: transformations
+ });
+ this.okaArray.push(okaFormGroup);
+ });
+ }, (error: ERRORDATA): void => {
+ this.restService.handleError(error, 'get');
+ });
+ }
+
+
+ /** On modal submit ksuAddSubmit will called @public */
+ public KSUAddSubmit(): void {
+ if (this.profileType === 'move') {
+ this.profileUrl = environment.KSU_URL + '/' + this.profileID + '/move';
+ this.payload = {
+ profile: {
+ _id: this.KsuForm.value.id,
+ profile_type: this.KsuForm.value.profile_type
+ }
+ };
+ this.getFormControl('description').disable();
+ this.getFormControl('oka').disable();
+ this.getFormControl('name').disable();
+ } else if (this.profileType === 'clone') {
+ this.getFormControl('description').disable();
+ this.getFormControl('oka').disable();
+ this.profileUrl = environment.KSU_URL + '/' + this.profileID + '/clone';
+ this.payload = {
+ name: this.KsuForm.value.name,
+ profile: {
+ _id: this.KsuForm.value.id,
+ profile_type: this.KsuForm.value.profile_type
+ }
+ };
+ } else if (this.profileType === 'edit' || this.profileType === 'add') {
+ this.addEditKSU();
+ }
+ this.submitted = true;
+ this.sharedService.cleanForm(this.KsuForm);
+ if (this.KsuForm.invalid) {
+ return;
+ }
+ if (this.profileType === 'edit') {
+ this.editKSU();
+ } else {
+ this.addKSU();
+ }
+ }
+
+ /** Add/Edit KSU @public */
+ public addEditKSU(): void {
+ this.okaArray = this.KsuForm.get('oka') as FormArray;
+ const transValue = this.okaArray.at(0).get('transformation').value;
+ const validJSON: boolean = this.sharedService.checkJson(transValue);
+ if (validJSON) {
+ for (let i = 0; i < this.okaArray.length; i++) {
+ const formGroup = this.okaArray.at(i) as FormGroup;
+ formGroup.patchValue({
+ transformation: JSON.parse(transValue)
+ });
+ }
+ } else {
+ const getConfigJson: string = jsyaml.load(transValue, { json: true });
+ for (let i = 0; i < this.okaArray.length; i++) {
+ const formGroup = this.okaArray.at(i) as FormGroup;
+ formGroup.patchValue({
+ transformation: JSON.parse(getConfigJson)
+ });
+ }
+ }
+ if (this.profileType === 'edit') {
+ this.profileUrl = environment.KSU_URL + '/' + this.profileID;
+ this.payload = {
+ name: this.KsuForm.value.name,
+ description: this.KsuForm.value.description,
+ profile: {
+ _id: this.KsuForm.value.id,
+ sw_catalog_path: this.KsuForm.value.sw_catalog_path,
+ profile_type: this.KsuForm.value.profile_type
+ },
+ oka: this.KsuForm.value.oka
+ };
+ } else {
+ this.profileUrl = environment.KSU_URL;
+ this.payload = {
+ ksus: [{
+ name: this.KsuForm.value.name,
+ description: this.KsuForm.value.description,
+ profile: {
+ _id: this.KsuForm.value.id,
+ sw_catalog_path: this.KsuForm.value.sw_catalog_path,
+ profile_type: this.KsuForm.value.profile_type
+ },
+ oka: this.KsuForm.value.oka
+ }]
+ };
+ }
+ }
+ /** Add/move/clone KSU @public */
+ public addKSU(): void {
+ this.isLoadingResults = true;
+ const modalData: MODALCLOSERESPONSEDATA = {
+ message: 'Done'
+ };
+ const apiURLHeader: APIURLHEADER = {
+ url: this.profileUrl,
+ httpOptions: { headers: this.headers }
+ };
+ this.restService.postResource(apiURLHeader, this.payload).subscribe((result: {}) => {
+ this.activeModal.close(modalData);
+ this.isLoadingResults = false;
+ if (this.profileType === 'move') {
+ this.notifierService.notify('success',
+ this.translateService.instant('PAGE.K8S.MOVEDSUCCESSFULLY'));
+ } else if (this.profileType === 'clone') {
+ this.notifierService.notify('success',
+ this.translateService.instant('PAGE.K8S.CLONEDSUCCESSFULLY'));
+ } else {
+ this.notifierService.notify('success',
+ this.translateService.instant('PAGE.K8S.KSUCREATEDSUCCESSFULLY'));
+ }
+ }, (error: ERRORDATA) => {
+ this.restService.handleError(error, 'post');
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ if (error.error.status === 422 || error.error.status === 400) {
+ this.activeModal.close(modalData);
+ }
+ this.isLoadingResults = false;
+ });
+ }
+
+ /** Edit KSU @public */
+ public editKSU(): void {
+ this.isLoadingResults = true;
+ const modalData: MODALCLOSERESPONSEDATA = {
+ message: 'Done'
+ };
+ const apiURLHeader: APIURLHEADER = {
+ url: this.profileUrl,
+ httpOptions: { headers: this.headers }
+ };
+ this.restService.patchResource(apiURLHeader, this.payload).subscribe((result: {}) => {
+ this.activeModal.close(modalData);
+ this.isLoadingResults = false;
+ this.notifierService.notify('success',
+ this.translateService.instant('PAGE.K8S.KSUEDITEDSUCCESSFULLY'));
+ }, (error: ERRORDATA) => {
+ this.restService.handleError(error, 'post');
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ if (error.error.status === 422 || error.error.status === 400) {
+ this.activeModal.close(modalData);
+ }
+ this.isLoadingResults = false;
+ });
+ }
+
+ /** Config file process @private */
+ public configFile(files: FileList): void {
+ if (files && files.length === 1) {
+ const fileFormat: string = this.sharedService.fetchFileExtension(files).toLocaleLowerCase();
+ if (fileFormat === 'yaml' || fileFormat === 'yml') {
+ this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
+ this.okaArray = this.KsuForm.get('oka') as FormArray;
+ for (let i = 0; i < this.okaArray.length; i++) {
+ const formGroup = this.okaArray.at(i) as FormGroup;
+ formGroup.patchValue({
+ transformation: fileContent // Set the value for the specified key
+ });
+ }
+ }).catch((err: string): void => {
+ if (err === 'typeError') {
+ this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
+ } else {
+ this.notifierService.notify('error', this.translateService.instant('ERROR'));
+ }
+ this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+ this.fileInputConfig.nativeElement.value = null;
+ });
+ } else if (fileFormat === 'json') {
+ this.sharedService.getFileString(files, 'json').then((fileContent: string): void => {
+ const getConfigJson: string = jsyaml.load(fileContent, { json: true });
+ this.KsuForm.get('transformation').setValue(JSON.stringify(getConfigJson));
+ }).catch((err: string): void => {
+ if (err === 'typeError') {
+ this.notifierService.notify('error', this.translateService.instant('JSONFILETYPEERRROR'));
+ } else {
+ this.notifierService.notify('error', this.translateService.instant('ERROR'));
+ }
+ this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
+ this.fileInputConfig.nativeElement.value = null;
+ });
+ }
+ } else if (files && files.length > 1) {
+ this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
+ }
+ this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
+ this.fileInputConfig.nativeElement.value = null;
+ }
+ /** Add OKA @public */
+ public addOka(): void {
+ this.okaFormArray = this.KsuForm.get('oka') as FormArray;
+ this.okaFormArray.push(this.okaParamsBuilder);
+ }
+
+ /** Remove OKA @public */
+ public removeMapping(index: number): void {
+ this.okaFormArray.removeAt(index);
+ }
+
+ /** Get profile details @public */
+ public getprofileDetails(event: string, name?: string): void {
+ this.profileData = [];
+ if (event === 'infra_config_profiles') {
+ this.profileUrl = environment.K8SINFRACONFIGPROFILE_URL;
+ } else if (event === 'infra_controller_profiles') {
+ this.profileUrl = environment.K8SINFRACONTROLLERPROFILE_URL;
+ } else if (event === 'app_profiles') {
+ this.profileUrl = environment.K8SAPPPROFILE_URL;
+ } else if (event === 'resource_profiles') {
+ this.profileUrl = environment.K8SRESOURCEPROFILE_URL;
+ }
+ this.restService.getResource(this.profileUrl)
+ .subscribe((profileData: []): void => {
+ profileData.forEach((profileDetail: INFRACONFIGPAYLOAD): void => {
+ const profile: {} = {
+ name: profileDetail.name,
+ id: profileDetail._id
+ };
+ this.profileData.push(profile);
+ });
+ this.profileDetails = this.profileData;
+ }, (error: ERRORDATA): void => {
+ this.restService.handleError(error, 'get');
+ });
+ }
+ /** Used to get the AbstractControl of controlName passed @private */
+ private getFormControl(controlName: string): AbstractControl {
+ // eslint-disable-next-line security/detect-object-injection
+ return this.KsuForm.controls[controlName];
+ }
+}
diff --git a/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.html b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.html
new file mode 100644
index 0000000..de83ac5
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.html
@@ -0,0 +1,45 @@
+<!--
+Copyright 2020 TATA ELXSI
+
+Licensed under the Apache License, Version 2.0 (the 'License');
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+-->
+<div class="d-flex flex-row justify-content-between">
+ <div class="d-flex align-items-center header-style">{{'PAGE.K8S.KSU' | translate}}</div>
+ <span class="button">
+ <button class="btn btn-primary me-2" type="button" placement="top" container="body"
+ ngbTooltip="{{'Create Profile' | translate}}" (click)="addKSU()">
+ <i class="fas fa-plus-circle" aria-hidden="true"></i> {{'PAGE.K8S.ADDKSU' | translate}}
+ </button>
+ </span>
+</div>
+<div class="mt-2 mb-2 list-utilites-actions">
+ <div class="col-auto me-auto">
+ <nav class="custom-items-config">
+ <span><i class="fas fa-clock text-success"></i>{{operationalStateFirstStep}}</span>
+ <span><i class="fas fa-spinner text-warning"></i>{{operationalStateSecondStep}}</span>
+ <span><i class="fas fa-spinner text-danger"></i>{{operationalStateThirdStep}}</span>
+ <span><i class="fas fa-times-circle text-danger"></i>{{operationalStateFourthStep}}</span>
+ <span><i class="fas fa-times-circle text-warning"></i>{{operationalStateFifthStep}}</span>
+ </nav>
+ </div>
+ <page-per-row class="me-2" (pagePerRow)="onChange($event)"></page-per-row>
+ <page-reload></page-reload>
+</div>
+<div class="smarttable-style bg-white mt-1">
+ <ng2-smart-table [ngClass]="checkDataClass" [settings]="settings" [source]="dataSource"
+ (userRowSelect)="onUserRowSelect($event)">
+ </ng2-smart-table>
+</div>
+<app-loader [waitingMessage]="message" *ngIf="isLoadingResults"></app-loader>
\ No newline at end of file
diff --git a/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.scss b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.scss
new file mode 100644
index 0000000..c55461a
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.scss
@@ -0,0 +1,17 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
\ No newline at end of file
diff --git a/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.ts b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.ts
new file mode 100644
index 0000000..2591b4c
--- /dev/null
+++ b/src/app/k8s/k8s-ksu/ksu-details/KSUComponent.ts
@@ -0,0 +1,254 @@
+/*
+ Copyright 2020 TATA ELXSI
+
+ Licensed under the Apache License, Version 2.0 (the 'License');
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Author: SANDHYA JS (sandhya.j@tataelxsi.co.in)
+*/
+/**
+ * @file KSUComponent.ts.
+ */
+import { Component, Injector, OnDestroy, OnInit } from '@angular/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import { TranslateService } from '@ngx-translate/core';
+import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel';
+import { DataService } from 'DataService';
+import { environment } from 'environment';
+import { K8sActionComponent } from 'K8sActionComponent';
+import { INFRACONFIGPAYLOAD, K8SCreateCLUSTERDATA } from 'K8sModel';
+import { LocalDataSource } from 'ng2-smart-table';
+import { RestService } from 'RestService';
+import { Subscription } from 'rxjs';
+import { SharedService } from 'SharedService';
+import { KSUAddComponent } from '../ksu-add/KSUAddComponent';
+/**
+ * Creating Component
+ * @Component takes KSUComponent.html as template url
+ */
+@Component({
+ selector: 'app-ksu-details',
+ templateUrl: './KSUComponent.html',
+ styleUrls: ['./KSUComponent.scss']
+})
+/** Exporting a class @exports KSUComponent */
+export class KSUComponent implements OnInit, OnDestroy {
+ /** To inject services @public */
+ public injector: Injector;
+
+ /** handle translate @public */
+ public translateService: TranslateService;
+
+ /** Data of smarttable populate through LocalDataSource @public */
+ public dataSource: LocalDataSource = new LocalDataSource();
+
+ /** Columns list of the smart table @public */
+ public columnList: object = {};
+
+ /** Settings for smarttable to populate the table with columns @public */
+ public settings: object = {};
+
+ /** operational State created data @public */
+ public operationalStateFirstStep: string = CONFIGCONSTANT.k8OperationalStateFirstStep;
+
+ /** operational State in creation data @public */
+ public operationalStateSecondStep: string = CONFIGCONSTANT.k8OperationalStateStateSecondStep;
+
+ /** operational State in deletion data @public */
+ public operationalStateThirdStep: string = CONFIGCONSTANT.k8OperationalStateThirdStep;
+
+ /** operational State failed deletion data @public */
+ public operationalStateFourthStep: string = CONFIGCONSTANT.k8OperationalStateFourthStep;
+
+ /** operational State failed creation data @public */
+ public operationalStateFifthStep: string = CONFIGCONSTANT.k8OperationalStateFifthStep;
+
+ /** Check the loading results @public */
+ public isLoadingResults: boolean = true;
+
+ /** Give the message for the loading @public */
+ public message: string = 'PLEASEWAIT';
+
+ /** Class for empty and present data @public */
+ public checkDataClass: string;
+
+ /** Instance of the rest service @private */
+ private restService: RestService;
+
+ /** dataService to pass the data from one component to another @private */
+ private dataService: DataService;
+
+ /** Formation of appropriate Data for LocalDatasource @private */
+ private ksuData: {}[] = [];
+
+ /** Contains all methods related to shared @private */
+ private sharedService: SharedService;
+
+ /** Instance of the modal service @private */
+ private modalService: NgbModal;
+
+ /** Instance of subscriptions @private */
+ private generateDataSub: Subscription;
+
+ constructor(injector: Injector) {
+ this.injector = injector;
+ this.restService = this.injector.get(RestService);
+ this.dataService = this.injector.get(DataService);
+ this.sharedService = this.injector.get(SharedService);
+ this.translateService = this.injector.get(TranslateService);
+ this.modalService = this.injector.get(NgbModal);
+ }
+ /** Lifecyle Hooks the trigger before component is instantiate @public */
+ public ngOnInit(): void {
+ this.generateColumns();
+ this.generateSettings();
+ this.generateData();
+ this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); });
+ }
+
+ /** smart table Header Colums @public */
+ public generateColumns(): void {
+ this.columnList = {
+ name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' },
+ identifier: { title: this.translateService.instant('IDENTIFIER'), width: '15%' },
+ state: {
+ title: this.translateService.instant('STATE'), width: '15%', type: 'html',
+ filter: {
+ type: 'list',
+ config: {
+ selectText: 'Select',
+ list: [
+ { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep },
+ { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep },
+ { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep },
+ { value: this.operationalStateThirdStep, title: this.operationalStateFourthStep },
+ { value: this.operationalStateThirdStep, title: this.operationalStateFifthStep }
+ ]
+ }
+ },
+ valuePrepareFunction: (cell: INFRACONFIGPAYLOAD, row: INFRACONFIGPAYLOAD): string => {
+ if (row.state === this.operationalStateFirstStep) {
+ return `<span class="icon-label" title="${row.state}">
+ <i class="fas fa-clock text-success"></i>
+ </span>`;
+ } else if (row.state === this.operationalStateSecondStep) {
+ return `<span class="icon-label" title="${row.state}">
+ <i class="fas fa-spinner text-warning"></i>
+ </span>`;
+ } else if (row.state === this.operationalStateThirdStep) {
+ return `<span class="icon-label" title="${row.state}">
+ <i class="fas fa-spinner text-danger"></i>
+ </span>`;
+ } else if (row.state === this.operationalStateFourthStep) {
+ return `<span class="icon-label" title="${row.state}">
+ <i class="fas fa-times-circle text-danger"></i>
+ </span>`;
+ } else if (row.state === this.operationalStateFifthStep) {
+ return `<span class="icon-label" title="${row.state}">
+ <i class="fas fa-times-circle text-warning"></i>
+ </span>`;
+ } else {
+ return `<span>${row.state}</span>`;
+ }
+ }
+ },
+ created: { title: this.translateService.instant('CREATED'), width: '10%' },
+ modified: { title: this.translateService.instant('MODIFIED'), width: '10%' },
+ Actions: {
+ name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom',
+ valuePrepareFunction: (cell: INFRACONFIGPAYLOAD, row: INFRACONFIGPAYLOAD): INFRACONFIGPAYLOAD => row,
+ renderComponent: K8sActionComponent
+ }
+ };
+ }
+
+ /** smart table Data Settings @public */
+ public generateSettings(): void {
+ this.settings = {
+ columns: this.columnList,
+ actions: { add: false, edit: false, delete: false, position: 'right' },
+ attr: this.sharedService.tableClassConfig(),
+ pager: this.sharedService.paginationPagerConfig(),
+ noDataMessage: this.translateService.instant('NODATAMSG')
+ };
+ }
+
+ /** smart table listing manipulation @public */
+ public onChange(perPageValue: number): void {
+ this.dataSource.setPaging(1, perPageValue, true);
+ }
+
+ /** smart table listing manipulation @public */
+ public onUserRowSelect(event: MessageEvent): void {
+ Object.assign(event.data, { page: 'k8-ksu' });
+ this.dataService.changeMessage(event.data);
+ }
+
+ /** Compose new KSU @public */
+ public addKSU(): void {
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
+ const modalRef: NgbModalRef = this.modalService.open(KSUAddComponent, { backdrop: 'static' });
+ modalRef.componentInstance.profileType = 'add';
+ modalRef.result.then((result: MODALCLOSERESPONSEDATA) => {
+ if (result) {
+ this.sharedService.callData();
+ }
+ }).catch((): void => {
+ // Catch Navigation Error
+ });
+ }
+
+ /**
+ * Lifecyle hook which get trigger on component destruction
+ */
+ public ngOnDestroy(): void {
+ this.generateDataSub.unsubscribe();
+ }
+
+ /** Generate KSU object from loop and return for the datasource @public */
+ public generateKSUData(ksudata: INFRACONFIGPAYLOAD): INFRACONFIGPAYLOAD {
+ return {
+ name: ksudata.name,
+ identifier: ksudata._id,
+ created: this.sharedService.convertEpochTime(Number(ksudata._admin.created)),
+ modified: this.sharedService.convertEpochTime(Number(ksudata._admin.modified)),
+ description: ksudata.description,
+ pageType: 'k8-ksu',
+ state: ksudata.state
+ };
+ }
+
+ /** Fetching the data from server to Load in the smarttable @protected */
+ protected generateData(): void {
+ this.isLoadingResults = true;
+ this.restService.getResource(environment.KSU_URL).subscribe((kSUData: K8SCreateCLUSTERDATA[]) => {
+ this.ksuData = [];
+ kSUData.forEach((KSUDetail: INFRACONFIGPAYLOAD) => {
+ const ksuDataObj: INFRACONFIGPAYLOAD = this.generateKSUData(KSUDetail);
+ this.ksuData.push(ksuDataObj);
+ });
+ if (this.ksuData.length > 0) {
+ this.checkDataClass = 'dataTables_present';
+ } else {
+ this.checkDataClass = 'dataTables_empty';
+ }
+ this.dataSource.load(this.ksuData).then((data: boolean) => {
+ this.isLoadingResults = false;
+ }).catch(() => {
+ this.isLoadingResults = false;
+ });
+ }, (error: ERRORDATA) => {
+ this.restService.handleError(error, 'get');
+ this.isLoadingResults = false;
+ });
+ }
+}