Commit 7fab984c authored by Paweł Szkup's avatar Paweł Szkup
Browse files

Merge pull request #41 in MEL/melodic-frontend from rc2.5 to master

* commit 'bbc19a88':
  default applicationId in deployment form, change info about error by getting deployment difference
  getting deployment difference off
  mat-spinner for active operation on cloud definition
  improve catching errors by getting models from CDO
  city on list of vms and functions
  fix problem with 'Upload all'
parents 7c683c61 bbc19a88
......@@ -56,6 +56,11 @@
<td mat-cell class="field-with-wrapping" *matCellDef="let row">{{row.stackId}}</td>
</ng-container>
<ng-container matColumnDef="city">
<th mat-header-cell *matHeaderCellDef mat-sort-header>City</th>
<td mat-cell *matCellDef="let row">{{row.city}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
......
......@@ -5,6 +5,7 @@ import {ApplicationService} from '../service/application.service';
import {ProcessOfferService} from '../../process/process-details/offer/service/process-offer.service';
import {Cloud} from '../../process/process-details/offer/model/cloud';
import {NodeCloudiator} from '../model/node-cloudiator';
import {OfferLocation} from '../../process/process-details/offer/model/offer-location';
@Component({
selector: 'app-function-list',
......@@ -16,10 +17,11 @@ export class FunctionListComponent implements OnInit {
@Input() faasList: Faas[];
cloudsList: Cloud[];
faasNodeList: NodeCloudiator[];
locationList: OfferLocation[];
loadingFaasListInProgress = false;
data: MatTableDataSource<Faas>;
displayedColumns: string[] = ['no', 'name', 'id', 'state', 'provider', 'locationId', 'memory', 'runtime', 'stackId'];
displayedColumns: string[] = ['no', 'name', 'id', 'state', 'provider', 'locationId', 'memory', 'runtime', 'stackId', 'city'];
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
......@@ -33,26 +35,35 @@ export class FunctionListComponent implements OnInit {
this.loadingFaasListInProgress = true;
this.processOfferService.getCloudList().subscribe(cloudsResponse => {
this.cloudsList = cloudsResponse;
this.applicationService.getFaasNodeList().subscribe(faasNodeResponse => {
this.faasNodeList = faasNodeResponse;
this.applicationService.getFunctionList().subscribe(functionsResponse => {
this.faasList = functionsResponse;
this.loadingFaasListInProgress = false;
this.updateTableData();
console.log('Successfully getting function list');
this.processOfferService.getLocationList().subscribe(locationResponse => {
this.locationList = locationResponse;
this.applicationService.getFaasNodeList().subscribe(faasNodeResponse => {
this.faasNodeList = faasNodeResponse;
this.applicationService.getFunctionList().subscribe(functionsResponse => {
this.faasList = functionsResponse;
this.loadingFaasListInProgress = false;
this.updateTableData();
console.log('Successfully getting function list');
},
error1 => {
this.faasList = [];
this.loadingFaasListInProgress = false;
this.updateTableData();
this.snackBar.open(`Problem by getting functions list: ${error1.error.message}`, 'Close');
});
},
error1 => {
this.faasList = [];
this.loadingFaasListInProgress = false;
this.updateTableData();
this.snackBar.open(`Problem by getting functions list: ${error1.error.message}`, 'Close');
this.snackBar.open(`Problem by getting FAAS nodes list: ${error1.error.message}`, 'Close');
});
},
error1 => {
this.faasList = [];
this.locationList = [];
this.loadingFaasListInProgress = false;
this.updateTableData();
this.snackBar.open(`Problem by getting FAAS nodes list: ${error1.error.message}`, 'Close');
this.snackBar.open(`Problem by getting data about locations: ${error1.error.message}`, 'Close');
});
}, error1 => {
console.log('Error by getting clouds for functions list: ', error1);
......@@ -68,6 +79,7 @@ export class FunctionListComponent implements OnInit {
value.name = this.getFunctionName(value);
value.provider = this.getProviderName(value);
value.state = this.getFunctionState(value);
value.city = this.getCity(value);
});
this.data = new MatTableDataSource<Faas>(this.faasList);
this.data.paginator = this.paginator;
......@@ -99,4 +111,10 @@ export class FunctionListComponent implements OnInit {
.find(value => value.originId === faas.id)
.state;
}
private getCity(faas: Faas) {
return this.locationList
.find(location => location.id === faas.locationId)
.geoLocation.city;
}
}
......@@ -8,4 +8,5 @@ export class Faas {
name: string;
state: string;
provider: string;
city: string;
}
......@@ -15,4 +15,5 @@ export class NodeCloudiator {
provider: string;
publicIp: string;
privateIp: string;
city: string;
}
......@@ -47,6 +47,11 @@
<td mat-cell *matCellDef="let row">{{row.provider}}</td>
</ng-container>
<ng-container matColumnDef="city">
<th mat-header-cell *matHeaderCellDef mat-sort-header>City</th>
<td mat-cell *matCellDef="let row">{{row.city}}</td>
</ng-container>
<ng-container matColumnDef="diagnostic">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Diagnostic</th>
<td mat-cell class="field-with-wrapping" *matCellDef="let row" class="field-with-wrapping">
......
......@@ -8,6 +8,7 @@ import {ProcessOfferService} from '../../process/process-details/offer/service/p
import {UserService} from '../../user/service/user.service';
import {UserRole} from '../../user/model/user-role.enum';
import {AppConfigService} from '../../app-config/service/app-config.service';
import {OfferLocation} from '../../process/process-details/offer/model/offer-location';
@Component({
selector: 'app-vm-list',
......@@ -18,10 +19,11 @@ export class VmListComponent implements OnInit {
@Input() vms: NodeCloudiator[];
cloudsList: Cloud[];
locationList: OfferLocation[];
loadingVmListInProgress = false;
data: MatTableDataSource<NodeCloudiator>;
displayedColumns: string[] = ['no', 'name', 'id', 'state', 'publicIP', 'privateIP', 'providerName', 'diagnostic', 'sshButton'];
displayedColumns: string[] = ['no', 'name', 'id', 'state', 'publicIP', 'privateIP', 'providerName', 'city', 'diagnostic', 'sshButton'];
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
......@@ -36,18 +38,27 @@ export class VmListComponent implements OnInit {
this.loadingVmListInProgress = true;
this.processOfferService.getCloudList().subscribe(cloudsResponse => {
this.cloudsList = cloudsResponse;
this.applicationService.getVmNodeList().subscribe(value => {
this.vms = value;
this.processOfferService.getLocationList().subscribe(locationResponse => {
this.locationList = locationResponse;
this.applicationService.getVmNodeList().subscribe(vmNodesResponse => {
this.vms = vmNodesResponse;
this.loadingVmListInProgress = false;
this.updateTableData();
console.log('Successfully getting VM list');
},
error1 => {
},
error1 => {
this.vms = [];
this.loadingVmListInProgress = false;
this.updateTableData();
this.snackBar.open(`Problem by getting VMs list: ${error1.error.message}`, 'Close');
});
},
error1 => {
this.locationList = [];
this.loadingVmListInProgress = false;
this.updateTableData();
this.snackBar.open(`Problem by getting data about locations: ${error1.error.message}`, 'Close');
});
}, error1 => {
console.log('Error by getting clouds for VMs list: ', error1);
this.vms = [];
......@@ -62,6 +73,7 @@ export class VmListComponent implements OnInit {
value.provider = this.getProviderName(value);
value.privateIp = this.getPrivateIp(value);
value.publicIp = this.getPublicIp(value);
value.city = this.getCity(value);
});
this.data = new MatTableDataSource<NodeCloudiator>(this.vms);
this.data.paginator = this.paginator;
......@@ -94,6 +106,13 @@ export class VmListComponent implements OnInit {
.api.providerName;
}
getCity(vm: NodeCloudiator): string {
const locationId = vm.originId.split('/')[0];
return this.locationList
.find(value => value.id === locationId)
.geoLocation.city;
}
userHasPermissionToSshConnection(): boolean {
return UserRole.ADMIN === UserRole[this.userService.currentUser.userRole];
}
......
......@@ -78,6 +78,9 @@ export class DeployingFormComponent implements OnInit {
this.deploymentService.getUploadedModels().subscribe(
value => {
this.applicationIds = value;
if (this.applicationIds.length > 0) {
this.form.applicationId.setValue(this.applicationIds[0]);
}
this.xmiModelsLoadingInProgress = false;
},
error1 => {
......
import {Injectable} from '@angular/core';
import {Injectable, QueryList} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {tap} from 'rxjs/operators';
import {Observable} from 'rxjs';
......@@ -8,6 +8,8 @@ import {CloudConfigurationForRead} from '../../provider/model/view/cloud-configu
import {CloudConfiguration} from '../../provider/model/cloud-configuration';
import {AppConfigService} from '../../app-config/service/app-config.service';
import {UserService} from '../../user/service/user.service';
import {FileUploaderComponent} from '../../file-uploader/uploader/file-uploader.component';
import {UploadXmiResponse} from '../../file-uploader/model/upload-xmi-response';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
......@@ -49,6 +51,19 @@ export class DeploymentService {
});
}
uploadMultipleModels(queryList: QueryList<FileUploaderComponent>): Observable<Array<UploadXmiResponse>> {
const formData = new FormData();
queryList.forEach(item => {
formData.append('files', item.uploadingFile, item.uploadingFile.name);
});
const uploadUrl = this.apiUrl + '/xmi/multiple';
return this.http.post(uploadUrl, formData).pipe(
tap((response: Array<UploadXmiResponse>) => {
console.log(`Multiple files in number of ${response.length} uploaded`);
},
e => console.log('Error by uploading multiple files', e)));
}
deleteModel(modelName: any): Observable<{}> {
const requestUrl = this.apiUrl + `/xmi/${modelName}`;
return this.http.delete(requestUrl, httpOptions).pipe(
......
......@@ -53,7 +53,7 @@
color="primary" mat-raised-button>
Define secure variables
</button>
<button (click)="onDeleteModelClick(model.name)" [disabled]="deletingInProgress" color="warn" mat-button
<button (click)="onDeleteModelClick(model)" [disabled]="deletingInProgress" color="warn" mat-button
class="model-button">
<mat-icon>cancel</mat-icon>
</button>
......
......@@ -70,11 +70,11 @@ export class UploaderXmiComponent implements OnInit {
console.log(`Getting all uploaded models`);
this.downloadingModelsListInProgress = false;
if (value.length === 0) {
localStorage.removeItem('uploadedModels');
localStorage.removeItem(this.secureVariablesService.modelsInLocalStorageLabel);
this.uploadedModels = [];
} else {
this.uploadedModels = this.secureVariablesService.mapUploadedModelNamesToModels(value);
let uploadedModelsFromLocalStorage = JSON.parse(localStorage.getItem('uploadedModels'));
let uploadedModelsFromLocalStorage = JSON.parse(localStorage.getItem(this.secureVariablesService.modelsInLocalStorageLabel));
uploadedModelsFromLocalStorage = uploadedModelsFromLocalStorage !== null ? uploadedModelsFromLocalStorage : [];
this.secureVariablesService.removeInfoFromLocalStorageAboutFilesNotFromCdo(value, uploadedModelsFromLocalStorage);
}
......@@ -82,16 +82,18 @@ export class UploaderXmiComponent implements OnInit {
},
error1 => {
this.downloadingModelsListInProgress = false;
this.uploadedModels = [];
console.log(`Problem by getting uploaded models`);
this.snackBar.open(`Problem by getting available models from CDO.`, 'Close', {duration: 10000});
});
}
onDeleteModelClick(modelName: string) {
onDeleteModelClick(model: UploadedModel) {
const modelName = model.name;
console.log(`Delete click for model with name: ${modelName}`);
this.deletingInProgress = true;
this.snackBar.open(`Deleting your model ${modelName} from CDO in progress...`, 'Close');
this.deploymentService.deleteModel(modelName).subscribe(value => {
this.deploymentService.deleteModel(modelName).subscribe(() => {
console.log(`Model ${modelName} successfully deleted`);
this.snackBar.open(`Model ${modelName} successfully deleted from CDO.`, 'Close', {duration: 10000});
this.deletingInProgress = false;
......
<ng-content></ng-content>
<button mat-raised-button color="primary" *ngIf="files.length > 0" (click)="uploadAll()">Upload All</button>
<button mat-raised-button color="primary" *ngIf="files.length > 0" (click)="uploadAll()">Upload</button>
<button mat-raised-button color="primary" *ngIf="files.length > 0" (click)="removeAll()">Remove All</button>
......@@ -3,6 +3,10 @@ import {merge, Subscription} from 'rxjs';
import {FileUploaderComponent} from '../uploader/file-uploader.component';
import {startWith} from 'rxjs/operators';
import {MatSnackBar} from '@angular/material';
import {DeploymentService} from '../../deploying-application/service/deployment.service';
import {SecureVariablesService} from '../service/secure-variables.service';
import {UploadXmiResponse} from '../model/upload-xmi-response';
import {UploadedModel} from '../../deploying-application/model/uploaded-model';
@Component({
selector: 'app-files-queue',
......@@ -29,7 +33,9 @@ export class FilesQueueComponent implements OnDestroy, AfterViewInit {
@Input()
notAllowedNames = [];
constructor(private snackBar: MatSnackBar) {
constructor(private snackBar: MatSnackBar,
private deploymentService: DeploymentService,
private secureVariablesService: SecureVariablesService) {
}
ngAfterViewInit() {
......@@ -62,9 +68,45 @@ export class FilesQueueComponent implements OnDestroy, AfterViewInit {
}
public uploadAll() {
this.fileUploads.forEach((fileUpload) => {
fileUpload.upload();
});
this.fileUploads.forEach(item => item.setUploadingInProgress());
this.deploymentService.uploadMultipleModels(this.fileUploads).subscribe(value => {
let successfullyUploadedFilesNames = '';
console.log('Files uploaded successfully');
this.fileUploads.forEach(item => {
item.setUploadingAsFinished();
console.log(`Removing file from list: ${item.file.name}`);
item.remove();
item.removeEvent.emit(item);
});
let uploadXmiResponseWithSecureVariable: UploadXmiResponse;
value.forEach(uploadedXmiFileResponse => {
console.log(`Uploaded file ${uploadedXmiFileResponse.modelName} with secure variables in number =
${uploadedXmiFileResponse.secureVariables.length}`);
if (uploadedXmiFileResponse.secureVariables.length !== 0) {
uploadXmiResponseWithSecureVariable = uploadedXmiFileResponse;
}
if (uploadedXmiFileResponse.httpStatus === 'CREATED') {
successfullyUploadedFilesNames += uploadedXmiFileResponse.modelName + ', ';
this.secureVariablesService.addUploadedModelToLocalStorage(uploadedXmiFileResponse.modelName,
uploadedXmiFileResponse.secureVariables);
}
});
this.fileUploads.first.getUploadedModelsList();
if (successfullyUploadedFilesNames.length !== 0) {
successfullyUploadedFilesNames = successfullyUploadedFilesNames.substring(0, successfullyUploadedFilesNames.length - 2);
this.snackBar.open(`Files: ${successfullyUploadedFilesNames} uploaded successfully`, 'Close');
} else {
this.snackBar.open('Any files did not uploaded successfully', 'Close');
}
if (uploadXmiResponseWithSecureVariable) {
this.fileUploads.first.openDialog(uploadXmiResponseWithSecureVariable.secureVariables,
uploadXmiResponseWithSecureVariable.modelName);
}
},
error1 => {
this.fileUploads.first.setUploadingAsFinished();
this.snackBar.open('Error by uploading files list', 'Close');
});
}
public removeAll() {
......@@ -86,6 +128,12 @@ export class FilesQueueComponent implements OnDestroy, AfterViewInit {
const isFileInQueue = this.files
.map(value => value.name)
.includes(file.name);
return !this.notAllowedNames.includes(modelName, 0) && !isFileInQueue;
let uploadedModelsFromLocalStorage: Array<UploadedModel> =
JSON.parse(localStorage.getItem(this.secureVariablesService.modelsInLocalStorageLabel));
uploadedModelsFromLocalStorage = uploadedModelsFromLocalStorage !== null ? uploadedModelsFromLocalStorage : [];
const isFileAlreadyUploaded = uploadedModelsFromLocalStorage
.map(value => value.name)
.includes(modelName);
return !this.notAllowedNames.includes(modelName, 0) && !isFileInQueue && !isFileAlreadyUploaded;
}
}
import {SecureVariable} from './secure-variable';
export class UploadXmiResponse {
modelName: string;
secureVariables: Array<SecureVariable>;
httpStatus: string;
message: string;
}
......@@ -66,7 +66,7 @@ export class SecureVariablesService {
mapUploadedModelNamesToModels(value: Array<string>): Array<UploadedModel> {
const uploadedModelsTmp = [];
let uploadedModelsFromLocalStorage = JSON.parse(localStorage.getItem('uploadedModels'));
let uploadedModelsFromLocalStorage = JSON.parse(localStorage.getItem(this.modelsInLocalStorageLabel));
uploadedModelsFromLocalStorage = uploadedModelsFromLocalStorage !== null ? uploadedModelsFromLocalStorage : [];
value.forEach(modelName => {
......
......@@ -58,7 +58,7 @@ export class FileUploaderComponent implements OnDestroy {
progressPercentage = 0;
total = 0;
public loaded = 0;
private uploadingFile: any;
public uploadingFile: any;
private fileId: number;
private fileUploadSubscription: any;
......@@ -106,6 +106,7 @@ export class FileUploaderComponent implements OnDestroy {
if (this.fileUploadSubscription) {
this.fileUploadSubscription.unsubscribe();
}
console.log('Removing file from list');
this.removeEvent.emit(this);
}
......@@ -155,4 +156,16 @@ export class FileUploaderComponent implements OnDestroy {
this.snackBar.open(`${error1.error.message}`, 'Close');
});
}
public getUploadedModelsList() {
this.uploaderXmiComponent.getUploadedModelsList();
}
public setUploadingInProgress() {
this.uploaderXmiComponent.uploadInProgress = true;
}
public setUploadingAsFinished() {
this.uploaderXmiComponent.uploadInProgress = false;
}
}
......@@ -37,8 +37,13 @@ export class DeploymentDifferenceComponent implements OnInit {
this.differenceAfterSolutionDownloaded = true;
},
error1 => {
this.snackBar.open(`Problem by getting deployment difference: ${error1.error.message}`, 'Close');
this.loadingDataInProgress = false;
if (error1.error.status === 404) {
console.log(`Deployment difference not created yet: ${error1.error.message}`);
this.loadingDataInProgress = false;
} else {
this.snackBar.open(`Problem by getting deployment difference: ${error1.error.message}`, 'Close');
this.loadingDataInProgress = false;
}
});
}
}
......@@ -108,8 +108,8 @@ export class ProcessViewComponent implements OnInit, AfterViewInit, OnDestroy {
this.updateNumberOfOffers();
this.updateVariablesView();
this.updateSolutionView();
this.updateDeploymentDifferenceViewAfterCreatingSolution();
this.updateDeploymentDifferenceViewAfterFinishedDeployment();
// this.updateDeploymentDifferenceViewAfterCreatingSolution();
// this.updateDeploymentDifferenceViewAfterFinishedDeployment();
if (!this.errorInVariable && !this.stopMonitoring) {
if (value.processState.toString() === VariableStatus[VariableStatus.SUCCESS]) {
console.log(`Process finished`);
......
......@@ -6,6 +6,10 @@
<mat-card>
<mat-form-field>
<input matInput formControlName="endpoint" placeholder="endpoint">
<mat-error
*ngIf="form.endpoint.hasError('missingEndpoint')">
{{getMissingEndpointMessage()}}
</mat-error>
</mat-form-field>
<mat-form-field class="halfWidthField">
......
......@@ -10,6 +10,7 @@ import {CloudPropertyFormComponent} from '../cloud-property-form/cloud-property-
import {ProviderService} from '../service/provider.service';
import {ConfirmationDialogComponent} from '../../common-template/confirmation-dialog/confirmation-dialog.component';
import {credentialsUserValidator} from '../validator/credential-user.validator';
import {requiredEndpointValidator} from '../validator/required-endpoint.validator';
@Component({
selector: 'app-cloud-definition-form',
......@@ -79,8 +80,9 @@ export class CloudDefinitionFormComponent implements OnInit {
credential: this.credentialForm,
cloudConfiguration: this.cloudConfigurationForm
}, {
validators: credentialsUserValidator(this.dialogData.cloudDefinitions, this.apiForm, this.credentialForm, this.cloudData ?
this.cloudData.credential.user : '', this.cloudData ? this.cloudData.api.providerName : '')
validators: [credentialsUserValidator(this.dialogData.cloudDefinitions, this.apiForm, this.credentialForm, this.cloudData ?
this.cloudData.credential.user : '', this.cloudData ? this.cloudData.api.providerName : ''),
requiredEndpointValidator('endpoint', 'cloudType')]
});
if (this.cloudData) {
......@@ -115,6 +117,10 @@ export class CloudDefinitionFormComponent implements OnInit {
return 'Such user for this provide already exists. User for provider must be unique.';
}
getMissingEndpointMessage() {
return 'Required field for private provider';
}
saveCloudDefinition(cloudForm: NgForm) {
this.cloudConfigurationFormControl.properties.setValue(this.cloudProperties);
const cloudDefinition = <CloudDefinition> cloudForm.value;
......
......@@ -48,7 +48,7 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-spinner [diameter]="150" *ngIf="loadingDataInProgress"></mat-spinner>
<mat-spinner [diameter]="150" *ngIf="operationOnDataInProgress"></mat-spinner>
<mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
</mat-card>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment