diff --git a/.eslintrc.json b/.eslintrc.json index 7c52faa3..0be733b7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,12 +1,12 @@ { "root": true, "ignorePatterns": ["**/*"], - "plugins": ["@nrwl/nx"], + "plugins": ["@nx"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": { - "@nrwl/nx/enforce-module-boundaries": [ + "@nx/enforce-module-boundaries": [ "error", { "enforceBuildableLibDependency": true, @@ -23,12 +23,12 @@ }, { "files": ["*.ts", "*.tsx"], - "extends": ["plugin:@nrwl/nx/typescript"], + "extends": ["plugin:@nx/typescript"], "rules": {} }, { "files": ["*.js", "*.jsx"], - "extends": ["plugin:@nrwl/nx/javascript"], + "extends": ["plugin:@nx/javascript"], "rules": {} }, { diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..f6d469a6 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,32 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs + +name: Node.js CI + +on: + push: + branches: ['master', 'development'] + pull_request: + branches: ['master', 'development'] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm i -g @angular/cli + - run: npm i -g nx + - run: npm i + - run: ng run-many --target=lint + - run: ng run-many --target=test -- --no-watch --no-progress --browsers=ChromeHeadlessCI diff --git a/.gitignore b/.gitignore index ddac9acc..5ade6818 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,9 @@ yarn-error.log testem.log /typings +apps/ramp-client/src/environments/environment* +apps/ramp-client/src/environments/environment.ts + # System Files .DS_Store Thumbs.db @@ -42,3 +45,5 @@ Thumbs.db .Rproj.user RaMP-Client.iml + +.nx/cache diff --git a/.prettierignore b/.prettierignore index d0b804da..bbd09b2a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,9 @@ /dist /coverage +/.angular +/.idea +/node_modules +/.nx/cache + +.angular diff --git a/.travis.yml b/.travis.yml index 1e55bf54..c312d8c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ +dist: jammy language: node_js node_js: - - '16' + - 20 addons: chrome: stable @@ -13,5 +14,5 @@ install: - npm install script: - - ng lint - - ng run-many --all --target=test -- --no-watch --no-progress --browsers=ChromeHeadlessCI + - ng run-many --all --target=lint + - ng run-many --all --target=test --no-watch --no-progress --browsers=ChromeHeadlessCI diff --git a/apps/README.md b/apps/README.md index 67b02ba7..581e19c7 100644 --- a/apps/README.md +++ b/apps/README.md @@ -15,23 +15,23 @@ These capabilities include generating applications, libraries, etc as well as th Below are our core plugins: - [React](https://reactjs.org) - - `npm install --save-dev @nrwl/react` + - `npm install --save-dev @nx/react` - Web (no framework frontends) - - `npm install --save-dev @nrwl/web` + - `npm install --save-dev @nx/web` - [Angular](https://angular.io) - - `npm install --save-dev @nrwl/angular` + - `npm install --save-dev @nx/angular` - [Nest](https://nestjs.com) - - `npm install --save-dev @nrwl/nest` + - `npm install --save-dev @nx/nest` - [Express](https://expressjs.com) - - `npm install --save-dev @nrwl/express` + - `npm install --save-dev @nx/express` - [Node](https://nodejs.org) - - `npm install --save-dev @nrwl/node` + - `npm install --save-dev @nx/node` There are also many [community plugins](https://nx.dev/community) you could add. ## Generate an application -Run `nx g @nrwl/react:app my-app` to generate an application. +Run `nx g @nx/react:app my-app` to generate an application. > You can use any of the plugins above to generate applications as well. @@ -39,7 +39,7 @@ When using Nx, you can create multiple applications and libraries in the same wo ## Generate a library -Run `nx g @nrwl/react:lib my-lib` to generate a library. +Run `nx g @nx/react:lib my-lib` to generate a library. > You can also use any of the plugins above to generate libraries as well. @@ -51,7 +51,7 @@ Run `nx serve my-app` for a dev server. Navigate to http://localhost:4200/. The ## Code scaffolding -Run `nx g @nrwl/react:component my-component --project=my-app` to generate a new component. +Run `nx g @nx/react:component my-component --project=my-app` to generate a new component. ## Build diff --git a/apps/ramp-client-e2e/project.json b/apps/ramp-client-e2e/project.json index 2972a954..d1e0f92c 100644 --- a/apps/ramp-client-e2e/project.json +++ b/apps/ramp-client-e2e/project.json @@ -5,7 +5,7 @@ "projectType": "application", "targets": { "e2e": { - "executor": "@nrwl/cypress:cypress", + "executor": "@nx/cypress:cypress", "options": { "cypressConfig": "apps/ramp-client-e2e/cypress.json", "devServerTarget": "ramp-client:serve:development", @@ -18,11 +18,7 @@ } }, "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/ramp-client-e2e/**/*.{js,ts}"] - } + "executor": "@nx/eslint:lint" } }, "tags": [], diff --git a/apps/ramp-client-e2e/tsconfig.json b/apps/ramp-client-e2e/tsconfig.json index 8ff0a820..1b681b96 100644 --- a/apps/ramp-client-e2e/tsconfig.json +++ b/apps/ramp-client-e2e/tsconfig.json @@ -8,12 +8,12 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, }, "include": ["src/**/*.ts", "src/**/*.js"], "angularCompilerOptions": { "strictInjectionParameters": true, "strictInputAccessModifiers": true, - "strictTemplates": true - } + "strictTemplates": true, + }, } diff --git a/apps/ramp-client/.eslintrc.json b/apps/ramp-client/.eslintrc.json index 7042428d..6d55b523 100644 --- a/apps/ramp-client/.eslintrc.json +++ b/apps/ramp-client/.eslintrc.json @@ -5,7 +5,7 @@ { "files": ["*.ts"], "extends": [ - "plugin:@nrwl/nx/angular", + "plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates" ], "rules": { @@ -29,7 +29,7 @@ }, { "files": ["*.html"], - "extends": ["plugin:@nrwl/nx/angular-template"], + "extends": ["plugin:@nx/angular-template"], "rules": {} } ] diff --git a/apps/ramp-client/CLIENT_INSTRUCTIONS.md b/apps/ramp-client/CLIENT_INSTRUCTIONS.md index b29ba662..860d69f7 100644 --- a/apps/ramp-client/CLIENT_INSTRUCTIONS.md +++ b/apps/ramp-client/CLIENT_INSTRUCTIONS.md @@ -8,5 +8,4 @@ To run the client application locally, please follow these steps: 4. Change directory (`cd`) to the `apps/ramp-client` directory of this repository 5. Type `ng s` or `nx run ramp-client:serve:development` and hit Enter -To build the application and run it in a container, just build and run the dockerfile in the client directory. - +To build the application and run it in a container, just build and run the dockerfile in the client directory. diff --git a/apps/ramp-client/Dockerfile b/apps/ramp-client/Dockerfile index 443633b3..364f0b0c 100644 --- a/apps/ramp-client/Dockerfile +++ b/apps/ramp-client/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18.16-alpine3.17 AS build +FROM node:20.11-alpine3.18 AS build ENV npm_config_unsafe_perm=true @@ -20,7 +20,7 @@ RUN npm install -g nx RUN npm install RUN nx g @nrwl/workspace:fix-configuration RUN npm i -RUN NODE_OPTIONS=--max_old_space_size=4096 nx run ramp-client:prerender:production --verbose +RUN NODE_OPTIONS=--max_old_space_size=8192 nx run ramp-client:build:production --verbose FROM registry.ncats.nih.gov:5000/labshare/docker-base-web diff --git a/apps/ramp-client/project.json b/apps/ramp-client/project.json index 4c81dfe8..4424106e 100644 --- a/apps/ramp-client/project.json +++ b/apps/ramp-client/project.json @@ -2,16 +2,20 @@ "name": "ramp-client", "$schema": "../../node_modules/nx/schemas/project-schema.json", "projectType": "application", - "sourceRoot": "apps/ramp-client/src", "prefix": "ramp-client", + "sourceRoot": "apps/ramp-client/src", + "tags": ["app:ramp-client"], "targets": { "build": { - "executor": "@angular-devkit/build-angular:browser", + "executor": "@angular-devkit/build-angular:application", "outputs": ["{options.outputPath}"], "options": { - "outputPath": "dist/ramp-client/browser", + "allowedCommonJsDependencies": [ + "swagger-ui" + ], + "outputPath": "dist/ramp-client", "index": "apps/ramp-client/src/index.html", - "main": "apps/ramp-client/src/main.ts", + "browser": "apps/ramp-client/src/main.ts", "polyfills": ["zone.js"], "tsConfig": "apps/ramp-client/tsconfig.app.json", "inlineStyleLanguage": "scss", @@ -36,20 +40,28 @@ "node_modules/swagger-ui/dist/swagger-ui.css", "apps/ramp-client/src/styles.scss" ], - "scripts": [] + "scripts": [], + "server": "apps/ramp-client/src/main.server.ts", + "prerender": { + "discoverRoutes": false, + "routesFile": "./apps/ramp-client/routes.txt" + }, + "ssr": { + "entry": "apps/ramp-client/server.ts" + } }, "configurations": { "production": { "budgets": [ { "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1000mb" + "maximumWarning": "5000kb", + "maximumError": "10000mb" }, { "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "500kb" + "maximumWarning": "2000kb", + "maximumError": "5000kb" } ], "fileReplacements": [ @@ -58,15 +70,20 @@ "with": "apps/ramp-client/src/environments/environment.prod.ts" } ], - "outputHashing": "all" + "outputHashing": "all", + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": true + }, + "fonts": false + } }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, - "sourceMap": true, - "namedChunks": true + "sourceMap": true } }, "defaultConfiguration": "production" @@ -75,10 +92,10 @@ "executor": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "ramp-client:build:production" + "buildTarget": "ramp-client:build:production" }, "development": { - "browserTarget": "ramp-client:build:development" + "buildTarget": "ramp-client:build:development" } }, "defaultConfiguration": "development" @@ -86,20 +103,14 @@ "extract-i18n": { "executor": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "ramp-client:build" + "buildTarget": "ramp-client:build" } }, "lint": { - "executor": "@nrwl/linter:eslint", - "options": { - "lintFilePatterns": [ - "apps/ramp-client/src/**/*.ts", - "apps/ramp-client/src/**/*.html" - ] - } + "executor": "@nx/eslint:lint" }, "test": { - "executor": "@nrwl/jest:jest", + "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/apps/ramp-client"], "options": { "jestConfig": "apps/ramp-client/jest.config.ts", @@ -128,9 +139,11 @@ ] }, "development": { + "buildOptimizer": false, "optimization": false, "sourceMap": true, - "extractLicenses": false + "extractLicenses": false, + "vendorChunk": true } }, "defaultConfiguration": "production", @@ -150,7 +163,7 @@ } }, "serve-ssr": { - "executor": "@nguniversal/builders:ssr-dev-server", + "executor": "@angular-devkit/build-angular:ssr-dev-server", "configurations": { "development": { "browserTarget": "ramp-client:build:development", @@ -164,10 +177,10 @@ "defaultConfiguration": "development" }, "prerender": { - "executor": "@nguniversal/builders:prerender", + "executor": "@angular-devkit/build-angular:prerender", "options": { - "guessRoutes": false, - "routesFile": "./apps/ramp-client/routes.txt" + "routesFile": "./apps/ramp-client/routes.txt", + "discoverRoutes": false }, "configurations": { "production": { @@ -181,6 +194,5 @@ }, "defaultConfiguration": "production" } - }, - "tags": ["app:ramp-client"] + } } diff --git a/apps/ramp-client/server.ts b/apps/ramp-client/server.ts index 8ede7113..1fc5a95e 100644 --- a/apps/ramp-client/server.ts +++ b/apps/ramp-client/server.ts @@ -1,39 +1,49 @@ -import 'zone.js/dist/zone-node'; +import 'zone.js/node'; -import { ngExpressEngine } from '@nguniversal/express-engine'; -import express from "express"; -import { join } from 'path'; - -import { AppServerModule } from './src/main.server'; import { APP_BASE_HREF } from '@angular/common'; -import { existsSync } from 'fs'; -import { InjectionToken } from '@angular/core'; +import { CommonEngine } from '@angular/ssr'; +import {default as express} from 'express'; +import { existsSync } from 'node:fs'; +import { join } from 'node:path'; +import bootstrap from './src/main.server'; // The Express app is exported so that it can be used by serverless Functions. export function app(): express.Express { const server = express(); - const distFolder = join(process.cwd(), "dist/ramp-client/browser"); - const indexHtml = existsSync(join(distFolder, "index.original.html")) ? "index.original.html" : "index"; + const distFolder = join(process.cwd(), 'dist/rdas/browser'); + const indexHtml = existsSync(join(distFolder, 'index.original.html')) + ? join(distFolder, 'index.original.html') + : join(distFolder, 'index.html'); - // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) - server.engine("html", ngExpressEngine({ - bootstrap: AppServerModule - })); + const commonEngine = new CommonEngine(); - server.set("view engine", "html"); - server.set("views", distFolder); + server.set('view engine', 'html'); + server.set('views', distFolder); // Example Express Rest API endpoints // server.get('/api/**', (req, res) => { }); // Serve static files from /browser - server.get("*.*", express.static(distFolder, { - maxAge: "1y" - })); - - // All regular routes use the Universal engine - server.get("*", ( - req: { baseUrl: any; }, res: { render: (arg0: string, arg1: { req: any; providers: { provide: InjectionToken; useValue: any; }[]; }) => void; }) => { - res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); + server.get( + '*.*', + express.static(distFolder, { + maxAge: '1y', + }), + ); + + // All regular routes use the Angular engine + server.get('*', (req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; + + commonEngine + .render({ + bootstrap, + documentFilePath: indexHtml, + url: `${protocol}://${headers.host}${originalUrl}`, + publicPath: distFolder, + providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], + }) + .then((html) => res.send(html)) + .catch((err) => next(err)); }); return server; @@ -54,9 +64,9 @@ function run(): void { // The below code is to ensure that the server is run only when not requiring the bundle. declare const __non_webpack_require__: NodeRequire; const mainModule = __non_webpack_require__.main; -const moduleFilename = mainModule && mainModule.filename || ''; +const moduleFilename = (mainModule && mainModule.filename) || ''; if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { run(); } -export * from './src/main.server'; +export default bootstrap; diff --git a/apps/ramp-client/src/app/app.component.html b/apps/ramp-client/src/app/app.component.html index a191a2ca..1aa64a6a 100644 --- a/apps/ramp-client/src/app/app.component.html +++ b/apps/ramp-client/src/app/app.component.html @@ -1,26 +1,45 @@ -
-
- -
-
-
- - -
-
- +
+
+ +
+ + + +
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
diff --git a/apps/ramp-client/src/app/app.component.scss b/apps/ramp-client/src/app/app.component.scss index 119cafd4..0850b6fd 100644 --- a/apps/ramp-client/src/app/app.component.scss +++ b/apps/ramp-client/src/app/app.component.scss @@ -1,18 +1,3 @@ -@use '@angular/material' as mat; -@import 'libs/styles/src/styles/ncats-theme'; - - - -.toolbar-template { - background-color: mat.get-color-from-palette($app-accent); - color: #ffffff; -} - -.footer-template { - background-color: mat.get-color-from-palette($app-accent); - color: #ffffff; -} - .toolbar-template button { color: #ffffff !important; padding: 0 1vw 0 1vw; @@ -31,3 +16,13 @@ .ramp-logo-footer { max-width: 100%; } + +.right-options { + display: flex; + flex-direction: row; + flex-wrap: wrap; + box-sizing: border-box; + align-content: center; + align-items: center; + justify-content: flex-start; +} diff --git a/apps/ramp-client/src/app/app.component.spec.ts b/apps/ramp-client/src/app/app.component.spec.ts index 2b74248d..57b18df2 100644 --- a/apps/ramp-client/src/app/app.component.spec.ts +++ b/apps/ramp-client/src/app/app.component.spec.ts @@ -1,41 +1,26 @@ -import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { MatDialogModule } from '@angular/material/dialog'; -import { RouterTestingModule } from '@angular/router/testing'; -import { EffectsModule } from '@ngrx/effects'; -import { StoreModule } from '@ngrx/store'; -import { FeaturesRampRampHeaderModule } from '@ramp/features/ramp/ramp-header'; -import { SharedNcatsNcatsFooterModule } from "@ramp/shared/ncats/ncats-footer"; -import { SharedUiLoadingSpinnerModule } from '@ramp/shared/ui/loading-spinner'; -import { RampFacade, StoresRampStoreModule } from '@ramp/stores/ramp-store'; -import { environment } from '../environments/environment'; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { provideEffects } from "@ngrx/effects"; +import { provideStore } from "@ngrx/store"; +import { provideStoreDevtools } from "@ngrx/store-devtools"; +import { RampEffects, rampReducer } from "@ramp/stores/ramp-store"; import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [AppComponent], + declarations: [], imports: [ - RouterTestingModule, - HttpClientTestingModule, - SharedUiLoadingSpinnerModule, - FeaturesRampRampHeaderModule, - SharedNcatsNcatsFooterModule, - MatDialogModule, - StoresRampStoreModule, - StoreModule.forRoot( - {}, - { - metaReducers: !environment.production ? [] : [], - runtimeChecks: { - strictActionImmutability: true, - strictStateImmutability: true, - }, - } - ), - EffectsModule.forRoot([]), + BrowserAnimationsModule, + AppComponent ], - providers: [RampFacade], + providers: [ + provideStore({ + rampStore: rampReducer + }), + provideEffects([RampEffects]), + provideStoreDevtools({ maxAge: 25, logOnly: false }) + ] }).compileComponents(); }); diff --git a/apps/ramp-client/src/app/app.component.ts b/apps/ramp-client/src/app/app.component.ts index d04c6fc9..428e7c5b 100644 --- a/apps/ramp-client/src/app/app.component.ts +++ b/apps/ramp-client/src/app/app.component.ts @@ -1,15 +1,27 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, - OnInit, ViewChild, - ViewEncapsulation -} from "@angular/core"; + Component, + DestroyRef, + inject, + OnInit, + ViewEncapsulation, +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatDialog } from '@angular/material/dialog'; -import { ErrorDialogComponent } from '@ramp/shared/ui/error-dialog'; -import { LinkTemplateProperty } from '@ramp/shared/ui/header-template'; -import { RampFacade } from '@ramp/stores/ramp-store'; +import { select, Store } from '@ngrx/store'; +import { + LinkTemplateProperty, + RampHeaderComponent, +} from '@ramp/features/ramp/ramp-header'; +import { NcatsFooterComponent } from '@ramp/shared/ncats/ncats-footer'; +import { LoadingComponent } from '@ramp/shared/ui/loading-spinner'; +import { map } from 'rxjs'; +import { RampFullBannerComponent } from '@ramp/shared/ramp/full-banner'; +import { environment } from '../environments/environment'; +import { RouterOutlet } from '@angular/router'; +import { RampSelectors } from '@ramp/stores/ramp-store'; @Component({ selector: 'ramp-root', @@ -17,10 +29,22 @@ import { RampFacade } from '@ramp/stores/ramp-store'; styleUrls: ['./app.component.scss'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + RouterOutlet, + NcatsFooterComponent, + LoadingComponent, + RampHeaderComponent, + RampFullBannerComponent, + ], }) export class AppComponent implements OnInit { + private readonly store = inject(Store); + destroyRef = inject(DestroyRef); + title = 'ramp-client'; loading = true; + isProd = false; links: LinkTemplateProperty[] = [ { link: 'Biological Pathways', @@ -32,7 +56,7 @@ export class AppComponent implements OnInit { { link: 'analytes-from-pathways', label: 'Analytes from Input Pathways', - } + }, ], }, { @@ -66,9 +90,10 @@ export class AppComponent implements OnInit { children: [ { link: 'common-reaction-analytes', - label: 'Retrieve Analytes involved in Same Reactions as input Analytes\n', - } - ] + label: + 'Retrieve Analytes involved in Same Reactions as input Analytes\n', + }, + ], }, { link: 'Enrichment Analyses', @@ -97,24 +122,30 @@ export class AppComponent implements OnInit { constructor( public dialog: MatDialog, private changeRef: ChangeDetectorRef, - protected rampFacade: RampFacade ) {} ngOnInit() { - this.rampFacade.error$.subscribe((error) => { + this.isProd = !environment.production; + /* this.error$.subscribe((error) => { if (error) { - console.log(error); - /* this.dialog.open(ErrorDialogComponent, { + // console.log(error); + /!* this.dialog.open(ErrorDialogComponent, { data: { error: error, }, - });*/ + });*!/ } - }); + });*/ - this.rampFacade.loading$.subscribe((res) => { - this.loading = res; - this.changeRef.markForCheck(); - }); + this.store + .pipe( + select(RampSelectors.getRampLoaded), + takeUntilDestroyed(this.destroyRef), + map((res: boolean) => { + this.loading = res; + this.changeRef.markForCheck(); + }), + ) + .subscribe(); } } diff --git a/apps/ramp-client/src/app/app.config.server.ts b/apps/ramp-client/src/app/app.config.server.ts new file mode 100644 index 00000000..49b1a539 --- /dev/null +++ b/apps/ramp-client/src/app/app.config.server.ts @@ -0,0 +1,10 @@ +import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; +import { provideClientHydration } from '@angular/platform-browser'; +import { provideServerRendering } from '@angular/platform-server'; +import { appConfig } from './app.config'; + +const serverConfig: ApplicationConfig = { + providers: [provideServerRendering(), provideClientHydration()], +}; + +export const config = mergeApplicationConfig(appConfig, serverConfig); diff --git a/apps/ramp-client/src/app/app.config.ts b/apps/ramp-client/src/app/app.config.ts new file mode 100644 index 00000000..d59cb13e --- /dev/null +++ b/apps/ramp-client/src/app/app.config.ts @@ -0,0 +1,83 @@ +import { + provideHttpClient, + withFetch, + withInterceptorsFromDi, +} from '@angular/common/http'; +import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core'; +import { provideClientHydration } from '@angular/platform-browser'; +import { provideAnimations } from '@angular/platform-browser/animations'; +import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; +import { + PreloadAllModules, + provideRouter, + withComponentInputBinding, + withEnabledBlockingInitialNavigation, + withInMemoryScrolling, + withPreloading, + withViewTransitions, +} from '@angular/router'; +import { provideEffects } from '@ngrx/effects'; +import { provideState, provideStore, Store } from '@ngrx/store'; +import { provideStoreDevtools } from '@ngrx/store-devtools'; +import { STRUCTURE_VIEWER_COMPONENT, StructureViewerComponent } from "@ramp/shared/ui/ncats-structure-viewer"; +import { + LoadRampActions, + RampService, + RampEffects, + rampReducer, + RAMP_STORE_FEATURE_KEY, +} from '@ramp/stores/ramp-store'; +import { environment } from '../environments/environment'; + +import { routes } from './app.routes'; + +export function set_url(rampService: RampService) { + return () => { + rampService._setUrl(environment.apiBaseUrl); + }; +} + +export function rampInit(store = inject(Store)) { + return () => { + store.dispatch(LoadRampActions.loadRamp()); + store.dispatch(LoadRampActions.loadRampStats()); + }; +} + +export const appConfig: ApplicationConfig = { + providers: [ + { + provide: APP_INITIALIZER, + useFactory: set_url, + deps: [RampService], + multi: true, + }, + { + provide: APP_INITIALIZER, + useFactory: rampInit, + deps: [], + multi: true, + }, + { provide: STRUCTURE_VIEWER_COMPONENT, useClass: StructureViewerComponent }, + provideRouter( + routes, + withViewTransitions(), + withComponentInputBinding(), + withEnabledBlockingInitialNavigation(), + withInMemoryScrolling({ + anchorScrolling: 'enabled', + scrollPositionRestoration: 'enabled', + }), + withPreloading(PreloadAllModules), + ), + provideStore({ rampStore: rampReducer }), + // provideRouterStore(), + provideStoreDevtools(), + provideEffects([RampEffects]), + provideState(RAMP_STORE_FEATURE_KEY, rampReducer), + provideAnimations(), + provideAnimationsAsync(), + provideHttpClient(withInterceptorsFromDi(), withFetch()), + provideClientHydration(), + ], +}; diff --git a/apps/ramp-client/src/app/app.module.ts b/apps/ramp-client/src/app/app.module.ts deleted file mode 100644 index 29ca6d83..00000000 --- a/apps/ramp-client/src/app/app.module.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { MatDialogModule } from '@angular/material/dialog'; -import { BrowserModule } from '@angular/platform-browser'; -import { APP_INITIALIZER, NgModule } from '@angular/core'; -import { EffectsModule } from '@ngrx/effects'; -import { StoreModule } from '@ngrx/store'; -import { StoreDevtoolsModule } from '@ngrx/store-devtools'; -import { SharedNcatsNcatsFooterModule } from "@ramp/shared/ncats/ncats-footer"; -import { SharedUiLoadingSpinnerModule } from '@ramp/shared/ui/loading-spinner'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { HttpClientModule } from '@angular/common/http'; -import { FeaturesRampRampHeaderModule } from '@ramp/features/ramp/ramp-header'; -import { - RampFacade, - RampService, - StoresRampStoreModule, -} from '@ramp/stores/ramp-store'; -import { environment } from '../environments/environment'; - -export function set_url(rampService: RampService) { - return () => { - rampService._setUrl(environment.apiBaseUrl); - }; -} - -export function rampInit(rampFacade: RampFacade) { - return () => { - rampFacade.init(); - }; -} - -@NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule.withServerTransition({ appId: 'serverApp' }), - AppRoutingModule, - BrowserAnimationsModule, - FormsModule, - MatDialogModule, - ReactiveFormsModule, - HttpClientModule, - SharedUiLoadingSpinnerModule, - FeaturesRampRampHeaderModule, - StoresRampStoreModule, - StoreModule.forRoot( - {}, - { - metaReducers: !environment.production ? [] : [], - runtimeChecks: { - strictActionImmutability: true, - strictStateImmutability: true - } - } - ), - EffectsModule.forRoot([]), - StoreDevtoolsModule.instrument({ - maxAge: 25, - logOnly: !environment.production - }), - SharedNcatsNcatsFooterModule - ], - providers: [ - RampFacade, - { - provide: APP_INITIALIZER, - useFactory: set_url, - deps: [RampService], - multi: true, - }, - { - provide: APP_INITIALIZER, - useFactory: rampInit, - deps: [RampFacade], - multi: true, - }, - ], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/apps/ramp-client/src/app/app-routing.module.ts b/apps/ramp-client/src/app/app.routes.ts similarity index 66% rename from apps/ramp-client/src/app/app-routing.module.ts rename to apps/ramp-client/src/app/app.routes.ts index d815abfa..c84bcf55 100644 --- a/apps/ramp-client/src/app/app-routing.module.ts +++ b/apps/ramp-client/src/app/app.routes.ts @@ -1,52 +1,48 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; +import { Routes } from '@angular/router'; +import { STRUCTURE_VIEWER_COMPONENT, StructureViewerComponent } from "@ramp/shared/ui/ncats-structure-viewer"; import rFunctions from '../assets/data/rFunctions.json'; import { environment } from '../environments/environment'; -const routes: Routes = [ +export const routes: Routes = [ { path: '', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => - import('@ramp/features/ramp/ramp-home').then( - (m) => m.FeaturesRampRampHomeModule - ), + loadComponent: () => + import('@ramp/features/ramp/ramp-home').then((m) => m.HomeComponent), }, { path: 'home', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => - import('@ramp/features/ramp/ramp-home').then( - (m) => m.FeaturesRampRampHomeModule - ), + loadComponent: () => + import('@ramp/features/ramp/ramp-home').then((m) => m.HomeComponent), }, { path: 'about', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => - import('@ramp/features/ramp/ramp-about').then( - (m) => m.FeaturesRampRampAboutModule - ), + providers: [ + // provideEffects([RampEffects]), + // provideState(RAMP_STORE_FEATURE_KEY, rampReducer) + ], + loadComponent: () => + import('@ramp/features/ramp/ramp-about').then((m) => m.AboutComponent), }, { path: 'api', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => - import('@ramp/features/ramp/ramp-api').then( - (m) => m.FeaturesRampRampApiModule - ), + loadComponent: () => + import('@ramp/features/ramp/ramp-api').then((m) => m.RampApiComponent), }, { path: 'ontologies-from-metabolites', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/ontologies-from-metabolites').then( - (m) => m.FeaturesRampOntologiesModule + (m) => m.OntologiesFromMetabolitesComponent, ), data: { ...rFunctions['ontologies-from-analytes'], @@ -56,9 +52,9 @@ const routes: Routes = [ path: 'metabolites-from-ontologies', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/metabolites-from-ontologies').then( - (m) => m.FeaturesRampMetabolitesFromOntologiesModule + (m) => m.MetabolitesFromOntologiesComponent, ), data: { ...rFunctions['metabolites-from-ontologies'], @@ -68,9 +64,9 @@ const routes: Routes = [ path: 'analytes-from-pathways', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/analytes-from-pathways').then( - (m) => m.FeaturesRampAnalytesFromPathwaysModule + (m) => m.AnalytesFromPathwaysComponent, ), data: { ...rFunctions['analytes-from-pathways'], @@ -80,9 +76,9 @@ const routes: Routes = [ path: 'pathways-from-analytes', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/pathways-from-analytes').then( - (m) => m.FeaturesRampPathwaysFromAnalytesModule + (m) => m.PathwaysFromAnalytesComponent, ), data: { ...rFunctions['pathways-from-analytes'], @@ -92,9 +88,9 @@ const routes: Routes = [ path: 'common-reaction-analytes', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/common-reaction-analytes').then( - (m) => m.FeaturesRampCommonReactionAnalytesModule + (m) => m.CommonReactionAnalytesComponent, ), data: { ...rFunctions['common-reaction-analytes'], @@ -104,9 +100,9 @@ const routes: Routes = [ path: 'classes-from-metabolites', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/classes-from-metabolites').then( - (m) => m.FeaturesRampClassesFromMetabolitesModule + (m) => m.ClassesFromMetabolitesComponent, ), data: { ...rFunctions['classes-from-metabolites'], @@ -116,9 +112,12 @@ const routes: Routes = [ path: 'properties-from-metabolites', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + providers: [ + { provide: STRUCTURE_VIEWER_COMPONENT, useValue: StructureViewerComponent }, + ], + loadComponent: () => import('@ramp/features/ramp/properties-from-metabolites').then( - (m) => m.FeaturesRampPropertiesFromMetabolitesModule + (m) => m.PropertiesFromMetabolitesComponent, ), data: { ...rFunctions['properties-from-metabolites'], @@ -129,9 +128,9 @@ const routes: Routes = [ path: 'chemical-enrichment', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/chemical-enrichment').then( - (m) => m.FeaturesRampChemicalEnrichmentModule + (m) => m.ChemicalEnrichmentComponent, ), data: { ...rFunctions['chemical-enrichment'], @@ -141,20 +140,12 @@ const routes: Routes = [ path: 'pathway-enrichment', pathMatch: 'full', runGuardsAndResolvers: 'paramsOrQueryParamsChange', - loadChildren: () => + loadComponent: () => import('@ramp/features/ramp/pathway-enrichment').then( - (m) => m.FeaturesRampPathwayEnrichmentModule + (m) => m.PathwayEnrichmentComponent, ), data: { ...rFunctions['pathway-enrichment'], }, - } + }, ]; - -@NgModule({ - imports: [RouterModule.forRoot(routes, { - initialNavigation: 'enabledBlocking' -})], - exports: [RouterModule], -}) -export class AppRoutingModule {} diff --git a/apps/ramp-client/src/app/app.server.module.ts b/apps/ramp-client/src/app/app.server.module.ts deleted file mode 100644 index ab0a4d73..00000000 --- a/apps/ramp-client/src/app/app.server.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { NgModule } from '@angular/core'; -import { FlexLayoutServerModule } from "@angular/flex-layout/server"; -import { ServerModule } from '@angular/platform-server'; - -import { AppModule } from './app.module'; -import { AppComponent } from './app.component'; - -@NgModule({ - imports: [ - AppModule, - ServerModule, - FlexLayoutServerModule - ], - bootstrap: [AppComponent], -}) -export class AppServerModule {} diff --git a/apps/ramp-client/src/assets/data/rFunctions.json b/apps/ramp-client/src/assets/data/rFunctions.json index 45ea63ff..ab100bc7 100644 --- a/apps/ramp-client/src/assets/data/rFunctions.json +++ b/apps/ramp-client/src/assets/data/rFunctions.json @@ -6,7 +6,7 @@ "examples": "ensembl:ENSG00000135679, hmdb:HMDB0000064, hmdb:HMDB0000148, ensembl:ENSG00000141510", "description": "Enter a list of metabolites. IDs should be prepended by ID source (e.g. kegg:C00412). See below for supported sources." }, - "metabolites-from-ontologies" : { + "metabolites-from-ontologies": { "title": "Retrieve Analytes (Metabolites) from Ontologies", "input": "ontology", "supportedIdTypes": [], @@ -27,9 +27,9 @@ "examples": "ensembl:ENSG00000135679, hmdb:HMDB0000064, hmdb:HMDB0000148, ensembl:ENSG00000141510", "description": "Retrieve pathway(s) for a given analyte(s). IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). See below for supported sources." }, - "analyteid-types" : { + "analyteid-types": { "title": "Retrieve Analyte ID types", - "function": "idtypes <- RaMP::getPrefixesFromAnalytes(\"metabolite\"); RaMP::getPrefixesFromAnalytes(\"gene\"))", + "function": "idtypes <- RaMP::getPrefixesFromAnalytes(\"metabolite\"); RaMP::getPrefixesFromAnalytes(\"gene\"))", "description": "Retrieve analyte ID types to be used as prefixes for other RaMP function calls." }, "common-reaction-analytes": { @@ -37,7 +37,7 @@ "input": "analytes", "supportedIdTypes": ["Metabolites", "Genes/Proteins"], "examples": "ensembl:ENSG00000135679, hmdb:HMDB0000064, hmdb:HMDB0000148, ensembl:ENSG00000141510", - "description": "Retrieve Analytes Involved in the Same Reaction. IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). See below for supported sources.." + "description": "Retrieve Analytes Involved in the Same Reaction. IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). See below for supported sources." }, "classes-from-metabolites": { "title": "Retrieve Chemical Classes from Input Metabolites", @@ -48,8 +48,8 @@ }, "properties-from-metabolites": { "title": "Retrieve Chemical Properties from Input Metabolites", - "input": "metabolites", - "function": "analytes <- RaMP::getChemicalProperties(mets=\"###REPLACE###\")", + "input": "metabolites", + "function": "analytes <- RaMP::getChemicalProperties(mets=\"###REPLACE###\")", "supportedIdTypes": ["Metabolites"], "examples": "hmdb:HMDB0000056, hmdb:HMDB0000439, hmdb:HMDB0000479, hmdb:HMDB0000532, hmdb:HMDB0001015, hmdb:HMDB0001138, hmdb:HMDB0029159, hmdb:HMDB0029412, hmdb:HMDB0034365, hmdb:HMDB0035227, hmdb:HMDB0007973, hmdb:HMDB0008057, hmdb:HMDB0011211", "description": "Retrieve chemical properties (smiles, inchi_key, inchi_key_prefix, inchi, mw, monoisotop_mass, formula, common_name) from input metabolites. IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). See below for supported sources." @@ -58,14 +58,14 @@ "title": "Perform Chemical Class Enrichment", "input": "metabolites", "supportedIdTypes": ["Metabolites"], - "function": "analytes <- RaMP::chemicalClassEnrichment(mets=\"###REPLACE###\")", + "function": "analytes <- RaMP::chemicalClassEnrichment(mets=\"###REPLACE###\")", "examples": "hmdb:HMDB0000056, hmdb:HMDB0000439, hmdb:HMDB0000479, hmdb:HMDB0000532, hmdb:HMDB0001015, hmdb:HMDB0001138, hmdb:HMDB0029159, hmdb:HMDB0029412, hmdb:HMDB0034365, hmdb:HMDB0035227, hmdb:HMDB0007973, hmdb:HMDB0008057, hmdb:HMDB0011211, hmdb:HMDB0001085, hmdb:HMDB0002122, hmdb:HMDB0002685, hmdb:HMDB0004241, hmdb:HMDB0005079, hmdb:HMDB0006245", "description": "Perform chemical class enrichment on ClassyFire and LIPIDMAPS classes. IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). See below for supported sources." }, "pathway-enrichment": { "title": "Perform Pathway Enrichment", - "input": "analytes", - "function": "analytes <- RaMP::runCombinedFisherTest(analytes=\"###REPLACE###\")", + "input": "analytes", + "function": "analytes <- RaMP::runCombinedFisherTest(analytes=\"###REPLACE###\")", "supportedIdTypes": ["Metabolites", "Genes/Proteins"], "examples": "hmdb:HMDB0000033, hmdb:HMDB0000052, hmdb:HMDB0000094, hmdb:HMDB0000161, hmdb:HMDB0000168, hmdb:HMDB0000191, hmdb:HMDB0000201, chemspider:10026, hmdb:HMDB0006059, Chemspider:6405,CAS:5657-19-2,hmdb:HMDB0002511, chemspider:20171375, CAS:133-32-4, CAS:5746-90-7, CAS:477251-67-5, hmdb:HMDB0000695, chebi:15934, CAS:838-07-3, hmdb:HMDBP00789, hmdb:HMDBP00283, hmdb:HMDBP00284,hmdb:HMDBP00850", "description": "Perform Pathway Enrichment. IDs should be prepended by ID source (e.g. hmdb:HMDB0000122). Input analyte IDs can be a mix of genes/proteins or metabolites. See below for supported sources." diff --git a/apps/ramp-client/src/index.html b/apps/ramp-client/src/index.html index 0215810e..f84887d8 100644 --- a/apps/ramp-client/src/index.html +++ b/apps/ramp-client/src/index.html @@ -1,4 +1,4 @@ - + @@ -7,10 +7,15 @@ - +