Commit 52eb06ec authored by Nestor Diaz's avatar Nestor Diaz

Merge branch 'beta'

# Conflicts:
#	package-lock.json
#	package.json
parents 18fc74e3 051c798d
Pipeline #110877 passed with stages
in 33 minutes and 18 seconds
{
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 120
}
# BioStudies - Submission Tool
- Angular v8
- Angular v10
- ExpressJS v4
- Node v10.16.2
......
......@@ -7,28 +7,30 @@
"root": "",
"sourceRoot": "src",
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"prefix": "st",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"aot": true,
"outputPath": ".build",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"tsConfig": "tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/images",
"src/thor-integration.html",
"src/styles/bootstrap/fonts",
"src/config.json"
],
"styles": [
"node_modules/ag-grid-community/dist/styles/ag-grid.css",
"node_modules/ag-grid-community/dist/styles/ag-theme-fresh.css",
"node_modules/ngx-bootstrap/datepicker/bs-datepicker.css",
"node_modules/@fortawesome/fontawesome-free/css/all.css",
"src/style.less",
"src/theme/custom-bootstrap.less"
"src/style.scss"
],
"scripts": [
"node_modules/marked/lib/marked.js"
......@@ -36,6 +38,12 @@
},
"configurations": {
"production": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
......@@ -76,10 +84,11 @@
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
"tsconfig.app.json"
],
"exclude": []
"exclude": [
"**/node_modules/**"
]
}
}
}
......@@ -107,7 +116,7 @@
"schematics": {
"@schematics/angular:component": {
"prefix": "st",
"styleext": "css"
"style": "css"
},
"@schematics/angular:directive": {
"prefix": "st"
......
module.exports = {};
module.exports = {
backend: {
context: ''
}
};
module.exports = {
assets: {
path: 'public'
}
};
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -16,6 +16,7 @@
"node:prod": "cross-env NODE_ENV=production node .",
"start:dev": "run-p node:dev ng:start",
"pretest": "npm run lint",
"postinstall": "ngcc",
"test": "jest --ci"
},
"jest": {
......@@ -23,7 +24,7 @@
"clearMocks": true,
"collectCoverage": true,
"setupFilesAfterEnv": [
"<rootDir>/src/setup-jest-after-env.ts"
"<rootDir>/src/tests/setupJestAfterEnv.ts"
],
"coverageThreshold": {
"global": {
......@@ -49,79 +50,85 @@
]
},
"dependencies": {
"@angular/animations": "^8.2.14",
"@angular/common": "^8.2.14",
"@angular/compiler": "^8.2.14",
"@angular/core": "^8.2.14",
"@angular/forms": "^8.2.14",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"@angular/router": "^8.2.14",
"@biostudies/ckeditor5-build-balloon": "^19.0.0",
"@ckeditor/ckeditor5-angular": "^1.2.3",
"@ckeditor/ckeditor5-clipboard": "^19.0.1",
"@fortawesome/fontawesome-free": "^5.12.1",
"@rxweb/reactive-form-validators": "^1.9.1",
"ag-grid-angular": "^22.1.1",
"ag-grid-community": "^22.1.1",
"core-js": "^2.4.1",
"fp-ts": "^1.9.0",
"helmet": "^3.21.1",
"http-status-codes": "^1.3.2",
"lodash": "^4.17.19",
"ng-recaptcha": "^5.0.0",
"ng2-cookies": "^1.0.2",
"ngx-bootstrap": "^5.5.0",
"ngx-markdown": "^8.1.0",
"ngx-sortablejs": "^3.1.4",
"pluralize": "^7.0.0",
"rxjs": "^6.5.4",
"sortablejs": "^1.10.2",
"zone.js": "~0.9.1"
"@angular/animations": "10.0.12",
"@angular/common": "10.0.12",
"@angular/compiler": "10.0.12",
"@angular/core": "10.0.12",
"@angular/forms": "10.0.12",
"@angular/platform-browser": "10.0.12",
"@angular/platform-browser-dynamic": "10.0.12",
"@angular/router": "10.0.12",
"@biostudies/ckeditor5-build-balloon": "19.0.0",
"@ckeditor/ckeditor5-angular": "1.2.3",
"@ckeditor/ckeditor5-clipboard": "19.0.1",
"@fortawesome/fontawesome-free": "5.14.0",
"@ng-select/ng-select": "^5.0.8",
"@rxweb/reactive-form-validators": "2.0.0",
"ag-grid-angular": "23.2.1",
"ag-grid-community": "23.2.1",
"bootstrap": "^4.5.2",
"fp-ts": "1.19.5",
"helmet": "3.21.1",
"http-status-codes": "1.3.2",
"lodash.debounce": "4.0.8",
"lodash.isempty": "4.4.0",
"ng-recaptcha": "5.0.0",
"ngx-bootstrap": "6.1.0",
"ngx-cookie-service": "10.0.1",
"ngx-markdown": "9.1.1",
"ngx-sortablejs": "3.1.4",
"ngx-toastr": "^13.1.0",
"pluralize": "8.0.0",
"rxjs": "6.6.2",
"sortablejs": "1.10.2",
"tslib": "2.0.0",
"zone.js": "0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.25",
"@angular/cli": "^8.3.25",
"@angular/compiler-cli": "^8.2.14",
"@testing-library/angular": "^8.0.3",
"@testing-library/jest-dom": "^4.2.4",
"@types/amqplib": "^0.5.13",
"@types/compression": "^1.7.0",
"@angular-devkit/build-angular": "0.1000.7",
"@angular/cli": "10.0.7",
"@angular/compiler-cli": "10.0.12",
"@testing-library/angular": "10.0.2",
"@testing-library/jest-dom": "5.11.4",
"@types/amqplib": "0.5.13",
"@types/compression": "1.7.0",
"@types/config": "0.0.36",
"@types/express": "^4.17.6",
"@types/express-http-proxy": "^1.6.1",
"@types/express-winston": "^4.0.0",
"@types/express": "4.17.6",
"@types/express-http-proxy": "1.6.1",
"@types/express-winston": "4.0.0",
"@types/helmet": "0.0.47",
"@types/jest": "^24.0.23",
"@types/jsdom": "^12.2.4",
"@types/node": "^14.0.14",
"@types/pluralize": "0.0.28",
"@types/request": "^2.48.5",
"@types/sortablejs": "^1.10.4",
"amqplib": "^0.5.6",
"body-parser": "^1.19.0",
"codelyzer": "^5.0.1",
"compression": "^1.7.4",
"config": "^3.1.0",
"cross-env": "^5.2.1",
"del": "^4.1.1",
"dotenv": "^8.0.0",
"express": "^4.17.1",
"express-http-proxy": "^1.5.1",
"express-winston": "^4.0.3",
"forever": "^2.0.0",
"gulp": "^4.0.0",
"gulp-zip": "^3.2.0",
"jest": "^24.9.0",
"jest-preset-angular": "^8.0.0",
"nodemon": "^1.19.1",
"npm-run-all": "^4.1.5",
"protractor": "^6.0.0",
"rxjs-tslint-rules": "^4.23.1",
"ts-node": "~2.0.0",
"ts-node-dev": "^1.0.0-pre.50",
"tslint": "^5.5.0",
"typescript": "3.5.3",
"winston": "^3.3.3"
"@types/jest": "26.0.10",
"@types/jsdom": "16.2.3",
"@types/node": "14.6.0",
"@types/pluralize": "0.0.29",
"@types/request": "2.48.5",
"@types/sortablejs": "1.10.4",
"amqplib": "0.5.6",
"body-parser": "1.19.0",
"codelyzer": "6.0.0",
"compression": "1.7.4",
"config": "3.1.0",
"cross-env": "5.2.1",
"del": "4.1.1",
"dotenv": "8.0.0",
"express": "4.17.1",
"express-http-proxy": "1.5.1",
"express-winston": "4.0.3",
"forever": "2.0.0",
"gulp": "4.0.0",
"gulp-zip": "3.2.0",
"jest": "26.4.2",
"jest-preset-angular": "8.3.1",
"nodemon": "1.19.1",
"npm-run-all": "4.1.5",
"prettier": "^2.1.1",
"protractor": "7.0.0",
"ts-node": "2.0.0",
"ts-node-dev": "1.0.0-pre.50",
"tslint": "6.1.0",
"tslint-config-prettier": "1.18.0",
"tslint-plugin-prettier": "2.3.0",
"typescript": "3.9.7",
"winston": "3.3.3"
}
}
......@@ -20,8 +20,8 @@ export const submStatusController = (path: string, router: Router) => {
res.write(new Array(1024 * 1024).fill(0).toString());
}
const sendEvent = (event: string, data: Date | string) => {
res.write(`event: ${String(event)}\n`);
const sendEvent = (event: string, data: string) => {
res.write(`event: ${event}\n`);
res.write(`data: ${data}`);
res.write('\n\n');
res.flushHeaders();
......@@ -30,7 +30,7 @@ export const submStatusController = (path: string, router: Router) => {
stream.on('push', sendEvent);
const intervalId = setInterval(() => {
sendEvent('ping', new Date().toLocaleTimeString());
sendEvent('ping', JSON.stringify({ time: new Date().toLocaleTimeString() }));
}, 60 * 1000);
req.on('close', () => {
......
......@@ -5,8 +5,7 @@ import { listenToQueue } from '../rabbitmq/rabbitmq-consumer';
import { logger } from '../logger';
export interface SubmStatus {
accNo: string,
status: string
accNo: string
}
const queueName: string = config.get('rabbitmq.submStatusQueueName');
......@@ -14,10 +13,10 @@ const queueName: string = config.get('rabbitmq.submStatusQueueName');
const processMessage = (message: ConsumeMessage | null) => {
try {
const submStatus: SubmStatus = JSON.parse(message!.content.toString());
const { accNo, status } = submStatus;
const { accNo } = submStatus;
// Only sends accNo and status to client.
stream.emit('push', 'subm-status', JSON.stringify({ accNo, status }));
// Only sends accNo to client.
stream.emit('push', 'message', JSON.stringify({ accNo }));
} catch (error) {
logger.error('submission-status-processor', error);
}
......
declare interface StringConstructor {
isString(string: any): boolean;
isDefined(s: string | undefined | null): boolean;
isNotDefinedOrEmpty(s: string | undefined | null): boolean;
isDefinedAndNotEmpty(s: string | undefined | null): boolean;
}
declare interface String {
isEqualIgnoringCase(value: string): boolean;
isEmpty(): boolean;
}
declare interface Array<T> {
isEmpty(): boolean;
uniqueValues(): Array<T>;
flatMap<U>(mapFunc: (x: T) => U[]): Array<U>;
}
declare type Dictionary<T> = { [key: string]: T | undefined }
declare type Nullable<T> = T | null | undefined
declare interface FullPathFile extends File {
webkitRelativePath: string;
}
......@@ -4,6 +4,7 @@ import {
} from '@angular/core';
import { UserSession } from 'app/auth/shared';
import { AppConfig } from 'app/app.config';
import { setTheme } from 'ngx-bootstrap/utils';
@Component({
selector: 'st-root',
......@@ -14,19 +15,26 @@ import { AppConfig } from 'app/app.config';
})
export class AppComponent implements OnInit {
constructor(private userSession: UserSession, private appConfig: AppConfig) {}
constructor(private userSession: UserSession, private appConfig: AppConfig) {
setTheme('bs4');
}
ngOnInit() {
ngOnInit(): void {
const bannerEl = document.createElement('script');
// Loads the GDPR bottom panel logic.
// NOTE: The banner should be called with 'other' to indicate a framework different from EBI's is in use.
// NOTE: ebiFrameworkRunDataProtectionBanner is defined after the script loads.
bannerEl.src = this.appConfig.bannerUrl;
bannerEl.onload = function () {
window['ebiFrameworkRunDataProtectionBanner']('other');
bannerEl.onload = () => {
if (window.ebiFrameworkRunDataProtectionBanner !== undefined) {
window.ebiFrameworkRunDataProtectionBanner('other');
}
};
document.head!.appendChild(bannerEl);
if (document.head !== undefined) {
document.head.appendChild(bannerEl);
}
this.userSession.init();
}
......
......@@ -23,7 +23,7 @@ export class AppConfig {
/**
* Synonym getter providing the threshold below which the current screen size will trigger
* tablet/mobile-geared layout.
* @returns {number} Upper-limit screen size in pixels for tablet-like devices.
* @returns Upper-limit screen size in pixels for tablet-like devices.
*/
get tabletBreak(): number {
return this.config.APP_TABLET_BREAKPOINT;
......@@ -31,7 +31,7 @@ export class AppConfig {
/**
* Synonym getter providing the format in which dates should be displayed when listing submissions.
* @returns {string} Format expressed in Angular's date pipe notation.
* @returns Format expressed in Angular's date pipe notation.
* @see {@link https://angular.io/api/common/DatePipe}
*/
get dateListFormat(): string {
......@@ -40,7 +40,7 @@ export class AppConfig {
/**
* Synonym getter providing the format in which dates should be displayed when editing submissions.
* @returns {string} Format following the Moment.js' notation.
* @returns Format following the Moment.js' notation.
* @see {@link https://momentjs.com/docs/#/parsing/string-format/}
*/
get dateInputFormat(): string {
......@@ -50,7 +50,7 @@ export class AppConfig {
/**
* Synonym getter providing the number of years ahead of the current date that the date picker will render
* selectable dates of.
* @returns {number} Maximum number of years into the future.
* @returns Maximum number of years into the future.
*/
get maxDateYears(): number {
return this.config.APP_MAX_DATE_YEARS;
......@@ -58,7 +58,7 @@ export class AppConfig {
/**
* Synonym getter providing the maximum number of suggested entries in a typeahead box.
* @returns {number} Maximum length of the suggestion list.
* @returns Maximum length of the suggestion list.
*/
get maxSuggestLength(): number {
return this.config.APP_MAX_SUGGEST_LENGTH;
......@@ -66,7 +66,7 @@ export class AppConfig {
/**
* Synonym getter providing the URL for the script containing the GDPR banner's logic.
* @returns {string} URL.
* @returns URL.
*/
get bannerUrl(): string {
return this.config.GDPR_BANNER_URL;
......@@ -76,7 +76,7 @@ export class AppConfig {
* Maximum number of concurrent connections supported by the browser. It should be in accordance to
* a ball-park average for different browsers.