mirror of
https://github.com/sartography/cr-connect-bpmn.git
synced 2025-01-09 16:45:51 +00:00
commit
c6d728b90d
@ -32,6 +32,6 @@ RUN echo "pushstate: enabled" > /etc/nginx/html/Staticfile
|
|||||||
# then starts/reloads nginx.
|
# then starts/reloads nginx.
|
||||||
ENTRYPOINT ["./entrypoint.sh", \
|
ENTRYPOINT ["./entrypoint.sh", \
|
||||||
"/etc/nginx/html/index.html,/etc/nginx/conf.d/default.conf", \
|
"/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", \
|
"/etc/nginx/html", \
|
||||||
"true"]
|
"true"]
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
version: "3.3"
|
version: "3.3"
|
||||||
services:
|
services:
|
||||||
|
ldap:
|
||||||
|
container_name: ldap
|
||||||
|
image: tuxmonteiro/ldap-mock
|
||||||
|
ports:
|
||||||
|
- "3890:3890"
|
||||||
|
|
||||||
db:
|
db:
|
||||||
container_name: db
|
container_name: db
|
||||||
image: sartography/cr-connect-db:dev
|
image: sartography/cr-connect-db:$E2E_TAG
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=rrt_user
|
- POSTGRES_USER=crc_user
|
||||||
- POSTGRES_PASSWORD=rrt_pass
|
- POSTGRES_PASSWORD=crc_pass
|
||||||
- POSTGRES_MULTIPLE_DATABASES=rrt
|
- POSTGRES_MULTIPLE_DATABASES=crc_test,pb_test
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "pg_isready"]
|
test: ["CMD", "pg_isready"]
|
||||||
timeout: 20s
|
timeout: 20s
|
||||||
@ -18,52 +24,73 @@ services:
|
|||||||
container_name: backend
|
container_name: backend
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
image: sartography/cr-connect-workflow:dev
|
image: sartography/cr-connect-workflow:$E2E_TAG
|
||||||
environment:
|
environment:
|
||||||
- APPLICATION_ROOT=/api
|
- APPLICATION_ROOT=/
|
||||||
- CORS_ALLOW_ORIGINS=localhost:5002,bpmn:5002,localhost:4200,frontend:4200
|
- CORS_ALLOW_ORIGINS=localhost:5002,bpmn:5002,localhost:4200,frontend:4200
|
||||||
- DB_HOST=db
|
- DB_HOST=db
|
||||||
- DB_NAME=rrt
|
- DB_NAME=crc_test
|
||||||
- DB_PASSWORD=rrt_pass
|
- DB_PASSWORD=crc_pass
|
||||||
- DB_PORT=5432
|
- DB_PORT=5432
|
||||||
- DB_USER=rrt_user
|
- DB_USER=crc_user
|
||||||
- LDAP_URL=ldap.virginia.edu
|
- LDAP_URL=ldap
|
||||||
- PB_ENABLED=false
|
- PB_ENABLED=true
|
||||||
|
- PB_BASE_URL=http://pb:5001/v2.0/
|
||||||
- PORT0=5000
|
- PORT0=5000
|
||||||
- RESET_DB=true
|
- RESET_DB=true
|
||||||
- UPGRADE_DB=true
|
- UPGRADE_DB=true
|
||||||
|
- TESTING=true
|
||||||
ports:
|
ports:
|
||||||
- "5000:5000"
|
- "5000:5000"
|
||||||
command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh
|
command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh
|
||||||
|
|
||||||
bpmn:
|
pb:
|
||||||
container_name: bpmn
|
container_name: pb
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
- backend
|
image: sartography/protocol-builder-mock:$E2E_TAG
|
||||||
image: sartography/cr-connect-bpmn:dev
|
|
||||||
environment:
|
environment:
|
||||||
- API_URL=http://localhost:5000/api/v1.0
|
- APPLICATION_ROOT=/
|
||||||
- BASE_HREF=/bpmn/
|
- CORS_ALLOW_ORIGINS=localhost:5000,backend:5000,localhost:5002,bpmn:5002,localhost:4200,frontend:4200
|
||||||
- DEPLOY_URL=/bpmn/
|
- DB_HOST=db
|
||||||
- HOME_ROUTE=home
|
- DB_NAME=pb_test
|
||||||
- PORT0=5002
|
- DB_PASSWORD=crc_pass
|
||||||
- PRODUCTION=false
|
- DB_PORT=5432
|
||||||
|
- DB_USER=crc_user
|
||||||
|
- PORT0=5001
|
||||||
|
- UPGRADE_DB=true
|
||||||
ports:
|
ports:
|
||||||
- "5002:5002"
|
- "5001:5001"
|
||||||
|
command: ./wait-for-it.sh db:5432 -t 0 -- ./docker_run.sh
|
||||||
|
|
||||||
frontend:
|
# bpmn:
|
||||||
container_name: frontend
|
# container_name: bpmn
|
||||||
depends_on:
|
# depends_on:
|
||||||
- db
|
# - db
|
||||||
- backend
|
# - backend
|
||||||
image: sartography/cr-connect-frontend:dev
|
# image: sartography/cr-connect-bpmn:dev
|
||||||
environment:
|
# environment:
|
||||||
- API_URL=http://localhost:5000/api/v1.0
|
# - API_URL=http://localhost:5000/api/v1.0
|
||||||
- BASE_HREF=/app/
|
# - BASE_HREF=/bpmn/
|
||||||
- DEPLOY_URL=/app/
|
# - DEPLOY_URL=/bpmn/
|
||||||
- HOME_ROUTE=home
|
# - HOME_ROUTE=home
|
||||||
- PORT0=4200
|
# - PORT0=5002
|
||||||
- PRODUCTION=false
|
# - PRODUCTION=false
|
||||||
ports:
|
# ports:
|
||||||
- "4200:4200"
|
# - "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"
|
||||||
|
63
package-lock.json
generated
63
package-lock.json
generated
@ -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": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
@ -12299,9 +12356,9 @@
|
|||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
"sartography-workflow-lib": {
|
"sartography-workflow-lib": {
|
||||||
"version": "0.0.213",
|
"version": "0.0.265",
|
||||||
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.213.tgz",
|
"resolved": "https://registry.npmjs.org/sartography-workflow-lib/-/sartography-workflow-lib-0.0.265.tgz",
|
||||||
"integrity": "sha512-2y4UQk3zYeY0Xu3wqq3UptORxVN/Dp8MPyr7JMNBjM9XCdoDL+nIyhpOA7pS+VfraoEzbm9m4CQamQ9YSGRu6w=="
|
"integrity": "sha512-cb1Wc09m83hgpjz7d60KHGDjHvrpq6oZns8lL+kgjFUrGwsL8lRxwsjt1cOGMnCTzi48icybEogvSsluhU7RhA=="
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.23.3",
|
"version": "1.23.3",
|
||||||
|
19
package.json
19
package.json
@ -12,16 +12,12 @@
|
|||||||
"test:coverage": "ng test --codeCoverage=true --watch=false --browsers=ChromeHeadless",
|
"test:coverage": "ng test --codeCoverage=true --watch=false --browsers=ChromeHeadless",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "./node_modules/protractor/bin/webdriver-manager update && ng e2e",
|
"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:with-wf": "npm run e2e-wf && ng e2e && npm run e2e-wf:stop",
|
||||||
"e2e-wf:stop": "docker stop db || true && docker stop backend || true && docker stop pb || true",
|
"e2e-wf:stop": "cd docker && docker-compose down && cd ..",
|
||||||
"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 && cd ..",
|
||||||
"e2e-wf:build": "cd docker && docker-compose pull && docker-compose build --no-cache && cd ..",
|
"e2e-wf:start": "cd docker && docker-compose up -d --force-recreate && cd ..",
|
||||||
"e2e-wf:start": "cd docker && docker-compose up -d && cd ..",
|
"e2e-wf": "npm run e2e-wf:stop && npm run e2e-wf:build && npm run e2e-wf:start",
|
||||||
"e2e-wf:db-upgrade": "docker exec -it backend pipenv run flask db upgrade",
|
"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",
|
||||||
"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",
|
|
||||||
"ci": "npm run lint && npm run test:coverage && sonar-scanner"
|
"ci": "npm run lint && npm run test:coverage && sonar-scanner"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -39,6 +35,7 @@
|
|||||||
"@angular/router": "^9.0.7",
|
"@angular/router": "^9.0.7",
|
||||||
"@ngx-formly/core": "^5.5.15",
|
"@ngx-formly/core": "^5.5.15",
|
||||||
"@ngx-formly/material": "^5.5.15",
|
"@ngx-formly/material": "^5.5.15",
|
||||||
|
"@sentry/browser": "^5.16.1",
|
||||||
"@yellowspot/ng-truncate": "^1.5.1",
|
"@yellowspot/ng-truncate": "^1.5.1",
|
||||||
"bpmn-js": "^6.4.2",
|
"bpmn-js": "^6.4.2",
|
||||||
"bpmn-js-properties-panel": "^0.33.2",
|
"bpmn-js-properties-panel": "^0.33.2",
|
||||||
@ -54,7 +51,7 @@
|
|||||||
"ngx-file-drop": "^8.0.8",
|
"ngx-file-drop": "^8.0.8",
|
||||||
"ngx-markdown": "^9.0.0",
|
"ngx-markdown": "^9.0.0",
|
||||||
"rxjs": "~6.5.4",
|
"rxjs": "~6.5.4",
|
||||||
"sartography-workflow-lib": "0.0.213",
|
"sartography-workflow-lib": "0.0.265",
|
||||||
"tslib": "^1.11.1",
|
"tslib": "^1.11.1",
|
||||||
"uuid": "^7.0.2",
|
"uuid": "^7.0.2",
|
||||||
"zone.js": "^0.10.3"
|
"zone.js": "^0.10.3"
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {FileMeta, FileType, WorkflowSpec, WorkflowSpecCategory} from 'sartography-workflow-lib';
|
import {FileMeta, FileType, WorkflowSpec, WorkflowSpecCategory} from 'sartography-workflow-lib';
|
||||||
import {ApiError} from 'sartography-workflow-lib/lib/types/api';
|
|
||||||
|
|
||||||
export interface FileMetaDialogData {
|
export interface FileMetaDialogData {
|
||||||
id?: number;
|
id?: number;
|
||||||
@ -49,7 +48,3 @@ export interface DeleteWorkflowSpecCategoryDialogData {
|
|||||||
confirm: boolean;
|
confirm: boolean;
|
||||||
category: WorkflowSpecCategory;
|
category: WorkflowSpecCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiErrorsBottomSheetData {
|
|
||||||
apiErrors: ApiError[];
|
|
||||||
}
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<div fxLayout="row">
|
|
||||||
<h2>Workflow Specification Errors</h2>
|
|
||||||
<span fxFlex></span>
|
|
||||||
<button mat-icon-button (click)="dismiss($event)"><mat-icon>close</mat-icon></button>
|
|
||||||
</div>
|
|
||||||
<mat-list>
|
|
||||||
<mat-list-item *ngFor="let e of apiErrors" class="api-error" [ngStyle]="{'height': 'auto'}">
|
|
||||||
<h3 mat-line *ngIf="e.status_code">{{e.code}}</h3>
|
|
||||||
<h4 mat-line *ngIf="e.code">{{e.status_code}}</h4>
|
|
||||||
<div mat-line *ngIf="e.task_name && e.task_id">{{e.task_name}} ({{e.task_id}})</div>
|
|
||||||
<div mat-line *ngIf="e.task_id && !e.task_name">Task ID: {{e.task_id}}</div>
|
|
||||||
<div mat-line *ngIf="!e.task_id && e.task_name">Task Name: {{e.task_name}}</div>
|
|
||||||
<div mat-line *ngIf="e.file_name">File: {{e.file_name}}</div>
|
|
||||||
<div mat-line *ngIf="e.tag">Tag: {{e.tag}}</div>
|
|
||||||
<ng-container *ngIf="e.message">
|
|
||||||
<div mat-line>
|
|
||||||
<code *ngIf="e.message">{{e.message}}</code>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
</mat-list-item>
|
|
||||||
</mat-list>
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<ApiErrorsComponent>;
|
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -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<ApiErrorsComponent>
|
|
||||||
) {
|
|
||||||
if (data && data.apiErrors && data.apiErrors.length > 0) {
|
|
||||||
this.apiErrors = data.apiErrors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss(event: MouseEvent) {
|
|
||||||
this._bottomSheetRef.dismiss();
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,6 +15,8 @@ export class ThisEnvironment implements AppEnvironment {
|
|||||||
api = environment.api;
|
api = environment.api;
|
||||||
irbUrl = environment.irbUrl;
|
irbUrl = environment.irbUrl;
|
||||||
title = environment.title;
|
title = environment.title;
|
||||||
|
googleAnalyticsKey = environment.googleAnalyticsKey;
|
||||||
|
sentryKey = environment.sentryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="mat-typography">
|
<div class="mat-typography">
|
||||||
<app-navbar *ngIf="isSignedIn" class="mat-elevation-z6" id="globalHeader"></app-navbar>
|
<app-navbar></app-navbar>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
<app-footer></app-footer>
|
<app-footer></app-footer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#globalHeader {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
@ -1,61 +1,57 @@
|
|||||||
import {APP_BASE_HREF} from '@angular/common';
|
import {APP_BASE_HREF} from '@angular/common';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
import {Component} from '@angular/core';
|
|
||||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
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 {RouterTestingModule} from '@angular/router/testing';
|
||||||
import {ApiService, MockEnvironment} from 'sartography-workflow-lib';
|
import {ApiService, MockEnvironment} from 'sartography-workflow-lib';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
|
import {FooterComponent} from './footer/footer.component';
|
||||||
|
import {NavbarComponent} from './navbar/navbar.component';
|
||||||
@Component({
|
|
||||||
selector: 'app-navbar',
|
|
||||||
template: ''
|
|
||||||
})
|
|
||||||
class MockNavbarComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-footer',
|
|
||||||
template: ''
|
|
||||||
})
|
|
||||||
class MockFooterComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
let component: AppComponent;
|
let component: AppComponent;
|
||||||
let fixture: ComponentFixture<AppComponent>;
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
const mockEnvironment = new MockEnvironment();
|
||||||
|
const mockTitle = `'Once,' said the Mock Title at last, with a deep sigh, 'I was a real Title.'`;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
MockNavbarComponent,
|
FooterComponent,
|
||||||
MockFooterComponent
|
NavbarComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
BrowserAnimationsModule,
|
MatIconModule,
|
||||||
|
MatMenuModule,
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
HttpClient,
|
HttpClient,
|
||||||
|
FakeMatIconRegistry,
|
||||||
ApiService,
|
ApiService,
|
||||||
{provide: 'APP_ENVIRONMENT', useClass: MockEnvironment},
|
{provide: 'APP_ENVIRONMENT', useValue: mockEnvironment},
|
||||||
{provide: APP_BASE_HREF, useValue: ''},
|
{provide: APP_BASE_HREF, useValue: ''},
|
||||||
],
|
]
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
mockEnvironment.title = mockTitle;
|
||||||
fixture = TestBed.createComponent(AppComponent);
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create', () => {
|
it('should create the app', () => {
|
||||||
expect(component).toBeTruthy();
|
expect(component).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should set the page title to match environment variable`, () => {
|
||||||
|
expect((component as any).titleService.getTitle()).toEqual(mockTitle);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component, Inject} from '@angular/core';
|
||||||
import {ApiService} from 'sartography-workflow-lib';
|
import {MatIconRegistry} from '@angular/material/icon';
|
||||||
|
import {DomSanitizer, Title} from '@angular/platform-browser';
|
||||||
|
import {AppEnvironment, FileType, GoogleAnalyticsService} from 'sartography-workflow-lib';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -7,12 +9,19 @@ import {ApiService} from 'sartography-workflow-lib';
|
|||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'CR Connect Configuration';
|
constructor(
|
||||||
|
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
|
||||||
constructor(private apiService: ApiService) {
|
private titleService: Title,
|
||||||
}
|
private matIconRegistry: MatIconRegistry,
|
||||||
|
private domSanitizer: DomSanitizer,
|
||||||
get isSignedIn() {
|
private googleAnalyticsService: GoogleAnalyticsService,
|
||||||
return this.apiService.isSignedIn();
|
) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {WorkflowSpecCategoryDialogComponent} from './_dialogs/workflow-spec-category-dialog/workflow-spec-category-dialog.component';
|
||||||
import {WorkflowSpecDialogComponent} from './_dialogs/workflow-spec-dialog/workflow-spec-dialog.component';
|
import {WorkflowSpecDialogComponent} from './_dialogs/workflow-spec-dialog/workflow-spec-dialog.component';
|
||||||
import {GetIconCodePipe} from './_pipes/get-icon-code.pipe';
|
import {GetIconCodePipe} from './_pipes/get-icon-code.pipe';
|
||||||
import {ApiErrorsComponent} from './api-errors/api-errors.component';
|
|
||||||
import {AppRoutingModule} from './app-routing.module';
|
import {AppRoutingModule} from './app-routing.module';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {DiagramComponent} from './diagram/diagram.component';
|
import {DiagramComponent} from './diagram/diagram.component';
|
||||||
@ -59,6 +58,8 @@ export class ThisEnvironment implements AppEnvironment {
|
|||||||
api = environment.api;
|
api = environment.api;
|
||||||
irbUrl = environment.irbUrl;
|
irbUrl = environment.irbUrl;
|
||||||
title = environment.title;
|
title = environment.title;
|
||||||
|
googleAnalyticsKey = environment.googleAnalyticsKey;
|
||||||
|
sentryKey = environment.sentryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,7 +97,6 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||||||
WorkflowSpecListComponent,
|
WorkflowSpecListComponent,
|
||||||
HomeComponent,
|
HomeComponent,
|
||||||
WorkflowSpecCardComponent,
|
WorkflowSpecCardComponent,
|
||||||
ApiErrorsComponent,
|
|
||||||
ProtocolBuilderComponent,
|
ProtocolBuilderComponent,
|
||||||
ReferenceFilesComponent,
|
ReferenceFilesComponent,
|
||||||
],
|
],
|
||||||
@ -128,7 +128,6 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
ApiErrorsComponent,
|
|
||||||
DeleteFileDialogComponent,
|
DeleteFileDialogComponent,
|
||||||
DeleteWorkflowSpecDialogComponent,
|
DeleteWorkflowSpecDialogComponent,
|
||||||
DeleteWorkflowSpecCategoryDialogComponent,
|
DeleteWorkflowSpecCategoryDialogComponent,
|
||||||
|
@ -5,6 +5,7 @@ import {MatDialog} from '@angular/material/dialog';
|
|||||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||||
import {
|
import {
|
||||||
|
ApiErrorsComponent,
|
||||||
ApiService,
|
ApiService,
|
||||||
FileMeta,
|
FileMeta,
|
||||||
FileType,
|
FileType,
|
||||||
@ -19,7 +20,6 @@ import {OpenFileDialogComponent} from '../_dialogs/open-file-dialog/open-file-di
|
|||||||
import {BpmnWarning} from '../_interfaces/bpmn-warning';
|
import {BpmnWarning} from '../_interfaces/bpmn-warning';
|
||||||
import {FileMetaDialogData, NewFileDialogData, OpenFileDialogData} from '../_interfaces/dialog-data';
|
import {FileMetaDialogData, NewFileDialogData, OpenFileDialogData} from '../_interfaces/dialog-data';
|
||||||
import {ImportEvent} from '../_interfaces/import-event';
|
import {ImportEvent} from '../_interfaces/import-event';
|
||||||
import {ApiErrorsComponent} from '../api-errors/api-errors.component';
|
|
||||||
import {DiagramComponent} from '../diagram/diagram.component';
|
import {DiagramComponent} from '../diagram/diagram.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Component, Inject, OnInit} from '@angular/core';
|
import {Component, Inject} from '@angular/core';
|
||||||
import {Router} from '@angular/router';
|
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 {
|
interface NavItem {
|
||||||
path?: string;
|
path?: string;
|
||||||
@ -25,6 +25,7 @@ export class NavbarComponent {
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
|
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
|
||||||
|
private googleAnalyticsService: GoogleAnalyticsService
|
||||||
) {
|
) {
|
||||||
this._loadUser();
|
this._loadUser();
|
||||||
this.title = environment.title;
|
this.title = environment.title;
|
||||||
@ -38,6 +39,11 @@ export class NavbarComponent {
|
|||||||
if (isSignedIn()) {
|
if (isSignedIn()) {
|
||||||
this.api.getUser().subscribe(u => {
|
this.api.getUser().subscribe(u => {
|
||||||
this.user = u;
|
this.user = u;
|
||||||
|
|
||||||
|
if (this.user && this.user.uid) {
|
||||||
|
this.googleAnalyticsService.setUser(this.user.uid);
|
||||||
|
}
|
||||||
|
|
||||||
this._loadNavLinks();
|
this._loadNavLinks();
|
||||||
}, error => {
|
}, error => {
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
|
@ -13,6 +13,7 @@ import {RouterTestingModule} from '@angular/router/testing';
|
|||||||
import createClone from 'rfdc';
|
import createClone from 'rfdc';
|
||||||
import {of} from 'rxjs';
|
import {of} from 'rxjs';
|
||||||
import {
|
import {
|
||||||
|
ApiErrorsComponent,
|
||||||
ApiService,
|
ApiService,
|
||||||
MockEnvironment,
|
MockEnvironment,
|
||||||
mockWorkflowSpec0,
|
mockWorkflowSpec0,
|
||||||
@ -34,7 +35,6 @@ import {
|
|||||||
WorkflowSpecDialogData
|
WorkflowSpecDialogData
|
||||||
} from '../_interfaces/dialog-data';
|
} from '../_interfaces/dialog-data';
|
||||||
import {GetIconCodePipe} from '../_pipes/get-icon-code.pipe';
|
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 {FileListComponent} from '../file-list/file-list.component';
|
||||||
import {WorkflowSpecListComponent} from './workflow-spec-list.component';
|
import {WorkflowSpecListComponent} from './workflow-spec-list.component';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
WorkflowSpecCategoryDialogData,
|
WorkflowSpecCategoryDialogData,
|
||||||
WorkflowSpecDialogData
|
WorkflowSpecDialogData
|
||||||
} from '../_interfaces/dialog-data';
|
} from '../_interfaces/dialog-data';
|
||||||
import {ApiErrorsComponent} from '../api-errors/api-errors.component';
|
import {ApiErrorsComponent} from 'sartography-workflow-lib';
|
||||||
|
|
||||||
|
|
||||||
export interface WorkflowSpecCategoryGroup {
|
export interface WorkflowSpecCategoryGroup {
|
||||||
|
@ -10,4 +10,6 @@ export const environment: AppEnvironment = {
|
|||||||
api: _has(ENV, 'api', '$API_URL') ? ENV.api : 'http://localhost:5000/v1.0',
|
api: _has(ENV, 'api', '$API_URL') ? ENV.api : 'http://localhost:5000/v1.0',
|
||||||
irbUrl: _has(ENV, 'irbUrl', '$IRB_URL') ? ENV.irbUrl : 'http://localhost:5001',
|
irbUrl: _has(ENV, 'irbUrl', '$IRB_URL') ? ENV.irbUrl : 'http://localhost:5001',
|
||||||
title: _has(ENV, 'title', '$TITLE') ? ENV.title : 'Research Ramp-Up Toolkit Configurator',
|
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,
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import {AppEnvironment} from 'sartography-workflow-lib';
|
|
||||||
import {_has, environment} from './environment.runtime';
|
import {_has, environment} from './environment.runtime';
|
||||||
|
|
||||||
declare var ENV;
|
declare var ENV;
|
||||||
|
|
||||||
describe('Environments', () => {
|
describe('Environments', () => {
|
||||||
it('should have settings for all the environments', () => {
|
it('should have default values for all the environments', () => {
|
||||||
expect(environment).toBeDefined();
|
expect(environment).toBeDefined();
|
||||||
expect(environment.production).toEqual(false);
|
expect(environment.production).toEqual(false);
|
||||||
expect(environment.api).toEqual('apiRoot');
|
expect(environment.api).toEqual('apiRoot');
|
||||||
expect(environment.irbUrl).toEqual('irbUrl');
|
expect(environment.irbUrl).toEqual('irbUrl');
|
||||||
expect(environment.homeRoute).toEqual('home');
|
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', () => {
|
it('should check if environment variables are defined', () => {
|
||||||
@ -18,31 +20,44 @@ describe('Environments', () => {
|
|||||||
production: '$PRODUCTION',
|
production: '$PRODUCTION',
|
||||||
api: '$API_URL',
|
api: '$API_URL',
|
||||||
irbUrl: '$IRB_URL',
|
irbUrl: '$IRB_URL',
|
||||||
|
title: '$TITLE',
|
||||||
|
googleAnalyticsKey: '$GOOGLE_ANALYTICS_KEY',
|
||||||
|
sentryKey: '$SENTRY_KEY',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
|
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
|
||||||
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
|
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
|
||||||
expect(_has(env, 'api', '$API_URL')).toBeFalse();
|
expect(_has(env, 'api', '$API_URL')).toBeFalse();
|
||||||
expect(_has(env, 'irbUrl', '$IRB_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.homeRoute = undefined;
|
||||||
env.production = undefined;
|
env.production = undefined;
|
||||||
env.api = undefined;
|
env.api = undefined;
|
||||||
env.irbUrl = undefined;
|
env.irbUrl = undefined;
|
||||||
|
env.title = undefined;
|
||||||
|
env.googleAnalyticsKey = undefined;
|
||||||
|
|
||||||
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
|
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeFalse();
|
||||||
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
|
expect(_has(env, 'production', '$PRODUCTION')).toBeFalse();
|
||||||
expect(_has(env, 'api', '$API_URL')).toBeFalse();
|
expect(_has(env, 'api', '$API_URL')).toBeFalse();
|
||||||
expect(_has(env, 'irbUrl', '$IRB_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.homeRoute = 'something';
|
||||||
env.production = 'something';
|
env.production = 'something';
|
||||||
env.api = 'something';
|
env.api = 'something';
|
||||||
env.irbUrl = 'something';
|
env.irbUrl = 'something';
|
||||||
|
env.title = 'something';
|
||||||
|
env.googleAnalyticsKey = 'something';
|
||||||
|
|
||||||
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeTrue();
|
expect(_has(env, 'homeRoute', '$HOME_ROUTE')).toBeTrue();
|
||||||
expect(_has(env, 'production', '$PRODUCTION')).toBeTrue();
|
expect(_has(env, 'production', '$PRODUCTION')).toBeTrue();
|
||||||
expect(_has(env, 'api', '$API_URL')).toBeTrue();
|
expect(_has(env, 'api', '$API_URL')).toBeTrue();
|
||||||
expect(_has(env, 'irbUrl', '$IRB_URL')).toBeTrue();
|
expect(_has(env, 'irbUrl', '$IRB_URL')).toBeTrue();
|
||||||
|
expect(_has(env, 'title', '$TITLE')).toBeTrue();
|
||||||
|
expect(_has(env, 'googleAnalyticsKey', '$GOOGLE_ANALYTICS_KEY')).toBeTrue();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 1.1 KiB |
@ -10,11 +10,14 @@
|
|||||||
production: '$PRODUCTION',
|
production: '$PRODUCTION',
|
||||||
api: '$API_URL',
|
api: '$API_URL',
|
||||||
irbUrl: '$IRB_URL',
|
irbUrl: '$IRB_URL',
|
||||||
baseHref: '$BASE_HREF',
|
title: '$TITLE',
|
||||||
|
googleAnalyticsKey: '$GOOGLE_ANALYTICS_KEY',
|
||||||
|
sentryKey: '$SENTRY_KEY',
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||||
<link href="favicon.ico" rel="icon" type="image/x-icon">
|
<meta name="google-site-verification" content="KBn1RBc_UR6VF025kfjl_fRlIoLufSHL5JIkwE_xrOc" />
|
||||||
|
<link href="favicon.ico?v=1" rel="icon" type="image/x-icon">
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
|
<link rel="stylesheet" href="https://use.typekit.net/kwp6dli.css">
|
||||||
<link href="assets/css/diagram-js.css" rel="stylesheet">
|
<link href="assets/css/diagram-js.css" rel="stylesheet">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user