From fc4027c34fb4a25fd4e2e6a384998865abdf94f3 Mon Sep 17 00:00:00 2001 From: Mantra Date: Tue, 5 Nov 2024 14:09:13 +0000 Subject: [PATCH 1/4] always use npm run dev on ci --- app/static/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/static/playwright.config.ts b/app/static/playwright.config.ts index d734a9a7..0c50b7d4 100644 --- a/app/static/playwright.config.ts +++ b/app/static/playwright.config.ts @@ -62,7 +62,7 @@ export default defineConfig({ * Use the preview server on CI for more realistic testing. * Playwright will re-use the local server if there is already a dev-server running. */ - command: process.env.CI ? 'npm run preview' : 'npm run dev', + command: 'npm run dev', port: 5173, reuseExistingServer: !process.env.CI } From 2c9eced0bb4db58e0aae479b97c2c491020730b5 Mon Sep 17 00:00:00 2001 From: Mantra Date: Tue, 5 Nov 2024 14:09:44 +0000 Subject: [PATCH 2/4] build on ci with playwright --- app/static/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/static/playwright.config.ts b/app/static/playwright.config.ts index 0c50b7d4..d7297985 100644 --- a/app/static/playwright.config.ts +++ b/app/static/playwright.config.ts @@ -62,7 +62,7 @@ export default defineConfig({ * Use the preview server on CI for more realistic testing. * Playwright will re-use the local server if there is already a dev-server running. */ - command: 'npm run dev', + command: process.env.CI ? 'npm run build' : 'npm run dev', port: 5173, reuseExistingServer: !process.env.CI } From 0e5f5a94ec515711ba9c3955a869cf32c07c6a41 Mon Sep 17 00:00:00 2001 From: Mantra Date: Tue, 5 Nov 2024 16:49:43 +0000 Subject: [PATCH 3/4] address misc comments --- README.md | 19 ++++++++++++--- app/server/src/controllers/appsController.ts | 9 +++---- app/server/src/server/args.ts | 12 +++++++++- app/server/src/types.ts | 2 +- app/server/views/app-hot-reload.hbs | 24 ------------------- app/server/views/app.hbs | 9 +++++-- app/static/package-lock.json | 9 ------- app/static/package.json | 1 - app/static/src/assets/fontawesome.css | 14 ++++++----- app/static/src/components/DownloadOutput.vue | 4 ++-- app/static/src/components/WodinPanels.vue | 2 +- app/static/src/components/WodinPlot.vue | 3 ++- .../src/components/WodinPlotDataSummary.vue | 8 +++---- .../src/components/help/DraggableDialog.vue | 4 ++-- .../src/components/help/MarkdownPanel.vue | 10 +++----- .../sensitivity/SensitivityTracesPlot.vue | 2 +- .../src/components/sessions/SessionsPage.vue | 4 ++-- app/static/src/plot.ts | 5 ++-- app/static/src/store/translations/codeTab.ts | 2 +- app/static/src/store/translations/dataTab.ts | 2 +- app/static/src/store/translations/fitTab.ts | 2 +- .../src/store/translations/genericHelp.ts | 2 +- app/static/src/store/translations/header.ts | 2 +- .../src/store/translations/indexPage.ts | 2 +- .../src/store/translations/optionsTab.ts | 2 +- app/static/src/store/translations/runTab.ts | 2 +- .../src/store/translations/sensitivityTab.ts | 2 +- app/static/src/store/translations/shared.ts | 2 +- .../store/translations/stochasticHelpTab.ts | 2 +- app/static/src/utils.ts | 2 +- config/index.html | 3 +-- 31 files changed, 79 insertions(+), 89 deletions(-) delete mode 100644 app/server/views/app-hot-reload.hbs diff --git a/README.md b/README.md index 59d98c1b..0410b648 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,7 @@ See the `/config` folder for example configuration, used in development. ## Development -This codebase has been tested with Node version 16.16.0. -If you have recently changed node version, you may see Node Sass binding errors - running `npm rebuild node-sass --prefix=app/static` -should fix this issue. +This codebase has been tested with Node version 20.9.0. ## Frontend @@ -93,6 +91,15 @@ The entry point script is `app/static/src/wodin.ts`. ### Unit Tests Run unit tests from `app/static` using `npm run test:unit`. Run [eslint](https://eslint.org/) with `npm run lint` or `npm run lint:fix`. +### Fontawesome +We use fontawesome for some icons (e.g. glyph in Monaco editor when there's an error or a warning). We have only the icons we need from fontawesome in `app/static/src/assets/fontawesome.css` so if you would like to add a new one, you can define a custom class: +``` +. { + content: "\" +} +``` +where you can define the `` and the `` for the icon can be found at [Fontawesome](https://fontawesome.com/search?o=r&s=solid&f=classic) (it is in the top right hand corner when you select an icon). Note: we only have the "solid" icons currently. + ## Backend The back end handles requests for apps by reading the corresponding config files and rendering an html [Handlebars](https://handlebarsjs.com/) template @@ -133,3 +140,9 @@ Use the `./scripts/run-version.sh` script setting the branch references for the ``` ./scripts/run-version.sh --app mrc-1234 --api mrc-2345 ``` + +## Hot Reloading + +This repo has two main parts: `app/server` (Express server) and `app/static` (Vue frontend). The normal way to spin up the app without hot reloading is build frontend, copy build files into public folder in the server and run the server. The html file will then look for its javascript src `wodin.js` and css src `wodin.css` in the `app/server/public` directory and load the app from these. + +The hot reloading setup is different. The `server.js` file (from building the server) takes in a `--hot-reload` boolean option which tells it to instead look for the javascript src at `http://localhost:5173/src/wodin.ts` since `wodin.ts` is our entrypoint (`http://localhost:5173` is the default url for `vite` dev mode and it serves the files, after transpiling to javascript, based on your folder structure) and css src at `http://localhost:5173/src/scss/style.scss`. diff --git a/app/server/src/controllers/appsController.ts b/app/server/src/controllers/appsController.ts index 2c07cd7d..2e5b8f2d 100644 --- a/app/server/src/controllers/appsController.ts +++ b/app/server/src/controllers/appsController.ts @@ -43,13 +43,10 @@ export class AppsController { shareNotFound: shareNotFound || "", mathjaxSrc: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js", enableI18n: wodinConfig.enableI18n ?? false, // if option not set then false by default - defaultLanguage: wodinConfig?.defaultLanguage || "en" + defaultLanguage: wodinConfig?.defaultLanguage || "en", + hotReload }; - if (hotReload === "true") { - res.render("app-hot-reload", viewOptions); - } else { - res.render("app", viewOptions); - } + res.render("app", viewOptions); } else { throw new WodinWebError( `App not found: ${appName}`, diff --git a/app/server/src/server/args.ts b/app/server/src/server/args.ts index 214f6aa7..ce98931c 100644 --- a/app/server/src/server/args.ts +++ b/app/server/src/server/args.ts @@ -25,6 +25,16 @@ const parseArgInteger = (arg: string | null, name: string): Perhaps => { return parseInt(arg, 10); }; +const parseArgBoolean = (arg: string | null, name: string): Perhaps => { + if (arg === null) { + return null; + } + if (arg.toLowerCase() !== "true" && arg.toLowerCase() !== "false") { + throw Error(`Expected a boolean for ${name}`); + } + return arg.toLowerCase() === "true"; +}; + export const processArgs = (argv: string[] = process.argv) => { const opts = docopt(doc, { argv: argv.slice(2), version, exit: false }); const path = opts[""] as string; @@ -32,7 +42,7 @@ export const processArgs = (argv: string[] = process.argv) => { baseUrl: opts["--base-url"] as Perhaps, odinApi: opts["--odin-api"] as Perhaps, redisUrl: opts["--redis-url"] as Perhaps, - hotReload: opts["--hot-reload"] as Perhaps, + hotReload: parseArgBoolean(opts["--hot-reload"], "hot-reload"), port: parseArgInteger(opts["--port"], "port") }; const { hotReload, ...prodGiven } = given; diff --git a/app/server/src/types.ts b/app/server/src/types.ts index f6ec2487..8ccd0234 100644 --- a/app/server/src/types.ts +++ b/app/server/src/types.ts @@ -53,7 +53,7 @@ export interface AppLocals { wodinConfig: WodinConfig, wodinVersion: String, redis: Redis, - hotReload: String + hotReload: Boolean } export interface SessionMetadata { diff --git a/app/server/views/app-hot-reload.hbs b/app/server/views/app-hot-reload.hbs deleted file mode 100644 index 01a869a8..00000000 --- a/app/server/views/app-hot-reload.hbs +++ /dev/null @@ -1,24 +0,0 @@ - - - - - {{title}} - -
- - - - - diff --git a/app/server/views/app.hbs b/app/server/views/app.hbs index 8a160b1f..d24da753 100644 --- a/app/server/views/app.hbs +++ b/app/server/views/app.hbs @@ -18,7 +18,12 @@ var loadSessionIdGlobal = "{{loadSessionId}}"; var shareNotFoundGlobal = "{{shareNotFound}}"; - - + {{#if hotReload}} + + + {{else}} + + + {{/if}} diff --git a/app/static/package-lock.json b/app/static/package-lock.json index 15b66fdc..3d89787a 100644 --- a/app/static/package-lock.json +++ b/app/static/package-lock.json @@ -8,7 +8,6 @@ "name": "wodin", "version": "0.0.0", "dependencies": { - "@fortawesome/fontawesome-free": "^6.6.0", "@monaco-editor/loader": "^1.4.0", "axios": "^1.7.7", "bootstrap": "^5.3.3", @@ -280,14 +279,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@fortawesome/fontawesome-free": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz", - "integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==", - "engines": { - "node": ">=6" - } - }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", diff --git a/app/static/package.json b/app/static/package.json index 9033d2a4..3bafcf3b 100644 --- a/app/static/package.json +++ b/app/static/package.json @@ -17,7 +17,6 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@fortawesome/fontawesome-free": "^6.6.0", "@monaco-editor/loader": "^1.4.0", "axios": "^1.7.7", "bootstrap": "^5.3.3", diff --git a/app/static/src/assets/fontawesome.css b/app/static/src/assets/fontawesome.css index 6d208c81..d9ffc50f 100644 --- a/app/static/src/assets/fontawesome.css +++ b/app/static/src/assets/fontawesome.css @@ -31,12 +31,6 @@ .fa-regular { font-family: 'Font Awesome 6 Free'; } -.fa-triangle-exclamation::before { - content: "\f071"; } - -.fa-circle-xmark::before { - content: "\f057"; } - :root, :host { --fa-style-family-classic: 'Font Awesome 6 Free'; --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; } @@ -51,3 +45,11 @@ .fas, .fa-solid { font-weight: 900; } + +/* current icons that we use, to add more see Fontawesome section in the README */ + +.fa-triangle-exclamation::before { + content: "\f071"; } + +.fa-circle-xmark::before { + content: "\f057"; } diff --git a/app/static/src/components/DownloadOutput.vue b/app/static/src/components/DownloadOutput.vue index 88283c52..ce4dbe70 100644 --- a/app/static/src/components/DownloadOutput.vue +++ b/app/static/src/components/DownloadOutput.vue @@ -59,7 +59,7 @@ import { computed, defineComponent, ref, watch } from "vue"; import { useStore } from "vuex"; import userMessages from "../userMessages"; -import { parseTime } from "@/utils"; +import { parseDateTime } from "@/utils"; export default defineComponent({ name: "DownloadOutput", @@ -101,7 +101,7 @@ export default defineComponent({ const generateDefaultFileName = () => { const now = new Date(Date.now()); - const { year, month, day, hour, minute, second } = parseTime(now); + const { year, month, day, hour, minute, second } = parseDateTime(now); const timestamp = `${year}${month}${day}-${hour}${minute}${second}` const type = props.downloadType.toLowerCase().replace(" ", "-"); return `${appName.value}-${type}-${timestamp}`; diff --git a/app/static/src/components/WodinPanels.vue b/app/static/src/components/WodinPanels.vue index f70ac5fe..aa8934a9 100644 --- a/app/static/src/components/WodinPanels.vue +++ b/app/static/src/components/WodinPanels.vue @@ -48,7 +48,7 @@ export enum HidePanelContent { None } -export enum DragStart { +enum DragStart { Icon, Edge } diff --git a/app/static/src/components/WodinPlot.vue b/app/static/src/components/WodinPlot.vue index bd68fc44..52907dfa 100644 --- a/app/static/src/components/WodinPlot.vue +++ b/app/static/src/components/WodinPlot.vue @@ -12,6 +12,7 @@