From 4e11aa17f01debea1a1c3b27a74951c15eb28a15 Mon Sep 17 00:00:00 2001 From: Etienne Boileau Date: Tue, 10 Sep 2024 10:17:54 +0200 Subject: [PATCH] UPD installation instructions --- README.md | 142 +++++----- client/package-lock.json | 329 +++++++++++------------ client/package.json | 12 +- docker/CONTAINER_SETUP.md | 172 ++++++------ docker/env_docker_example | 19 +- docker/scripts/__create_local_folders.py | 1 - server/docs/source/flask.rst | 2 +- server/env_example | 116 ++++---- server/src/scimodom/__init__.py | 2 +- 9 files changed, 376 insertions(+), 419 deletions(-) diff --git a/README.md b/README.md index dc21c1ae..992bd4e4 100644 --- a/README.md +++ b/README.md @@ -1,154 +1,145 @@ # Sci-ModoM -## Overview - The application consists of the following components: - Database: MariaDB -- Server: A REST-API backend using Python3 and Flask +- Server: A REST-API backend using the SQLAlchemy Database Toolkit for Python and Flask - Client: A Web-GUI using Vue.js -### General setup +## General setup + +At launch time, the app uses tables defined in `SetupService` to populate the database. These tables **must** exist and be located under `IMPORT_PATH`. By default, this path is located under _server/import_, and can be specified in the environment file. Once setup is complete, assembly and annotation files must be added. See [Flask CLI - Setup](https://dieterich-lab.github.io/scimodom/flask.html#setup) for details. -At lauchtime, the app uses tables defined in `SetupService` to populate the database. These tables **must** exist. They are used both in development and production. They **must** be located under `IMPORT_PATH` (defaults to _server/import_, or specify in _.env_ file). +For project and data management, consult the **Documentation** tab on the Web-GUI, or [Flask CLI - Project and data management](https://dieterich-lab.github.io/scimodom/flask.html#project-and-data-management). ## Production setup -The recommended way to run Sci-ModoM in production is to use podman compose to create, manage, and deploy the application and the database containers, see [Container Setup](docker/CONTAINER_SETUP.md) for details. +The recommended way to run Sci-ModoM in production is to use Podman to create, manage, and deploy the application and the database containers, see [Container setup](docker/CONTAINER_SETUP.md) for details. ## Development setup ### Database setup -Set up a MariaDB database. One way to do this is to run a MariaDB container image, see the _Development Setup_ section in [Container Setup](docker/CONTAINER_SETUP.md). The following steps are required: - -- Create a database -- Create a database user -- Grant access to the database to this user +Set up a MariaDB database. One way to do this is to run a MariaDB container image, see the _General_ and _Development setup_ sections in [Container setup](docker/CONTAINER_SETUP.md). ### Server setup -Create a Python3 virtual environment with your preferred method and activate it _e.g._: +Create a Python3 virtual environment and activate it: ```bash python3 -m venv ~/.virtualenvs/scimodom -. ~/.virtualenvs/scimodom/bin/activate +source ~/.virtualenvs/scimodom/bin/activate ``` -Get the source code and install : +Get the source code and install: ```bash git clone https://github.com/dieterich-lab/scimodom.git -cd scimodom +cd scimodom/server pip install --upgrade pip setuptools -pip --verbose install 2>&1 | tee install.log +pip --verbose install -e '.[dev,tests,docs]' 2>&1 | tee install.log ``` -**Note:** The package depends on [mysqlclient](https://pypi.org/project/mysqlclient/). You may have to install MySQL development headers and -libraries before. You also need a working installation of [Bedtools](https://bedtools.readthedocs.io/en/latest/), _e.g._ -[pre-compiled binaries](https://bedtools.readthedocs.io/en/latest/content/installation.html#downloading-a-pre-compiled-binary). +**Note:** The package depends on [mysqlclient](https://pypi.org/project/mysqlclient/). You may have to install MySQL development headers and libraries before. You also need a working installation of [Bedtools](https://bedtools.readthedocs.io/en/latest/), _e.g._ [pre-compiled binaries](https://bedtools.readthedocs.io/en/latest/content/installation.html#downloading-a-pre-compiled-binary). -Set up your environment configuration in _server/.env_ like this: +Set up your environment configuration in _server/.env_: -``` -DATABASE_URI=mysql+mysqldb://scimodom:*some password*@127.0.0.1:3306/scimodom -SECRET_KEY=*some secret* +```bash +DATABASE_URI=mysql+mysqldb://scimodom:PASSWORD@127.0.0.1:3307/scimodom +SECRET_KEY=SECRET_KEY SESSION_COOKIE_SAMESITE=None SESSION_COOKIE_SECURE=True +SMTP_SERVER=mail-server.my-site.org +SMTP_FROM_ADDRESS=scimodom@my-site.org +NOTIFICATION_ADDRESS=scimodom@my-site.org +HTTP_PUBLIC_URL=http://localhost:5173/ UPLOAD_PATH=/path/to/upload DATA_PATH=/path/to/data -BEDTOOLS_TMP_PATH=path/to/bedtools_tmp -SMTP_SERVER=outgoing-email-server.my-site.org -SMTP_FROM_ADDRESS=sci-modom-admin@my-site.org -NOTIFICATION_ADDRESS=notification-email@my-site.org -HTTP_PUBLIC_URL=https://sci-modom.my-site.org +BEDTOOLS_TMP_PATH=/path/to/tmp ``` +where `PASSWORD` is the password for the scimodom user for the MariaDB database in _docker/secrets/mariadb-scimodom_, `3307` is the `MARIADB_DEV_PORT` (we recommend to use a non-standard port _e.g._ 3307 to avoid clashes with a local MariaDB/MySQL installation), and `SECRET_KEY` is the key found in _docker/secrets/flask-secret_, see [Container setup](docker/CONTAINER_SETUP.md) for details. You need to adjust the paths, and make sure they are valid and exist. + **Important:** If the host name _localhost_ is used in the `DATABASE_URI` the database driver will assume that the database is contacted using a named socket. That will not work if a container is used! -In addition to _server/.env/_, a Flask-specific configuration in _server/.flaskenv_ can be used: +You can also create a _server/.flaskenv_ file with Flask-only variables: -``` +```bash FLASK_APP=src/scimodom/app FLASK_DEBUG=True ``` -Now the database container must be started under the _docker_ directory: +#### Running the application -```bash -# under scimodom/docker -docker compose -f docker-compose-db-only.yml up -d -``` - -The database schema can then be initialized by executing this command under the _server_ directory: +Start the database container under the _docker_ directory, see [Container setup](docker/CONTAINER_SETUP.md) (Development setup). +Under the _server_ directory, initialize the database schema: ```bash -# under scimodom/server alembic upgrade head ``` -The API backend can be started with: +and start the API backend: ```bash -# under scimodom/server flask run ``` -Most Python IDEs can run this process in the integrated debugger. +Most Python IDEs can run this process in the integrated debugger. You are now ready to add assemblies, annotations, projects, and data (General setup). -### Client setup +##### Email functionality, local login and registration -To bring up the frontend, go to the _client_ directory and execute: +To register in development mode, use the _Sign up_ button. This requires a functional email server. You first need build the frontend (see Client setup below). Once you receive a link via email, click on this link, but change the frontend server address to that of the Flask development server URL, _e.g._ change http://localhost:5173/ to http://localhost:5000. This is only necessary if you run the database using a container and connect it with the local Flask application. -```bash -# under scimodom/client -npm install # first time install -npm run dev -``` - -Now the application is available here: +Note that email functionality may be limited, as your mail server must be willing to relay emails for your `SMTP_FROM_ADDRESS`, _e.g._ Google or Gmail addresses will most likely not work. This may be problematic if you wish to register, as registration is done via a link sent by email. One way to avoid this problem is to patch the database. Open a python console under your environment and do the following -- http://localhost:5173/ +```python +from werkzeug.security import generate_password_hash +generate_password_hash("mypassword", method="pbkdf2") +# this will return e.g. 'pbkdf2:sha256:600000$vpYjirPAT8xBuPHo$1001474730f96085cdafbf0f159d12e20ec36342b4faddbf226d637c695ee642' +``` -To test the bundled frontend, run under the _client_ directory: +Then go to the database, see _e.g._ [Container setup - Manual database connection](docker/CONTAINER_SETUP.md) and do the following: -```bash -npm run build +```mysql +INSERT INTO user (email, state, password_hash) VALUES ('test@uni-heidelberg', 'active', 'pbkdf2:sha256:600000$vpYjirPAT8xBuPHo$1001474730f96085cdafbf0f159d12e20ec36342b4faddbf226d637c695ee642'); ``` -This will populate the folder _client/dist_ with the bundled static HTML/JavaScript code as it should be deployed in production. -The server can now also serve this code. The complete application is now also available under the Flask development server URL: - -- http://127.0.0.1:5000 +A new user is now registered, and you can login using whatever email address you used _e.g._ "test@uni-heidelberg" with the chosen password _e.g._ "mypassword". -#### Local login +### Client setup -Registration is completed via email. These environment variables are required: +The first time, you need to install the local packages that the project needs, go to the _client_ directory and execute: -``` -SMTP_SERVER=outgoing-email-server.my-site.org -SMTP_FROM_ADDRESS=sci-modom-admin@my-site.org +```bash +npm install ``` -**Important:** Make sure to build the frontend beforehand (see above). After receiving the registration link via email, click on the link, but change the default port `5173` to `5000` to point to the Flask development server URL. +This creates a _node_modules_ folder. You are now ready to bring up the frontend -Alternatively, you can patch the database (add user). +```bash +npm run dev +``` -### Development hints +The application is now available at http://localhost:5173/, and any change you make _e.g._ to the HTML code will be reflected in the page you see in your browser. -For development: +To test the bundled frontend, run: ```bash -pip --verbose install -e '.[dev,tests,docs]' 2>&1 | tee install.log +npm run build ``` +This will populate the folder _dist_ with the bundled static HTML/JavaScript code as it should be deployed in production. +The server can now also serve this code. The complete application is now also available under the Flask development server URL _e.g._ at http://127.0.0.1:5000. + +### Development hints + #### Pre-commit and static type checker Under the _server_ directory: ```bash -# first time, you might have to +# the first time, you might have to pre-commit install # the first time pre-commit runs on a file it will automatically download, install, and run the hook # runs on all file at commit or run manually @@ -161,30 +152,23 @@ mypy -p scimodom #### Tests -To execute the Python tests run under the _server_ directory: +To execute the tests, run under the _server_ directory: ```bash pytest tests ``` -To run pytest from command line, adjust the `PYTHONPATH` _e.g._ - -```bash -export PYTHONPATH="${PYTHONPATH}:/path/to/scimodom/server/tests/" -``` - #### Database schema updates The database schema is tracked using Alembic. Changes to the database must be coded at two locations: -- An Alembic version must be defined in server/migrations/versions +- An Alembic migration script under server/migrations/versions - The model must be updated in server/src/scimodom/database/models.py Any change to the schema is generally tracked with: ```bash -# under client/server -alembic revision --autogenerate [-m "message"] +alembic revision [--autogenerate] -m "message" alembic upgrade head ``` diff --git a/client/package-lock.json b/client/package-lock.json index 01e1ac42..bc43f5fe 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,10 +8,10 @@ "name": "client", "version": "0.0.0", "dependencies": { - "axios": "^1.7.3", + "axios": "^1.7.7", "jwt-decode": "^4.0.0", - "pinia": "^2.2.1", - "plotly.js-dist": "^2.34.0", + "pinia": "^2.2.2", + "plotly.js-dist": "^2.35.1", "primeicons": "^7.0.0", "primevue": "^3.53.0", "vee-validate": "^4.13.2", @@ -28,11 +28,11 @@ "@vue/test-utils": "^2.4.6", "autoprefixer": "^10.4.20", "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.27.0", + "eslint-plugin-vue": "^9.28.0", "jsdom": "^21.1.2", - "postcss": "^8.4.41", + "postcss": "^8.4.45", "prettier": "^2.8.8", - "tailwindcss": "^3.4.9", + "tailwindcss": "^3.4.10", "vite": "^4.5.3", "vitest": "^0.29.8" } @@ -69,12 +69,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", - "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.2" + "@babel/types": "^7.25.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -84,9 +84,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", - "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -588,9 +588,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -751,9 +751,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.17", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.17.tgz", - "integrity": "sha512-zmZ21EWzR71B4Sscphjief5djsLre50M6lI622OSySTmn9DB3j+C3kWroHfBQWXbOBwbgg/M8CG/hUxDLIloow==", + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", + "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", "dev": true, "license": "MIT" }, @@ -768,13 +768,13 @@ } }, "node_modules/@types/node": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", - "integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", + "version": "22.5.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.13.0" + "undici-types": "~6.19.2" } }, "node_modules/@ungap/structured-clone": { @@ -875,71 +875,59 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.37.tgz", - "integrity": "sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.3.tgz", + "integrity": "sha512-adAfy9boPkP233NTyvLbGEqVuIfK/R0ZsBsIOW4BZNfb4BRpRW41Do1u+ozJpsb+mdoy80O20IzAsHaihRb5qA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.37", - "entities": "^5.0.0", + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.3", + "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, - "node_modules/@vue/compiler-core/node_modules/entities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz", - "integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/@vue/compiler-dom": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.37.tgz", - "integrity": "sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.3.tgz", + "integrity": "sha512-wnzFArg9zpvk/811CDOZOadJRugf1Bgl/TQ3RfV4nKfSPok4hi0w10ziYUQR6LnnBAUlEXYLUfZ71Oj9ds/+QA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-core": "3.5.3", + "@vue/shared": "3.5.3" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.37.tgz", - "integrity": "sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.3.tgz", + "integrity": "sha512-P3uATLny2tfyvMB04OQFe7Sczteno7SLFxwrOA/dw01pBWQHB5HL15a8PosoNX2aG/EAMGqnXTu+1LnmzFhpTQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.37", - "@vue/compiler-dom": "3.4.37", - "@vue/compiler-ssr": "3.4.37", - "@vue/shared": "3.4.37", + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.3", + "@vue/compiler-dom": "3.5.3", + "@vue/compiler-ssr": "3.5.3", + "@vue/shared": "3.5.3", "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.40", + "magic-string": "^0.30.11", + "postcss": "^8.4.44", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.37.tgz", - "integrity": "sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.3.tgz", + "integrity": "sha512-F/5f+r2WzL/2YAPl7UlKcJWHrvoZN8XwEBLnT7S4BXwncH25iDOabhO2M2DWioyTguJAGavDOawejkFXj8EM1w==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-dom": "3.5.3", + "@vue/shared": "3.5.3" } }, "node_modules/@vue/devtools-api": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.3.tgz", - "integrity": "sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, "node_modules/@vue/eslint-config-prettier": { @@ -958,53 +946,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.37.tgz", - "integrity": "sha512-UmdKXGx0BZ5kkxPqQr3PK3tElz6adTey4307NzZ3whZu19i5VavYal7u2FfOmAzlcDVgE8+X0HZ2LxLb/jgbYw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.3.tgz", + "integrity": "sha512-2w61UnRWTP7+rj1H/j6FH706gRBHdFVpIqEkSDAyIpafBXYH8xt4gttstbbCWdU3OlcSWO8/3mbKl/93/HSMpw==", "license": "MIT", "dependencies": { - "@vue/shared": "3.4.37" + "@vue/shared": "3.5.3" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.37.tgz", - "integrity": "sha512-MNjrVoLV/sirHZoD7QAilU1Ifs7m/KJv4/84QVbE6nyAZGQNVOa1HGxaOzp9YqCG+GpLt1hNDC4RbH+KtanV7w==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.3.tgz", + "integrity": "sha512-5b2AQw5OZlmCzSsSBWYoZOsy75N4UdMWenTfDdI5bAzXnuVR7iR8Q4AOzQm2OGoA41xjk53VQKrqQhOz2ktWaw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/reactivity": "3.5.3", + "@vue/shared": "3.5.3" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.37.tgz", - "integrity": "sha512-Mg2EwgGZqtwKrqdL/FKMF2NEaOHuH+Ks9TQn3DHKyX//hQTYOun+7Tqp1eo0P4Ds+SjltZshOSRq6VsU0baaNg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.3.tgz", + "integrity": "sha512-wPR1DEGc3XnQ7yHbmkTt3GoY0cEnVGQnARRdAkDzZ8MbUKEs26gogCQo6AOvvgahfjIcnvWJzkZArQ1fmWjcSg==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.37", - "@vue/runtime-core": "3.4.37", - "@vue/shared": "3.4.37", + "@vue/reactivity": "3.5.3", + "@vue/runtime-core": "3.5.3", + "@vue/shared": "3.5.3", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.37.tgz", - "integrity": "sha512-jZ5FAHDR2KBq2FsRUJW6GKDOAG9lUTX8aBEGq4Vf6B/35I9fPce66BornuwmqmKgfiSlecwuOb6oeoamYMohkg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.3.tgz", + "integrity": "sha512-28volmaZVG2PGO3V3+gBPKoSHvLlE8FGfG/GKXKkjjfxLuj/50B/0OQGakM/g6ehQeqCrZYM4eHC4Ks48eig1Q==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-ssr": "3.5.3", + "@vue/shared": "3.5.3" }, "peerDependencies": { - "vue": "3.4.37" + "vue": "3.5.3" } }, "node_modules/@vue/shared": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.37.tgz", - "integrity": "sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.3.tgz", + "integrity": "sha512-Jp2v8nylKBT+PlOUjun2Wp/f++TfJVFjshLzNtJDdmFJabJa7noGMncqXRM1vXGX+Yo2V7WykQFNxusSim8SCA==", "license": "MIT" }, "node_modules/@vue/test-utils": { @@ -1071,9 +1059,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -1229,9 +1217,10 @@ } }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -1352,9 +1341,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001651", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", - "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", "dev": true, "funding": [ { @@ -1680,13 +1669,13 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1892,9 +1881,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz", - "integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==", + "version": "1.5.18", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.18.tgz", + "integrity": "sha512-1OfuVACu+zKlmjsNdcJuVQuVE61sZOLbNM4JAQ1Rvh6EOj0/EUKhMJjRH73InPlXSh8HIJk1cVZ8pyOV/FMdUQ==", "dev": true, "license": "ISC" }, @@ -1956,9 +1945,9 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2092,9 +2081,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.27.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.27.0.tgz", - "integrity": "sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.28.0.tgz", + "integrity": "sha512-ShrihdjIhOTxs+MfWun6oJWuk+g/LAhN+CiuOl/jjkG3l0F2AuK5NMTaWqyvBgkFtpYmyks6P4603mLmhNJW8g==", "dev": true, "license": "MIT", "dependencies": { @@ -2103,7 +2092,7 @@ "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", - "semver": "^7.6.0", + "semver": "^7.6.3", "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, @@ -2362,9 +2351,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", @@ -2706,9 +2695,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", - "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3062,9 +3051,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { @@ -3133,9 +3122,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -3423,9 +3412,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "license": "ISC" }, "node_modules/picomatch": { @@ -3452,9 +3441,9 @@ } }, "node_modules/pinia": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.1.tgz", - "integrity": "sha512-ltEU3xwiz5ojVMizdP93AHi84Rtfz0+yKd8ud75hr9LVyWX2alxp7vLbY1kFm7MXFmHHr/9B08Xf8Jj6IHTEiQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.2.tgz", + "integrity": "sha512-ja2XqFWZC36mupU4z1ZzxeTApV7DOw44cV4dhQ9sGwun+N89v/XP7+j7q6TanS1u1tdbK4r+1BUx7heMaIdagA==", "license": "MIT", "dependencies": { "@vue/devtools-api": "^6.6.3", @@ -3514,9 +3503,9 @@ } }, "node_modules/pkg-types": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", - "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz", + "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==", "dev": true, "license": "MIT", "dependencies": { @@ -3526,15 +3515,15 @@ } }, "node_modules/plotly.js-dist": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/plotly.js-dist/-/plotly.js-dist-2.34.0.tgz", - "integrity": "sha512-FZR9QT60vtE1ocdSIfop+zDIJEoy1lejwOvAjTSy+AmE4GZ//rW1nnIXwCRv4o9ejfzWq++lQMu6FJf9G+NtFg==", + "version": "2.35.1", + "resolved": "https://registry.npmjs.org/plotly.js-dist/-/plotly.js-dist-2.35.1.tgz", + "integrity": "sha512-PJMVbzCdKu275oIlqzMZ0vlX7xfsZMK/RBhcukImw+ITgFzBZ2D0rjWWfWdu55oyyh1cdGtmEyJJnieeGLzFcQ==", "license": "MIT" }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", "funding": [ { "type": "opencollective", @@ -4132,9 +4121,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4196,9 +4185,9 @@ "license": "MIT" }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -4378,9 +4367,9 @@ "license": "MIT" }, "node_modules/tailwindcss": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz", - "integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", + "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==", "dev": true, "license": "MIT", "dependencies": { @@ -4586,9 +4575,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, @@ -4675,9 +4664,9 @@ } }, "node_modules/vee-validate/node_modules/type-fest": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.24.0.tgz", - "integrity": "sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==", + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" @@ -4855,16 +4844,16 @@ } }, "node_modules/vue": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.37.tgz", - "integrity": "sha512-3vXvNfkKTBsSJ7JP+LyR7GBuwQuckbWvuwAid3xbqK9ppsKt/DUvfqgZ48fgOLEfpy1IacL5f8QhUVl77RaI7A==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.3.tgz", + "integrity": "sha512-xvRbd0HpuLovYbOHXRHlSBsSvmUJbo0pzbkKTApWnQGf3/cu5Z39mQeA5cZdLRVIoNf3zI6MSoOgHUT5i2jO+Q==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.4.37", - "@vue/compiler-sfc": "3.4.37", - "@vue/runtime-dom": "3.4.37", - "@vue/server-renderer": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-dom": "3.5.3", + "@vue/compiler-sfc": "3.5.3", + "@vue/runtime-dom": "3.5.3", + "@vue/server-renderer": "3.5.3", + "@vue/shared": "3.5.3" }, "peerDependencies": { "typescript": "*" @@ -4876,9 +4865,9 @@ } }, "node_modules/vue-component-type-helpers": { - "version": "2.0.29", - "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.0.29.tgz", - "integrity": "sha512-58i+ZhUAUpwQ+9h5Hck0D+jr1qbYl4voRt5KffBx8qzELViQ4XdT/Tuo+mzq8u63teAG8K0lLaOiL5ofqW38rg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.1.6.tgz", + "integrity": "sha512-ng11B8B/ZADUMMOsRbqv0arc442q7lifSubD0v8oDXIFoMg/mXwAPUunrroIDkY+mcD0dHKccdaznSVp8EoX3w==", "dev": true, "license": "MIT" }, @@ -5091,9 +5080,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -5179,9 +5168,9 @@ "license": "MIT" }, "node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", "dev": true, "license": "ISC", "bin": { diff --git a/client/package.json b/client/package.json index 60a89400..f0d9ec3e 100644 --- a/client/package.json +++ b/client/package.json @@ -11,10 +11,10 @@ "format": "prettier --write src/" }, "dependencies": { - "axios": "^1.7.3", + "axios": "^1.7.7", "jwt-decode": "^4.0.0", - "pinia": "^2.2.1", - "plotly.js-dist": "^2.34.0", + "pinia": "^2.2.2", + "plotly.js-dist": "^2.35.1", "primeicons": "^7.0.0", "primevue": "^3.53.0", "vee-validate": "^4.13.2", @@ -31,11 +31,11 @@ "@vue/test-utils": "^2.4.6", "autoprefixer": "^10.4.20", "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.27.0", + "eslint-plugin-vue": "^9.28.0", "jsdom": "^21.1.2", - "postcss": "^8.4.41", + "postcss": "^8.4.45", "prettier": "^2.8.8", - "tailwindcss": "^3.4.9", + "tailwindcss": "^3.4.10", "vite": "^4.5.3", "vitest": "^0.29.8" } diff --git a/docker/CONTAINER_SETUP.md b/docker/CONTAINER_SETUP.md index 8d7dc368..bf64d29b 100644 --- a/docker/CONTAINER_SETUP.md +++ b/docker/CONTAINER_SETUP.md @@ -1,155 +1,149 @@ -# Container Setup +# Container setup ## Prerequisites -### Container tools: podman-compose or docker-compose +### Container tools -You need a container CLI to handle docker-compose-like files _e.g._ podman-compose or the original docker-compose. -Docker Swarm is very restricted and may **not** work. The following versions are known to work: +A container management CLI is required such as `podman-compose` or `docker compose` ([Compose V2](https://docs.docker.com/compose/migrate)). +Docker Swarm has not been tested and may not work. The following versions are known to work: -- podman 4.3.1 with podman-compose 1.0.3 on Debian 12 -- docker 20.10 with docker-compose 1.25.0 on Debian 11 +- Podman version 4.3.1 with podman-compose version 1.0.3 on Debian 12 +- Docker version 27.2.0 with docker compose version 2.29.2 on Debian 12 -If podman is correctly installed, with podman all operations can be done as a non-root user. +Podman handles rootless containers. -### Image building: Node.js +### Image building -In addition, Node.js and npm are required on the machine, which builds the container images. Vue.js presently requires Node.js 16 or newer. +Node.js and npm are required to build the container images. Vue.js presently requires Node.js 16 or newer. The following version is known to work: -- Node.js 18.13.0 on Debian 12 -- Node.js 18.17.1 on Debian 11 from nodesource.com +- Node.js version 18.19.0 on Debian 12 +- npm version 9.2.0 and 10.8.2 on Debian 12 -## Configure .env_docker +## General setup -Create a file _.env_docker_ in the _docker_ directory based on [env_docker_example](env_docker_example). -You may stick with the relative path names used there, but then you need to make sure that all scripts are run from the _docker_ directory. +### Configure the docker/.env_docker file -## Build the images +Create a file _.env_docker_ in the _docker_ directory using [env_docker_example](env_docker_example) as template. Environment variables +defined in this file are used to build the images. + +### Configure the .env file + +Create a file _.env_ in the same directory as the YAML file used to define the services _i.e._ _docker-compose.yml_ or _docker-compose-db-only.yml_, using [env_example](../server/env_example) as template. This is the environment file used by compose. For development, this file is typically located in the _docker_ directory, but under production it may be located in a separate deployment directory. + +### Set up the local directories + +Under your deployment directory, or under the _docker_ directory in development setup, create the directory structure for the database: + +```bash +./scripts/create_local_folders.sh +``` + +In particular, the following files are created: + +- secrets/mariadb-root: Password for the root user for the MariaDB database. +- secrets/mariadb-scimodom: Password for the scimodom user for the MariaDB database. + +## Production setup + +### Build the images ```bash -# check https://hub.docker.com/_/mariadb for reference cd docker/db_container ./build.sh cd ../app_container ./build.sh ``` -## Optional: copy to live instance +### Optional: copy to a live instance If the images are built on a different machine, or if multiple deployments are run on the same container host, the required data must be deployed to that system or a separate folder per instance. -In case of a deployment to a different container host the following data need to be transferred: +In case of a deployment to a different container host, the following data need to be transferred: - The images, _e.g._ via a Docker repository - - The database image, e.g. scimodom_db:latest - - The application image, e.g. scimodom_app:latest -- The docker/scripts folder -- The docker-compose.yml -- Your .env file - see below. + - The database image _e.g._ scimodom_db:latest + - The application image _e.g._ scimodom_app:latest +- The docker/scripts folder and the necessary import tables (import folder) +- The _docker-compose.yml_ file +- The _.env_ file -In case multiple instances are run on the same host, a separate folder needs to be created for each instance. The same data is needed as above. -Make sure that the ports, paths and names in the _.env_ files don't collide! +If multiple instances are run on the same host, a separate folder needs to be created for each instance. Make sure that the ports, paths and names in the _.env_ files don't collide! -## Set up your .env file +### Starting and stopping the containers -Create a file .env in the same folder as the docker-compose.yml you use. -An example may be found here: [../server/env_example](env_example). - -## Set up the local directories +```bash +# or docker compose +podman-compose -f docker-compose.yml up -d +``` -In the folder where your keep your _.env_ and your _docker-compose.yml_ file create the folder _secrets_ containing your secrets. Also, you will -have to create folders for the database and it's backups. This can be done a follows: +And to stop: ```bash -./scripts/create_local_folders.sh +# or docker compose +podman-compose -f docker-compose.yml down ``` -The following files are required: - -- secrets/mariadb-root: Password of the root user of the MariaDB database. -- secrets/mariadb-scimodom: Password of the scimodom user of the MariaDB database. +## Development setup -Use just letters and digits in the passwords because they may be used in database connect strings. Characters with special meanings in URLs -like '/', '@' or ':' may not work. Later changes only have effect if the database container is recreated. That will reset the database -completely. So you may have to restore from backup. +The database can be run using a container and connected with the application running locally by using _docker-compose-db-only.yml_. The _docker/.env_ file needs a few variables only, see [env_example](../server/env_example) (database only). -## Starting and stopping +### Set up the local directories -To start the containers just use the _docker-compose.yml_: +For development, running ```bash -podman-compose up -d +./scripts/create_local_folders.sh ``` -And to stop: +does not create the development database folder, this must be done manually. The name of this folder matches the value from `HOST_DEV_DB_DATA_DIR` defined in the _.env_ file, _e.g._ ```bash -podman-compose down -d +# if HOST_DEV_DB_DATA_DIR=./db_data_dev +# in the docker/ directory +mkdir db_data_dev ``` -## Backup and restore - -The setup described above supplies two scripts: - -- **./scripts/pre_backup.sh:** Dumps the database to the $HOST*BACKUP_DIR as - defined in your setup. Run it before doing a file-level backup of these folder, - \_e.g.* as 'pre' script of your backup solution. -- **./scripts/post_restore.sh:** Load the database from $HOST_BACKUP_DIR. - Run it just after you restored that folder from a suitable backup. - -## Troubleshooting - -### Manual database connection - -To directly connect use this: +### Build the images ```bash -podman exec -it docker_scimodom_db_1 mariadb -u root -p --database scimodom +cd docker/db_container +./build.sh ``` -Use the password found in secrets/mariadb-root. +### Starting and stopping the database container -## Development Setup - -The database can be run using a container and connected with the application running locally by using -_docker-compose-db-only.yml_. To do so, you first need a separate _docker/.env_ file. It may be as short -as this: +The database container must be started under the _docker_ directory: ```bash -DB_IMAGE_NAME=scimodom_db:latest -MARIADB_DEV_PORT=3307 -HOST_BACKUP_DIR=backup -HOST_SECRETS_DIR=secrets -HOST_DEV_DB_DATA_DIR=db_data_dev +# or docker compose +podman-compose -f docker-compose-db-only.yml up -d ``` -Please note, that the example above use the non-standard port 3307 to avoid clashes with a local MariaDB/Mysql -installation. +And to stop: ```bash -./scripts/create_local_folders.sh -mkdir db_data_dev -podman-compose -f docker-compose-db-only.yml up -d +# or docker compose +podman-compose -f docker-compose-db-only.yml down ``` -Now you can set up _server/.env_: +## Backup and restore -- Start with server/env_example. -- Change _DATABASE_URI_ to match your setup, especially: -- The port must match _MARIADB_DEV_PORT_ from docker/.env -- The password is one you find in the file _docker/secrets/mariadb-scimodom_. +The setup described above supplies two scripts: -The resulting line should look like this: +- **./scripts/pre_backup.sh:** Dumps the database to the `HOST_BACKUP_DIR`. Run it before doing a file-level backup, _e.g._ as "pre" script of your backup solution. +- **./scripts/post_restore.sh:** Load the database from `HOST_BACKUP_DIR`. Run it just after you restored that folder from a suitable backup. -``` -DATABASE_URI=mysql+mysqldb://scimodom:YourPassword@127.0.0.1:3307/scimodom -``` +## Troubleshooting -Now the database schema can be initialized with alembic: +### Manual database connection + +To directly connect to the database: ```bash -cd ../server -alembic upgrade head +# or docker +podman exec -it docker_scimodom_db_1 mariadb -u root -p scimodom ``` + +Use the password found in _secrets/mariadb-root_. diff --git a/docker/env_docker_example b/docker/env_docker_example index 8258c0f6..8f5139d4 100644 --- a/docker/env_docker_example +++ b/docker/env_docker_example @@ -1,20 +1,13 @@ # -# This is the template for the .env_docker file which is used -# by docker-compose/podman-compose and the backup scripts. -# So it needs to work both as a shell script and a -# docker-compose .env file. That is usually not much -# of a problem. +# This is the template for the .env_docker file used by podman or docker and the backup scripts. # -# Your preferred container CLI -# Both podman/podman-compose and docker/docker-compose should work -# if available the target platform +# Use your preferred container CLI. + DOCKER=podman -DOCKER_COMPOSE=podman-compose -# Names used to tag the freshly build docker images. -# If you work with multiple deployments, you may want -# to change them. If they don't match what is configured -# in your .env file, you will to manually tag your images. +# Tag images. Use names to handle multiple deployments. +# If names don't match what is configured in your .env file, you will have to manually tag your images! + DB_IMAGE_NAME=scimodom_db:latest APP_IMAGE_NAME=scimodom_app:latest diff --git a/docker/scripts/__create_local_folders.py b/docker/scripts/__create_local_folders.py index 2a93b9a6..35037612 100755 --- a/docker/scripts/__create_local_folders.py +++ b/docker/scripts/__create_local_folders.py @@ -10,7 +10,6 @@ HOST_CONFIG_DIR = environ.get("HOST_CONFIG_DIR") HOST_DB_DATA_DIR = environ.get("HOST_DB_DATA_DIR") HOST_IMPORT_DIR = environ.get("HOST_IMPORT_DIR") -HOST_DATA_DIR = environ.get("HOST_DATA_DIR") HOST_FOLDERS = [ HOST_BACKUP_DIR, diff --git a/server/docs/source/flask.rst b/server/docs/source/flask.rst index 14ebb3ef..c3143dec 100644 --- a/server/docs/source/flask.rst +++ b/server/docs/source/flask.rst @@ -10,7 +10,7 @@ Flask CLI documentation. Setup ----- -At lauchtime, the app uses tables defined in ``SetupService.FILE_NAME_TO_DB_TABLE_MAP`` to perform an ``INSERT... ON DUPLICATE KEY UPDATE`` +At launch time, the app uses tables defined in ``SetupService.FILE_NAME_TO_DB_TABLE_MAP`` to perform an ``INSERT... ON DUPLICATE KEY UPDATE`` .. code-block:: python diff --git a/server/env_example b/server/env_example index 2603f31c..c839278c 100644 --- a/server/env_example +++ b/server/env_example @@ -1,78 +1,76 @@ -## -## Common part (container and local setup) -## +# +# This is the template for the .env file used by compose: +# - for running a multi-container application (server and database) with docker-compose.yml; or +# - for running a development server using docker-compose-db-only.yml (database only). +# + +# Use your preferred container CLI. + +DOCKER=podman + +# Define the docker images to use. +DB_IMAGE_NAME=scimodom_db:latest +APP_IMAGE_NAME=scimodom_app:latest + +# Used for pre/post restore scripts. +DB_CONTAINER_NAME=docker-scimodom_db-1 + +# The parameters below are only used inside the containers. +# There should be no need to ever change them. +MARIADB_USER=scimodom +MARIADB_DATABASE=scimodom +MARIADB_ROOT_PASSWORD_FILE=/run/secrets/mariadb-root +MARIADB_PASSWORD_FILE=/run/secrets/mariadb-scimodom + +## -------------------------------------------------------- +## To be used with docker-compose.yml (server and database) +## -------------------------------------------------------- # Configuration for the web server + HTTP_PORT=8000 HTTP_WORKER_PROCESSES=4 HTTP_WORKER_TIMEOUT=120 -# Usually you will have a reverse proxy in front to terminate TLS. -# Use it's name below. +# Usually you will have a reverse proxy in front to terminate TLS, use it's name below. HTTP_PUBLIC_URL=https://scimodom.my-site.org # If we run behind a reverse proxy we need to know it's IP address(es) so that we trust -# the X-Forwarded-Proto header. Otherwise, we might generate incorrect redirects -# (http instead of https). -HTTP_REVERSE_PROXY_IPS=... +# the X-Forwarded-Proto header. Otherwise, we might generate incorrect redirects (http instead of https). +HTTP_REVERSE_PROXY_IPS='' -# Mail server to use. It must be willing to relay emails -# for your host/SMTP_FROM_ADDRESS. +# Mail server to use. It must be willing to relay emails for your host/SMTP_FROM_ADDRESS. SMTP_SERVER=mail-server.my-site.org -# Email address to use als sender for emails. +# Email address to use as sender for emails. SMTP_FROM_ADDRESS=scimodom@my-site.org -# Address to sent notifications about user requests to +# Address to send notifications to about user requests NOTIFICATION_ADDRESS=scimodom@my-site.org -## -## Local part - only use if the Flask app runs locally -## - -# DATABASE_URI=mysql+mysqldb://scimodom:XXX-DB_PASSWORD-XXX@127.0.0.1:3306/scimodom -# SECRET_KEY=asgddfgsdfgshbsfrdaDSAS -SESSION_COOKIE_SAMESITE=None -SESSION_COOKIE_SECURE=True - -IMPORT_PATH=/path/to/scimodom/server/import -UPLOAD_PATH=/path/to/upload -DATA_PATH=/path/to/data -BEDTOOLS_TMP_PATH=/path/to/tmp - -## -## Container part - only use with docker-compose.yml -## - -# Your preferred container CLI. -# Only used for a container setup. -# Both podman/podman-compose and docker/docker-compose should work -# if available the target platform -DOCKER=podman -DOCKER_COMPOSE=podman-compose +# Directories to use for various stuff on the host machine. +# The path may be absolute or relative to the place where you run compose. -# The docker images to use. -DB_IMAGE_NAME=scimodom_db:latest -APP_IMAGE_NAME=scimodom_app:latest +# Used for database backup. +HOST_BACKUP_DIR=/path/to/backup +# Auto-configured passwords. +HOST_SECRETS_DIR=/path/to/secrets -# Directories to use for various stuff on the host machine. -# The path may be absolute or relative to the place where you -# run docker-compose +HOST_IMPORT_DIR=/path/to/import +HOST_CONFIG_DIR=/path/to/config +HOST_DB_DATA_DIR=/path/to/db_data +HOST_DATA_DIR=/path/to/data -# Here the database backup goes -HOST_BACKUP_DIR=backup -# Find here auto-configured passwords -HOST_SECRETS_DIR=secrets +## ---------------------------------------------------------- +## To be used with docker-compose-db-only.yml (database only) +## ---------------------------------------------------------- -HOST_IMPORT_DIR=import -HOST_CONFIG_DIR=config -HOST_DB_DATA_DIR=db_data -HOST_DATA_DIR=data +# If running the app locally with a database container (docker-compose-db-only.yml). +# The remaining environment variables must be defined in server/.env. -# The parameters below are only used inside the containers. -# There should be no need to ever change them. -MARIADB_USER=scimodom -MARIADB_DATABASE=scimodom -MARIADB_ROOT_PASSWORD_FILE=/run/secrets/mariadb-root -MARIADB_PASSWORD_FILE=/run/secrets/mariadb-scimodom +# Used for database backup. +HOST_BACKUP_DIR=/path/to/backup +# Auto-configured passwords. +HOST_SECRETS_DIR=/path/to/secrets -# If running the app locally with a database container (docker-compose-db-only.yml) -# the parameters below are required and need to be adjusted accordingly -HOST_DEV_DB_DATA_DIR=db_data_dev +HOST_DEV_DB_DATA_DIR=/path/to/db_data_dev MARIADB_DEV_PORT=3307 + +# NOTE: if running ./scripts/create_local_folders.sh, additional variables are required. These variables +# are not used by the database container, but are required by default: HTTP_PUBLIC_URL, HOST_IMPORT_DIR, HOST_CONFIG_DIR, HOST_DB_DATA_DIR. diff --git a/server/src/scimodom/__init__.py b/server/src/scimodom/__init__.py index c9ca121a..5fc637b2 100644 --- a/server/src/scimodom/__init__.py +++ b/server/src/scimodom/__init__.py @@ -1,2 +1,2 @@ -__version_info__ = ("0", "0", "1") +__version_info__ = ("2", "0", "6") __version__ = ".".join(__version_info__)