diff --git a/README.md b/README.md index 876ea23..2c89b00 100644 --- a/README.md +++ b/README.md @@ -26,20 +26,22 @@ git clone https://github.com/soft-eng-practicum/AnalySim.git After you have cloned the Analysim repository on your local machine, use the terminal to navigate to the -`AnalySim\src\Analysim.Web\ClientApp` folder and run the following +`src/Analysim.Web/ClientApp` folder and run the following command. ```sh npm install ``` -Then navigate to `AnalySim\src\Analysim.Web\ClientApp\src\assets\jupyter` folder and run the following commands. +Then navigate to `src/Analysim.Web/ClientApp/src/assets/jupyter` folder and run the following commands. ```sh python -m pip install -r requirements.txt jupyter-lite build --output-dir dist ``` +Then copy the file `index.html` under `dist\lab\index.html`. + ### Connecting to databases and other services Analysim requires two databases to operate: one SQL database (PostgreSQL) for relational data and one Azure BlobStorage database for keeping uploaded user files. In addition, an Outlook account is needed for the email functionality. All of these services are accessed via authentication information stored in the `appsettings.json` and `appsettings.Development.json` files under the `src/Analysim.Web` folder. The structure of the files are as follows (`XXX` means redacted): diff --git a/deploy/cert-renew b/deploy/cert-renew index 2980b1e..fb3d8ad 100755 --- a/deploy/cert-renew +++ b/deploy/cert-renew @@ -1,8 +1,10 @@ +#! /bin/bash +CERT_DIR=`find /etc/letsencrypt/live -type d | tail -1` # Currently must pause .Net server before doing this http-server -p 80 /home/exouser/wwwroot/ & sleep 3s certbot renew -./convert-pem2pfx.sh -cp /etc/letsencrypt/live/analysim.tech/fullchain.pfx ~/.aspnet/https/ +./convert-pem2pfx.sh $CERT_DIR +cp $CERT_DIR/fullchain.pfx ~/.aspnet/https/ # kill the http server kill $(jobs -p) diff --git a/deploy/convert-pem2pfx.sh b/deploy/convert-pem2pfx.sh index bc48012..3d4f6f0 100755 --- a/deploy/convert-pem2pfx.sh +++ b/deploy/convert-pem2pfx.sh @@ -1 +1,7 @@ -openssl pkcs12 -inkey /etc/letsencrypt/live/analysim.tech/privkey.pem -in /etc/letsencrypt/live/analysim.tech/fullchain.pem -export -out /etc/letsencrypt/live/analysim.tech/fullchain.pfx -password pass:analysim +#! /bin/bash +if [ "$1" == "" ]; then + echo "Usage: ./cert-renew " + echo "Example: ./cert-renew /etc/letsencrypt/live/analysim.tech/" + exit -1 +fi +openssl pkcs12 -inkey $1/privkey.pem -in $1/fullchain.pem -export -out $1/fullchain.pfx -password pass:analysim diff --git a/src/Analysim.Web/ClientApp/angular.json b/src/Analysim.Web/ClientApp/angular.json index 19c195a..bff0a6c 100644 --- a/src/Analysim.Web/ClientApp/angular.json +++ b/src/Analysim.Web/ClientApp/angular.json @@ -55,7 +55,7 @@ { "type": "anyComponentStyle", "maximumWarning": "2kb", - "maximumError": "8kb" + "maximumError": "12kb" } ], "fileReplacements": [ diff --git a/src/Analysim.Web/ClientApp/package-lock.json b/src/Analysim.Web/ClientApp/package-lock.json index e82d36b..361c055 100644 --- a/src/Analysim.Web/ClientApp/package-lock.json +++ b/src/Analysim.Web/ClientApp/package-lock.json @@ -15757,15 +15757,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.1.tgz", "integrity": "sha512-f1G1WGDXEU/RN1TWAxBPQgQudtLnLQPyiWdtypkPC+mVYNKFKH/HYXSxH4MVNqwF8M0eDsoiU7HumJHCg/L/jg==", - "dev": true, - "requires": {} + "dev": true }, "@csstools/selector-specificity": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz", "integrity": "sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA==", - "dev": true, - "requires": {} + "dev": true }, "@discoveryjs/json-ext": { "version": "0.5.7", @@ -15934,8 +15932,7 @@ "version": "14.0.3", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.0.3.tgz", "integrity": "sha512-PwvgCeY7mbijazovpA0ggeo81A3yzwOb8AfVD3yfGT15Z2qnEVyL+05Tj6ttRTngceF3gsERamFcB6lRKdcjdw==", - "dev": true, - "requires": {} + "dev": true }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -16837,8 +16834,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -17238,8 +17234,7 @@ "bootstrap": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", - "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", - "requires": {} + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==" }, "bootstrap-icons": { "version": "1.11.3", @@ -17926,8 +17921,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "dev": true, - "requires": {} + "dev": true }, "css-select": { "version": "4.3.0", @@ -19688,8 +19682,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} + "dev": true }, "ieee754": { "version": "1.2.1", @@ -20494,8 +20487,7 @@ "ws": { "version": "7.5.9", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==" } } }, @@ -20719,8 +20711,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", - "dev": true, - "requires": {} + "dev": true }, "karma-source-map-support": { "version": "1.4.0", @@ -21117,8 +21108,7 @@ "marked-highlight": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/marked-highlight/-/marked-highlight-2.1.3.tgz", - "integrity": "sha512-t35JWm2u8HanOJ+gSJBAYQ0Jgr3vy+gl7ORAXN8bSEQFHl5FYXH0A7YXVMrfhmKaSuBSy6LidXECn3U9Qv/dHA==", - "requires": {} + "integrity": "sha512-t35JWm2u8HanOJ+gSJBAYQ0Jgr3vy+gl7ORAXN8bSEQFHl5FYXH0A7YXVMrfhmKaSuBSy6LidXECn3U9Qv/dHA==" }, "media-typer": { "version": "0.3.0", @@ -22280,15 +22270,13 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "requires": {} + "dev": true }, "postcss-gap-properties": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-image-set-function": { "version": "4.0.6", @@ -22314,8 +22302,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-lab-function": { "version": "4.2.0", @@ -22342,22 +22329,19 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true, - "requires": {} + "dev": true }, "postcss-media-minmax": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-extract-imports": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.5", @@ -22408,15 +22392,13 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", - "dev": true, - "requires": {} + "dev": true }, "postcss-page-break": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "requires": {} + "dev": true }, "postcss-place": { "version": "7.0.4", @@ -22493,8 +22475,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-selector-not": { "version": "5.0.0", @@ -23055,8 +23036,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -23608,8 +23588,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", - "dev": true, - "requires": {} + "dev": true }, "stylus": { "version": "0.57.0", @@ -23769,8 +23748,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -24190,8 +24168,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -24291,8 +24268,7 @@ "version": "8.8.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -24433,8 +24409,7 @@ "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", diff --git a/src/Analysim.Web/ClientApp/src/app/projects/project-overview/project-overview-view/project-content/project-notebook-item/project-notebook-item-display/localforageIndexdb.ts b/src/Analysim.Web/ClientApp/src/app/projects/project-overview/project-overview-view/project-content/project-notebook-item/project-notebook-item-display/localforageIndexdb.ts index 82ef112..da3d2cb 100644 --- a/src/Analysim.Web/ClientApp/src/app/projects/project-overview/project-overview-view/project-content/project-notebook-item/project-notebook-item-display/localforageIndexdb.ts +++ b/src/Analysim.Web/ClientApp/src/app/projects/project-overview/project-overview-view/project-content/project-notebook-item/project-notebook-item-display/localforageIndexdb.ts @@ -10,12 +10,12 @@ export class JupyterLiteStorageService { constructor() { this.filesStore = localforage.createInstance({ - name: 'JupyterLite Storage', + name: 'JupyterLite Storage - /assets/jupyter/dist/', storeName: 'files', // Object store name description: 'Storage for JupyterLite files', }); this.checkpointsStore = localforage.createInstance({ - name: 'JupyterLite Storage', + name: 'JupyterLite Storage - /assets/jupyter/dist/', storeName: 'checkpoints', // Object store name description: 'Storage for JupyterLite checkpoints', }); diff --git a/src/Analysim.Web/ClientApp/src/assets/jupyter/index.html b/src/Analysim.Web/ClientApp/src/assets/jupyter/index.html index 8513e4a..3e3cde5 100644 --- a/src/Analysim.Web/ClientApp/src/assets/jupyter/index.html +++ b/src/Analysim.Web/ClientApp/src/assets/jupyter/index.html @@ -1,42 +1,137 @@ - - - JupyterLite - - - - - - - - + const originalConsoleLog = console.info; + console.log("copying files through dotnet run succeeded"); + console.info = function (...args) { + originalConsoleLog.apply(console, args); + if (args[0] && typeof args[0] === 'string' && args[0].includes('Pyodide contents will be synced with Jupyter Contents')) { + // Send a message to the parent window + console.log('Analysim: Sending jupyterlite-loaded message to window'); + window.parent.postMessage('jupyterlite-load', '*'); + } + }; + }.call(this)); + + + + + + + diff --git a/src/Analysim.Web/ClientApp/src/assets/jupyter/requirements.txt b/src/Analysim.Web/ClientApp/src/assets/jupyter/requirements.txt index ab4a32b..de1e6b2 100644 --- a/src/Analysim.Web/ClientApp/src/assets/jupyter/requirements.txt +++ b/src/Analysim.Web/ClientApp/src/assets/jupyter/requirements.txt @@ -1,11 +1,11 @@ # Core modules (mandatory) -jupyterlite-core==0.3.0 -jupyterlab~=4.1.6 -notebook~=7.1.2 +jupyterlite-core==0.7.1 +jupyterlab~=4.5.1 +notebook~=7.5.1 # Python kernel (optional) -jupyterlite-pyodide-kernel==0.3.1 +jupyterlite-pyodide-kernel==0.7.0 # JavaScript kernel (optional) jupyterlite-javascript-kernel==0.3.0 @@ -30,7 +30,7 @@ jupyterlab-night jupyterlab_miami_nights # Python: ipywidget library for Jupyter notebooks (optional) -ipywidgets>=8.1.1,<9 +ipywidgets>=8.1.3,<9 # Python: ipyevents library for Jupyter notebooks (optional) ipyevents>=2.0.1 # Python: interactive Matplotlib library for Jupyter notebooks (optional) @@ -41,5 +41,5 @@ ipycanvas>=0.9.1 ipyleaflet # Python: plotting libraries (optional) -plotly>=5,<6 +plotly>=6,<7 bqplot diff --git a/src/Analysim.Web/Startup.cs b/src/Analysim.Web/Startup.cs index 8d00382..028ed82 100644 --- a/src/Analysim.Web/Startup.cs +++ b/src/Analysim.Web/Startup.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.SpaServices.AngularCli; +using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -104,11 +105,19 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerM app.ConfigureExceptionHandler(logger); app.UseHttpsRedirection(); + + // Add MIME type for Jupyter Lite wheel files by creating a provider and add the .whl mapping + var provider = new FileExtensionContentTypeProvider(); + provider.Mappings[".whl"] = "application/octet-stream"; + app.UseStaticFiles(); if (!env.IsDevelopment()) { - app.UseSpaStaticFiles(); + app.UseSpaStaticFiles(new StaticFileOptions + { + ContentTypeProvider = provider + }); } app.UseCors("CorsPolicy");