diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 44acb8756c..1fccc6bbf8 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -89,6 +89,7 @@ jobs: docker run --rm inventree-test invoke --list docker run --rm inventree-test gunicorn --version docker run --rm inventree-test pg_dump --version + docker run --rm inventree-test test -f /home/inventree/src/backend/InvenTree/manage.py - name: Build Docker Image # Build the development docker image (using docker-compose.yml) run: docker compose --project-directory . -f contrib/container/dev-docker-compose.yml build --no-cache diff --git a/contrib/container/Dockerfile b/contrib/container/Dockerfile index 67921c33de..38901aae1a 100644 --- a/contrib/container/Dockerfile +++ b/contrib/container/Dockerfile @@ -33,6 +33,8 @@ ENV INVENTREE_MEDIA_ROOT="${INVENTREE_DATA_DIR}/media" ENV INVENTREE_BACKUP_DIR="${INVENTREE_DATA_DIR}/backup" ENV INVENTREE_PLUGIN_DIR="${INVENTREE_DATA_DIR}/plugins" +ENV INVENTREE_BACKEND_DIR="${INVENTREE_HOME}/src/backend" + # InvenTree configuration files ENV INVENTREE_CONFIG_FILE="${INVENTREE_DATA_DIR}/config.yaml" ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DATA_DIR}/secret_key.txt" @@ -122,10 +124,9 @@ ENV INVENTREE_COMMIT_DATE="${commit_date}" ENV PATH=/root/.local/bin:$PATH COPY --from=prebuild /root/.local /root/.local -ENV INVENTREE_BACKEND_DIR="${INVENTREE_HOME}" # Copy source code -COPY src/backend/InvenTree ./InvenTree +COPY src/backend/InvenTree ${INVENTREE_HOME}/src/backend/InvenTree COPY --from=frontend ${INVENTREE_HOME}/src/backend/InvenTree/web/static/web ./src/backend/InvenTree/web/static/web # Launch the production server @@ -133,8 +134,6 @@ CMD gunicorn -c ./gunicorn.conf.py InvenTree.wsgi -b 0.0.0.0:8000 --chdir ./Inve FROM inventree_base AS dev -ENV INVENTREE_BACKEND_DIR="${INVENTREE_HOME}/src/backend" - # Vite server (for local frontend development) EXPOSE 5173 diff --git a/docs/docs/start/docker_install.md b/docs/docs/start/docker_install.md index 28c787da67..36cd804c76 100644 --- a/docs/docs/start/docker_install.md +++ b/docs/docs/start/docker_install.md @@ -27,13 +27,13 @@ The following guide provides a streamlined production InvenTree installation, wi ### Required Files -The following files required for this setup are provided with the InvenTree source, located in the `./docker/` directory of the [InvenTree source code](https://github.com/inventree/InvenTree/tree/master/docker/): +The following files required for this setup are provided with the InvenTree source, located in the `/contrib/container/` directory of the [InvenTree source code](https://github.com/inventree/InvenTree/tree/master/contrib/container/): | Filename | Description | | --- | --- | -| [docker-compose.yml](https://github.com/inventree/InvenTree/blob/master/docker/docker-compose.yml) | The docker compose script | -| [.env](https://github.com/inventree/InvenTree/blob/master/docker/.env) | Environment variables | -| [Caddyfile](https://github.com/inventree/InvenTree/blob/master/docker/Caddyfile) | Caddy configuration file | +| [docker-compose.yml](https://github.com/inventree/InvenTree/blob/master/contrib/container/docker-compose.yml) | The docker compose script | +| [.env](https://github.com/inventree/InvenTree/blob/master/contrib/container/.env) | Environment variables | +| [Caddyfile](https://github.com/inventree/InvenTree/blob/master/contrib/container/Caddyfile) | Caddy configuration file | Download these files to a directory on your local machine. diff --git a/src/backend/InvenTree/InvenTree/settings.py b/src/backend/InvenTree/InvenTree/settings.py index de32aae38c..516096a6b4 100644 --- a/src/backend/InvenTree/InvenTree/settings.py +++ b/src/backend/InvenTree/InvenTree/settings.py @@ -268,6 +268,26 @@ MIDDLEWARE = CONFIG.get( ], ) +# In DEBUG mode, add support for django-querycount +# Ref: https://github.com/bradmontgomery/django-querycount +if DEBUG and get_boolean_setting( + 'INVENTREE_DEBUG_QUERYCOUNT', 'debug_querycount', False +): + MIDDLEWARE.append('querycount.middleware.QueryCountMiddleware') + +QUERYCOUNT = { + 'THRESHOLDS': { + 'MEDIUM': 50, + 'HIGH': 200, + 'MIN_TIME_TO_LOG': 0, + 'MIN_QUERY_COUNT_TO_LOG': 0, + }, + 'IGNORE_REQUEST_PATTERNS': ['^(?!\/(api)?(plugin)?\/).*'], + 'IGNORE_SQL_PATTERNS': [], + 'DISPLAY_DUPLICATES': 3, + 'RESPONSE_HEADER': 'X-Django-Query-Count', +} + AUTHENTICATION_BACKENDS = CONFIG.get( 'authentication_backends', [ diff --git a/src/backend/InvenTree/plugin/base/integration/SettingsMixin.py b/src/backend/InvenTree/plugin/base/integration/SettingsMixin.py index d5a5ec9a5e..92f77182fc 100644 --- a/src/backend/InvenTree/plugin/base/integration/SettingsMixin.py +++ b/src/backend/InvenTree/plugin/base/integration/SettingsMixin.py @@ -62,16 +62,19 @@ class SettingsMixin: """Does this plugin use custom global settings.""" return bool(self.settings) - def get_setting(self, key, cache=False): + def get_setting(self, key, cache=False, backup_value=None): """Return the 'value' of the setting associated with this plugin. Arguments: key: The 'name' of the setting value to be retrieved cache: Whether to use RAM cached value (default = False) + backup_value: A backup value to return if the setting is not found """ from plugin.models import PluginSetting - return PluginSetting.get_setting(key, plugin=self.plugin_config(), cache=cache) + return PluginSetting.get_setting( + key, plugin=self.plugin_config(), cache=cache, backup_value=backup_value + ) def set_setting(self, key, value, user=None): """Set plugin setting value by key.""" diff --git a/src/backend/requirements-dev.in b/src/backend/requirements-dev.in index d27042e739..ab3c583153 100644 --- a/src/backend/requirements-dev.in +++ b/src/backend/requirements-dev.in @@ -2,6 +2,7 @@ -c requirements.txt coverage[toml] # Unit test coverage coveralls==2.1.2 # Coveralls linking (for tracking coverage) # PINNED 2022-06-28 - Old version needed for correct upload +django-querycount # Display number of URL queries for requests django-slowtests # Show which unit tests are running slowly django-test-migrations # Unit testing for database migrations isort # python import sorting diff --git a/src/backend/requirements-dev.txt b/src/backend/requirements-dev.txt index 845ccd2ca6..2f3df9693a 100644 --- a/src/backend/requirements-dev.txt +++ b/src/backend/requirements-dev.txt @@ -25,6 +25,7 @@ distlib==0.3.8 # via virtualenv django==4.2.11 # via django-slowtests +django-querycount==0.8.3 django-slowtests==1.1.1 django-test-migrations==1.3.0 docopt==0.6.2 diff --git a/src/frontend/src/states/states.tsx b/src/frontend/src/states/states.tsx index 41d45dde0d..fba98fc4c6 100644 --- a/src/frontend/src/states/states.tsx +++ b/src/frontend/src/states/states.tsx @@ -1,4 +1,5 @@ import { setApiDefaults } from '../App'; +import { useServerApiState } from './ApiState'; import { useSessionState } from './SessionState'; import { useGlobalSettingsState, useUserSettingsState } from './SettingsState'; import { useGlobalStatusState } from './StatusState'; @@ -131,6 +132,7 @@ export function fetchGlobalStates() { setApiDefaults(); + useServerApiState.getState().fetchServerApiState(); useUserState.getState().fetchUserState(); useUserSettingsState.getState().fetchSettings(); useGlobalSettingsState.getState().fetchSettings();