Commits (11)
......@@ -9,4 +9,5 @@
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
not IE 9-11 # For IE 9-11 support, remove 'not'.
not IE_Mob 9-11 # For IE 9-11 support, remove 'not'.
......@@ -24,7 +24,9 @@
"styles": [
"src/styles.css"
],
"scripts": []
"scripts": [
"node_modules/marked/lib/marked.js"
]
},
"configurations": {
"production": {
......
This diff is collapsed.
......@@ -9,47 +9,48 @@
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "ngcc"
"postinstall": "ngcc --tsconfig ./src/tsconfig.app.json"
},
"private": true,
"dependencies": {
"@angular/animations": "10.0.6",
"@angular/cdk": "^10.1.1",
"@angular/common": "10.0.6",
"@angular/compiler": "10.0.6",
"@angular/core": "10.0.6",
"@angular/forms": "10.0.6",
"@angular/material": "^10.1.1",
"@angular/platform-browser": "10.0.6",
"@angular/platform-browser-dynamic": "10.0.6",
"@angular/animations": "10.0.8",
"@angular/cdk": "^10.1.2",
"@angular/common": "10.0.8",
"@angular/compiler": "10.0.8",
"@angular/core": "10.0.8",
"@angular/forms": "10.0.8",
"@angular/material": "^10.1.2",
"@angular/platform-browser": "10.0.8",
"@angular/platform-browser-dynamic": "10.0.8",
"@stomp/ng2-stompjs": "^7.2.0",
"core-js": "^2.6.11",
"markdown-to-html-pipe": "^1.2.5",
"ngx-cookie-service": "^2.4.0",
"npm": "^6.14.4",
"rxjs": "^6.6.0",
"tslib": "^2.0.0",
"marked": "^1.1.1",
"ngx-cookie-service": "^10.0.1",
"ngx-markdown": "^10.1.0",
"npm": "^6.14.7",
"rxjs": "^6.6.2",
"tslib": "^2.0.1",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1000.4",
"@angular/cli": "10.0.4",
"@angular/compiler-cli": "10.0.6",
"@types/jasmine": "^3.5.10",
"@angular-devkit/build-angular": "~0.1000.5",
"@angular/cli": "10.0.5",
"@angular/compiler-cli": "10.0.8",
"@types/jasmine": "^3.5.12",
"@types/jasminewd2": "^2.0.8",
"@types/node": "^12.11.1",
"@types/node": "^14.0.27",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0",
"karma": "^5.1.1",
"karma-chrome-launcher": "~3.1.0",
"karma-cli": "~2.0.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~3.3.0",
"karma-jasmine-html-reporter": "^1.5.0",
"karma-jasmine-html-reporter": "^1.5.4",
"protractor": "~7.0.0",
"ts-node": "^8.9.1",
"tslint": "~6.1.0",
"ts-node": "^8.10.2",
"tslint": "^6.1.3",
"typescript": "3.9.7"
}
}
div#footer {
text-align: center;
}
......@@ -39,4 +39,6 @@
</div>
</div>
</div>
<footer feudal-footer class="footer"></footer>
<div id="footer">
<a href="/static/privacy_policy.html">FEUDAL Privacy Policy</a>
</div>
......@@ -8,7 +8,7 @@ import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
// Other libs
import { StompRService } from '@stomp/ng2-stompjs';
import { CookieService } from 'ngx-cookie-service';
import { MarkdownToHtmlModule } from 'markdown-to-html-pipe';
import { MarkdownModule } from 'ngx-markdown';
// Our stuff
......@@ -27,7 +27,6 @@ import { SshkeysModule } from './sshkeys/sshkeys.module';
// declarations
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { VoDataComponent } from './vo-data/vo-data.component';
import { ServiceComponent } from './service/service.component';
import { StateComponent } from './state/state.component';
......@@ -48,12 +47,11 @@ import { AccountComponent } from './account/account.component';
MaterialModule,
SharedModule,
SshkeysModule,
MarkdownToHtmlModule,
MarkdownModule.forRoot(),
],
declarations: [
AppComponent,
HeaderComponent,
FooterComponent,
VoDataComponent,
ServiceComponent,
StateComponent,
......@@ -76,4 +74,3 @@ export class AppModule {
constructor() {
}
}
<div *ngIf="(userService.userSrc() | async) as user" class="mat-typography" style="margin-bottom: 50px;">
<h2>User Info</h2>
<p>
You can inspect the user information we received about you.
</p>
<button mat-raised-button mat-dialog-close color="primary" (click)="profileDialog.open(user)">
Show User Info
</button>
</div>
<h1 mat-dialog-title>Your FEUDAL account</h1>
<div mat-dialog-content>
<div *ngIf="(userService.userSrc() | async) as user" class="mat-typography" style="margin-bottom: 50px;">
<h2>User Info</h2>
<p>
You can inspect the user information we received about you.
</p>
<button mat-raised-button mat-dialog-close color="primary" (click)="profileDialog.open(user)">
Show User Info
</button>
</div>
<app-sshkeys></app-sshkeys>
<app-sshkeys></app-sshkeys>
<app-preferences></app-preferences>
<app-preferences></app-preferences>
<div class="mat-typography">
<h2>Account Management</h2>
<p class="mat-body-1">
You can delete your account. All deployments will be removed if you choose to do so. You will not be able to use the deployed credentials.
</p>
<p class="mat-body-2">
<mat-checkbox [(ngModel)]="sure" style="margin-right: 8px" [checked]="sure">
I'm sure I want to delete my data from the server.
</mat-checkbox>
<p>
<button mat-raised-button mat-dialog-close color="primary" (click)="userService.deleteUser()" [disabled]="!sure">
Delete
</button>
</p>
<div class="mat-typography">
<h2>Account Management</h2>
<p class="mat-body-1">
You can delete your account. All deployments will be removed if you choose to do so. You will not be able to use the deployed credentials.
</p>
<p class="mat-body-2">
<mat-checkbox [(ngModel)]="sure" style="margin-right: 8px" [checked]="sure">
I'm sure I want to delete my data from the server.
</mat-checkbox>
<p>
<button mat-raised-button mat-dialog-close color="primary" (click)="userService.deleteUser()" [disabled]="!sure">
Delete
</button>
</p>
</div>
</div>
......@@ -8,7 +8,7 @@ import { QuestionnaireComponent } from './questionnaire/questionnaire.component'
import { CredentialsComponent } from './credentials/credentials.component';
import { MessageComponent } from './message/message.component';
import { User, DeploymentState } from '../types/types.module';
import { DeploymentState } from '../types/types.module';
@Injectable()
export class DialogService {
......
<div class="mat-typography">
<h2>Deployment State</h2>
<h2 mat-dialog-title>Deployment State</h2>
<div mat-dialog-content>
<div [ngSwitch]="stateItem.state">
<p *ngSwitchCase="'failed'">
The deployment of your credentials failed:
......@@ -15,6 +15,6 @@
</p>
</div>
<p>
{{ stateItem.message }}
{{ stateItem.message }}
</p>
</div>
......@@ -20,6 +20,7 @@ export class ProfileDialogService {
{
panelClass: 'scrolling-dialog',
data: user,
autoFocus: false, // don't focus the copy button automatically
},
);
}
......
table {
width: 100%;
margin: 0px; /* Unfortunately i set a global default margin in style.css and have to overwrite here */
}
/* more padding around the firt column */
th.mat-header-cell:first-of-type, td.mat-cell:first-of-type, td.mat-footer-cell:first-of-type {
padding: 0px 24px 0px 24px;
}
<div class="mat-typography">
<h2>User Info</h2>
<mat-table [dataSource]="dataSource()">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.name}}</mat-cell>
<h1 mat-dialog-title>Your User Info</h1>
<div mat-dialog-content>
<table mat-table [dataSource]="userInfoList">
<ng-container matColumnDef="key">
<th mat-header-cell *matHeaderCellDef>Key</th>
<td mat-cell *matCellDef="let row">{{ row.key }}</td>
</ng-container>
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef>Info</mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.info | json }}</mat-cell>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef>Value</th>
<td mat-cell *matCellDef="let row">
<pre>{{ row.value | json }}</pre>
</td>
</ng-container>
<mat-header-row *matHeaderRowDef="columns"></mat-header-row>
<mat-row *matRowDef="let row; columns: columns;"></mat-row>
</mat-table>
<tr mat-header-row *matHeaderRowDef="columns"></tr>
<tr mat-row *matRowDef="let row; columns: columns;"></tr>
</table>
</div>
<div mat-dialog-action align="end" style="padding-top: 24px;">
<button mat-icon-button matTooltip="Copy User Info JSON to the clipboard" [cdkCopyToClipboard]="userInfoJSON" (click)="snackBar.open('User Info JSON copied to clipboard')">
<mat-icon>file_copy</mat-icon>
</button>
</div>
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatTableDataSource } from '@angular/material/table';
import { SnackBarService } from '../../snackbar.service';
import { User } from '../../types/types.module';
......@@ -10,22 +11,21 @@ import { User } from '../../types/types.module';
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
columns = ['name', 'info'];
columns = ['key', 'value'];
public userInfoList = [];
public userInfoJSON: string;
constructor(
@Inject(MAT_DIALOG_DATA) public user: User,
public snackBar: SnackBarService,
) { }
ngOnInit() {
}
dataSource(): MatTableDataSource<any> {
const userInfoList = [];
for (const key in this.user.userinfo) {
if (this.user.userinfo.hasOwnProperty(key)) {
userInfoList.push({name: key, info: this.user.userinfo[key]});
}
for (const [key, value] of Object.entries(this.user.userinfo)) {
this.userInfoList.push({key: key, value: value});
}
return new MatTableDataSource(userInfoList);
// add pretty printed json
this.userInfoJSON = JSON.stringify(this.user.userinfo, null, 2);
}
}
......@@ -2,3 +2,11 @@
div.answer {
margin-bottom: 20px;
}
form {
margin-left: 24px;
}
div#button-div {
text-align: right;
}
<div *ngIf="(state$ | async) as state" class="mat-typography">
<h1>Service registration</h1>
<h1 mat-dialog-title>Service registration</h1>
<div mat-dialog-content *ngIf="(state$ | async) as state">
<p style="margin-bottom: 20px;">
The site {{ state.site.name }} needs more information to give you access to the service {{ state.service.name }}:
</p>
<form *ngIf="(answers$ | async) as answers" class="form-vertical" #answerForm="ngForm">
<form class="form-vertical" #answerForm="ngForm">
<div *ngFor="let key of (state.questionnaire | ObjKeys)" class="qa">
<div [innerHTML]="state.questionnaire[key] | MarkdownToHtml" class="question"></div>
<div [ngSwitch]="getInputType(state, key)" class="answer">
<div [innerHTML]="state.questionnaire[key] | markdown" class="question"></div>
<div [ngSwitch]="inputTypes[key]" class="answer">
<mat-form-field *ngSwitchDefault>
<input matInput matNativeControl required [type]="getInputType(state, key)" [(ngModel)]="answers[key]" [name]="key">
<input matInput matNativeControl required [type]="inputTypes[key]" [(ngModel)]="answers[key]" [name]="key">
</mat-form-field>
<mat-form-field *ngSwitchCase="'selector'">
<mat-select matNativeControl required [(ngModel)]="answers[key]" [name]="key">
......@@ -20,8 +21,10 @@
<mat-checkbox *ngSwitchCase="'checkbox'" [(ngModel)]="answers[key]" [name]="key"></mat-checkbox>
</div>
</div>
<button (click)="sendAnswers(state, answers)" color="primary" type="submit" [disabled]="!answerForm.form.valid" mat-dialog-close mat-raised-button>
Submit
</button>
<div id="button-div">
<button (click)="sendAnswers(state, answers)" color="primary" type="submit" [disabled]="!answerForm.form.valid" mat-dialog-close mat-raised-button>
Submit
</button>
</div>
</form>
</div>
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { Observable, BehaviorSubject } from 'rxjs';
import { Observable } from 'rxjs';
import { UserService } from '../../user.service';
import { Answers, DeploymentState } from '../../types/types.module';
......@@ -13,7 +13,8 @@ import { Answers, DeploymentState } from '../../types/types.module';
})
export class QuestionnaireComponent implements OnInit {
public answers$ = <BehaviorSubject<Answers>> new BehaviorSubject(undefined);
public answers: Answers;
public inputTypes: Object = new Object; // input types for the answers
constructor(
public userService: UserService,
......@@ -22,24 +23,20 @@ export class QuestionnaireComponent implements OnInit {
state$.subscribe(
(state: DeploymentState) => {
let answers: Answers;
Object.keys(state.questionnaire_answers).forEach(
(key: string) => this.inputTypes[key] = this.getInputType(state, key)
);
// initialize the answers if needed
if (state.answers === undefined) {
answers = state.questionnaire;
this.answers = state.answers;
Object.keys(state.questionnaire).forEach(
(key: string) => {
answers[key] = this.getDefaultValue(state, key);
// initialize the answers if needed
Object.keys(state.questionnaire).forEach(
(key: string) => {
if (!(key in this.answers)) {
this.answers[key] = this.getDefaultValue(state, key);
}
);
// console.log('Initialized answers');
} else {
answers = state.answers;
// console.log('Old answers:', answers);
}
this.answers$.next(answers);
}
);
}
);
}
......@@ -52,14 +49,14 @@ export class QuestionnaireComponent implements OnInit {
}
getDefaultValue(state: DeploymentState, key: string): any {
if (state.questionnaire_answers.has(key)) {
const val = state.questionnaire_answers.get(key);
if (key in state.questionnaire_answers) {
const val = state.questionnaire_answers[key];
if (Array.isArray(val)) {
return val.length > 0 ? val[0] : '';
return val.length > 0 ? val[0] : null;
}
return val;
}
return '';
return null;
}
getInputType(state: DeploymentState, key: string): string {
......
<div>
<div style="display: flex;">
<span class="centered">
<a href="/static/privacy_policy.html">FEUDAL Privacy Policy</a>
</span>
</div>
</div>
import { Component, OnInit } from '@angular/core';
@Component({
selector: '[feudal-footer]',
templateUrl: './footer.component.html',
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
::ng-deep .mat-select-panel {
max-height: 800vh !important;
}
/* abbreviate the title if its too long */
#header-long {
display: block;
}
#header-short {
display: none;
}
@media only screen and (max-width: 800px) {
#header-long {
display: none;
}
#header-short {
display: block;
}
}