diff --git a/Dockerfile b/Dockerfile index 1cedae5..ef32b0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,6 @@ RUN echo "pushstate: enabled" > /etc/nginx/html/Staticfile # then starts/reloads nginx. ENTRYPOINT ["./entrypoint.sh", \ "/etc/nginx/html/index.html,/etc/nginx/conf.d/default.conf", \ - "PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,DEPLOY_URL,PORT0", \ + "PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,DEPLOY_URL,PORT0,GOOGLE_ANALYTICS_KEY,SENTRY_KEY,TITLE", \ "/etc/nginx/html", \ "true"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4fb688f..6a5c4e7 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,14 +1,20 @@ version: "3.3" services: + ldap: + container_name: ldap + image: tuxmonteiro/ldap-mock + ports: + - "3890:3890" + db: container_name: db - image: sartography/cr-connect-db:dev + image: sartography/cr-connect-db:$E2E_TAG ports: - "5432:5432" environment: - - POSTGRES_USER=rrt_user - - POSTGRES_PASSWORD=rrt_pass - - POSTGRES_MULTIPLE_DATABASES=rrt + - POSTGRES_USER=crc_user + - POSTGRES_PASSWORD=crc_pass + - POSTGRES_MULTIPLE_DATABASES=crc_test,pb_test healthcheck: test: ["CMD", "pg_isready"] timeout: 20s @@ -18,52 +24,73 @@ services: container_name: backend depends_on: - db - image: sartography/cr-connect-workflow:dev + image: sartography/cr-connect-workflow:$E2E_TAG environment: - - APPLICATION_ROOT=/api + - APPLICATION_ROOT=/ - CORS_ALLOW_ORIGINS=localhost:5002,bpmn:5002,localhost:4200,frontend:4200 - DB_HOST=db - - DB_NAME=rrt - - DB_PASSWORD=rrt_pass + - DB_NAME=crc_test + - DB_PASSWORD=crc_pass - DB_PORT=5432 - - DB_USER=rrt_user - - LDAP_URL=ldap.virginia.edu - - PB_ENABLED=false + - DB_USER=crc_user + - LDAP_URL=ldap + - PB_ENABLED=true + - PB_BASE_URL=http://pb:5001/v2.0/ - PORT0=5000 - RESET_DB=true - UPGRADE_DB=true + - TESTING=true ports: - "5000:5000" command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh - bpmn: - container_name: bpmn + pb: + container_name: pb depends_on: - db - - backend - image: sartography/cr-connect-bpmn:dev + image: sartography/protocol-builder-mock:$E2E_TAG environment: - - API_URL=http://localhost:5000/api/v1.0 - - BASE_HREF=/bpmn/ - - DEPLOY_URL=/bpmn/ - - HOME_ROUTE=home - - PORT0=5002 - - PRODUCTION=false + - APPLICATION_ROOT=/ + - CORS_ALLOW_ORIGINS=localhost:5000,backend:5000,localhost:5002,bpmn:5002,localhost:4200,frontend:4200 + - DB_HOST=db + - DB_NAME=pb_test + - DB_PASSWORD=crc_pass + - DB_PORT=5432 + - DB_USER=crc_user + - PORT0=5001 + - UPGRADE_DB=true ports: - - "5002:5002" + - "5001:5001" + command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh - frontend: - container_name: frontend - depends_on: - - db - - backend - image: sartography/cr-connect-frontend:dev - environment: - - API_URL=http://localhost:5000/api/v1.0 - - BASE_HREF=/app/ - - DEPLOY_URL=/app/ - - HOME_ROUTE=home - - PORT0=4200 - - PRODUCTION=false - ports: - - "4200:4200" +# bpmn: +# container_name: bpmn +# depends_on: +# - db +# - backend +# image: sartography/cr-connect-bpmn:dev +# environment: +# - API_URL=http://localhost:5000/api/v1.0 +# - BASE_HREF=/bpmn/ +# - DEPLOY_URL=/bpmn/ +# - HOME_ROUTE=home +# - PORT0=5002 +# - PRODUCTION=false +# ports: +# - "5002:5002" +# +# frontend: +# container_name: frontend +# depends_on: +# - db +# - backend +# image: sartography/cr-connect-frontend:dev +# environment: +# - API_URL=http://localhost:5000/api/v1.0 +# - BASE_HREF=/app/ +# - DEPLOY_URL=/app/ +# - HOME_ROUTE=home +# - PORT0=4200 +# - PRODUCTION=false +# ports: +# - "4200:4200" diff --git a/package-lock.json b/package-lock.json index e6b4544..15db4d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3138,6 +3138,63 @@ } } }, + "@sentry/browser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.16.1.tgz", + "integrity": "sha512-uXXKRGLWDqwaKO09K1GTTV0Yj+OfELVs+0cDDYqPDow+DlIXyx0gSnZPd0caCqFllUy8JSxb4S9OprYinvks2A==", + "requires": { + "@sentry/core": "5.16.1", + "@sentry/types": "5.16.1", + "@sentry/utils": "5.16.1", + "tslib": "^1.9.3" + } + }, + "@sentry/core": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.16.1.tgz", + "integrity": "sha512-CDKUAUWefZ+bx7tUGm7pgkuJbwn+onAlwzKkLGVg730IP+N/AWSpVtbvFTPiel2+NPiFhWX5/F0SpxDMLPRKfg==", + "requires": { + "@sentry/hub": "5.16.1", + "@sentry/minimal": "5.16.1", + "@sentry/types": "5.16.1", + "@sentry/utils": "5.16.1", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.16.1.tgz", + "integrity": "sha512-Og4zxp0lM9yS6TyKbZ5lQR94f/fNOalodm71Dk4qfBWi0OzfFCVpO4fPOhHtbXEsvMNg5xh0Pe8ezqX3CZ3hTw==", + "requires": { + "@sentry/types": "5.16.1", + "@sentry/utils": "5.16.1", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.16.1.tgz", + "integrity": "sha512-RCwEKLneV5BQlv1MEmsCR3I5jajHgVGusBgwGgnFv+4Cn4cNC7OHWH4QbuZ3IHOEHJl7YS074BeluM+7jn0+Tw==", + "requires": { + "@sentry/hub": "5.16.1", + "@sentry/types": "5.16.1", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.16.1.tgz", + "integrity": "sha512-uERNhBdsiWvWG7qTC9QVsvFmOSL8rFfy8usEXeH3l4oCQao9TvGUvXJv6gRfiWmoiJZ1A0608Lj15CORygdbng==" + }, + "@sentry/utils": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.16.1.tgz", + "integrity": "sha512-hn2jTc6ZH1lXGij7yqkV6cGhEYxsdjqB5P4MjfrRHB5bk5opY9R89bsAhs1rpanTdwv6Ul0ieR1z18gdIgUf0g==", + "requires": { + "@sentry/types": "5.16.1", + "tslib": "^1.9.3" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -12299,9 +12356,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sartography-workflow-lib": { - "version": "0.0.213", - "resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.213.tgz", - "integrity": "sha512-2y4UQk3zYeY0Xu3wqq3UptORxVN/Dp8MPyr7JMNBjM9XCdoDL+nIyhpOA7pS+VfraoEzbm9m4CQamQ9YSGRu6w==" + "version": "0.0.265", + "resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.265.tgz", + "integrity": "sha512-cb1Wc09m83hgpjz7d60KHGDjHvrpq6oZns8lL+kgjFUrGwsL8lRxwsjt1cOGMnCTzi48icybEogvSsluhU7RhA==" }, "sass": { "version": "1.23.3", diff --git a/package.json b/package.json index e33ae8c..de3ad60 100644 --- a/package.json +++ b/package.json @@ -12,16 +12,12 @@ "test:coverage": "ng test --codeCoverage=true --watch=false --browsers=ChromeHeadless", "lint": "ng lint", "e2e": "./node_modules/protractor/bin/webdriver-manager update && ng e2e", - "e2e:with-wf": "npm run e2e-wf && ng e2e && npm run e2e-wf:stop && npm run e2e-wf:clean", - "e2e-wf:stop": "docker stop db || true && docker stop backend || true && docker stop pb || true", - "e2e-wf:clean": "docker system prune -f && cd docker && docker-compose rm -f -v -s && cd ..", - "e2e-wf:build": "cd docker && docker-compose pull && docker-compose build --no-cache && cd ..", - "e2e-wf:start": "cd docker && docker-compose up -d && cd ..", - "e2e-wf:db-upgrade": "docker exec -it backend pipenv run flask db upgrade", - "e2e-wf:db-setup": "docker exec -it backend pipenv run flask load-example-data", - "e2e-wf:pb-setup": "docker exec -it pb pipenv run flask db upgrade", - "e2e-wf": "npm run e2e-wf:stop && npm run e2e-wf:clean && npm run e2e-wf:build && npm run e2e-wf:start && npm run e2e-wf:db-upgrade && npm run e2e-wf:db-setup && npm run e2e-wf:pb-setup", - "env": "chmod +x ./docker/substitute-env-variables.sh && ./docker/substitute-env-variables.sh src/index.html PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,PORT0", + "e2e:with-wf": "npm run e2e-wf && ng e2e && npm run e2e-wf:stop", + "e2e-wf:stop": "cd docker && docker-compose down && cd ..", + "e2e-wf:build": "cd docker && docker-compose pull && docker-compose build && cd ..", + "e2e-wf:start": "cd docker && docker-compose up -d --force-recreate && cd ..", + "e2e-wf": "npm run e2e-wf:stop && npm run e2e-wf:build && npm run e2e-wf:start", + "env": "chmod +x ./docker/substitute-env-variables.sh && ./docker/substitute-env-variables.sh src/index.html PRODUCTION,API_URL,IRB_URL,HOME_ROUTE,BASE_HREF,DEPLOY_URL,PORT0,GOOGLE_ANALYTICS_KEY,SENTRY_KEY,TITLE", "ci": "npm run lint && npm run test:coverage && sonar-scanner" }, "private": true, @@ -39,6 +35,7 @@ "@angular/router": "^9.0.7", "@ngx-formly/core": "^5.5.15", "@ngx-formly/material": "^5.5.15", + "@sentry/browser": "^5.16.1", "@yellowspot/ng-truncate": "^1.5.1", "bpmn-js": "^6.4.2", "bpmn-js-properties-panel": "^0.33.2", @@ -54,7 +51,7 @@ "ngx-file-drop": "^8.0.8", "ngx-markdown": "^9.0.0", "rxjs": "~6.5.4", - "sartography-workflow-lib": "0.0.213", + "sartography-workflow-lib": "0.0.265", "tslib": "^1.11.1", "uuid": "^7.0.2", "zone.js": "^0.10.3" diff --git a/src/app/_interfaces/dialog-data.ts b/src/app/_interfaces/dialog-data.ts index cd0dea0..48ce9db 100644 --- a/src/app/_interfaces/dialog-data.ts +++ b/src/app/_interfaces/dialog-data.ts @@ -1,5 +1,4 @@ import {FileMeta, FileType, WorkflowSpec, WorkflowSpecCategory} from 'sartography-workflow-lib'; -import {ApiError} from 'sartography-workflow-lib/lib/types/api'; export interface FileMetaDialogData { id?: number; @@ -49,7 +48,3 @@ export interface DeleteWorkflowSpecCategoryDialogData { confirm: boolean; category: WorkflowSpecCategory; } - -export interface ApiErrorsBottomSheetData { - apiErrors: ApiError[]; -} diff --git a/src/app/api-errors/api-errors.component.html b/src/app/api-errors/api-errors.component.html deleted file mode 100644 index f51de56..0000000 --- a/src/app/api-errors/api-errors.component.html +++ /dev/null @@ -1,21 +0,0 @@ -
-

