Commit c7091df6 authored by Lukas Burgey's avatar Lukas Burgey

Fix the service list

parent a07a5a1e
...@@ -11,7 +11,7 @@ import { SSHKey, NewSSHKey } from '../../types/types.module'; ...@@ -11,7 +11,7 @@ import { SSHKey, NewSSHKey } from '../../types/types.module';
}) })
export class SshKeysComponent implements OnInit { export class SshKeysComponent implements OnInit {
columns = ['name', 'key', 'action']; columns = ['name', 'key', 'action'];
// does the user want to update a key? // does the user want to upload a key?
upload: boolean; upload: boolean;
newKeyName: string; newKeyName: string;
newKeyKey: string; newKeyKey: string;
...@@ -31,7 +31,7 @@ export class SshKeysComponent implements OnInit { ...@@ -31,7 +31,7 @@ export class SshKeysComponent implements OnInit {
name: this.newKeyName, name: this.newKeyName,
key: this.newKeyKey, key: this.newKeyKey,
}; };
this.userService.addSshKey(newKey); this.userService.uploadSshKey(newKey);
this.ngOnInit(); this.ngOnInit();
} }
......
<div *ngIf="userService.loggedIn()"> <div *ngIf="userService.loggedIn()">
<div style="padding-bottom: 30px;"> <div style="padding-bottom: 30px;">
<h2>Services</h2> <h2>Services</h2>
<div *ngIf="userService.services.length > 0"> <mat-accordion *ngIf="userService.deploymentIDs.length > 0">
<mat-accordion> <app-service *ngFor="let dID of userService.deploymentIDs" [deployment]="userService.getDeployment(dID)"></app-service>
<app-service *ngFor="let service of userService.services" </mat-accordion>
[service]="service"></app-service> <p *ngIf="userService.deploymentIDs.length === 0">
</mat-accordion>
</div>
<p *ngIf="userService.services?.length == 0">
You have no available services.<br/> You have no available services.<br/>
This is due services requiring users to be member of a certain group. This is due services requiring users to be member of a certain group.
</p> </p>
</div> </div>
<!--
<div *ngIf="userService.user.deployment_tasks.length > 0">
<h3>Uncompleted tasks</h3>
<div>
<pre *ngFor="let task of userService.user.deployment_tasks">
{{ task | json }}
</pre>
</div>
</div>
<div *ngIf="userService.messages.length > 0">
<h3>Messages</h3>
<div>
<p *ngFor="let message of userService.messages">
{{ message }}
</p>
</div>
</div>
-->
</div> </div>
<mat-expansion-panel *ngIf="service"> <mat-expansion-panel *ngIf="deployment">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title>{{ service.name }}</mat-panel-title> <mat-panel-title>{{ service.name }}</mat-panel-title>
<mat-panel-description>{{ service.description }}</mat-panel-description> <mat-panel-description>{{ service.description }}</mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<table width="60%"> <table>
<tr style="margin-bottom: 15px;"> <tr style="margin-bottom: 25px;">
<td *ngFor="let site of service.site"> <td>
<span matTooltip="Provided at site {{ site.name }}" style="margin-right: 10px;"> <span *ngFor="let site of service.site" style="margin-right: 15px;">
<mat-icon style="vertical-align: middle; padding-right: 5px;">storage</mat-icon> <span matTooltip="Provided at site {{ site.name }}" style="margin-right: 10px;">
{{ site.name }} <mat-icon style="vertical-align: middle; padding-right: 5px;">storage</mat-icon>
</span> {{ site.name }}
<span *ngIf="userService.user.ssh_keys.length > 0"> </span>
<span *ngFor="let key of userService.user.ssh_keys" <span *ngIf="userService.user.ssh_keys.length > 0" style="margin-right: 10px;">
[ngSwitch]="userService.taskState(site, service, key)" class="childs-inline" style="margin-right: 5px;"> <span *ngFor="let key of userService.user.ssh_keys"
<!-- states with actions --> [ngSwitch]="taskState(site, key)" class="childs-inline">
<button *ngSwitchCase="'deployed'" mat-button mat-icon-button <!-- states with actions -->
matTooltip="The key {{key.name}} is deployed to the site. Click to see details."> <button *ngSwitchCase="'deployed'" mat-button mat-icon-button
<mat-icon style="vertical-align: middle">call_made</mat-icon> matTooltip="The key {{key.name}} is deployed to the site. Click to see details.">
</button> <mat-icon style="vertical-align: middle">call_made</mat-icon>
<button *ngSwitchCase="'questionnaire'" mat-button mat-icon-button </button>
(click)="dialog.openQuestionnaire(userService.taskItem(site, service))" <button *ngSwitchCase="'questionnaire'" mat-button mat-icon-button
matTooltip="This site needs more data to deploy the keys. Please click to submit the data."> (click)="dialog.openQuestionnaire(userService.taskItem(site, service))"
<mat-icon>warning</mat-icon> matTooltip="This site needs more data to deploy the keys. Please click to submit the data.">
</button> <mat-icon>warning</mat-icon>
<!-- states without actions --> </button>
<span *ngSwitchCase="'deployment_pending'" matTooltip="Waiting for the deployment of the key {{ key.name }} by the site"> <!-- states without actions -->
<mat-progress-spinner diameter="24" mode="indeterminate"></mat-progress-spinner> <span *ngSwitchCase="'deployment_pending'" mat-icon-button matTooltip="Waiting for the deployment of the key {{ key.name }} by the site">
</span> <mat-progress-spinner diameter="24" mode="indeterminate"></mat-progress-spinner>
<span *ngSwitchCase="'removal_pending'" matTooltip="Waiting for the removal of the key {{ key.name }} from the site"> </span>
<mat-progress-spinner diameter="24" mode="indeterminate"></mat-progress-spinner> <span *ngSwitchCase="'removal_pending'" mat-icon-button matTooltip="Waiting for the removal of the key {{ key.name }} from the site">
</span> <mat-progress-spinner diameter="24" mode="indeterminate"></mat-progress-spinner>
<span *ngSwitchCase="'not_deployed'" matTooltip="The key {{ key.name }} is not deployed to this site."> </span>
<mat-icon style="vertical-align: middle">call_received</mat-icon> <span *ngSwitchCase="'not_deployed'" mat-icon-button matTooltip="The key {{ key.name }} is not deployed to this site.">
</span> <mat-icon style="vertical-align: middle">call_received</mat-icon>
<span *ngSwitchCase="'failed'" matTooltip="This site failed to deploy the credentials. The deployment will be retried."> </span>
<mat-icon style="vertical-align: middle">error</mat-icon> <span *ngSwitchCase="'failed'" mat-icon-button matTooltip="This site failed to deploy the credentials. The deployment will be retried.">
</span> <mat-icon style="vertical-align: middle">error</mat-icon>
<span *ngSwitchCase="'rejected'" matTooltip="This site rejected the deployment of the key {{ key.name }}."> </span>
<mat-icon style="vertical-align: middle">error</mat-icon> <span *ngSwitchCase="'rejected'" mat-icon-button matTooltip="This site rejected the deployment of the key {{ key.name }}.">
</span> <mat-icon style="vertical-align: middle">error</mat-icon>
<span *ngSwitchDefault matTooltip="Unrecognized state"> </span>
<mat-icon style="vertical-align: middle">error</mat-icon> <!-- hacky solution -->
<span *ngSwitchDefault mat-icon-button matTooltip="Receiving update from backend">
<mat-progress-spinner diameter="24" mode="indeterminate"></mat-progress-spinner>
</span>
</span> </span>
</span> </span>
</span> </span>
...@@ -48,8 +51,8 @@ ...@@ -48,8 +51,8 @@
</tr> </tr>
<tr> <tr>
<td style="padding-right: 35px;" <td style="padding-right: 35px;"
*ngFor="let group of service.groups" *ngFor="let group of service.groups"
matTooltip="Can be used with membership of group {{ group.name }}"> matTooltip="Can be used with membership of group {{ group.name }}">
<mat-icon style="vertical-align: middle; padding-right: 5px;">lock outline</mat-icon> <mat-icon style="vertical-align: middle; padding-right: 5px;">lock outline</mat-icon>
{{ group.name }} {{ group.name }}
</td> </td>
...@@ -62,9 +65,9 @@ ...@@ -62,9 +65,9 @@
SSH Keys: SSH Keys:
</span> </span>
<mat-checkbox *ngFor="let key of userService.user.ssh_keys" <mat-checkbox *ngFor="let key of userService.user.ssh_keys"
style="margin-right: 8px" style="margin-right: 8px"
[checked]="isDeployed(key)" [checked]="isDeployed(key)"
(change)="deploymentChange(key)"> (change)="deploymentChange(key)">
{{ key.name }} {{ key.name }}
</mat-checkbox> </mat-checkbox>
</ng-template> </ng-template>
......
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input } from '@angular/core';
import { MatCheckboxChange } from '@angular/material/checkbox'; import { MatCheckboxChange } from '@angular/material/checkbox';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import { UserService } from '../user.service'; import { UserService } from '../user.service';
import { DialogService } from '../dialogues/dialog.service'; import { DialogService } from '../dialogues/dialog.service';
...@@ -12,23 +14,18 @@ import * as t from '../types/types.module'; ...@@ -12,23 +14,18 @@ import * as t from '../types/types.module';
styleUrls: ['./service.component.css'] styleUrls: ['./service.component.css']
}) })
export class ServiceComponent implements OnInit { export class ServiceComponent implements OnInit {
@Input() service: t.Service; @Input() deployment: t.Deployment;
public sshKeys: t.SSHKeyRef[]; public service: t.Service;
public deployment: t.Deployment;
constructor( constructor(
public userService: UserService, public userService: UserService,
public dialog: DialogService, public dialog: DialogService,
public http: HttpClient,
) { ) {
} }
ngOnInit() { ngOnInit() {
this.sshKeys = this.userService.user.ssh_keys; this.service = this.deployment.service;
this.deployment = this.userService.userState.deployments.find(
d => {
return d.service.id === this.service.id;
}
);
} }
public isDeployed(key: t.SSHKeyRef): boolean { public isDeployed(key: t.SSHKeyRef): boolean {
...@@ -40,11 +37,55 @@ export class ServiceComponent implements OnInit { ...@@ -40,11 +37,55 @@ export class ServiceComponent implements OnInit {
return false; return false;
} }
public deploymentChange(key) { public taskItem(site: t.Site, key: t.SSHKeyRef): t.DeploymentStateItem {
if (this.deployment) {
const deploymentState = this.deployment.states.find(
state => {
return state.key.id === key.id
}
);
if (deploymentState) {
return deploymentState.state_items.find(
item => {
return item.site.id === site.id
}
);
}
}
}
public taskState(site: t.Site, key: t.SSHKeyRef): string {
let item = this.taskItem(site, key);
if (item) {
return item.state;
}
return "";
}
public changeDeployment(key: t.SSHKeyRef, action: string) {
const body = {
'type': action,
'key': key.id,
'service': this.service.id,
};
return this.http.post('/backend/api/deployments', body).subscribe(
(newDep: t.Deployment) => {
// update the deployment
this.deployment = newDep;
},
(err) => {
console.log(err);
this.userService.update();
}
);
}
public deploymentChange(key: t.SSHKeyRef) {
if (!this.isDeployed(key)) { if (!this.isDeployed(key)) {
this.userService.addDeployment(this.service, key); this.changeDeployment(key, 'add');
} else { } else {
this.userService.removeDeployment(this.service, key); this.changeDeployment(key, 'remove');
} }
} }
} }
...@@ -63,9 +63,11 @@ export interface DeploymentStateItem { ...@@ -63,9 +63,11 @@ export interface DeploymentStateItem {
export interface DeploymentState { export interface DeploymentState {
id: number; id: number;
service: Service; service: Service;
key: SSHKeyRef;
state_items: DeploymentStateItem[]; state_items: DeploymentStateItem[];
} }
export interface Deployment { export interface Deployment {
id: number;
service: Service; service: Service;
ssh_keys: SSHKeyRef[]; ssh_keys: SSHKeyRef[];
ssh_keys_to_withdraw: SSHKeyRef[]; ssh_keys_to_withdraw: SSHKeyRef[];
......
...@@ -22,8 +22,10 @@ export class UserService { ...@@ -22,8 +22,10 @@ export class UserService {
public user: t.User; public user: t.User;
public userState: t.UserState; public userState: t.UserState;
public messages: string[] = []; public messages: string[] = [];
public services: t.Service[]; // local copy of deployments
public deploymentIDs: number[] = [];
constructor( constructor(
...@@ -92,6 +94,14 @@ export class UserService { ...@@ -92,6 +94,14 @@ export class UserService {
this.user = newUser; this.user = newUser;
} }
private updateDeployments(newDeployments: t.Deployment[]){
if (this.deploymentIDs.length !== newDeployments.length) {
for (let dep of newDeployments) {
this.deploymentIDs.push(dep.id);
}
}
}
private updateUserState(newState: t.UserState) { private updateUserState(newState: t.UserState) {
// did a login occur? // did a login occur?
let login = (!this._loggedIn && newState); let login = (!this._loggedIn && newState);
...@@ -110,13 +120,14 @@ export class UserService { ...@@ -110,13 +120,14 @@ export class UserService {
this._stompService.disconnect(); this._stompService.disconnect();
} }
this.updateDeployments(newState.deployments);
this.userState = newState; this.userState = newState;
} }
private stateAPIUpdate(update: t.StateAPIResult) { private stateAPIUpdate(update: t.StateAPIResult) {
this.updateUser(update.user) this.updateUser(update.user)
this.updateUserState(update.user_state); this.updateUserState(update.user_state);
this.services = update.services;
// report an occured error // report an occured error
if (update.error) { if (update.error) {
...@@ -129,6 +140,13 @@ export class UserService { ...@@ -129,6 +140,13 @@ export class UserService {
} }
// PUBLIC API // PUBLIC API
public getDeployment(id: number): t.Deployment {
return this.userState.deployments.find(
dep => {
return dep.id == id
}
);
}
public userInfo(): MatTableDataSource<any> { public userInfo(): MatTableDataSource<any> {
const userInfoList = []; const userInfoList = [];
for (const key in this.user.userinfo) { for (const key in this.user.userinfo) {
...@@ -211,7 +229,7 @@ export class UserService { ...@@ -211,7 +229,7 @@ export class UserService {
); );
} }
public addSshKey(key: t.NewSSHKey) { public uploadSshKey(key: t.NewSSHKey) {
const body = { const body = {
'type': 'add', 'type': 'add',
'key': key, 'key': key,
...@@ -236,6 +254,9 @@ export class UserService { ...@@ -236,6 +254,9 @@ export class UserService {
return this.http.post('/backend/api/sshkey', body).subscribe( return this.http.post('/backend/api/sshkey', body).subscribe(
(data: t.UserState) => { (data: t.UserState) => {
this.updateUserState(data); this.updateUserState(data);
this.user.ssh_keys = this.user.ssh_keys.filter(
k => key.id == k.id
);
}, },
(err) => { (err) => {
this.snackBar.open('Error deleting key'); this.snackBar.open('Error deleting key');
...@@ -245,45 +266,6 @@ export class UserService { ...@@ -245,45 +266,6 @@ export class UserService {
); );
} }
public addDeployment(service: t.Service, key: t.SSHKey) {
const body = {
'type': 'add',
'key': key.id,
'service': service.id,
};
return this.http.post('/backend/api/deployments', body).subscribe(
(data: t.UserState) => {
//this.snackBar.open('Deployed key ' + key.name);
this.updateUserState(data);
},
(err) => {
this.snackBar.open('Error deploying key ' + key.name);
console.log(err);
this.update();
}
);
}
public removeDeployment(service: t.Service, key: t.SSHKey) {
const body = {
'type': 'remove',
'key': key.id,
'service': service.id,
};
return this.http.post('/backend/api/deployments', body).subscribe(
(data: t.UserState) => {
//this.snackBar.open('Withdrew key ' + key.name);
this.updateUserState(data);
},
(err) => {
this.snackBar.open('Error withdrawing key ' + key.name);
console.log(err);
this.update();
}
);
}
public sentQuestionnaire(taskItemID: number, answers: any) { public sentQuestionnaire(taskItemID: number, answers: any) {
return this.http.post('/backend/api/questionnaire?id='+String(taskItemID), answers).subscribe( return this.http.post('/backend/api/questionnaire?id='+String(taskItemID), answers).subscribe(
(data: t.UserState) => { (data: t.UserState) => {
...@@ -312,25 +294,4 @@ export class UserService { ...@@ -312,25 +294,4 @@ export class UserService {
} }
); );
} }
public taskItem(site: t.Site, service: t.Service, key: t.SSHKeyRef): t.DeploymentStateItem {
if (this.userState.deployment_state_items && site && service && key) {
for (const item of this.userState.deployment_state_items){
if (item.site.id == site.id
&& item.key.id == key.id
&& item.service.id == service.id) {
return item;
}
}
}
return null;
}
public taskState(site: t.Site, service: t.Service, key: t.SSHKeyRef): string {
let item = this.taskItem(site, service, key);
if (item !== null) {
return item.state;
}
return "";
}
} }
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