[frontend] Add hoodspage dashboard component

This commit is contained in:
Cathy Hu 2020-08-25 12:59:23 +02:00
parent 88466b08eb
commit bfe4485996
16 changed files with 305 additions and 26 deletions

View file

@ -1725,6 +1725,11 @@
"integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
"dev": true
},
"@types/marked": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.1.0.tgz",
"integrity": "sha512-j8XXj6/l9kFvCwMyVqozznqpd/nk80krrW+QiIJN60Uu9gX5Pvn4/qPJ2YngQrR3QREPwmrE1f9/EWKVTFzoEw=="
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@ -3075,6 +3080,17 @@
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
"dev": true
},
"clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"optional": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@ -3225,8 +3241,7 @@
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"commondir": {
"version": "1.0.1",
@ -4142,6 +4157,12 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"optional": true
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@ -4375,6 +4396,11 @@
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"emoji-toolkit": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-6.0.1.tgz",
"integrity": "sha512-QZZq0beHg753JxcBt89UBFqzwYNuMtXhNO+jY3viSAndewmn9biTE5glaro1RA0uWJ4hKqw4k1Mboe1M6sGkMA=="
},
"emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
@ -5343,6 +5369,15 @@
"slash": "^3.0.0"
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"optional": true,
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
@ -7013,6 +7048,14 @@
"source-map-support": "^0.5.5"
}
},
"katex": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.12.0.tgz",
"integrity": "sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg==",
"requires": {
"commander": "^2.19.0"
}
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -7340,6 +7383,11 @@
"object-visit": "^1.0.0"
}
},
"marked": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.1.1.tgz",
"integrity": "sha512-mJzT8D2yPxoPh7h0UXkB+dBj4FykPJ2OIfxAWeIHrvoHDkFxukV/29QxoFQoPM6RLEwhIFdJpmKBlqVM3s2ZIw=="
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -7738,6 +7786,26 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true
},
"ngx-markdown": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-10.1.1.tgz",
"integrity": "sha512-bUVgN6asb35d5U4xM5CNfo7pSpuwqJSdTgK0PhNZzLiaiyPIK2owtLF6sWGhxTThJu+LngJPjj4MQ+AFe/s8XQ==",
"requires": {
"@types/marked": "^1.1.0",
"emoji-toolkit": "^6.0.1",
"katex": "^0.12.0",
"marked": "^1.1.0",
"prismjs": "^1.20.0",
"tslib": "^2.0.0"
},
"dependencies": {
"tslib": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz",
"integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ=="
}
}
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@ -9344,6 +9412,14 @@
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
"dev": true
},
"prismjs": {
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz",
"integrity": "sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw==",
"requires": {
"clipboard": "^2.0.0"
}
},
"process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@ -10420,6 +10496,12 @@
"ajv-keywords": "^3.4.1"
}
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"optional": true
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@ -11842,6 +11924,12 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",

View file

@ -22,6 +22,7 @@
"@angular/platform-browser": "~9.1.4",
"@angular/platform-browser-dynamic": "~9.1.4",
"@angular/router": "~9.1.4",
"ngx-markdown": "^10.1.1",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"

View file