Workflow Specification Errors

- - -
- - -

{{e.code}}

-

{{e.status_code}}

-
{{e.task_name}} ({{e.task_id}})
-
Task ID: {{e.task_id}}
-
Task Name: {{e.task_name}}
-
File: {{e.file_name}}
-
Tag: {{e.tag}}
- -
- {{e.message}} -
-
-
-
diff --git a/src/app/api-errors/api-errors.component.scss b/src/app/api-errors/api-errors.component.scss deleted file mode 100644 index eda4773..0000000 --- a/src/app/api-errors/api-errors.component.scss +++ /dev/null @@ -1,16 +0,0 @@ -@import "../../config"; - -::ng-deep mat-list-item.api-error, mat-list-item.api-error:hover { - border-left: 4px solid $brand-warning; - background-color: $brand-warning-light; - cursor: default; - - .mat-line { - text-overflow: initial; - height: auto; - - code { - white-space: normal; - } - } -} diff --git a/src/app/api-errors/api-errors.component.spec.ts b/src/app/api-errors/api-errors.component.spec.ts deleted file mode 100644 index 73864c4..0000000 --- a/src/app/api-errors/api-errors.component.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetRef} from '@angular/material/bottom-sheet'; -import {MatIconModule} from '@angular/material/icon'; -import {MatListModule} from '@angular/material/list'; - -import { ApiErrorsComponent } from './api-errors.component'; - -describe('ApiErrorsComponent', () => { - let component: ApiErrorsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - ApiErrorsComponent - ], - imports: [ - MatIconModule, - MatListModule, - ], - providers: [ - { - provide: MatBottomSheetRef, - useValue: { - dismiss: (dialogResult: any) => { - } - } - }, - {provide: MAT_BOTTOM_SHEET_DATA, useValue: {apiErrors: [{ - status_code: 400, - code: 'error_code' - }]}}, - ] - - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ApiErrorsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - expect(component.data).toBeTruthy(); - expect(component.apiErrors).toBeTruthy(); - }); - - it('should dismiss', () => { - const dismissSpy = spyOn((component as any)._bottomSheetRef, 'dismiss').and.stub(); - component.dismiss(new MouseEvent('click')); - expect(dismissSpy).toHaveBeenCalled(); - }); - -}); diff --git a/src/app/api-errors/api-errors.component.ts b/src/app/api-errors/api-errors.component.ts deleted file mode 100644 index af16458..0000000 --- a/src/app/api-errors/api-errors.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {MAT_BOTTOM_SHEET_DATA, MatBottomSheetRef} from '@angular/material/bottom-sheet'; -import {ApiError} from 'sartography-workflow-lib/lib/types/api'; -import {ApiErrorsBottomSheetData} from '../_interfaces/dialog-data'; - -@Component({ - selector: 'app-api-errors', - templateUrl: './api-errors.component.html', - styleUrls: ['./api-errors.component.scss'] -}) -export class ApiErrorsComponent implements OnInit { - apiErrors: ApiError[]; - - constructor( - @Inject(MAT_BOTTOM_SHEET_DATA) public data: ApiErrorsBottomSheetData, - private _bottomSheetRef: MatBottomSheetRef - ) { - if (data && data.apiErrors && data.apiErrors.length > 0) { - this.apiErrors = data.apiErrors; - } - } - - ngOnInit(): void { - } - - dismiss(event: MouseEvent) { - this._bottomSheetRef.dismiss(); - event.preventDefault(); - } -} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 2f759e1..ca7543e 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -15,6 +15,8 @@ export class ThisEnvironment implements AppEnvironment { api = environment.api; irbUrl = environment.irbUrl; title = environment.title; + googleAnalyticsKey = environment.googleAnalyticsKey; + sentryKey = environment.sentryKey; } const routes: Routes = [ diff --git a/src/app/app.component.html b/src/app/app.component.html index 80ac792..aafc157 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,5 +1,5 @@
- +
diff --git a/src/app/app.component.scss b/src/app/app.component.scss index e25ee2c..e69de29 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,7 +0,0 @@ -#globalHeader { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 2; -} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index e619fbd..b583860 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,61 +1,57 @@ import {APP_BASE_HREF} from '@angular/common'; import {HttpClient} from '@angular/common/http'; import {HttpClientTestingModule} from '@angular/common/http/testing'; -import {Component} from '@angular/core'; import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {MatIconModule} from '@angular/material/icon'; +import {FakeMatIconRegistry} from '@angular/material/icon/testing'; +import {MatMenuModule} from '@angular/material/menu'; import {RouterTestingModule} from '@angular/router/testing'; import {ApiService, MockEnvironment} from 'sartography-workflow-lib'; import {AppComponent} from './app.component'; - - -@Component({ - selector: 'app-navbar', - template: '' -}) -class MockNavbarComponent { -} - -@Component({ - selector: 'app-footer', - template: '' -}) -class MockFooterComponent { -} +import {FooterComponent} from './footer/footer.component'; +import {NavbarComponent} from './navbar/navbar.component'; describe('AppComponent', () => { let component: AppComponent; let fixture: ComponentFixture; + const mockEnvironment = new MockEnvironment(); + const mockTitle = `'Once,' said the Mock Title at last, with a deep sigh, 'I was a real Title.'`; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ AppComponent, - MockNavbarComponent, - MockFooterComponent + FooterComponent, + NavbarComponent, ], imports: [ HttpClientTestingModule, - BrowserAnimationsModule, + MatIconModule, + MatMenuModule, RouterTestingModule, ], providers: [ HttpClient, + FakeMatIconRegistry, ApiService, - {provide: 'APP_ENVIRONMENT', useClass: MockEnvironment}, + {provide: 'APP_ENVIRONMENT', useValue: mockEnvironment}, {provide: APP_BASE_HREF, useValue: ''}, - ], - }) - .compileComponents(); + ] + }).compileComponents(); })); beforeEach(() => { + mockEnvironment.title = mockTitle; fixture = TestBed.createComponent(AppComponent); component = fixture.componentInstance; fixture.detectChanges(); }); - it('should create', () => { + it('should create the app', () => { expect(component).toBeTruthy(); }); + + it(`should set the page title to match environment variable`, () => { + expect((component as any).titleService.getTitle()).toEqual(mockTitle); + }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a1d377a..80ba960 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,7 @@ -import {Component} from '@angular/core'; -import {ApiService} from 'sartography-workflow-lib'; +import {Component, Inject} from '@angular/core'; +import {MatIconRegistry} from '@angular/material/icon'; +import {DomSanitizer, Title} from '@angular/platform-browser'; +import {AppEnvironment, FileType, GoogleAnalyticsService} from 'sartography-workflow-lib'; @Component({ selector: 'app-root', @@ -7,12 +9,19 @@ import {ApiService} from 'sartography-workflow-lib'; styleUrls: ['./app.component.scss'] }) export class AppComponent { - title = 'CR Connect Configuration'; - - constructor(private apiService: ApiService) { - } - - get isSignedIn() { - return this.apiService.isSignedIn(); + constructor( + @Inject('APP_ENVIRONMENT') private environment: AppEnvironment, + private titleService: Title, + private matIconRegistry: MatIconRegistry, + private domSanitizer: DomSanitizer, + private googleAnalyticsService: GoogleAnalyticsService, + ) { + this.googleAnalyticsService.init(this.environment.googleAnalyticsKey); + const fileTypes = Object.values(FileType); + fileTypes.forEach(t => { + const url = this.domSanitizer.bypassSecurityTrustResourceUrl(`assets/icons/file_types/${t}.svg`); + this.matIconRegistry.addSvgIconInNamespace('crc', t, url); + }); + this.titleService.setTitle(this.environment.title); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7521467..e890441 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -38,7 +38,6 @@ import {OpenFileDialogComponent} from './_dialogs/open-file-dialog/open-file-dia import {WorkflowSpecCategoryDialogComponent} from './_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component'; import {WorkflowSpecDialogComponent} from './_dialogs/workflow-spec-dialog/workflow-spec-dialog.component'; import {GetIconCodePipe} from './_pipes/get-icon-code.pipe'; -import {ApiErrorsComponent} from './api-errors/api-errors.component'; import {AppRoutingModule} from './app-routing.module'; import {AppComponent} from './app.component'; import {DiagramComponent} from './diagram/diagram.component'; @@ -59,6 +58,8 @@ export class ThisEnvironment implements AppEnvironment { api = environment.api; irbUrl = environment.irbUrl; title = environment.title; + googleAnalyticsKey = environment.googleAnalyticsKey; + sentryKey = environment.sentryKey; } /** @@ -96,7 +97,6 @@ export function getBaseHref(platformLocation: PlatformLocation): string { WorkflowSpecListComponent, HomeComponent, WorkflowSpecCardComponent, - ApiErrorsComponent, ProtocolBuilderComponent, ReferenceFilesComponent, ], @@ -128,7 +128,6 @@ export function getBaseHref(platformLocation: PlatformLocation): string { ], bootstrap: [AppComponent], entryComponents: [ - ApiErrorsComponent, DeleteFileDialogComponent, DeleteWorkflowSpecDialogComponent, DeleteWorkflowSpecCategoryDialogComponent, diff --git a/src/app/modeler/modeler.component.ts b/src/app/modeler/modeler.component.ts index 6d53c8a..60b9914 100644 --- a/src/app/modeler/modeler.component.ts +++ b/src/app/modeler/modeler.component.ts @@ -5,6 +5,7 @@ import {MatDialog} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; import {ActivatedRoute, Params, Router} from '@angular/router'; import { + ApiErrorsComponent, ApiService, FileMeta, FileType, @@ -19,7 +20,6 @@ import {OpenFileDialogComponent} from '../_dialogs/open-file-dialog/open-file-di import {BpmnWarning} from '../_interfaces/bpmn-warning'; import {FileMetaDialogData, NewFileDialogData, OpenFileDialogData} from '../_interfaces/dialog-data'; import {ImportEvent} from '../_interfaces/import-event'; -import {ApiErrorsComponent} from '../api-errors/api-errors.component'; import {DiagramComponent} from '../diagram/diagram.component'; @Component({ diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts index 7e1af1c..288ba4c 100644 --- a/src/app/navbar/navbar.component.ts +++ b/src/app/navbar/navbar.component.ts @@ -1,6 +1,6 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {Component, Inject} from '@angular/core'; import {Router} from '@angular/router'; -import {ApiService, AppEnvironment, isSignedIn, User, UserParams} from 'sartography-workflow-lib'; +import {ApiService, AppEnvironment, GoogleAnalyticsService, isSignedIn, User} from 'sartography-workflow-lib'; interface NavItem { path?: string; @@ -25,6 +25,7 @@ export class NavbarComponent { private router: Router, private api: ApiService, @Inject('APP_ENVIRONMENT') private environment: AppEnvironment, + private googleAnalyticsService: GoogleAnalyticsService ) { this._loadUser(); this.title = environment.title; @@ -38,6 +39,11 @@ export class NavbarComponent { if (isSignedIn()) { this.api.getUser().subscribe(u => { this.user = u; + + if (this.user && this.user.uid) { + this.googleAnalyticsService.setUser(this.user.uid); + } + this._loadNavLinks(); }, error => { localStorage.removeItem('token'); diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts b/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts index fd65069..f9fe120 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts +++ b/src/app/workflow-spec-list/workflow-spec-list.component.spec.ts @@ -13,6 +13,7 @@ import {RouterTestingModule} from '@angular/router/testing'; import createClone from 'rfdc'; import {of} from 'rxjs'; import { + ApiErrorsComponent, ApiService, MockEnvironment, mockWorkflowSpec0, @@ -34,7 +35,6 @@ import { WorkflowSpecDialogData } from '../_interfaces/dialog-data'; import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe'; -import {ApiErrorsComponent} from '../api-errors/api-errors.component'; import {FileListComponent} from '../file-list/file-list.component'; import {WorkflowSpecListComponent} from './workflow-spec-list.component'; diff --git a/src/app/workflow-spec-list/workflow-spec-list.component.ts b/src/app/workflow-spec-list/workflow-spec-list.component.ts index 0f5770b..39c5f71 100644 --- a/src/app/workflow-spec-list/workflow-spec-list.component.ts +++ b/src/app/workflow-spec-list/workflow-spec-list.component.ts @@ -21,7 +21,7 @@ import { WorkflowSpecCategoryDialogData, WorkflowSpecDialogData } from '../_interfaces/dialog-data'; -import {ApiErrorsComponent} from '../api-errors/api-errors.component'; +import {ApiErrorsComponent} from 'sartography-workflow-lib'; export interface WorkflowSpecCategoryGroup { diff --git a/src/environments/environment.runtime.ts b/src/environments/environment.runtime.ts index c40401d..d49a424 100644 --- a/src/environments/environment.runtime.ts +++ b/src/environments/environment.runtime.ts @@ -10,4 +10,6 @@ export const environment: AppEnvironment = { api: _has(ENV, 'api', '$API_URL') ? ENV.api : 'http://localhost:5000/v1.0', irbUrl: _has(ENV, 'irbUrl', '$IRB_URL') ? ENV.irbUrl : 'http://localhost:5001', title: _has(ENV, 'title', '$TITLE') ? ENV.title : 'Research Ramp-Up Toolkit Configurator', + googleAnalyticsKey: _has(ENV, 'googleAnalyticsKey', '$GOOGLE_ANALYTICS_KEY') ? ENV.googleAnalyticsKey : 'UA-168203235-5', + sentryKey: _has(ENV, 'sentryKey', '$SENTRY_KEY') ? ENV.sentryKey : undefined, }; diff --git a/src/environments/environment.spec.ts b/src/environments/environment.spec.ts index f5ffbe4..ce06af4 100644 --- a/src/environments/environment.spec.ts +++ b/src/environments/environment.spec.ts @@ -1,15 +1,17 @@ -import {AppEnvironment} from 'sartography-workflow-lib'; import {_has, environment} from './environment.runtime'; declare var ENV; describe('Environments', () => { - it('should have settings for all the environments', () => { + it('should have default values for all the environments', () => { expect(environment).toBeDefined(); expect(environment.production).toEqual(false); expect(environment.api).toEqual('apiRoot'); expect(environment.irbUrl).toEqual('irbUrl'); expect(environment.homeRoute).toEqual('home'); + expect(environment.title).toEqual('Research Ramp-Up Toolkit Configurator'); + expect(environment.googleAnalyticsKey).toEqual('UA-168203235-5'); + expect(environment.sentryKey).toEqual(undefined); }); it('should check if environment variables are defined', () => { @@ -18,31 +20,44 @@ describe('Environments', () => { production: '$PRODUCTION', api: '$API_URL', irbUrl: '$IRB_URL', + title: '$TITLE', + googleAnalyticsKey: '$GOOGLE_ANALYTICS_KEY', + sentryKey: '$SENTRY_KEY', }; expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse(); expect(_has(env, 'production', '$PRODUCTION')).toBeFalse(); expect(_has(env, 'api', '$API_URL')).toBeFalse(); expect(_has(env, 'irbUrl', '$IRB_URL')).toBeFalse(); + expect(_has(env, 'title', '$TITLE')).toBeFalse(); + expect(_has(env, 'googleAnalyticsKey', '$GOOGLE_ANALYTICS_KEY')).toBeFalse(); env.homeRoute = undefined; env.production = undefined; env.api = undefined; env.irbUrl = undefined; + env.title = undefined; + env.googleAnalyticsKey = undefined; expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse(); expect(_has(env, 'production', '$PRODUCTION')).toBeFalse(); expect(_has(env, 'api', '$API_URL')).toBeFalse(); expect(_has(env, 'irbUrl', '$IRB_URL')).toBeFalse(); + expect(_has(env, 'title', '$TITLE')).toBeFalse(); + expect(_has(env, 'googleAnalyticsKey', '$GOOGLE_ANALYTICS_KEY')).toBeFalse(); env.homeRoute = 'something'; env.production = 'something'; env.api = 'something'; env.irbUrl = 'something'; + env.title = 'something'; + env.googleAnalyticsKey = 'something'; expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeTrue(); expect(_has(env, 'production', '$PRODUCTION')).toBeTrue(); expect(_has(env, 'api', '$API_URL')).toBeTrue(); expect(_has(env, 'irbUrl', '$IRB_URL')).toBeTrue(); + expect(_has(env, 'title', '$TITLE')).toBeTrue(); + expect(_has(env, 'googleAnalyticsKey', '$GOOGLE_ANALYTICS_KEY')).toBeTrue(); }); }); diff --git a/src/favicon.ico b/src/favicon.ico index 8081c7c..df273c3 100644 Binary files a/src/favicon.ico and b/src/favicon.ico differ diff --git a/src/index.html b/src/index.html index 124a135..a5136bc 100644 --- a/src/index.html +++ b/src/index.html @@ -10,11 +10,14 @@ production: '$PRODUCTION', api: '$API_URL', irbUrl: '$IRB_URL', - baseHref: '$BASE_HREF', + title: '$TITLE', + googleAnalyticsKey: '$GOOGLE_ANALYTICS_KEY', + sentryKey: '$SENTRY_KEY', }; - + +