diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6c6a62f9f9..ade75a833a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -31,7 +31,8 @@ "ms-python.python", "ms-python.vscode-pylance", "batisteo.vscode-django", - "eamodio.gitlens" + "eamodio.gitlens", + "biomejs.biome" ] } }, diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 218b64eda7..05de516f6b 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -308,7 +308,7 @@ jobs: - name: Coverage Tests run: invoke dev.test --coverage - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # pin@v4.6.0 + uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} @@ -440,7 +440,7 @@ jobs: - name: Run Tests run: invoke dev.test --migrations --report --coverage - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # pin@v4.6.0 + uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} @@ -545,7 +545,7 @@ jobs: if: always() run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # pin@v4.6.0 + uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # pin@v5.0.2 if: always() with: token: ${{ secrets.CODECOV_TOKEN }} @@ -584,3 +584,4 @@ jobs: with: name: frontend-build path: src/backend/InvenTree/web/static/web + include-hidden-files: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 77ee9eea1c..52b3da2bb9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -49,7 +49,7 @@ jobs: - name: Build frontend run: cd src/frontend && npm run compile && npm run build - name: Create SBOM for frontend - uses: anchore/sbom-action@251a468eed47e5082b105c3ba6ee500c0e65a764 # pin@v0 + uses: anchore/sbom-action@fc46e51fd3cb168ffb36c6d1915723c47db58abb # pin@v0 with: artifact-name: frontend-build.spdx path: src/frontend @@ -63,7 +63,7 @@ jobs: zip -r ../frontend-build.zip * .vite - name: Attest Build Provenance id: attest - uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # pin@v1 + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # pin@v1 with: subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip" diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index a1fdebafbb..5a91f078ef 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 + uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 with: sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index da5a08bd2a..1cde3d5d9a 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,10 @@ env/ src/backend/InvenTree/InvenTree/locale_stats.json src/backend/InvenTree/InvenTree/licenses.txt +# Logs +src/backend/InvenTree/logs.json +src/backend/InvenTree/logs.log + # node.js node_modules/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 302c7d4a69..5185cbac91 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,14 +10,14 @@ exclude: | )$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: mixed-line-ending - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.0 + rev: v0.7.3 hooks: - id: ruff-format args: [--preview] @@ -28,7 +28,7 @@ repos: --preview ] - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.4.24 + rev: 0.5.1 hooks: - id: pip-compile name: pip-compile requirements-dev.in @@ -51,7 +51,7 @@ repos: args: [contrib/container/requirements.in, -o, contrib/container/requirements.txt, --python-version=3.11, --no-strip-extras, --generate-hashes] files: contrib/container/requirements\.(in|txt)$ - repo: https://github.com/Riverside-Healthcare/djLint - rev: v1.35.2 + rev: v1.36.1 hooks: - id: djlint-django - repo: https://github.com/codespell-project/codespell @@ -69,28 +69,14 @@ repos: pyproject.toml | src/frontend/vite.config.ts | )$ -- repo: https://github.com/pre-commit/mirrors-prettier - rev: "v4.0.0-alpha.8" - hooks: - - id: prettier - files: ^src/frontend/.*\.(js|jsx|ts|tsx)$ - additional_dependencies: - - "prettier@^2.4.1" - - "@trivago/prettier-plugin-sort-imports" -- repo: https://github.com/pre-commit/mirrors-eslint - rev: "v9.12.0" - hooks: - - id: eslint - additional_dependencies: - - eslint@^8.41.0 - - eslint-config-google@^0.14.0 - - eslint-plugin-react@6.10.3 - - babel-eslint@6.1.2 - - "@typescript-eslint/eslint-plugin@latest" - - "@typescript-eslint/parser" - files: ^src/frontend/.*\.(js|jsx|ts|tsx)$ +- repo: https://github.com/biomejs/pre-commit + rev: "v0.5.0" + hooks: + - id: biome-check + additional_dependencies: ["@biomejs/biome@1.9.4"] + files: ^src/frontend/.*\.(js|ts|tsx)$ - repo: https://github.com/gitleaks/gitleaks - rev: v8.21.0 + rev: v8.21.2 hooks: - id: gitleaks #- repo: https://github.com/jumanjihouse/pre-commit-hooks diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..dcc97bee63 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "biomejs.biome" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..04b0a9dd9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "editor.codeActionsOnSave": { + "quickfix.biome": "explicit" + } +} diff --git a/biome.json b/biome.json new file mode 100644 index 0000000000..1db36e4666 --- /dev/null +++ b/biome.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "javascript": { + "formatter": { + "quoteStyle": "single", + "jsxQuoteStyle": "single", + "trailingCommas": "none", + "indentStyle": "space" + } + }, + "linter": { + "rules": { + "suspicious" : { + "noExplicitAny": "off", + "noDoubleEquals": "off", + "noArrayIndexKey": "off", + "useDefaultSwitchClauseLast": "off" + }, + "style": { + "noUselessElse": "off", + "noNonNullAssertion": "off", + "noParameterAssign": "off" + }, "correctness":{ + "useExhaustiveDependencies": "off", + "useJsxKeyInIterable": "off", + "noUnsafeOptionalChaining": "off", + "noSwitchDeclarations": "off", + "noUnusedImports":"error" + }, "complexity": { + "noBannedTypes": "off", + "noExtraBooleanCast": "off", + "noForEach": "off", + "noUselessSwitchCase": "off", + "useLiteralKeys":"off" + }, "performance": { + "noDelete":"off" + } + } +} +} diff --git a/contrib/container/.env b/contrib/container/.env index a180d82dc2..7124be1938 100644 --- a/contrib/container/.env +++ b/contrib/container/.env @@ -24,13 +24,11 @@ INVENTREE_DB_PORT=5432 INVENTREE_DB_USER=pguser INVENTREE_DB_PASSWORD=pgpassword -# Redis cache setup (disabled by default) -# Un-comment the following lines to enable Redis cache -# Note that you will also have to run docker-compose with the --profile redis command +# Redis cache setup # Refer to settings.py for other cache options -#INVENTREE_CACHE_ENABLED=True -#INVENTREE_CACHE_HOST=inventree-cache -#INVENTREE_CACHE_PORT=6379 +INVENTREE_CACHE_ENABLED=True +INVENTREE_CACHE_HOST=inventree-cache +INVENTREE_CACHE_PORT=6379 # Options for gunicorn server INVENTREE_GUNICORN_TIMEOUT=90 diff --git a/contrib/container/docker-compose.yml b/contrib/container/docker-compose.yml index 6a0b001f8b..9a7a00927f 100644 --- a/contrib/container/docker-compose.yml +++ b/contrib/container/docker-compose.yml @@ -71,6 +71,7 @@ services: - 8000 depends_on: - inventree-db + - inventree-cache env_file: - .env volumes: diff --git a/docs/docs/develop/react-frontend.md b/docs/docs/develop/react-frontend.md index ab841e9008..7b0274cf8e 100644 --- a/docs/docs/develop/react-frontend.md +++ b/docs/docs/develop/react-frontend.md @@ -112,3 +112,25 @@ npx playwright test --ui ``` This will first launch the backend server (at `http://localhost:8000`), and then run the tests against the frontend server (at `http://localhost:5173`). An interactive browser window will open, and you can run the tests individually or as a group. + +### Viewing Reports + +The playwright tests are run automatically as part of the project's CI pipeline, and the results are stored as a downloadable report. The report file can be "replayed" using playwright, to view the results of the test run, as well as closely inspect any failed tests. + +To view the report, you can use the following command, after downloading the report and extracting from the zipped file: + +```bash +npx playwright show-report path/to/report +``` + +### No Tests Found + +If there is any problem in the testing launch sequence, the playwright UI will display the message "No Tests". In this case, an error has occurred, likely launching the InvenTree server process (which runs in the background). + +To debug this situation, and determine what error needs to be resolved, run the following command: + +```bash +npx playwright test --debug +``` + +This will print out any errors to the console, allowing you to resolve issues before continuing. In all likelihood, your InvenTree installation needs to be updated, and simply running `invoke update` will allow you to continue. diff --git a/docs/docs/extend/machines/overview.md b/docs/docs/extend/machines/overview.md index f132903cd3..1ec4cc26be 100644 --- a/docs/docs/extend/machines/overview.md +++ b/docs/docs/extend/machines/overview.md @@ -7,7 +7,7 @@ title: Machines InvenTree has a builtin machine registry. There are different machine types available where each type can have different drivers. Drivers and even custom machine types can be provided by plugins. !!! info "Requires Redis" - If the machines features is used in production setup using workers, a shared [redis cache](../../start/docker.md#redis-cache) is required to function properly. + If the machines features is used in production setup using workers, a shared [redis cache](../../start/processes.md#cache-server) is required to function properly. ### Registry diff --git a/docs/docs/extend/plugins.md b/docs/docs/extend/plugins.md index 37b17238ea..707cf4a1f5 100644 --- a/docs/docs/extend/plugins.md +++ b/docs/docs/extend/plugins.md @@ -83,7 +83,7 @@ The configuration entries must be enabled via the [InvenTree admin interface](.. !!! warning "Disabled by Default" Newly discovered plugins are disabled by default, and must be manually enabled (in the admin interface) by a user with staff privileges. -### Plugin Mixins +## Plugin Mixins Common use cases are covered by pre-supplied modules in the form of *mixins* (similar to how [Django]({% include "django.html" %}/topics/class-based-views/mixins/) does it). Each mixin enables the integration into a specific area of InvenTree. Sometimes it also enhances the plugin with helper functions to supply often used functions out-of-the-box. @@ -106,3 +106,11 @@ Supported mixin classes are: | [SettingsMixin](./plugins/settings.md) | Integrate user configurable settings | | [UrlsMixin](./plugins/urls.md) | Respond to custom URL endpoints | | [ValidationMixin](./plugins/validation.md) | Provide custom validation of database models | + +## Static Files + +If your plugin requires static files (e.g. CSS, JavaScript, images), these should be placed in the top level `static` directory within the distributed plugin package. These files will be automatically collected by InvenTree when the plugin is installed, and copied to an appropriate location. + +These files will be available to the InvenTree web interface, and can be accessed via the URL `/static/plugins//`. Static files are served by the [proxy server](../start/processes.md#proxy-server). + +For example, if the plugin is named `my_plugin`, and contains a file `CustomPanel.js`, it can be accessed via the URL `/static/plugins/my_plugin/CustomPanel.js`. diff --git a/docs/docs/extend/plugins/ui.md b/docs/docs/extend/plugins/ui.md index 16988ca2e3..fd6618131d 100644 --- a/docs/docs/extend/plugins/ui.md +++ b/docs/docs/extend/plugins/ui.md @@ -173,9 +173,17 @@ This context data can be used to provide additional information to the rendering Note that additional context can be passed to the rendering functions by adding additional key-value pairs to the `context` field in the `UIFeature` return type (provided by the backend via the API). This field is optional, and can be used at the discretion of the plugin developer. +## File Distribution + +When distributing a custom UI plugin, the plugin should include the necessary frontend code to render the custom content. This frontend code should be included in the plugin package, and should be made available to the InvenTree frontend when the plugin is installed. + +The simplest (and recommended) way to achieve this is to distribute the compiled javascript files with the plugin package, in a top-level `static` directory. This directory will be automatically collected by InvenTree when the plugin is installed, and the files will be copied to the appropriate location. + +Read more about [static plugin files](../plugins.md#static-files) for more information. + ## Sample Plugin -A sample plugin which implements custom user interface functionality is provided in the InvenTree source code, which provides a full working example of how to implement custom user interface functionality. +A (very simple) sample plugin which implements custom user interface functionality is provided in the InvenTree source code, which provides a full working example of how to implement custom user interface functionality. ::: plugin.samples.integration.user_interface_sample.SampleUserInterfacePlugin options: @@ -184,3 +192,28 @@ A sample plugin which implements custom user interface functionality is provided show_root_toc_entry: False show_source: True members: [] + +### More Examples + +Some more complex examples of user interface plugins can be found on the InvenTree GitHub repository: + +- [inventree-test-statistics](https://github.com/inventree/inventree-test-statistics) +- [inventree-order-history](https://github.com/inventree/inventree-order-history) + +## Consistent Theming + +When developing a custom UI plugin for InvenTree, the plugin should aim to match the existing InvenTree theme as closely as possible. This will help to ensure that the custom content fits seamlessly into the existing user interface. + +To achieve this, we strongly recommend that you use the same framework as the InvenTree frontend - which is built using [React](https://react.dev) on top of the [Mantine](https://mantine.dev) UI component library. + +### Mantine + +The Mantine UI component library is used throughout the InvenTree frontend, and provides a consistent look and feel to the user interface. By using Mantine components in your custom UI plugin, you can ensure that your custom content fits seamlessly into the existing InvenTree theme. + +### InvenTree Component Library + +We are working to develop and distribute a library of custom InvenTree components which can be used to build custom UI plugins. This library will be made available to plugin developers in the near future. + +### Examples + +Refer to some of the existing InvenTree plugins linked above for examples of building custom UI plugins using the Mantine component library for seamless integration. diff --git a/docs/docs/faq.md b/docs/docs/faq.md index 98cd2cdb1b..0b3afe9d55 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -63,6 +63,10 @@ For more information, refer to the installation guides: !!! warning "Invoke Update" You must ensure that the `invoke update` command is performed *every time* you update InvenTree +### Breaking Changes + +Before performing an update, check the release notes! Any *breaking changes* (changes which require user intervention) will be clearly noted. + ### Feature *x* does not work after update If a particular menu / item is not visible after updating InvenTree, or a certain function no longer seems to work, it may be due to your internet browser caching old versions of CSS and JavaScript files. diff --git a/docs/docs/report/helpers.md b/docs/docs/report/helpers.md index 6dc90fb7a6..125d021016 100644 --- a/docs/docs/report/helpers.md +++ b/docs/docs/report/helpers.md @@ -41,6 +41,13 @@ A number of helper functions are available for accessing data contained in a par To return the element at a given index in a container which supports indexed access (such as a [list](https://www.w3schools.com/python/python_lists.asp)), use the `getindex` function: +::: report.templatetags.report.getindex + options: + show_docstring_description: false + show_source: False + +#### Example + ```html {% raw %} {% getindex my_list 1 as value %} @@ -53,6 +60,13 @@ Item: {{ value }} To return an element corresponding to a certain key in a container which supports key access (such as a [dictionary](https://www.w3schools.com/python/python_dictionaries.asp)), use the `getkey` function: +::: report.templatetags.report.getkey + options: + show_docstring_description: false + show_source: False + +#### Example + ```html {% raw %}