@ -10,7 +10,11 @@ import { DashboardModule } from './dashboard/dashboard.module';
import { HoodpageComponent } from './hoodpage/hoodpage.component';
import { HoodspageComponent } from './hoodspage/hoodspage.component';
import { ApiModule } from './core/api/api.module';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import {
HttpClientModule,
HTTP_INTERCEPTORS,
HttpClient,
} from '@angular/common/http';
import { BASE_PATH } from './core/api/variables';
import { environment } from 'src/environments/environment';
import { LoginComponent } from './auth/login/login.component';
@ -20,6 +24,7 @@ import { AuthTokenInterceptor } from './core/auth/auth-token.interceptor';
import { ConfirmComponent } from './auth/confirm/confirm.component';
import { ErrorInterceptor } from './core/auth/error.interceptor';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MarkdownModule } from 'ngx-markdown';
@NgModule({
declarations: [
@ -41,6 +46,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
HttpClientModule,
ReactiveFormsModule,
BrowserAnimationsModule,
MarkdownModule.forRoot({ loader: HttpClient }),
],
providers: [
{ provide: BASE_PATH, useValue: environment.API_BASE_PATH },

View file

@ -1,18 +1,23 @@
<div class="back">
<a mat-button [routerLink]="['/dashboard']"
><mat-icon>keyboard_backspace</mat-icon> back</a
>
</div>
<div class="dashboard">
<mat-card>
<mat-card-title> Dashboard: {{ (hood$ | async).name }} </mat-card-title>
<mat-card-subtitle>Lorem ipsum</mat-card-subtitle>
<mat-card-title> Hood: {{ (hood$ | async).name }} </mat-card-title>
<mat-card-subtitle>Dashboard</mat-card-subtitle>
</mat-card>
<mat-tab-group>
<mat-tab label="Overview">
<mat-tab label="Filters">
<app-hoodsettings [hoodId]="hoodId"> </app-hoodsettings>
</mat-tab>
<mat-tab label="Platforms">
<app-platforms></app-platforms>
</mat-tab>
<mat-tab label="Hoodpage">
<app-hoodpage></app-hoodpage>
<app-hoodpage [hoodId]="hoodId"></app-hoodpage>
</mat-tab>
</mat-tab-group>
</div>

View file

@ -5,3 +5,7 @@
.dashboard {
margin: 10px;
}
.back {
color: grey;
}

View file

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HoodsService, BodyHood } from 'src/app/core/api';
import { first } from 'rxjs/operators';

View file

@ -1 +1,61 @@
<p>hoodpage works!</p>
<div class="settings">
<div class="explanation">
<mat-accordion>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>info</mat-icon>
<div class="info-title">How to configure the public hood page</div>
</mat-panel-title>
</mat-expansion-panel-header>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis
malesuada orci justo, id cursus orci bibendum ac. Nulla ut sapien a
dolor sodales facilisis at ac lacus. Nam nulla felis, malesuada id
pharetra varius, congue luctus magna. Duis et tellus pretium, euismod
ipsum nec, fringilla orci. Sed dapibus at velit id posuere. Aenean at
nunc sed arcu malesuada dapibus. Nunc quis rutrum diam. Morbi placerat
diam sit amet tincidunt hendrerit. Cras viverra, tortor sed congue
congue, dui ante lobortis purus, quis elementum tortor nulla vel mi.
Etiam nec leo consectetur lorem fringilla commodo. Duis lectus est,
vulputate sit amet ipsum eget, efficitur condimentum diam. Duis eget
quam est. Ut et semper turpis. Aliquam eget fermentum sem.
</p>
</mat-expansion-panel>
</mat-accordion>
</div>
<div class="buttonbar">
<div *ngIf="!saved && submit" class="saved-button">
<mat-icon>warning</mat-icon>
</div>
<div *ngIf="saved" class="saved-button">
<mat-icon>done</mat-icon>
</div>
<button
mat-raised-button
color="primary"
class="save-button"
(click)="onSubmit()"
>
Save
</button>
<a
mat-icon-button
[routerLink]="['/hoods', hoodId]"
target="_blank"
aria-label="Open in new tab"
>
<mat-icon>open_in_new</mat-icon>
</a>
</div>
<div class="container">
<textarea
class="textarea"
matInput
[(ngModel)]="markdown"
wrap="soft"
(change)="onChange()"
></textarea>
<markdown class="markdown" [data]="markdown"></markdown>
</div>
</div>

View file

@ -0,0 +1,54 @@
.container {
display: grid;
margin: 10px;
grid-template-columns: 1fr 1fr;
gap: 10px;
align-items: stretch;
justify-items: stretch;
@media (max-width: 600px) {
grid-template-columns: 1fr;
grid-template-rows: 1fr 1fr;
}
}
.info-title {
margin-top: 2px;
margin-left: 10px;
}
.textarea {
box-sizing: border-box;
resize: none;
max-width: 100%;
max-height: 100%;
min-height: 200px;
border: thin dotted gray;
padding: 10px;
}
.markdown {
box-sizing: border-box;
border: thin solid black;
background-color: #fafafa;
padding: 10px;
}
.explanation {
margin-top: 20px;
margin-bottom: 20px;
}
.buttonbar {
margin: 10px;
display: flex;
justify-content: flex-end;
}
.settings {
margin: 1%;
}
.saved-button {
margin: 7px;
color: green;
}

View file

@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { HoodsService, BodyHood } from 'src/app/core/api';
import { first } from 'rxjs/operators';
@Component({
selector: 'app-hoodpage',
@ -6,7 +8,44 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./hoodpage.component.scss'],
})
export class HoodpageComponent implements OnInit {
constructor() {}
@Input() hoodId: number;
saved = false;
submit = false;
hood: BodyHood;
ngOnInit(): void {}
constructor(private hoodService: HoodsService) {}
markdown = `# TODO Hoodpage`;
ngOnInit(): void {
this.hoodService.getHood(this.hoodId).subscribe((hood) => {
if (hood) {
this.hood = hood;
if (hood.landingpage && hood.landingpage !== '') {
this.markdown = hood.landingpage;
}
}
});
}
onSubmit() {
this.submit = true;
this.hood.landingpage = this.markdown;
this.hoodService
.updateHood(this.hoodId, this.hood)
.pipe(first())
.subscribe(
(data) => {
this.saved = true;
},
(error) => {
this.saved = false;
}
);
}
onChange() {
this.saved = false;
this.submit = false;
}
}

View file

@ -54,7 +54,6 @@ export class BadwordsComponent implements OnInit {
this.reload();
},
(error) => {
console.log(error);
this.regexForm.controls['regex'].setErrors({ incorrect: true });
}
);

View file

@ -5,19 +5,20 @@
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon>info</mat-icon>
<div class="info-title">
How to use triggers and badwords to filter messages
</div>
</mat-panel-title>
<mat-panel-description>
How to use triggers and badwords to filter messages
</mat-panel-description>
</mat-expansion-panel-header>
<p>
To avoid misuse of the service, some safety mechanisms are in place.
For a message to be shared, it needs to contain
<strong>at least one trigger word</strong>. Additionally, <strong>no badwords
may occur in the message</strong>. Therefore triggers are words that only
appear in legitimate messages. Badwords on the other hand, are words
that completely discard the message, even if the remaining message is
legitimate. For example insults or spam words like "blockchain".
<strong>at least one trigger word</strong>. Additionally,
<strong>no badwords may occur in the message</strong>. Therefore
triggers are words that only appear in legitimate messages. Badwords
on the other hand, are words that completely discard the message, even
if the remaining message is legitimate. For example insults or spam
words like "blockchain".
</p>
</mat-expansion-panel>
</mat-accordion>

View file

@ -17,3 +17,8 @@
margin-top: 20px;
margin-bottom: 20px;
}
.info-title {
margin-top: 2px;
margin-left: 10px;
}

