From e9c58608108a98660fa976b7a61835f663f6aa2b Mon Sep 17 00:00:00 2001 From: Eamon Bauman Date: Wed, 9 Jun 2021 11:15:08 -0500 Subject: [PATCH] Ability to print scenarios from UI (#76) * added ngx-markdown as dependency * added printable endpoint * added printable component * printable component and ngx-markdown init * routing for printable page * printable button --- package-lock.json | 85 ++++++++++++++++++- package.json | 1 + src/app/app-routing.module.ts | 8 ++ src/app/app.module.ts | 12 ++- src/app/data/scenario.service.ts | 4 + src/app/printable/printable.component.html | 1 + src/app/printable/printable.component.scss | 0 src/app/printable/printable.component.spec.ts | 25 ++++++ src/app/printable/printable.component.ts | 38 +++++++++ src/app/scenario/scenario.component.html | 3 + 10 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 src/app/printable/printable.component.html create mode 100644 src/app/printable/printable.component.scss create mode 100644 src/app/printable/printable.component.spec.ts create mode 100644 src/app/printable/printable.component.ts diff --git a/package-lock.json b/package-lock.json index 83af2fa8..5f1d3461 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3201,6 +3201,11 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "@types/marked": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.2.2.tgz", + "integrity": "sha512-wLfw1hnuuDYrFz97IzJja0pdVsC0oedtS4QsKH1/inyW9qkLQbXgMUqEQT0MVtUBx3twjWeInUfjQbhBVLECXw==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -4716,6 +4721,17 @@ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true }, + "clipboard": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", + "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -4913,8 +4929,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", @@ -5805,6 +5820,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 + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -6077,6 +6098,11 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "emoji-toolkit": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-6.5.1.tgz", + "integrity": "sha512-oY5E81cXvRUxXkbVgOI8NxYHKF5FeWfJhFCIYUKhbVfSmdCH8+bmJzgDdhufExa7t1+WEzpUFdHwYxJTXS90vQ==" + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -7247,6 +7273,15 @@ "minimatch": "~3.0.2" } }, + "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", @@ -8907,6 +8942,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", @@ -9374,6 +9417,11 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -9822,6 +9870,19 @@ "dragula": "^3.7.2" } }, + "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" + } + }, "ngx-markdown-editor": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ngx-markdown-editor/-/ngx-markdown-editor-2.5.0.tgz", @@ -11763,6 +11824,14 @@ "utila": "~0.4" } }, + "prismjs": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", + "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", + "requires": { + "clipboard": "^2.0.0" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -13038,6 +13107,12 @@ } } }, + "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", @@ -14378,6 +14453,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", diff --git a/package.json b/package.json index 044426f6..19060c0e 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "lodash-es": "^4.17.15", "moment": "^2.24.0", "ng2-dragula": "^2.1.1", + "ngx-markdown": "^10.1.1", "ngx-markdown-editor": "^2.5.0", "rxjs": "^6.5.4", "tslib": "^2.0.0", diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index a66d8f18..0c36820a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -10,6 +10,7 @@ import { ConfigurationComponent } from './configuration/configuration.component' import { EnvironmentsComponent } from './configuration/environments/environments.component'; import { ContentComponent } from './content/content.component'; import { CourseComponent } from './course/course.component'; +import { PrintableComponent } from './printable/printable.component'; const routes: Routes = [ {path: '', redirectTo: '/home', pathMatch: 'full'}, @@ -64,6 +65,13 @@ const routes: Routes = [ component: EnvironmentsComponent } ] + }, + { + path: 'scenario/:scenario/printable', + component: PrintableComponent, + canActivate: [ + AuthGuard + ] } ]; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2ab8fa54..edbf3543 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,5 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { NgModule, CUSTOM_ELEMENTS_SCHEMA, SecurityContext } from '@angular/core'; import '@clr/icons'; import '@clr/icons/shapes/all-shapes'; import { AppRoutingModule } from './app-routing.module'; @@ -37,6 +37,8 @@ import { DeleteConfirmationComponent } from './delete-confirmation/delete-confir import { EventStatusFilterComponent } from './event/event-status-filter/event-status-filter.component'; import { EditUserComponent } from './user/edit-user/edit-user.component'; import { EditAccessCodesComponent } from './user/edit-access-codes/edit-access-codes.component'; +import { PrintableComponent } from './printable/printable.component'; +import { MarkdownModule } from 'ngx-markdown'; export function jwtOptionsFactory() { return { @@ -77,7 +79,8 @@ export function jwtOptionsFactory() { DeleteConfirmationComponent, EventStatusFilterComponent, EditUserComponent, - EditAccessCodesComponent + EditAccessCodesComponent, + PrintableComponent ], imports: [ BrowserModule, @@ -97,7 +100,10 @@ export function jwtOptionsFactory() { } }), BrowserAnimationsModule, - DragulaModule.forRoot() + DragulaModule.forRoot(), + MarkdownModule.forRoot({ + sanitize: SecurityContext.NONE + }) ], providers: [ ScenarioService diff --git a/src/app/data/scenario.service.ts b/src/app/data/scenario.service.ts index df172ef5..3679d764 100644 --- a/src/app/data/scenario.service.ts +++ b/src/app/data/scenario.service.ts @@ -105,4 +105,8 @@ export class ScenarioService { return this.http.post(environment.server + "/a/scenario/new", params) } + + public printable(id: string) { + return this.http.get(environment.server + "/a/scenario/" + id + "/printable", {responseType: 'text'}) + } } diff --git a/src/app/printable/printable.component.html b/src/app/printable/printable.component.html new file mode 100644 index 00000000..1c3dc876 --- /dev/null +++ b/src/app/printable/printable.component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/app/printable/printable.component.scss b/src/app/printable/printable.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/printable/printable.component.spec.ts b/src/app/printable/printable.component.spec.ts new file mode 100644 index 00000000..35360211 --- /dev/null +++ b/src/app/printable/printable.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PrintableComponent } from './printable.component'; + +describe('PrintableComponent', () => { + let component: PrintableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PrintableComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PrintableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/printable/printable.component.ts b/src/app/printable/printable.component.ts new file mode 100644 index 00000000..a3b5e5e2 --- /dev/null +++ b/src/app/printable/printable.component.ts @@ -0,0 +1,38 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { first, switchMap } from 'rxjs/operators'; +import { ScenarioService } from '../data/scenario.service'; + +@Component({ + selector: 'app-printable', + templateUrl: './printable.component.html', + styleUrls: ['./printable.component.scss'] +}) +export class PrintableComponent implements OnInit { + + public scenario: string = ""; + + constructor( + public route: ActivatedRoute, + public scenarioService: ScenarioService + ) {} + + ngOnInit(): void { + this.route.paramMap + .pipe( + first(), + switchMap((p: ParamMap) => { + return this.scenarioService.printable(p.get("scenario")) + }) + ).subscribe( + (content: any) => { + this.scenario = content; + }, + (error: HttpErrorResponse) => { + this.scenario = "There was an error rendering printable scenario content: " + error.message + } + ) + } + +} diff --git a/src/app/scenario/scenario.component.html b/src/app/scenario/scenario.component.html index 2f8fd09c..4d9889e6 100644 --- a/src/app/scenario/scenario.component.html +++ b/src/app/scenario/scenario.component.html @@ -119,6 +119,9 @@

Scenarios

+ + +