Commit 9a4a1275 authored by Simone Vuotto's avatar Simone Vuotto

Update project details with tabs and task

parent e3f37adb
......@@ -13,12 +13,15 @@ import { AlertComponent } from './alert/alert.component';
import { ProjectDialogComponent } from './project-dialog/project-dialog.component';
import { ProjectDetailsComponent } from './project-details/project-details.component';
import { RequirementDetailsComponent } from './requirement-details/requirement-details.component';
import { RequirementsTabComponent } from './project-details/requirements-tab/requirements-tab.component';
import { TasksTabComponent } from './project-details/tasks-tab/tasks-tab.component';
// Services
import { AuthenticationService } from './services/authentication.service';
import { AlertService } from './alert/alert.service';
import { ProjectService } from './services/project.service';
import { RequirementService } from './services/requirement.service';
import { TaskService } from './services/task.service';
// Guards
import {AuthGuard} from './auth.guard';
......@@ -36,6 +39,8 @@ import { JwtInterceptor } from './jwt.interceptor.js';
ProjectDialogComponent,
ProjectDetailsComponent,
RequirementDetailsComponent,
RequirementsTabComponent,
TasksTabComponent,
],
imports: [
BrowserModule,
......@@ -55,6 +60,7 @@ import { JwtInterceptor } from './jwt.interceptor.js';
},
ProjectService,
RequirementService,
TaskService,
],
bootstrap: [ AppComponent ]
})
......
......@@ -2,10 +2,6 @@
margin-bottom: 2em;
}
.btn-top {
margin-left: 0.5em;
}
.hidden {
display: none !important;
visibility: hidden !important;
......
......@@ -2,47 +2,29 @@
<div class="col-md-8">
<h1 *ngIf="project != null">{{ project.name }}</h1>
</div>
<div class="col-md-4">
<div class="hidden"><input type="file" #fileInput (change)="fileChange($event)"/></div>
<button type="button" class="btn btn-primary pull-right btn-top" (click)="fileInput.click()"
[disabled]="uploadLoading">
<i class="fa fa-upload" aria-hidden="true" *ngIf="!uploadLoading"></i>
<i class='fa fa-spinner fa-spin' *ngIf="uploadLoading"></i>
&nbsp;Upload File
</button>
<button type="button" class="btn btn-primary pull-right btn-top" [disabled]="translateLoading" (click)="getTranslation()">
<i class="fa fa-download" aria-hidden="true" *ngIf="!translateLoading"></i>
<i class='fa fa-spinner fa-spin' *ngIf="translateLoading"></i>
&nbsp;Translate
</button>
<button type="button" class="btn btn-primary pull-right btn-top" [disabled]="true">
<i class="fa fa-play" aria-hidden="true"></i>
&nbsp;Validate
</button>
</div>
</div>
<div class="container"></div>
<table class="table table-hover">
<thead>
<tr>
<th class="col-md-1">Id</th>
<th class="col-md-9">Requirement</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let req of requirements"
[ngClass]="{'table-success': req.compliant,
'table-primary': req.error,
'table-dange': req.warning,
'table-light': req.notChecked}"
(click)="requirementDetails(req)">
<td scope="row">{{ req.id }}</td>
<td>{{ req.text }}</td>
</tr>
</tbody>
</table>
<div class="container">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active show" data-toggle="tab" href="#requirements">Requirements</a>
</li>
<li class="nav-item">
<a class="nav-link active show" data-toggle="tab" href="#tasks">Tasks</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade in active show" id="requirements">
<app-requirements-tab [projectId]="projectId"></app-requirements-tab>
</div>
<div class="tab-pane fade show" id="tasks">
<app-tasks-tab [projectId]="projectId"></app-tasks-tab>
</div>
</div>
</div>
<app-requirement-details [req]="selectedRequirement" (update)="onChange($event)"></app-requirement-details>
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Project } from '../models/project';
import { Requirement } from '../models/requirement';
import { ProjectService } from '../services/project.service';
import { RequirementService } from '../services/requirement.service';
import { AlertService } from '../alert/alert.service';
import { saveAs } from 'file-saver/FileSaver';
@Component({
......@@ -18,21 +13,13 @@ export class ProjectDetailsComponent implements OnInit {
projectId: number;
project: Project;
requirements: Requirement[];
uploadLoading = false;
translateLoading = false;
selectedRequirement = new Requirement();
constructor(private route: ActivatedRoute,
private projectService: ProjectService,
private requirementService: RequirementService,
private alertService: AlertService) { }
private projectService: ProjectService) { }
ngOnInit() {
this.projectId = +this.route.snapshot.paramMap.get('projectId');
this.getProject();
this.getRequirements();
}
getProject() {
......@@ -40,57 +27,4 @@ export class ProjectDetailsComponent implements OnInit {
project => this.project = project);
}
getRequirements() {
this.requirementService.getRequirements(this.projectId).subscribe(
requirements => this.requirements = requirements.map(req => new Requirement().clone(req)));
}
fileChange(event) {
const fileList: FileList = event.target.files;
if (fileList.length > 0) {
this.uploadLoading = true;
this.requirementService.uploadFile(fileList[0], this.projectId).subscribe(
data => {
this.uploadLoading = false;
this.requirements = this.requirements.concat(data.map(req => new Requirement().clone(req)));
this.alertService.success('File uploaded correctly!');
},
error => {
this.alertService.error('Error uploading the file!');
console.error(error);
this.uploadLoading = false;
}
);
}
}
requirementDetails(req: Requirement) {
this.selectedRequirement = new Requirement().clone(req);
}
onChange(req: Requirement) {
const index = this.requirements.findIndex(r => r.id === req.id);
if (index >= 0) {
this.requirements[index] = req;
}
}
getTranslation() {
this.translateLoading = true;
this.requirementService.getTranslation(this.projectId).subscribe(
response => {
const blob = new Blob([response.body], { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'output.nusmv');
this.translateLoading = false;
},
error => {
this.alertService.error(error);
console.log(error);
this.translateLoading = false;
}
);
}
}
<div class="tab-header clearfix">
<div class="hidden"><input type="file" #fileInput (change)="fileChange($event)"/></div>
<button type="button" class="btn btn-primary pull-right" (click)="fileInput.click()"
[disabled]="uploadLoading">
<i class="fa fa-upload" aria-hidden="true" *ngIf="!uploadLoading"></i>
<i class='fa fa-spinner fa-spin' *ngIf="uploadLoading"></i>
&nbsp;Upload File
</button>
</div>
<table class="table table-hover">
<thead>
<tr>
<th class="col-md-1">Id</th>
<th class="col-md-9">Requirement</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let req of requirements"
[ngClass]="{'table-success': req.compliant,
'table-primary': req.error,
'table-dange': req.warning,
'table-light': req.notChecked}"
(click)="requirementDetails(req)">
<td scope="row">{{ req.id }}</td>
<td>{{ req.text }}</td>
</tr>
</tbody>
</table>
<app-requirement-details [req]="selectedRequirement" (update)="onChange($event)"></app-requirement-details>
import { Component, Input, OnInit } from '@angular/core';
import { Requirement } from '../../models/requirement';
import { ActivatedRoute } from '@angular/router';
import { RequirementService } from '../../services/requirement.service';
import { AlertService } from '../../alert/alert.service';
@Component({
selector: 'app-requirements-tab',
templateUrl: './requirements-tab.component.html',
styleUrls: ['./requirements-tab.component.css']
})
export class RequirementsTabComponent implements OnInit {
@Input() projectId: number;
requirements: Requirement[];
selectedRequirement = new Requirement();
uploadLoading = false;
constructor(private requirementService: RequirementService,
private alertService: AlertService) { }
ngOnInit() {
this.getRequirements();
}
requirementDetails(req: Requirement) {
this.selectedRequirement = new Requirement().clone(req);
}
onChange(req: Requirement) {
const index = this.requirements.findIndex(r => r.id === req.id);
if (index >= 0) {
this.requirements[index] = req;
}
}
getRequirements() {
this.requirementService.getRequirements(this.projectId).subscribe(
requirements => this.requirements = requirements.map(req => new Requirement().clone(req)));
}
fileChange(event) {
const fileList: FileList = event.target.files;
if (fileList.length > 0) {
this.uploadLoading = true;
this.requirementService.uploadFile(fileList[0], this.projectId).subscribe(
data => {
this.uploadLoading = false;
this.requirements = this.requirements.concat(data.map(req => new Requirement().clone(req)));
this.alertService.success('File uploaded correctly!');
},
error => {
this.alertService.error('Error uploading the file!');
console.error(error);
this.uploadLoading = false;
}
);
}
}
}
<div class="tab-header clearfix">
<button type="button" class="btn btn-primary pull-right" [disabled]="translateLoading" (click)="getTranslation()">
<i class="fa fa-download" aria-hidden="true" *ngIf="!translateLoading"></i>
<i class='fa fa-spinner fa-spin' *ngIf="translateLoading"></i>
&nbsp;Translate
</button>
<button type="button" class="btn btn-primary pull-right" [disabled]="!taskIsRunning" (click)="consistencyCheck()">
<i class="fa fa-play" aria-hidden="true"></i>
&nbsp;Validate
</button>
</div>
<div>
<div class="card" *ngFor="let task of tasks">
<div class="card-body">
<h4 class="card-title">{{task.description}}
<i class="fa fa-circle pull-right"
[ngClass]="{'status-success': task.success,
'status-fail': task.fail,
'status-running': task.running
}"
title="{{task.status}}"></i>
</h4>
<h6 class="card-subtitle mb-2 text-muted">{{task.timestamp}}</h6>
<div class="card-text">
<div>
<label >Logs:</label>
<textarea class="form-control" readonly="readonly">{{task.log}}</textarea>
</div>
</div>
</div>
</div>
</div>
import { Component, Input, OnInit } from '@angular/core';
import { TaskService } from '../../services/task.service';
import { Task } from '../../models/task';
import { AlertService } from '../../alert/alert.service';
import { saveAs } from 'file-saver/FileSaver';
@Component({
selector: 'app-tasks-tab',
templateUrl: './tasks-tab.component.html',
styleUrls: ['./tasks-tab.component.css']
})
export class TasksTabComponent implements OnInit {
@Input() projectId: number;
tasks: Task[];
translateLoading = false;
taskIsRunning = false;
constructor(private taskService: TaskService,
private alertService: AlertService) { }
ngOnInit() {
this.getTasks();
}
getTasks() {
this.taskService.getTasks(this.projectId).subscribe(
tasks => {
this.tasks = tasks.map(t => new Task(t));
this.taskIsRunning = this.tasks.every(t => !t.running);
this.tasks.forEach(task => {
if (task.running) {
this.checkRunningTask(task);
}
});
});
}
getTranslation() {
this.translateLoading = true;
this.taskService.getTranslation(this.projectId).subscribe(
response => {
const blob = new Blob([response.body], { type: 'text/plain' });
saveAs(blob, 'output.nusmv');
this.translateLoading = false;
},
error => {
this.alertService.error(error);
console.log(error);
this.translateLoading = false;
}
);
}
consistencyCheck() {
this.taskIsRunning = true;
this.taskService.performConsistencyCheck(this.projectId).subscribe(
task => {
this.tasks.unshift(new Task(task));
this.checkRunningTask(task);
}
);
}
checkRunningTask(task: Task) {
setTimeout(() => {
this.taskService.getTask(this.projectId, task.id).subscribe(
t => {
task = new Task(t);
if (task.running) {
this.checkRunningTask(task);
} else {
const index = this.tasks.findIndex( x => x.id === task.id);
this.tasks[index] = task;
}
}
);
}, 2500);
}
}
......@@ -33,11 +33,4 @@ export class RequirementService {
}
getTranslation(projectId: number): Observable<HttpResponse<Blob>> {
const params = new HttpParams().set('pId', projectId.toString());
const options = {params: params, observe: 'response' as 'response', responseType: 'blob' as 'blob'};
return this.http.get(this.reqTranslateUrl, options);
}
}
Markdown is supported
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