View file

@ -11,6 +11,8 @@ import { TriggerComponent } from './board/hoodsettings/trigger/trigger.component
import { BadwordsComponent } from './board/hoodsettings/badwords/badwords.component';
import { SharedModule } from '../shared/shared.module';
import { CommonModule } from '@angular/common';
import { MarkdownModule } from 'ngx-markdown';
import { HttpClient } from '@angular/common/http';
@NgModule({
declarations: [
@ -23,6 +25,12 @@ import { CommonModule } from '@angular/common';
TriggerComponent,
BadwordsComponent,
],
imports: [DashboardRoutingModule, MaterialModule, SharedModule, CommonModule],
imports: [
DashboardRoutingModule,
MaterialModule,
SharedModule,
CommonModule,
MarkdownModule.forRoot({ loader: HttpClient }),
],
})
export class DashboardModule {}

View file

@ -1,3 +1,5 @@
<p>hoodpage works!</p>
<h1>
{{ hood.name }}
</h1>
{{ hood.landingpage }}
<markdown class="markdown" [data]="hood.landingpage"></markdown>

View file

@ -2,16 +2,19 @@ import { NgModule } from '@angular/core';
import { ToolbarComponent } from './toolbar/toolbar.component';
import { MaterialModule } from './material/material.module';
import { NotFoundComponent } from './not-found/not-found.component';
import { ReactiveFormsModule } from '@angular/forms';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { MarkdownModule } from 'ngx-markdown';
import { HttpClient } from '@angular/common/http';
@NgModule({
declarations: [ToolbarComponent, NotFoundComponent],
imports: [MaterialModule, ReactiveFormsModule],
imports: [MaterialModule, ReactiveFormsModule, FormsModule],
exports: [
ToolbarComponent,
NotFoundComponent,
MaterialModule,
ReactiveFormsModule,
FormsModule,
],
})
export class SharedModule {}

View file

@ -8,3 +8,7 @@ body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.mat-tab-body-content {
overflow: hidden !important;
}