Merge branch 'master' into matmair/issue11460
This commit is contained in:
commit
f20d3456f6
|
|
@ -165,7 +165,7 @@ jobs:
|
|||
pip install --require-hashes -r docs/requirements.txt
|
||||
python docs/ci/check_mkdocs_config.py
|
||||
- name: Check Links
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368 # pin@v1
|
||||
uses: tcort/github-action-markdown-link-check@e7c7a18363c842693fadde5d41a3bd3573a7a225 # pin@v1
|
||||
with:
|
||||
folder-path: docs
|
||||
config-file: docs/mlc_config.json
|
||||
|
|
@ -713,9 +713,24 @@ jobs:
|
|||
invoke dev.setup-test -iv
|
||||
invoke int.rebuild-thumbnails
|
||||
- name: Install dependencies
|
||||
run: invoke int.frontend-compile --extract
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }}
|
||||
- name: Install Playwright browsers
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
run: cd src/frontend && npx playwright install --with-deps
|
||||
- name: Install Playwright OS dependencies
|
||||
if: steps.playwright-cache.outputs.cache-hit == 'true'
|
||||
run: cd src/frontend && npx playwright install-deps
|
||||
- name: Install Sample Plugin
|
||||
run: |
|
||||
invoke int.frontend-compile --extract
|
||||
cd src/frontend && npx playwright install --with-deps
|
||||
pip install -U inventree-plugin-creator
|
||||
create-inventree-plugin --default
|
||||
cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build
|
||||
- name: Run Playwright tests
|
||||
id: tests
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ jobs:
|
|||
INVENTREE_PLUGIN_FILE=/opt/inventree/plugins.txt
|
||||
INVENTREE_CONFIG_FILE=/opt/inventree/config.yaml
|
||||
APP_REPO=inventree/InvenTree
|
||||
- name: Publish to go.packager.io
|
||||
- name: Publish to go.packager.io - current release channel
|
||||
uses: pkgr/action/publish@3bce081ae512c5020856e237d37b3f5479d4aa71 # pin@main
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
|
|
@ -235,10 +235,18 @@ jobs:
|
|||
repository: inventree/InvenTree
|
||||
channel: ${{ env.pkg_channel }}
|
||||
file: ${{ steps.package.outputs.package_path }}
|
||||
- name: Publish to go.packager.io - stable release channel
|
||||
uses: pkgr/action/publish@3bce081ae512c5020856e237d37b3f5479d4aa71 # pin@main
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
token: ${{ secrets.PACKAGER_RELEASE_TOKEN }}
|
||||
repository: inventree/InvenTree
|
||||
channel: stable
|
||||
file: ${{ steps.package.outputs.package_path }}
|
||||
- name: Publish to artifact
|
||||
run: gh release upload ${REF} ${PACKAGE_PATH}#${PACKAGE_NAME}
|
||||
env:
|
||||
REF: ${{ github.ref_name }}
|
||||
PACKAGE_PATH: ${{ steps.package.outputs.package_path }}
|
||||
PACKAGE_NAME: ${{ matrix.target }}-{{ steps.setup.outputs.version }}.tar.gz
|
||||
PACKAGE_NAME: ${{ matrix.target }}-${{ steps.setup.outputs.version }}.tar.gz
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ threads = 4
|
|||
|
||||
|
||||
# Worker timeout (default = 90 seconds)
|
||||
timeout = os.environ.get('INVENTREE_GUNICORN_TIMEOUT', '90')
|
||||
timeout = int(os.environ.get('INVENTREE_GUNICORN_TIMEOUT', '90'))
|
||||
|
||||
# Number of worker processes
|
||||
workers = os.environ.get('INVENTREE_GUNICORN_WORKERS', None)
|
||||
|
|
@ -43,7 +43,13 @@ preload_app = True
|
|||
|
||||
|
||||
def post_fork(server, worker):
|
||||
"""Post-fork hook to set up logging for each worker."""
|
||||
"""Post-fork hook called after each worker process is forked."""
|
||||
from django.db import connections
|
||||
|
||||
# Close any DB connections inherited from the master process — PostgreSQL
|
||||
# connections are not fork-safe, so each worker must open its own.
|
||||
connections.close_all()
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
if not settings.TRACING_ENABLED:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt -c src/backend/requirements.txt
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
|
|
@ -139,9 +139,9 @@ charset-normalizer==3.4.7 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ Transfer the currently selected stock location into another location. Scanning a
|
|||
|
||||
Receive incoming purchase order items into the selected location. Scanning a *new* barcode which is associated with an item in an incoming purchase order will receive the item into the selected location.
|
||||
|
||||
*Note: Both purchase order number and supplier SKU's are required to be found on the barcode for this function to find the associated line item. Missing one will lead to an error.*
|
||||
|
||||
#### Scan Items Into Location
|
||||
|
||||
the *Scan Items Into Location* action allows you to scan items into the selected location. Scanning a valid barcode associated with a stock item (already in the database) will result in that item being transferred to the selected location.
|
||||
|
|
@ -105,6 +107,8 @@ From the [Purchase Order detail page](./po.md#purchase-order-detail) page, the f
|
|||
|
||||
Receive incoming purchase order items against the selected purchase order. Scanning a *new* barcode which is associated with an item in an incoming purchase order will receive the item into stock.
|
||||
|
||||
*Note: supplier SKU's are required to be found on the barcode for this function to find the associated line item.*
|
||||
|
||||
### Sales Order Actions
|
||||
|
||||
The following barcode actions are available for [Sales Orders](./so.md):
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ The *Display Settings* screen shows general display configuration options:
|
|||
{{ usersetting("SHOW_FULL_CATEGORY_IN_TABLES")}}
|
||||
{{ usersetting("SHOW_BOM_SUBASSEMBLY_LEVELS")}}
|
||||
{{ usersetting("ENABLE_LAST_BREADCRUMB") }}
|
||||
{{ usersetting("SHOW_EXTRA_MODEL_INFO") }}
|
||||
{{ usersetting("SHOW_FULL_LOCATION_IN_TABLES") }}
|
||||
{{ usersetting("DISPLAY_ITEMS_FINAL_LEVEL") }}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,6 +256,9 @@ The following database options can be configured:
|
|||
{{ configsetting("INVENTREE_DB_PASSWORD") }} Database password (if required) |
|
||||
{{ configsetting("INVENTREE_DB_HOST") }} Database host address (if required) |
|
||||
{{ configsetting("INVENTREE_DB_PORT") }} Database host port (if required) |
|
||||
{{ configsetting("INVENTREE_DB_CONN_MAX_AGE") }} Database connection max age (s) |
|
||||
{{ configsetting("INVENTREE_DB_CONN_HEALTH_CHECKS") }} Enable database connection health checks |
|
||||
|
||||
{{ configsetting("INVENTREE_DB_OPTIONS") }} Additional database options (as a JSON object) |
|
||||
|
||||
!!! tip "Database Password"
|
||||
|
|
@ -266,11 +269,12 @@ The following database options can be configured:
|
|||
If running with a PostgreSQL database backend, the following additional options are available:
|
||||
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DB_TIMEOUT", default="2") }} Database connection timeout (s) |
|
||||
{{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES` | database.tcp_keepalives | 1 | TCP keepalive |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 1 | Idle TCP keepalive |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 1| TCP keepalive interval |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_IDLE` | database.tcp_keepalives_idle | 5 | Idle TCP keepalive |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_INTERVAL` | database.tcp_keepalives_interval | 5 | TCP keepalive interval |
|
||||
| `INVENTREE_DB_TCP_KEEPALIVES_COUNT` | database.tcp_keepalives_count | 5 | TCP keepalive count |
|
||||
| `INVENTREE_DB_TCP_USER_TIMEOUT` | database.tcp_user_timeout | 2000 | TCP user timeout (ms) |
|
||||
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||
|
||||
### MySQL Settings
|
||||
|
|
@ -278,6 +282,7 @@ If running with a PostgreSQL database backend, the following additional options
|
|||
If running with a MySQL database backend, the following additional options are available:
|
||||
|
||||
{{ configtable() }}
|
||||
{{ configsetting("INVENTREE_DB_TIMEOUT", default="10") }} Database connection timeout (s) |
|
||||
| `INVENTREE_DB_ISOLATION_SERIALIZABLE` | database.serializable | False | Database isolation level configured to "serializable" |
|
||||
|
||||
### SQLite Settings
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ bracex==2.6 \
|
|||
--hash=sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952 \
|
||||
--hash=sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7
|
||||
# via wcmatch
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# httpcore
|
||||
|
|
@ -169,9 +169,9 @@ charset-normalizer==3.4.7 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
click==8.3.3 \
|
||||
--hash=sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2 \
|
||||
--hash=sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613
|
||||
click==8.4.1 \
|
||||
--hash=sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2 \
|
||||
--hash=sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96
|
||||
# via
|
||||
# mkdocs
|
||||
# neoteroi-mkdocs
|
||||
|
|
@ -227,9 +227,9 @@ httpx==0.28.1 \
|
|||
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
|
||||
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
|
||||
# via neoteroi-mkdocs
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# anyio
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@
|
|||
|
||||
from django.contrib import admin
|
||||
from django.http.request import HttpRequest
|
||||
from django.utils import timezone
|
||||
|
||||
from allauth.usersessions.admin import UserSessionAdmin
|
||||
from allauth.usersessions.models import UserSession
|
||||
from django_q.admin import ScheduleAdmin
|
||||
from django_q.models import Schedule
|
||||
from djmoney.contrib.exchange.admin import RateAdmin
|
||||
from djmoney.contrib.exchange.models import Rate
|
||||
|
||||
|
|
@ -17,3 +22,51 @@ class CustomRateAdmin(RateAdmin):
|
|||
|
||||
admin.site.unregister(Rate)
|
||||
admin.site.register(Rate, CustomRateAdmin)
|
||||
|
||||
|
||||
def run_schedule_now(modeladmin, request, queryset):
|
||||
"""Immediately queue the selected scheduled tasks for execution."""
|
||||
queryset.update(next_run=timezone.now())
|
||||
count = queryset.count()
|
||||
modeladmin.message_user(request, f'{count} task(s) queued for immediate execution.')
|
||||
|
||||
|
||||
run_schedule_now.short_description = 'Run selected tasks now'
|
||||
|
||||
|
||||
class ReadOnlyScheduleAdmin(ScheduleAdmin):
|
||||
"""Read-only admin interface for django-q Schedule objects."""
|
||||
|
||||
actions = [run_schedule_now]
|
||||
|
||||
def has_add_permission(self, request: HttpRequest) -> bool:
|
||||
"""Prevent adding new Schedule objects."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request: HttpRequest, obj=None) -> bool:
|
||||
"""Prevent changing existing Schedule objects."""
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request: HttpRequest, obj=None) -> bool:
|
||||
"""Prevent deleting Schedule objects."""
|
||||
return False
|
||||
|
||||
|
||||
admin.site.unregister(Schedule)
|
||||
admin.site.register(Schedule, ReadOnlyScheduleAdmin)
|
||||
|
||||
|
||||
class InvenTreeUserSessionAdmin(UserSessionAdmin):
|
||||
"""Admin interface for UserSession - view and delete only, no add or edit."""
|
||||
|
||||
def has_add_permission(self, request: HttpRequest) -> bool:
|
||||
"""Prevent creating sessions via admin."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request: HttpRequest, obj=None) -> bool:
|
||||
"""Prevent editing sessions via admin."""
|
||||
return False
|
||||
|
||||
|
||||
admin.site.unregister(UserSession)
|
||||
admin.site.register(UserSession, InvenTreeUserSessionAdmin)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 497
|
||||
INVENTREE_API_VERSION = 499
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v499 -> 2026-06-01 : https://github.com/inventree/InvenTree/pull/12057
|
||||
- Fixes search field issues on the BarcodeScanHistory API endpoint
|
||||
|
||||
v498 -> 2026-05-31 : https://github.com/inventree/InvenTree/pull/12055
|
||||
- Updates the "status_text" field for models which support custom status values
|
||||
|
||||
v497 -> 2026-05-27 : https://github.com/inventree/InvenTree/pull/12019
|
||||
- Adds "location" field to StockCount API endpoint
|
||||
|
||||
|
|
|
|||
|
|
@ -64,9 +64,20 @@ class InvenTreeConfig(AppConfig):
|
|||
self.collect_tasks()
|
||||
self.start_background_tasks()
|
||||
|
||||
if not InvenTree.ready.isInTestMode(): # pragma: no cover
|
||||
if (
|
||||
not InvenTree.ready.isInTestMode()
|
||||
and not InvenTree.ready.isInWorkerThread()
|
||||
): # pragma: no cover
|
||||
# Let the background worker check for migrations
|
||||
InvenTree.tasks.offload_task(InvenTree.tasks.check_for_migrations)
|
||||
# Don't offload task if we are already *in* the background worker, otherwise we might end up in a deadlock situation
|
||||
|
||||
try:
|
||||
InvenTree.tasks.offload_task(InvenTree.tasks.check_for_migrations)
|
||||
except Exception as exc:
|
||||
logger.exception(
|
||||
'Failed to offload check_for_migrations task: %s', exc
|
||||
)
|
||||
|
||||
# Update exchange rates
|
||||
InvenTree.tasks.offload_task(
|
||||
InvenTree.tasks.update_exchange_rates, force_async=True
|
||||
|
|
|
|||
|
|
@ -764,6 +764,56 @@ class InvenTreeDecimalField(serializers.FloatField):
|
|||
raise serializers.ValidationError(_('Invalid value'))
|
||||
|
||||
|
||||
class CustomStatusSerializerMixin(serializers.Serializer):
|
||||
"""Serializer mixin for models that support custom status values.
|
||||
|
||||
Provides a `status_text` SerializerMethodField that resolves custom
|
||||
status labels with a single database query per model per serializer
|
||||
context (i.e. one query for a whole list page) rather than one query per
|
||||
object (N+1).
|
||||
"""
|
||||
|
||||
status_text = serializers.SerializerMethodField()
|
||||
|
||||
@extend_schema_field(serializers.CharField(allow_null=True))
|
||||
def get_status_text(self, instance) -> Optional[str]:
|
||||
"""Return the human-readable status text for the instance.
|
||||
|
||||
Uses a per-context cache keyed by model name so that all objects in a
|
||||
single serialization pass share one DB hit for custom label lookup.
|
||||
|
||||
During write operations DRF may call to_representation on the raw
|
||||
validated_data dict rather than a model instance (e.g. when building
|
||||
response headers). Return None in that case — the response body is
|
||||
always produced from a real instance via a separate serializer call.
|
||||
"""
|
||||
if not hasattr(instance, 'get_custom_status'):
|
||||
return None
|
||||
|
||||
custom_key = instance.get_custom_status()
|
||||
|
||||
if custom_key is None:
|
||||
return instance.status_class.label(instance.get_status())
|
||||
|
||||
model_name = instance._meta.model_name
|
||||
cache_key = f'_custom_status_labels_{model_name}'
|
||||
|
||||
# Cache a dict of custom status labels for this model, if not already cached
|
||||
if cache_key not in self.context:
|
||||
from common.models import InvenTreeCustomUserStateModel
|
||||
|
||||
self.context[cache_key] = {
|
||||
obj.key: obj.label
|
||||
for obj in InvenTreeCustomUserStateModel.objects.filter(
|
||||
model__model=model_name
|
||||
)
|
||||
}
|
||||
|
||||
return self.context[cache_key].get(
|
||||
custom_key, instance.status_class.label(instance.get_status())
|
||||
)
|
||||
|
||||
|
||||
class NotesFieldMixin:
|
||||
"""Serializer mixin for handling 'notes' fields.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,23 @@ from pathlib import Path
|
|||
import structlog
|
||||
|
||||
from InvenTree.config import get_boolean_setting, get_config_value, get_setting
|
||||
from InvenTree.ready import isInWorkerThread
|
||||
|
||||
logger = structlog.get_logger('inventree')
|
||||
|
||||
|
||||
def _get_conn_max_age() -> int | None:
|
||||
"""Return the configured CONN_MAX_AGE value.
|
||||
|
||||
Accepts an integer number of seconds, or 'None' for unlimited persistence.
|
||||
Defaults to 0 (close the connection after each request).
|
||||
"""
|
||||
value = get_setting('INVENTREE_DB_CONN_MAX_AGE', 'database.conn_max_age', 0)
|
||||
if value is None or str(value).strip().lower() == 'none':
|
||||
return None
|
||||
return int(value)
|
||||
|
||||
|
||||
def get_db_backend():
|
||||
"""Return the database backend configuration."""
|
||||
# For the core database configuration values, we test for UPPERCASE configuration values as a backup,
|
||||
|
|
@ -43,6 +56,13 @@ def get_db_backend():
|
|||
)
|
||||
or get_config_value('database.OPTIONS')
|
||||
or {},
|
||||
# Seconds to keep idle connections open across requests (0 = close after each request).
|
||||
# Set to None for unlimited. Enable CONN_HEALTH_CHECKS alongside any non-zero value
|
||||
# so stale connections are detected before use rather than causing request failures.
|
||||
'CONN_MAX_AGE': _get_conn_max_age(),
|
||||
'CONN_HEALTH_CHECKS': get_boolean_setting(
|
||||
'INVENTREE_DB_CONN_HEALTH_CHECKS', 'database.conn_health_checks', False
|
||||
),
|
||||
}
|
||||
|
||||
# Check for required keys
|
||||
|
|
@ -113,9 +133,9 @@ def set_postgres_options(db_options: dict):
|
|||
if 'connect_timeout' not in db_options:
|
||||
# The DB server is in the same data center, it should not take very
|
||||
# long to connect to the database server
|
||||
# # seconds, 2 is minimum allowed by libpq
|
||||
db_options['connect_timeout'] = int(
|
||||
get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 2)
|
||||
# Note: 2 seconds is minimum allowed by libpq
|
||||
db_options['connect_timeout'] = max(
|
||||
2, int(get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 10))
|
||||
)
|
||||
|
||||
# Setup TCP keepalive
|
||||
|
|
@ -133,7 +153,7 @@ def set_postgres_options(db_options: dict):
|
|||
if 'keepalives_idle' not in db_options:
|
||||
db_options['keepalives_idle'] = int(
|
||||
get_setting(
|
||||
'INVENTREE_DB_TCP_KEEPALIVES_IDLE', 'database.tcp_keepalives_idle', 1
|
||||
'INVENTREE_DB_TCP_KEEPALIVES_IDLE', 'database.tcp_keepalives_idle', 5
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -143,7 +163,7 @@ def set_postgres_options(db_options: dict):
|
|||
get_setting(
|
||||
'INVENTREE_DB_TCP_KEEPALIVES_INTERVAL',
|
||||
'database.tcp_keepalives_interval',
|
||||
'1',
|
||||
'5',
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -157,10 +177,13 @@ def set_postgres_options(db_options: dict):
|
|||
)
|
||||
)
|
||||
|
||||
# # Milliseconds for how long pending data should remain unacked
|
||||
# by the remote server
|
||||
# TODO: Supported starting in PSQL 11
|
||||
# "tcp_user_timeout": int(os.getenv("PGTCP_USER_TIMEOUT", "1000"),
|
||||
# # Milliseconds for how long pending data should remain unacked by the remote server
|
||||
if 'tcp_user_timeout' not in db_options:
|
||||
db_options['tcp_user_timeout'] = int(
|
||||
get_setting(
|
||||
'INVENTREE_DB_TCP_USER_TIMEOUT', 'database.tcp_user_timeout', '2000'
|
||||
)
|
||||
)
|
||||
|
||||
# Postgres's default isolation level is Read Committed which is
|
||||
# normally fine, but most developers think the database server is
|
||||
|
|
@ -178,10 +201,21 @@ def set_postgres_options(db_options: dict):
|
|||
else IsolationLevel.READ_COMMITTED
|
||||
)
|
||||
|
||||
# Specify the application name for the database connection
|
||||
# This can be useful for debugging and monitoring purposes
|
||||
if 'application_name' not in db_options:
|
||||
db_options['application_name'] = (
|
||||
'inventree-worker' if isInWorkerThread() else 'inventree-server'
|
||||
)
|
||||
|
||||
|
||||
def set_mysql_options(db_options: dict):
|
||||
"""Set database options specific to mysql backend."""
|
||||
# TODO TCP time outs and keepalives
|
||||
# Timeout values
|
||||
if 'connect_timeout' not in db_options:
|
||||
db_options['connect_timeout'] = int(
|
||||
get_setting('INVENTREE_DB_TIMEOUT', 'database.timeout', 10)
|
||||
)
|
||||
|
||||
# MariaDB's default isolation level is Repeatable Read which is
|
||||
# normally fine, but most developers think the database server is
|
||||
|
|
|
|||
|
|
@ -56,7 +56,11 @@ INVENTREE_BASE_URL = 'https://inventree.org'
|
|||
INVENTREE_NEWS_URL = f'{INVENTREE_BASE_URL}/news/feed.atom'
|
||||
|
||||
# Determine if we are running in "test" mode e.g. "manage.py test"
|
||||
TESTING = 'test' in sys.argv or 'TESTING' in os.environ or 'pytest' in sys.argv
|
||||
TESTING = (
|
||||
'test' in sys.argv
|
||||
or 'TESTING' in os.environ
|
||||
or any('pytest' in arg for arg in sys.argv)
|
||||
)
|
||||
|
||||
if TESTING:
|
||||
# Use a weaker password hasher for testing (improves testing speed)
|
||||
|
|
|
|||
|
|
@ -282,40 +282,31 @@ def offload_task(
|
|||
# function was passed - use that
|
||||
_func = taskname
|
||||
else:
|
||||
# Split path
|
||||
# Split on the last dot: everything before is the module path,
|
||||
# everything after is the function name. rsplit handles any depth
|
||||
# (e.g. 'app.module.func' or 'app.sub.module.func').
|
||||
try:
|
||||
app, mod, func = taskname.split('.')
|
||||
app_mod = app + '.' + mod
|
||||
module_path, func_name = taskname.rsplit('.', 1)
|
||||
except ValueError:
|
||||
raise_warning(
|
||||
f"WARNING: '{taskname}' not started - Malformed function path"
|
||||
)
|
||||
return False
|
||||
|
||||
# Import module from app
|
||||
try:
|
||||
_mod = importlib.import_module(app_mod)
|
||||
_mod = importlib.import_module(module_path)
|
||||
except ModuleNotFoundError:
|
||||
log_error('offload_task', scope='worker')
|
||||
raise_warning(
|
||||
f"WARNING: '{taskname}' not started - No module named '{app_mod}'"
|
||||
f"WARNING: '{taskname}' not started - No module named '{module_path}'"
|
||||
)
|
||||
return False
|
||||
|
||||
# Retrieve function
|
||||
try:
|
||||
_func = getattr(_mod, func)
|
||||
except AttributeError: # pragma: no cover
|
||||
# getattr does not work for local import
|
||||
_func = None
|
||||
|
||||
try:
|
||||
if not _func:
|
||||
_func = eval(func) # pragma: no cover
|
||||
except NameError:
|
||||
_func = getattr(_mod, func_name, None)
|
||||
if _func is None:
|
||||
log_error('offload_task', scope='worker')
|
||||
raise_warning(
|
||||
f"WARNING: '{taskname}' not started - No function named '{func}'"
|
||||
f"WARNING: '{taskname}' not started - No function named '{func_name}'"
|
||||
)
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
"""Sample task functions used by offload_task unit tests."""
|
||||
|
||||
|
||||
def get_result():
|
||||
"""Return a fixed value; used to verify 4-part module paths resolve correctly."""
|
||||
return 'abc'
|
||||
|
|
@ -67,26 +67,72 @@ class InvenTreeTaskTests(PluginRegistryMixin, TestCase):
|
|||
# Run with string ref
|
||||
InvenTree.tasks.offload_task('InvenTree.test_tasks.get_result')
|
||||
|
||||
# Error runs
|
||||
# The error-path tests below all use force_sync=True so that the sync
|
||||
# resolution code is exercised regardless of whether background workers
|
||||
# happen to be running in this environment.
|
||||
|
||||
# Malformed taskname
|
||||
with self.assertWarnsMessage(
|
||||
UserWarning, "WARNING: 'InvenTree' not started - Malformed function path"
|
||||
):
|
||||
InvenTree.tasks.offload_task('InvenTree')
|
||||
InvenTree.tasks.offload_task('InvenTree', force_sync=True)
|
||||
|
||||
# Non existent app
|
||||
with self.assertWarnsMessage(
|
||||
UserWarning,
|
||||
"WARNING: 'InvenTreeABC.test_tasks.doesnotmatter' not started - No module named 'InvenTreeABC.test_tasks'",
|
||||
):
|
||||
InvenTree.tasks.offload_task('InvenTreeABC.test_tasks.doesnotmatter')
|
||||
InvenTree.tasks.offload_task(
|
||||
'InvenTreeABC.test_tasks.doesnotmatter', force_sync=True
|
||||
)
|
||||
|
||||
# Non existent function
|
||||
with self.assertWarnsMessage(
|
||||
UserWarning,
|
||||
"WARNING: 'InvenTree.test_tasks.doesnotexist' not started - No function named 'doesnotexist'",
|
||||
):
|
||||
InvenTree.tasks.offload_task('InvenTree.test_tasks.doesnotexist')
|
||||
InvenTree.tasks.offload_task(
|
||||
'InvenTree.test_tasks.doesnotexist', force_sync=True
|
||||
)
|
||||
|
||||
def test_offloading_deep_path(self):
|
||||
"""Test that task paths with more than 3 components are resolved correctly.
|
||||
|
||||
Previously the sync fallback split on '.' requiring exactly 3 parts,
|
||||
so a 4-part path raised ValueError and returned False with no warning.
|
||||
Now rsplit('.', 1) is used, so any depth works.
|
||||
"""
|
||||
# 4-part valid path: module = 'InvenTree.test_helpers.sample_tasks', func = 'get_result'
|
||||
InvenTree.tasks.offload_task(
|
||||
'InvenTree.test_helpers.sample_tasks.get_result', force_sync=True
|
||||
)
|
||||
|
||||
# 4-part path with a non-existent module — should warn cleanly rather than crash
|
||||
with self.assertWarnsMessage(
|
||||
UserWarning,
|
||||
"WARNING: 'InvenTreeABC.sub.tasks.doesnotmatter' not started - No module named 'InvenTreeABC.sub.tasks'",
|
||||
):
|
||||
InvenTree.tasks.offload_task(
|
||||
'InvenTreeABC.sub.tasks.doesnotmatter', force_sync=True
|
||||
)
|
||||
|
||||
def test_offloading_no_eval_bypass(self):
|
||||
"""Verify that names in tasks.py scope cannot be resolved via an eval bypass.
|
||||
|
||||
The previous implementation fell back to eval(func) when getattr returned
|
||||
None, evaluating the function name in the local scope of offload_task rather
|
||||
than in the target module. This meant a Python builtin like 'eval', or any
|
||||
name imported into tasks.py, could be invoked via a crafted taskname. The
|
||||
replacement uses only getattr on the imported module and rejects anything
|
||||
not found there.
|
||||
"""
|
||||
# 'eval' is a Python builtin; it is not an attribute of InvenTree.test_tasks.
|
||||
# Previously eval('eval') in tasks.py's scope would resolve it; now it fails.
|
||||
with self.assertWarnsMessage(
|
||||
UserWarning,
|
||||
"WARNING: 'InvenTree.test_tasks.eval' not started - No function named 'eval'",
|
||||
):
|
||||
InvenTree.tasks.offload_task('InvenTree.test_tasks.eval', force_sync=True)
|
||||
|
||||
def test_task_heartbeat(self):
|
||||
"""Test the task heartbeat."""
|
||||
|
|
|
|||
|
|
@ -1488,7 +1488,7 @@ class TestOffloadTask(InvenTreeTestCase):
|
|||
offload_task('dummy_task.numbers', 1, 1, 1, force_sync=True)
|
||||
)
|
||||
|
||||
self.assertIn('Malformed function path', str(log.output))
|
||||
self.assertIn("No module named \\'dummy_task\\'", str(log.output))
|
||||
|
||||
# Offload dummy task with a Part instance
|
||||
# This should succeed, ensuring that the Part instance is correctly pickled
|
||||
|
|
|
|||
|
|
@ -50,12 +50,17 @@ def setup_tracing(
|
|||
"""
|
||||
if InvenTree.ready.isImportingData() or InvenTree.ready.isRunningMigrations():
|
||||
return
|
||||
|
||||
if endpoint is None or headers is None:
|
||||
print(
|
||||
'Tracing endpoint or headers not specified - skipping tracing setup'
|
||||
) # pragma: no cover
|
||||
return # pragma: no cover
|
||||
|
||||
# check if trace is already set up - if so, skip
|
||||
if trace.get_tracer_provider() is not None:
|
||||
return
|
||||
|
||||
# Logger configuration
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
|
@ -163,29 +168,34 @@ def setup_tracing(
|
|||
|
||||
def setup_instruments(db_engine: str): # pragma: no cover
|
||||
"""Run auto-instrumentation for OpenTelemetry tracing."""
|
||||
DjangoInstrumentor().instrument()
|
||||
RedisInstrumentor().instrument()
|
||||
RequestsInstrumentor().instrument()
|
||||
SystemMetricsInstrumentor().instrument()
|
||||
if not DjangoInstrumentor()._is_instrumented_by_opentelemetry:
|
||||
DjangoInstrumentor().instrument()
|
||||
RedisInstrumentor().instrument()
|
||||
RequestsInstrumentor().instrument()
|
||||
SystemMetricsInstrumentor().instrument()
|
||||
|
||||
db_engine = str(db_engine).lower().strip()
|
||||
|
||||
# DBs
|
||||
if 'sqlite' in db_engine:
|
||||
SQLite3Instrumentor().instrument()
|
||||
inst = SQLite3Instrumentor()
|
||||
if not inst._is_instrumented_by_opentelemetry:
|
||||
inst.instrument()
|
||||
elif 'postgresql' in db_engine:
|
||||
try:
|
||||
from opentelemetry.instrumentation.psycopg import PsycopgInstrumentor
|
||||
|
||||
PsycopgInstrumentor().instrument(
|
||||
enable_commenter=False, commenter_options={}
|
||||
)
|
||||
inst = PsycopgInstrumentor()
|
||||
if not inst._is_instrumented_by_opentelemetry:
|
||||
inst.instrument(enable_commenter=False, commenter_options={})
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
elif 'mysql' in db_engine:
|
||||
try:
|
||||
from opentelemetry.instrumentation.pymysql import PyMySQLInstrumentor
|
||||
|
||||
PyMySQLInstrumentor().instrument()
|
||||
inst = PyMySQLInstrumentor()
|
||||
if not inst._is_instrumented_by_opentelemetry:
|
||||
inst.instrument()
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ from common.settings import get_global_setting
|
|||
from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeDecimalField,
|
||||
InvenTreeModelSerializer,
|
||||
|
|
@ -53,6 +54,7 @@ from .status_codes import BuildStatus
|
|||
|
||||
|
||||
class BuildSerializer(
|
||||
CustomStatusSerializerMixin,
|
||||
FilterableSerializerMixin,
|
||||
NotesFieldMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
|
|
@ -116,8 +118,6 @@ class BuildSerializer(
|
|||
|
||||
level = serializers.IntegerField(label=_('Build Level'), read_only=True)
|
||||
|
||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||
|
||||
part_detail = OptionalField(
|
||||
serializer_class=part_serializers.PartBriefSerializer,
|
||||
serializer_kwargs={'source': 'part', 'many': False, 'read_only': True},
|
||||
|
|
|
|||
|
|
@ -1817,6 +1817,97 @@ class BuildConsumeTest(BuildAPITest):
|
|||
self.assertEqual(line.consumed, 100)
|
||||
|
||||
|
||||
class BuildCustomStatusTest(BuildAPITest):
|
||||
"""Tests for custom status values on Build orders."""
|
||||
|
||||
url = reverse('api-build-list')
|
||||
|
||||
def test_custom_status_query_count(self):
|
||||
"""Test that listing Build orders with custom statuses does not cause N+1 queries.
|
||||
|
||||
Ensures that resolving 'status_text' for custom status values is O(1)
|
||||
in database queries, not O(N) relative to the number of results.
|
||||
"""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from common.models import InvenTreeCustomUserStateModel
|
||||
|
||||
build_content_type = ContentType.objects.get_for_model(Build)
|
||||
|
||||
# 10 custom status values - different keys, labels, and logical_keys
|
||||
logical_keys = [
|
||||
BuildStatus.PENDING.value,
|
||||
BuildStatus.PRODUCTION.value,
|
||||
BuildStatus.ON_HOLD.value,
|
||||
BuildStatus.CANCELLED.value,
|
||||
BuildStatus.COMPLETE.value,
|
||||
BuildStatus.PENDING.value,
|
||||
BuildStatus.PRODUCTION.value,
|
||||
BuildStatus.ON_HOLD.value,
|
||||
BuildStatus.CANCELLED.value,
|
||||
BuildStatus.COMPLETE.value,
|
||||
]
|
||||
|
||||
custom_statuses = [
|
||||
InvenTreeCustomUserStateModel.objects.create(
|
||||
key=3000 + i,
|
||||
name=f'BuildCustomStatus{i}',
|
||||
label=f'Build Custom Status Label {i}',
|
||||
color='secondary',
|
||||
logical_key=logical_keys[i],
|
||||
model=build_content_type,
|
||||
reference_status='BuildStatus',
|
||||
)
|
||||
for i in range(10)
|
||||
]
|
||||
|
||||
part = Part.objects.filter(assembly=True).first()
|
||||
|
||||
# Build is an MPTT tree model; bulk_create requires tree fields to be
|
||||
# populated manually. All new orders are root nodes (no parent) so each
|
||||
# gets its own unique tree_id.
|
||||
from django.db.models import Max
|
||||
|
||||
next_tree_id = (Build.objects.aggregate(m=Max('tree_id'))['m'] or 0) + 1
|
||||
|
||||
# Create 100 build orders, cycling through the 10 custom statuses
|
||||
Build.objects.bulk_create([
|
||||
Build(
|
||||
part=part,
|
||||
reference=f'BO-QTEST-{i}',
|
||||
quantity=1,
|
||||
status=custom_statuses[i % 10].logical_key,
|
||||
status_custom_key=custom_statuses[i % 10].key,
|
||||
lft=1,
|
||||
rght=2,
|
||||
level=0,
|
||||
tree_id=next_tree_id + i,
|
||||
)
|
||||
for i in range(100)
|
||||
])
|
||||
|
||||
# Lookup: custom_key -> custom_status_object, for quick per-row assertions
|
||||
custom_lookup = {cs.key: cs for cs in custom_statuses}
|
||||
|
||||
# Query count must stay below the fixed threshold regardless of limit.
|
||||
# An N+1 bug would push limit=50 or limit=100 well over the threshold.
|
||||
for limit in [1, 10, 50, 100]:
|
||||
response = self.get(
|
||||
self.url, data={'limit': limit}, expected_code=200, max_query_count=50
|
||||
)
|
||||
|
||||
for result in response.data['results']:
|
||||
cs = custom_lookup.get(result['status_custom_key'])
|
||||
|
||||
if cs is None:
|
||||
# Build from fixtures - no custom status assigned
|
||||
continue
|
||||
|
||||
self.assertEqual(result['status'], cs.logical_key)
|
||||
self.assertEqual(result['status_custom_key'], cs.key)
|
||||
self.assertEqual(result['status_text'], cs.label)
|
||||
|
||||
|
||||
class BuildAutoAllocateAPITest(InvenTreeAPITestCase):
|
||||
"""API integration tests for BuildAutoAllocate endpoint back-ports (stock_sort_by, build_lines)."""
|
||||
|
||||
|
|
|
|||
|
|
@ -79,21 +79,37 @@ class AttachmentAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(common.models.DataOutput)
|
||||
class DataOutputAdmin(admin.ModelAdmin):
|
||||
"""Admin interface for DataOutput objects."""
|
||||
"""Admin interface for DataOutput objects - view and delete only."""
|
||||
|
||||
list_display = ('user', 'created', 'output_type', 'output')
|
||||
|
||||
list_filter = ('user', 'output_type')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new DataOutput objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of DataOutput objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
@admin.register(common.models.BarcodeScanResult)
|
||||
class BarcodeScanResultAdmin(admin.ModelAdmin):
|
||||
"""Admin interface for BarcodeScanResult objects."""
|
||||
"""Admin interface for BarcodeScanResult objects - read-only audit log."""
|
||||
|
||||
list_display = ('data', 'timestamp', 'user', 'endpoint', 'result')
|
||||
|
||||
list_filter = ('user', 'endpoint', 'result')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new BarcodeScanResult objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of BarcodeScanResult objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
@admin.register(common.models.ProjectCode)
|
||||
class ProjectCodeAdmin(admin.ModelAdmin):
|
||||
|
|
@ -139,14 +155,22 @@ class WebhookAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(common.models.NotificationEntry)
|
||||
class NotificationEntryAdmin(admin.ModelAdmin):
|
||||
"""Admin settings for NotificationEntry."""
|
||||
"""Admin settings for NotificationEntry - view and delete only."""
|
||||
|
||||
list_display = ('key', 'uid', 'updated')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new NotificationEntry objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of NotificationEntry objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
@admin.register(common.models.NotificationMessage)
|
||||
class NotificationMessageAdmin(admin.ModelAdmin):
|
||||
"""Admin settings for NotificationMessage."""
|
||||
"""Admin settings for NotificationMessage - view and delete only."""
|
||||
|
||||
list_display = (
|
||||
'age_human',
|
||||
|
|
@ -162,14 +186,46 @@ class NotificationMessageAdmin(admin.ModelAdmin):
|
|||
|
||||
search_fields = ('name', 'category', 'message')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new NotificationMessage objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of NotificationMessage objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
@admin.register(common.models.NewsFeedEntry)
|
||||
class NewsFeedEntryAdmin(admin.ModelAdmin):
|
||||
"""Admin settings for NewsFeedEntry."""
|
||||
"""Admin settings for NewsFeedEntry - view and delete only."""
|
||||
|
||||
list_display = ('title', 'author', 'published', 'summary')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new NewsFeedEntry objects via the admin interface."""
|
||||
return False
|
||||
|
||||
admin.site.register(common.models.WebhookMessage, admin.ModelAdmin)
|
||||
admin.site.register(common.models.EmailMessage, admin.ModelAdmin)
|
||||
admin.site.register(common.models.EmailThread, admin.ModelAdmin)
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of NewsFeedEntry objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
class ReadOnlyAdmin(admin.ModelAdmin):
|
||||
"""Base admin class that prevents all modifications."""
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of objects via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
"""Prevent deletion of objects via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
admin.site.register(common.models.WebhookMessage, ReadOnlyAdmin)
|
||||
admin.site.register(common.models.EmailMessage, ReadOnlyAdmin)
|
||||
admin.site.register(common.models.EmailThread, ReadOnlyAdmin)
|
||||
|
|
|
|||
|
|
@ -3355,6 +3355,11 @@ class EmailThread(InvenTree.models.InvenTreeMetadataModel):
|
|||
unique_together = [['key', 'global_id']]
|
||||
ordering = ['-updated']
|
||||
|
||||
@staticmethod
|
||||
def get_api_url():
|
||||
"""Return the API URL associated with the EmailThread model."""
|
||||
return reverse('api-email-list')
|
||||
|
||||
key = models.CharField(
|
||||
max_length=250,
|
||||
verbose_name=_('Key'),
|
||||
|
|
|
|||
|
|
@ -235,6 +235,12 @@ USER_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
|
|||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'SHOW_EXTRA_MODEL_INFO': {
|
||||
'name': _('Show Extra Model Information'),
|
||||
'description': _('Display extra information in model selection dropdowns'),
|
||||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'SHOW_FULL_LOCATION_IN_TABLES': {
|
||||
'name': _('Show full stock location in tables'),
|
||||
'description': _(
|
||||
|
|
|
|||
|
|
@ -121,3 +121,7 @@ class TransitionTests(InvenTreeTestCase):
|
|||
self.assertIn(
|
||||
"ValueError('This is a broken transition plugin!')", str(cm.output[0])
|
||||
)
|
||||
|
||||
# Ensure the plugin is now disabled
|
||||
registry.set_plugin_state('sample-transition', False)
|
||||
registry.set_plugin_state('sample-broken-transition', False)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class TransitionMethod:
|
|||
**kwargs: Additional keyword arguments for custom logic.
|
||||
|
||||
Returns:
|
||||
result: bool - True if the transition method was successful, False otherwise.
|
||||
result: bool - True if the transition method was successful (and no further transitions are attempted), False otherwise.
|
||||
|
||||
Raises:
|
||||
ValidationError: Alert the user that the transition failed
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -31,6 +31,7 @@ from importer.registry import register_importer
|
|||
from InvenTree.helpers import extract_serial_numbers, hash_barcode, normalize, str2bool
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
|
|
@ -100,7 +101,10 @@ class DuplicateOrderSerializer(serializers.Serializer):
|
|||
|
||||
|
||||
class AbstractOrderSerializer(
|
||||
DataImportExportSerializerMixin, FilterableSerializerMixin, serializers.Serializer
|
||||
CustomStatusSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
FilterableSerializerMixin,
|
||||
serializers.Serializer,
|
||||
):
|
||||
"""Abstract serializer class which provides fields common to all order types."""
|
||||
|
||||
|
|
@ -118,9 +122,6 @@ class AbstractOrderSerializer(
|
|||
read_only=True, allow_null=True, label=_('Completed Lines')
|
||||
)
|
||||
|
||||
# Human-readable status text (read-only)
|
||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||
|
||||
# status field cannot be set directly
|
||||
status = serializers.IntegerField(read_only=True, label=_('Order Status'))
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from icalendar import Calendar
|
|||
from rest_framework import status
|
||||
|
||||
from common.currency import currency_codes
|
||||
from common.models import InvenTreeSetting
|
||||
from common.models import InvenTreeCustomUserStateModel, InvenTreeSetting
|
||||
from common.settings import set_global_setting
|
||||
from company.models import Company, SupplierPart, SupplierPriceBreak
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
|
|
@ -737,6 +737,69 @@ class PurchaseOrderTest(OrderTest):
|
|||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_po_custom_status_query_count(self):
|
||||
"""Test that listing PurchaseOrders with custom statuses does not cause N+1 queries.
|
||||
|
||||
Ensures that resolving the 'status_text' field for custom status values
|
||||
is O(1) in database queries, not O(N) relative to the number of results.
|
||||
"""
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
po_content_type = ContentType.objects.get_for_model(models.PurchaseOrder)
|
||||
|
||||
# 10 custom status values - different keys, labels, and logical_keys
|
||||
logical_keys = [
|
||||
PurchaseOrderStatus.PENDING.value,
|
||||
PurchaseOrderStatus.PLACED.value,
|
||||
PurchaseOrderStatus.ON_HOLD.value,
|
||||
PurchaseOrderStatus.COMPLETE.value,
|
||||
PurchaseOrderStatus.CANCELLED.value,
|
||||
PurchaseOrderStatus.LOST.value,
|
||||
PurchaseOrderStatus.RETURNED.value,
|
||||
PurchaseOrderStatus.PENDING.value,
|
||||
PurchaseOrderStatus.PLACED.value,
|
||||
PurchaseOrderStatus.ON_HOLD.value,
|
||||
]
|
||||
|
||||
custom_statuses = [
|
||||
InvenTreeCustomUserStateModel.objects.create(
|
||||
key=1000 + i,
|
||||
name=f'PoCustomStatus{i}',
|
||||
label=f'PO Custom Status Label {i}',
|
||||
color='secondary',
|
||||
logical_key=logical_keys[i],
|
||||
model=po_content_type,
|
||||
reference_status='PurchaseOrderStatus',
|
||||
)
|
||||
for i in range(10)
|
||||
]
|
||||
|
||||
# Create 100 purchase orders, cycling through the custom statuses
|
||||
supplier = Company.objects.filter(is_supplier=True).first()
|
||||
models.PurchaseOrder.objects.bulk_create([
|
||||
models.PurchaseOrder(
|
||||
supplier=supplier,
|
||||
reference=f'PO-QTEST-{i}',
|
||||
status=custom_statuses[i % 10].logical_key,
|
||||
status_custom_key=custom_statuses[i % 10].key,
|
||||
)
|
||||
for i in range(100)
|
||||
])
|
||||
|
||||
# Query count must stay below the fixed threshold for all limit values.
|
||||
# An N+1 bug would push limit=50 or limit=100 well over the threshold.
|
||||
for limit in [1, 5, 10, 25, 50, 100]:
|
||||
response = self.get(
|
||||
self.LIST_URL,
|
||||
data={'limit': limit},
|
||||
expected_code=200,
|
||||
max_query_count=50,
|
||||
)
|
||||
|
||||
for result in response.data['results']:
|
||||
self.assertIn('status_text', result)
|
||||
self.assertIsNotNone(result['status_text'])
|
||||
|
||||
|
||||
class PurchaseOrderLineItemTest(OrderTest):
|
||||
"""Unit tests for PurchaseOrderLineItems."""
|
||||
|
|
@ -771,7 +834,7 @@ class PurchaseOrderLineItemTest(OrderTest):
|
|||
# Try to delete a set of line items via their IDs
|
||||
self.delete(url, {'items': [1, 2]}, expected_code=200)
|
||||
|
||||
# We should have 2 less PurchaseOrderLineItems after deletign them
|
||||
# We should have 2 less PurchaseOrderLineItems after deleting them
|
||||
self.assertEqual(models.PurchaseOrderLineItem.objects.count(), n - 2)
|
||||
|
||||
def test_po_line_merge_pricing(self):
|
||||
|
|
|
|||
|
|
@ -533,10 +533,23 @@ class BarcodePOReceive(BarcodeView):
|
|||
# Now, look just for "supplier-barcode" plugins
|
||||
plugins = registry.with_mixin(PluginMixinEnum.SUPPLIER_BARCODE)
|
||||
|
||||
plugin_slug = None
|
||||
|
||||
plugin_response = None
|
||||
|
||||
plugin_error = None
|
||||
|
||||
no_supplier_plugin_error = []
|
||||
|
||||
supplier_purchase_order = None
|
||||
|
||||
plugin_supplier = None
|
||||
|
||||
supplier_part = None
|
||||
|
||||
for current_plugin in plugins:
|
||||
try:
|
||||
# Will either Output Debugresponse if No_Match is True or return the regular response if No_Match is False
|
||||
result = current_plugin.scan_receive_item(
|
||||
barcode,
|
||||
request.user,
|
||||
|
|
@ -546,12 +559,58 @@ class BarcodePOReceive(BarcodeView):
|
|||
line_item=line_item,
|
||||
auto_allocate=auto_allocate,
|
||||
)
|
||||
|
||||
except Exception:
|
||||
log_error('BarcodePOReceive.handle_barcode', plugin=current_plugin.slug)
|
||||
continue
|
||||
|
||||
if result is None:
|
||||
continue
|
||||
no_match = result.get('no_match', True)
|
||||
|
||||
# No_Match Determines if it found a exact match for all the required fields from scan_recieve_item
|
||||
if no_match is True:
|
||||
supplier_found = False
|
||||
|
||||
try:
|
||||
plugin_slug = current_plugin.slug
|
||||
supplier_purchase_order = result.get('PO')
|
||||
plugin_supplier = result.get('supplier')
|
||||
supplier_part = result.get('supplier_part')
|
||||
except KeyError as e:
|
||||
log_error(
|
||||
f'BarcodePOReceive.handle_barcode debugresponse: KeyError {e}'
|
||||
)
|
||||
continue
|
||||
|
||||
# Supplier does not have associated Supplier ID
|
||||
if plugin_supplier is None:
|
||||
no_supplier_plugin_error.append(plugin_slug)
|
||||
continue
|
||||
|
||||
# No Purchase Order or Supplier Part Found
|
||||
if supplier_purchase_order is None and supplier_part is None:
|
||||
continue
|
||||
|
||||
# Purchase Order exists and is found but Supplier part does not exist
|
||||
if supplier_purchase_order != None and supplier_part is None:
|
||||
# Supplier was Found
|
||||
supplier_found = True
|
||||
plugin_error = _('Purchase order Found\rNo supplier Part Match')
|
||||
|
||||
# Supplier Part is Found but Purchase Order does not exist
|
||||
elif supplier_purchase_order is None and supplier_part != None:
|
||||
# Supplier was Found
|
||||
supplier_found = True
|
||||
plugin_error = _('Supplier Part Found\rNo Purchase Order Match')
|
||||
|
||||
# Supplier for PO or Supplier part in barcode was found
|
||||
if supplier_found is True:
|
||||
# Adds info on for what was found in the barcode
|
||||
response['supplier_matches'] = {
|
||||
'purchase_order': supplier_purchase_order,
|
||||
'no_match': no_match,
|
||||
'supplier': plugin_supplier,
|
||||
'supplier_part': supplier_part,
|
||||
}
|
||||
|
||||
if 'error' in result:
|
||||
logger.info(
|
||||
|
|
@ -569,13 +628,20 @@ class BarcodePOReceive(BarcodeView):
|
|||
|
||||
response['plugin'] = plugin.name if plugin else None
|
||||
|
||||
if plugin_response:
|
||||
# If there is a plugin response, and there is a match (no_match = false), combine the dictionaries
|
||||
if plugin_response and plugin_response.get('no_match') is False:
|
||||
response = {**response, **plugin_response}
|
||||
elif no_supplier_plugin_error:
|
||||
response['no_supplier_plugin_error'] = no_supplier_plugin_error
|
||||
|
||||
# A plugin has not been found!
|
||||
if plugin is None:
|
||||
response['error'] = _('No plugin match for supplier barcode')
|
||||
|
||||
# A plugin was found, with a Error
|
||||
elif plugin_error:
|
||||
response['error'] = plugin_error
|
||||
|
||||
self.log_scan(request, response, 'success' in response)
|
||||
|
||||
if 'error' in response:
|
||||
|
|
@ -787,11 +853,11 @@ class BarcodeScanResultList(BarcodeScanResultMixin, BulkDeleteMixin, ListAPI):
|
|||
filterset_class = BarcodeScanResultFilter
|
||||
filter_backends = SEARCH_ORDER_FILTER
|
||||
|
||||
ordering_fields = ['user', 'plugin', 'timestamp', 'endpoint', 'result']
|
||||
ordering_fields = ['user', 'timestamp', 'endpoint', 'result']
|
||||
|
||||
ordering = '-timestamp'
|
||||
|
||||
search_fields = ['plugin']
|
||||
search_fields = ['data']
|
||||
|
||||
|
||||
class BarcodeScanResultDetail(BarcodeScanResultMixin, RetrieveDestroyAPI):
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ class SupplierBarcodeMixin(BarcodeMixin):
|
|||
location=None,
|
||||
auto_allocate: bool = True,
|
||||
**kwargs,
|
||||
) -> dict | None:
|
||||
) -> dict:
|
||||
"""Attempt to receive an item against a PurchaseOrder via barcode scanning.
|
||||
|
||||
Arguments:
|
||||
|
|
@ -344,32 +344,50 @@ class SupplierBarcodeMixin(BarcodeMixin):
|
|||
# Extract supplier information
|
||||
supplier = supplier or self.get_supplier(cache=True)
|
||||
|
||||
if not supplier:
|
||||
"""Construct Debug Response
|
||||
This is returned if a perfect match is not found with the info provided from the barcode
|
||||
|
||||
Response Info:
|
||||
'supplier': get supplier ID
|
||||
'PO': Represented for "Purchase Order", find PO number to supplier
|
||||
'supplier_part': find supplier part info to supplier
|
||||
'no_match': Boolean, did we find a perfect match with info given? False is Yes, True is No
|
||||
"""
|
||||
debug_response = {}
|
||||
|
||||
if supplier is None:
|
||||
# No supplier information available
|
||||
return None
|
||||
debug_response['supplier'] = None
|
||||
else:
|
||||
debug_response['supplier'] = supplier.name
|
||||
|
||||
# Extract purchase order information
|
||||
purchase_order = purchase_order or self.get_purchase_order()
|
||||
|
||||
if not purchase_order or purchase_order.supplier != supplier:
|
||||
if purchase_order is None or purchase_order.supplier != supplier:
|
||||
# Purchase order does not match supplier
|
||||
return None
|
||||
debug_response['PO'] = None
|
||||
else:
|
||||
debug_response['PO'] = purchase_order.reference
|
||||
|
||||
supplier_part = self.get_supplier_part()
|
||||
|
||||
if not supplier_part:
|
||||
if supplier_part is None:
|
||||
# No supplier part information available
|
||||
return None
|
||||
debug_response['supplier_part'] = None
|
||||
else:
|
||||
debug_response['supplier_part'] = str(supplier_part.part)
|
||||
|
||||
# Attempt to find matching line item
|
||||
if not line_item:
|
||||
if not line_item and purchase_order != None:
|
||||
line_items = purchase_order.lines.filter(part=supplier_part)
|
||||
if line_items.count() == 1:
|
||||
line_item = line_items.first()
|
||||
|
||||
if not line_item:
|
||||
# No line item information available
|
||||
return None
|
||||
# If Purchase Order or Supplier Part does not exist, throw debug response
|
||||
if debug_response['PO'] is None or debug_response['supplier_part'] is None:
|
||||
debug_response['no_match'] = True
|
||||
return debug_response
|
||||
|
||||
if line_item.part != supplier_part:
|
||||
return {'error': _('Supplier part does not match line item')}
|
||||
|
|
@ -406,7 +424,8 @@ class SupplierBarcodeMixin(BarcodeMixin):
|
|||
'supplier_part': supplier_part.pk,
|
||||
'purchase_order': purchase_order.pk,
|
||||
'location': location.pk if location else None,
|
||||
}
|
||||
},
|
||||
'no_match': False,
|
||||
}
|
||||
|
||||
if action_required:
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ class AppMixin:
|
|||
"""
|
||||
from common.settings import get_global_setting
|
||||
|
||||
if settings.PLUGIN_TESTING or get_global_setting('ENABLE_PLUGINS_APP'):
|
||||
if settings.PLUGIN_TESTING or get_global_setting(
|
||||
'ENABLE_PLUGINS_APP', create=False
|
||||
):
|
||||
logger.info('Registering IntegrationPlugin apps')
|
||||
apps_changed = False
|
||||
|
||||
|
|
|
|||
|
|
@ -428,6 +428,95 @@ class SupplierBarcodePOReceiveTests(InvenTreeAPITestCase):
|
|||
# Quantity should be pre-filled with the remaining quantity
|
||||
self.assertEqual(5, response.data['lineitem']['quantity'])
|
||||
|
||||
def test_receive_includes_no_match_false(self):
|
||||
"""Successful receive merges no_match=False from the plugin response."""
|
||||
self.purchase_order1.place_order()
|
||||
url = reverse('api-barcode-po-receive')
|
||||
|
||||
result = self.post(url, data={'barcode': DIGIKEY_BARCODE}, expected_code=200)
|
||||
|
||||
self.assertIn('success', result.data)
|
||||
self.assertIn('no_match', result.data)
|
||||
self.assertFalse(result.data['no_match'])
|
||||
|
||||
def test_partial_match_po_found_no_supplier_part(self):
|
||||
"""Barcode references a known PO but the SKU has no matching supplier part."""
|
||||
url = reverse('api-barcode-po-receive')
|
||||
|
||||
# '1K72991337' matches purchase_order1 via supplier_reference; SKU is unknown
|
||||
result = self.post(
|
||||
url, data={'barcode': DIGIKEY_BARCODE_PO_NO_PART}, expected_code=400
|
||||
)
|
||||
|
||||
self.assertIn('error', result.data)
|
||||
self.assertIn('Purchase order Found', result.data['error'])
|
||||
self.assertIn('No supplier Part Match', result.data['error'])
|
||||
|
||||
self.assertIn('supplier_matches', result.data)
|
||||
matches = result.data['supplier_matches']
|
||||
self.assertIsNotNone(matches['purchase_order'])
|
||||
# DRF's ValidationError converts None leaves to ErrorDetail('None')
|
||||
self.assertEqual(str(matches['supplier_part']), 'None')
|
||||
self.assertIsNotNone(matches['supplier'])
|
||||
self.assertTrue(matches['no_match'])
|
||||
|
||||
def test_partial_match_supplier_part_found_no_po(self):
|
||||
"""Barcode references a known supplier part but the PO reference has no match."""
|
||||
url = reverse('api-barcode-po-receive')
|
||||
|
||||
# 'P296-LM358BIDDFRCT-ND' matches the existing supplier part; PO ref is unknown
|
||||
result = self.post(
|
||||
url, data={'barcode': DIGIKEY_BARCODE_PART_NO_PO}, expected_code=400
|
||||
)
|
||||
|
||||
self.assertIn('error', result.data)
|
||||
self.assertIn('Supplier Part Found', result.data['error'])
|
||||
self.assertIn('No Purchase Order Match', result.data['error'])
|
||||
|
||||
self.assertIn('supplier_matches', result.data)
|
||||
matches = result.data['supplier_matches']
|
||||
# DRF's ValidationError converts None leaves to ErrorDetail('None')
|
||||
self.assertEqual(str(matches['purchase_order']), 'None')
|
||||
self.assertIsNotNone(matches['supplier_part'])
|
||||
self.assertIsNotNone(matches['supplier'])
|
||||
self.assertTrue(matches['no_match'])
|
||||
|
||||
def test_no_supplier_plugin_error(self):
|
||||
"""Plugins that cannot resolve a supplier are listed in no_supplier_plugin_error."""
|
||||
url = reverse('api-barcode-po-receive')
|
||||
|
||||
digikey_plugin = registry.get_plugin('digikeyplugin')
|
||||
original_supplier_id = digikey_plugin.get_setting('SUPPLIER_ID')
|
||||
|
||||
# Use a non-existent PK so get_supplier() returns None
|
||||
digikey_plugin.set_setting('SUPPLIER_ID', 99999)
|
||||
if hasattr(digikey_plugin, '_supplier'):
|
||||
del digikey_plugin._supplier
|
||||
|
||||
try:
|
||||
result = self.post(
|
||||
url, data={'barcode': DIGIKEY_BARCODE}, expected_code=400
|
||||
)
|
||||
|
||||
self.assertIn('no_supplier_plugin_error', result.data)
|
||||
self.assertIn('digikeyplugin', result.data['no_supplier_plugin_error'])
|
||||
finally:
|
||||
digikey_plugin.set_setting('SUPPLIER_ID', original_supplier_id)
|
||||
if hasattr(digikey_plugin, '_supplier'):
|
||||
del digikey_plugin._supplier
|
||||
|
||||
def test_no_supplier_matches_when_both_missing(self):
|
||||
"""When neither PO nor supplier part can be resolved, no supplier_matches is set."""
|
||||
url = reverse('api-barcode-po-receive')
|
||||
|
||||
# Completely unknown barcode — no PO, no part, no supplier
|
||||
result = self.post(
|
||||
url, data={'barcode': 'COMPLETELY-UNKNOWN-BARCODE-XYZ'}, expected_code=400
|
||||
)
|
||||
|
||||
self.assertIn('error', result.data)
|
||||
self.assertNotIn('supplier_matches', result.data)
|
||||
|
||||
|
||||
DIGIKEY_BARCODE = (
|
||||
'[)>\x1e06\x1dP296-LM358BIDDFRCT-ND\x1d1PLM358BIDDFR\x1dK\x1d1K72991337\x1d'
|
||||
|
|
@ -476,3 +565,17 @@ TME_QRCODE = (
|
|||
)
|
||||
|
||||
TME_DATAMATRIX_CODE = 'PWBP-302 1PMPNWBP-302 Q1 K19361337/1'
|
||||
|
||||
# DigiKey barcode: '1K72991337' matches purchase_order1 via supplier_reference,
|
||||
# but 'PNONEXISTENT-SKU' has no matching supplier part in the test database.
|
||||
DIGIKEY_BARCODE_PO_NO_PART = (
|
||||
'[)>\x1e06\x1dPNONEXISTENT-SKU-XXXX\x1d1PNONEXISTENT-MPN\x1dK\x1d1K72991337\x1d'
|
||||
'10K85781337\x1d11K1\x1d4LPH\x1dQ10\x1d11ZPICK'
|
||||
)
|
||||
|
||||
# DigiKey barcode: 'P296-LM358BIDDFRCT-ND' matches the existing supplier part,
|
||||
# but '1KBADORDER-XXXXX' matches no purchase order in the test database.
|
||||
DIGIKEY_BARCODE_PART_NO_PO = (
|
||||
'[)>\x1e06\x1dP296-LM358BIDDFRCT-ND\x1d1PLM358BIDDFR\x1dK\x1d1KBADORDER-XXXXX\x1d'
|
||||
'10K85781337\x1d11K1\x1d4LPH\x1dQ10\x1d11ZPICK'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -77,12 +77,24 @@ class StockItemAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(StockItemTracking)
|
||||
class StockTrackingAdmin(admin.ModelAdmin):
|
||||
"""Admin class for StockTracking."""
|
||||
"""Admin class for StockTracking - read-only to preserve audit trail integrity."""
|
||||
|
||||
list_display = ('item', 'date', 'label')
|
||||
|
||||
autocomplete_fields = ['item']
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Prevent addition of new tracking entries via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
"""Prevent modification of tracking entries via the admin interface."""
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
"""Prevent deletion of tracking entries via the admin interface."""
|
||||
return False
|
||||
|
||||
|
||||
@admin.register(StockItemTestResult)
|
||||
class StockItemTestResultAdmin(admin.ModelAdmin):
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
|||
from importer.registry import register_importer
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
OptionalField,
|
||||
|
|
@ -308,6 +309,7 @@ class StockItemTestResultSerializer(
|
|||
|
||||
@register_importer()
|
||||
class StockItemSerializer(
|
||||
CustomStatusSerializerMixin,
|
||||
InvenTree.serializers.FilterableSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
InvenTreeCustomStatusSerializerMixin,
|
||||
|
|
@ -565,10 +567,6 @@ class StockItemSerializer(
|
|||
|
||||
return queryset
|
||||
|
||||
status_text = serializers.CharField(
|
||||
source='get_status_display', read_only=True, label=_('Status')
|
||||
)
|
||||
|
||||
SKU = serializers.CharField(
|
||||
source='supplier_part.SKU',
|
||||
read_only=True,
|
||||
|
|
|
|||
|
|
@ -1411,6 +1411,82 @@ class CustomStockItemStatusTest(StockAPITestCase):
|
|||
self.assertEqual(status['value'], self.status.key)
|
||||
self.assertEqual(status['display_name'], self.status.label)
|
||||
|
||||
def test_custom_status_query_count(self):
|
||||
"""Test that listing StockItems with custom statuses does not cause N+1 queries.
|
||||
|
||||
Ensures that resolving 'status_text' for custom status values is O(1)
|
||||
in database queries, not O(N) relative to the number of results.
|
||||
"""
|
||||
stock_content_type = ContentType.objects.get(model='stockitem')
|
||||
|
||||
# 10 custom status values - different keys, labels, and logical_keys
|
||||
logical_keys = [
|
||||
StockStatus.OK.value,
|
||||
StockStatus.ATTENTION.value,
|
||||
StockStatus.DAMAGED.value,
|
||||
StockStatus.DESTROYED.value,
|
||||
StockStatus.REJECTED.value,
|
||||
StockStatus.LOST.value,
|
||||
StockStatus.QUARANTINED.value,
|
||||
StockStatus.RETURNED.value,
|
||||
StockStatus.OK.value,
|
||||
StockStatus.ATTENTION.value,
|
||||
]
|
||||
|
||||
custom_statuses = [
|
||||
InvenTreeCustomUserStateModel.objects.create(
|
||||
key=2000 + i,
|
||||
name=f'StockCustomStatus{i}',
|
||||
label=f'Stock Custom Status Label {i}',
|
||||
color='secondary',
|
||||
logical_key=logical_keys[i],
|
||||
model=stock_content_type,
|
||||
reference_status='StockStatus',
|
||||
)
|
||||
for i in range(10)
|
||||
]
|
||||
|
||||
part = Part.objects.filter(active=True, virtual=False).first()
|
||||
|
||||
# Create 500 stock items, cycling through the 10 custom statuses
|
||||
StockItem.objects.bulk_create([
|
||||
StockItem(
|
||||
part=part,
|
||||
quantity=1,
|
||||
level=0,
|
||||
tree_id=0,
|
||||
lft=0,
|
||||
rght=0,
|
||||
status=custom_statuses[i % 10].logical_key,
|
||||
status_custom_key=custom_statuses[i % 10].key,
|
||||
)
|
||||
for i in range(500)
|
||||
])
|
||||
|
||||
# Lookup: custom_key -> custom_status_object, for quick per-row assertions
|
||||
custom_lookup = {cs.key: cs for cs in custom_statuses}
|
||||
|
||||
# Query count must stay below the fixed threshold regardless of limit.
|
||||
# An N+1 bug would push limit=100 or limit=500 well over the threshold.
|
||||
for limit in [50, 100, 500]:
|
||||
response = self.get(
|
||||
self.list_url,
|
||||
data={'limit': limit},
|
||||
expected_code=200,
|
||||
max_query_count=50,
|
||||
)
|
||||
|
||||
for result in response.data['results']:
|
||||
cs = custom_lookup.get(result['status_custom_key'])
|
||||
|
||||
if cs is None:
|
||||
# Item from fixtures - no custom status assigned
|
||||
continue
|
||||
|
||||
self.assertEqual(result['status'], cs.logical_key)
|
||||
self.assertEqual(result['status_custom_key'], cs.key)
|
||||
self.assertEqual(result['status_text'], cs.label)
|
||||
|
||||
|
||||
class StockItemTest(StockAPITestCase):
|
||||
"""Series of API tests for the StockItem API."""
|
||||
|
|
|
|||
|
|
@ -118,10 +118,8 @@ class InvenTreeGroupAdminForm(forms.ModelForm):
|
|||
class InvenTreeUserAdmin(UserAdmin):
|
||||
"""Custom admin page for the User model.
|
||||
|
||||
Hides the "permissions" view as this is now handled
|
||||
entirely by groups and RuleSets.
|
||||
|
||||
(And it's confusing!)
|
||||
- Restrict user creation and editing to superuser accounts
|
||||
- Hides the "permissions" view as this is handled by RuleSets
|
||||
"""
|
||||
|
||||
list_display = (
|
||||
|
|
@ -132,6 +130,7 @@ class InvenTreeUserAdmin(UserAdmin):
|
|||
'is_staff',
|
||||
'last_login',
|
||||
) # display last connection for each user in user admin panel.
|
||||
|
||||
fieldsets = (
|
||||
(None, {'fields': ('username', 'password')}),
|
||||
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
|
||||
|
|
@ -142,6 +141,15 @@ class InvenTreeUserAdmin(UserAdmin):
|
|||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||
)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
"""Make all fields read-only for non-superusers."""
|
||||
fields = super().get_readonly_fields(request, obj)
|
||||
|
||||
if not request.user.is_superuser:
|
||||
fields += ('is_staff', 'is_superuser')
|
||||
|
||||
return fields
|
||||
|
||||
|
||||
@admin.register(Owner)
|
||||
class OwnerAdmin(admin.ModelAdmin):
|
||||
|
|
|
|||
|
|
@ -95,22 +95,22 @@ bleach==4.1.0 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-markdownify
|
||||
blessed==1.39.0 \
|
||||
--hash=sha256:666e7e3fd0a4e38c3a262eaaf1e22a4ce2c81337aa17593c3f60ea136ec24fe1 \
|
||||
--hash=sha256:b04fc7141a20a3b2ade6cad741051f1e3ac59cc1e7e90915ed1f9e521332bea4
|
||||
blessed==1.42.0 \
|
||||
--hash=sha256:34b460b77562ed21f807cfd7c527b983b0cc300c98810c8076f283b7bcd45ba7 \
|
||||
--hash=sha256:f96c4a6dc664b48e0b832fa732acc16df67abd30f0ec35babf99025982f21852
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
boto3==1.43.8 \
|
||||
--hash=sha256:1894497c383e3cdf50e210f1f57a43e9f4047a5d3accc73ffdb7eacc3b0f011b \
|
||||
--hash=sha256:d1235602d715c727c1923ef4bcdb5612a20575a9a5e4f2db00d571e0ea1f85fc
|
||||
boto3==1.43.14 \
|
||||
--hash=sha256:574335744656cfed0b362a0a0467aaf2eb2bf15526edcd02d31d3c661f4b09e4 \
|
||||
--hash=sha256:5c0a994b3182061ee101812e721100717a4d664f9f4ceaf4a86b6d032ce9fc2d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-anymail
|
||||
# django-storages
|
||||
botocore==1.43.8 \
|
||||
--hash=sha256:611ad8b1f60661373cd39d9391ff16f1eaf8f5cb1d0a691563a4201d1a2603ce \
|
||||
--hash=sha256:6257d2655c3abe75eaa49e218b7d883cdc7cea64652b451e5feb08a6c169da3c
|
||||
botocore==1.43.14 \
|
||||
--hash=sha256:1f4a2a95ea78c10398e78431e98c1fe47adb54a7b10a32975144c1f541186658 \
|
||||
--hash=sha256:b9e500737e43d2f147c9d4e23b54360335e77d4c0ba90a318f51b65e06cb8516
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# boto3
|
||||
|
|
@ -219,9 +219,9 @@ brotli==1.2.0 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# fonttools
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
|
|
@ -762,49 +762,49 @@ drf-spectacular==0.29.0 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
dulwich==1.2.1 \
|
||||
--hash=sha256:011d37afa0922b500c938d6417317e3e6d29d33a6fbaf12b3696fe2a216aa170 \
|
||||
--hash=sha256:01f43a1b6953c93b4e957c0902f7de80267285e0c59c9b44f4801f7da9f11107 \
|
||||
--hash=sha256:04215befa00c82accda97d0e3ce760d9344a67f081d5b92ade8ad00007fb38d8 \
|
||||
--hash=sha256:09ca37d7a9086f96e535a6474644588e4502f69e2b202c39d92901e3606f6501 \
|
||||
--hash=sha256:0b1181f4ae225bbde373fc16279c4e61fdf04aedd30ec21fab387be642567453 \
|
||||
--hash=sha256:1073c75db1f5da845d219d1b5b601aeaaa7be5f999f3c77f4966f9ca2327bf44 \
|
||||
--hash=sha256:11a51dba8454b4c64bf242a918ca4c4300097f7cec84a13164845e638a26f9de \
|
||||
--hash=sha256:121d2d181407cd7bb051922dc3bc00841ca0959b8299880529525db93dfbdca9 \
|
||||
--hash=sha256:1961e0b6c0b1f2920f4ab05821652d8eb12f19ddb5a4c167c385902391c08dd3 \
|
||||
--hash=sha256:21f48480bb1e6501bdec7f0877639cdfc64a16e0dd97c24947582fbeed3baf21 \
|
||||
--hash=sha256:23560643c1cc85737c87985761666a59b35b06a1cbb06db5ba642fa35c67be93 \
|
||||
--hash=sha256:3183b7db09282842459fbeb37e77e498c8339e6db4d0cb6b5d3685c97ce79dac \
|
||||
--hash=sha256:3412eca24fd79d5413ac7003f8f29b2e01008d7c9d6fce159f77602f70058aea \
|
||||
--hash=sha256:3a95dd2649ef3c6e59095d5bd3de08470b3ba908dc41343f5823666a10a326f8 \
|
||||
--hash=sha256:4198f79ff04b07f6f6dc81047041f341b35e774cf0207f496b35f34dd2e1bb9c \
|
||||
--hash=sha256:41dfe1b1cb0f0202102e90f9f47f54458f27da6b746939a6ed85362b68e3e3a5 \
|
||||
--hash=sha256:4b6cd8104bf4adf2824221ba4f3b399c641a7a6a026dfa193c2f516531971315 \
|
||||
--hash=sha256:55c8415fb19068a5956e0d5bd83b0fb6e06b291d3b096d8fb6a604c105fc6ca0 \
|
||||
--hash=sha256:5a0245dccd69fba9dfe2ed88eff9212bad3e04107bc41676fffbc7f706428cdb \
|
||||
--hash=sha256:5e875729df04991732959f52e29c1de96d00eaf62feddfc60f0b2b08c6e38870 \
|
||||
--hash=sha256:6349b475a1b17b224191a4801687a2486574c9526e00835db2ba9ed081124b11 \
|
||||
--hash=sha256:674b21a9025c00a00495fa03a9bb5f2da67a13ee513c74f16bd91c56678d0a77 \
|
||||
--hash=sha256:74b01505b8e2ba81a715213101c790e0794f5c0b8021f8ce1100131a1e8cfa55 \
|
||||
--hash=sha256:879abd15550b6abcebf97823905a167623f331eeca5e12dc0cac62bcd9e70bcd \
|
||||
--hash=sha256:96846ef600378739a64e347412c22d5f87f1b67d68526c633b465589335e9387 \
|
||||
--hash=sha256:96c160d68173ae55f68bf734e7fddae04ea025f3541996b0b5f28dc2025b42dc \
|
||||
--hash=sha256:9d0ea88273a7ee6fd3b1d75e231cc6fc614774e19bdd7c1de5df274b4b492dde \
|
||||
--hash=sha256:9f7249c1090be7e7e841edda369d843617314092bb05f2a6a8b7f88660bbb2a6 \
|
||||
--hash=sha256:a65527eda5f6a463168c6338d781b05d325ba85dc05c6f8217ddd8454911bb53 \
|
||||
--hash=sha256:ba43bfb3a7cad40d9607170561e8c3be42e7083b4b57af89a5f54e01577ff791 \
|
||||
--hash=sha256:bad94416de9a76ad36dc19f0e65a829b89fc845282bdcc8c43285a4addc1ad2e \
|
||||
--hash=sha256:cedc717cf9ee973df63293bcbaa51bb03ab6f87ff631d1dd329078b3f48712a7 \
|
||||
--hash=sha256:cf3aa983ca4907c96a0b98b357a3cac7381192786495522a65944da1b284bc02 \
|
||||
--hash=sha256:d0ddda4e165ea14c70e1d0531aa97e527332f1133ea0c65eebaa5afb8786029e \
|
||||
--hash=sha256:da2fdcc9e4f178b2b4ec1194d8e17d111d572f111fdaa7c6c5a3f46bbe686eaf \
|
||||
--hash=sha256:e2f14d20aea48dd1d48714d637c70399b140825d930b4f5aa6fbb62199429740 \
|
||||
--hash=sha256:e45a68da922a4abe8fd015ed020ec0123ee58176a6984a34d2a2c74c959e45d3 \
|
||||
--hash=sha256:e88fd960a9327d87556a3bad76ad84b6346d3a07409fe8f081877a775977c86b \
|
||||
--hash=sha256:efd394fcb926ec8e9ed63fe0883784abf8ef7bb1d30a492e950ca8c2f369ce7b \
|
||||
--hash=sha256:f944b742962d9933e60863f577491743328b287251ae57a1e7cd84c289acfc23 \
|
||||
--hash=sha256:fb855620d04d0c286058db941c106cfc60bc1e4882ea20b6dd499f3668a1afbe \
|
||||
--hash=sha256:fd774825510350b614121bfa84d95c6eb08f7e93c0fe7faf8760423a43dbad8b
|
||||
dulwich==1.2.5 \
|
||||
--hash=sha256:00b54a1d56ddbacdd8eadd6d4787a51b3a05fefa30eadbf9165fd283a00b90ed \
|
||||
--hash=sha256:0395b2c8924c3424bafe2d9c1edd5348cc4b21ce9c1d6655bf01f9a5c47164c8 \
|
||||
--hash=sha256:07cb75b58216440e2c170fff4f3d55a5f387358d9489863af8cb11f24ee37121 \
|
||||
--hash=sha256:1679b376433a0fc7f36586afda1d4ed7427afa7a79d4bf17e5014474eea69fa4 \
|
||||
--hash=sha256:1699a4cf8d44c174408325a9594a1498d05786cea34e3004c8732420ee1b8182 \
|
||||
--hash=sha256:1ba83ec3cfb4c506c277400357a51523c8258fa07b841ee06e8e1071da4cfed1 \
|
||||
--hash=sha256:1c151a7f3995ccf9d433a603b747e76141a7ebe7c385c8909e9f7e7a6422c28f \
|
||||
--hash=sha256:2f10dafa1ef5660b1331364bc8d68446448608a8d8f493ed0e260eaf5133e71c \
|
||||
--hash=sha256:2f90d68bfa97c4ca71de7507984365aefe27b6d248cb28dc99644d0f3ae8c60b \
|
||||
--hash=sha256:41ccffb0521f3f9ad73fac78772f321d731607336cee48911e7c26963459481c \
|
||||
--hash=sha256:46db47394ba8a95748ae739f5d3a5a3e1724a2f857bf2437bc71bfc0baaed91d \
|
||||
--hash=sha256:5108acead814d1de8b6262d6d8fb90af7e82f5a4d83788b6b48e39d01800a92f \
|
||||
--hash=sha256:517fb7e20f91d2bd48dc5de9edc90ff8974a5512ce7f243284b191f8be6344c3 \
|
||||
--hash=sha256:53599909d54a2fae49fcd50047f1daf4b8b9eda6a5500a08b71da689f5431c24 \
|
||||
--hash=sha256:556593fd11637f80f6018bee1916b1a84f5b420423b470ebb3f1a782ad6ef081 \
|
||||
--hash=sha256:5e067b7feceb7034bc99e7c7143a704f1d97d4be7027d9a0aa5a83c0657ff091 \
|
||||
--hash=sha256:66aded7d364341b55941973a1562323f25bd205f0809692b687ec36ccd31242c \
|
||||
--hash=sha256:6c683c0f4a062894b6826c61102d415dae86ade61a10003c82ccc2b91858d5fb \
|
||||
--hash=sha256:701a9ecf7a8a44f5e2459e46befa93530cf36a8b1ae3140aefc007db1d7d0207 \
|
||||
--hash=sha256:77d2d2e43ad975459491de1ebf47990c74ff17f12586c8561e9890239bc422db \
|
||||
--hash=sha256:827366331603150de5976d72dd456a3fd5fc91e856471dc1d10fd64758c05f02 \
|
||||
--hash=sha256:8929134acf4ff967203df7600b38535f9b5b590462067a7e30dbce01acb97af9 \
|
||||
--hash=sha256:8e55f36a7f52ba0976dd72100273523908b16fb9dda6ce96d9aa9df9cceed4cc \
|
||||
--hash=sha256:9008ef25cabd379cda4fa86000fc38ca14b72afe17db798a8c85c0b2b7ce4d1e \
|
||||
--hash=sha256:93d2d87acf75d60c5a2b8c5c8a45aff17bbbd00c17bdccb4ba013d3ab590a65f \
|
||||
--hash=sha256:9693d2c9e226b2ea855c1dc3a87e2f4d972f7523fc0f7924e5997e9f4c23d97f \
|
||||
--hash=sha256:9b6d234f1f91335e9f01d9daac42ddc2d2e5c2fdbe285d8eeef50353b283648a \
|
||||
--hash=sha256:9f3c98f5fa90a842c1f545463834f712aa2eed785fc3d5e42836c0df2d691bb6 \
|
||||
--hash=sha256:9fc113c1348c7eb22c4e8790f68b562bb4f42a721fafb813e89a57e9cd632040 \
|
||||
--hash=sha256:a5549f4afc973e0a15ea6b0244d57f848d3f3ee13dac557eb311024aebebf128 \
|
||||
--hash=sha256:a6620963196c49212c511cd909f367dacf771f199a27d116f357cc671ea956c7 \
|
||||
--hash=sha256:a70477c991e96cfe8fdd7c866e7251faf71b38bfeb51d6f27554c9cce1caabf3 \
|
||||
--hash=sha256:ade416833214f3ee13af9b0199fff4de00fa6e0fde3deced776532fd91df5515 \
|
||||
--hash=sha256:c65230abaa52c72093b70d3b499d5689d1d8f9627e88ad3c3b4f8154e86ac0c8 \
|
||||
--hash=sha256:ccc58f26a1b94bef255316311678b03854f7192069bdf11cf501a6c85f61b83c \
|
||||
--hash=sha256:d33bae2b3292ed0235522682316251658187f43b1ebad6cd2b127069b94afb3b \
|
||||
--hash=sha256:d46e35c473646efb3b2ff8032f37ac5b6d48da52a669577187d3796a6d5987a3 \
|
||||
--hash=sha256:d8f7ea8f47e38e5b0de3fab97e07e9c9161ffddc90b3964512cab2b7749df4e6 \
|
||||
--hash=sha256:dd9569bc26174a3437d749114d36c81fc6c7478b55370ae50125e34e9629e4fe \
|
||||
--hash=sha256:df4ac3746099562c8160d78d55bb2fa10c9ada7ef970af3e2536bd133cb7830e \
|
||||
--hash=sha256:e128cddeccae4146b556684a0d5426454fff5bfe7306862e5a8ce6b471568af4 \
|
||||
--hash=sha256:fa37da7ad16c47391016b5f984fb60e175e1ab0b478f04920fd6d1f61123ce4d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
|
|
@ -971,25 +971,19 @@ gunicorn==26.0.0 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
icalendar==7.1.0 \
|
||||
--hash=sha256:10cd223c792fcc43bee4c3ebe3149d4cf32406c85cfef146624df5a0d414260f \
|
||||
--hash=sha256:6de875370d22fc4aff172ad7c439b39fb109dc2eab9ce358fcb95e8689ad7b56
|
||||
icalendar==7.1.2 \
|
||||
--hash=sha256:01c76243c76c549f58bb51510a8f0a4edb7c539726adda1356dfd0dc04fb7a53 \
|
||||
--hash=sha256:ebc43ebeb357be98984b573d975118008dee3410d8df28b054ef2943cf3e367e
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-ical
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-anymail
|
||||
# requests
|
||||
importlib-metadata==8.7.1 \
|
||||
--hash=sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb \
|
||||
--hash=sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-api
|
||||
inflection==0.5.1 \
|
||||
--hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \
|
||||
--hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
|
||||
|
|
@ -1014,6 +1008,12 @@ jinja2==3.1.6 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
jinxed==2.0.4 \
|
||||
--hash=sha256:58ae0a4a2930b51e9de162208c356b382f5e25b3bc0ad73e2013b02a62d84e8b \
|
||||
--hash=sha256:a92ac48923433c0a88577bb0479191788813fd5055ef17ff2b04a701a1b83f19
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# blessed
|
||||
jmespath==1.1.0 \
|
||||
--hash=sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d \
|
||||
--hash=sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64
|
||||
|
|
@ -1039,141 +1039,141 @@ jwcrypto==1.5.7 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-oauth-toolkit
|
||||
lxml==6.1.0 \
|
||||
--hash=sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2 \
|
||||
--hash=sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773 \
|
||||
--hash=sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7 \
|
||||
--hash=sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad \
|
||||
--hash=sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635 \
|
||||
--hash=sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286 \
|
||||
--hash=sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9 \
|
||||
--hash=sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54 \
|
||||
--hash=sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c \
|
||||
--hash=sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618 \
|
||||
--hash=sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7 \
|
||||
--hash=sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39 \
|
||||
--hash=sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69 \
|
||||
--hash=sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551 \
|
||||
--hash=sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc \
|
||||
--hash=sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd \
|
||||
--hash=sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd \
|
||||
--hash=sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405 \
|
||||
--hash=sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289 \
|
||||
--hash=sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b \
|
||||
--hash=sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a \
|
||||
--hash=sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d \
|
||||
--hash=sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd \
|
||||
--hash=sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac \
|
||||
--hash=sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62 \
|
||||
--hash=sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad \
|
||||
--hash=sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f \
|
||||
--hash=sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad \
|
||||
--hash=sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c \
|
||||
--hash=sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292 \
|
||||
--hash=sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544 \
|
||||
--hash=sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491 \
|
||||
--hash=sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120 \
|
||||
--hash=sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512 \
|
||||
--hash=sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb \
|
||||
--hash=sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32 \
|
||||
--hash=sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2 \
|
||||
--hash=sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec \
|
||||
--hash=sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88 \
|
||||
--hash=sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43 \
|
||||
--hash=sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037 \
|
||||
--hash=sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13 \
|
||||
--hash=sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03 \
|
||||
--hash=sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64 \
|
||||
--hash=sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485 \
|
||||
--hash=sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16 \
|
||||
--hash=sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb \
|
||||
--hash=sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9 \
|
||||
--hash=sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8 \
|
||||
--hash=sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39 \
|
||||
--hash=sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842 \
|
||||
--hash=sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f \
|
||||
--hash=sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105 \
|
||||
--hash=sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c \
|
||||
--hash=sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7 \
|
||||
--hash=sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6 \
|
||||
--hash=sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5 \
|
||||
--hash=sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d \
|
||||
--hash=sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9 \
|
||||
--hash=sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d \
|
||||
--hash=sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb \
|
||||
--hash=sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f \
|
||||
--hash=sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755 \
|
||||
--hash=sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb \
|
||||
--hash=sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280 \
|
||||
--hash=sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace \
|
||||
--hash=sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e \
|
||||
--hash=sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33 \
|
||||
--hash=sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5 \
|
||||
--hash=sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2 \
|
||||
--hash=sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3 \
|
||||
--hash=sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585 \
|
||||
--hash=sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce \
|
||||
--hash=sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946 \
|
||||
--hash=sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e \
|
||||
--hash=sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a \
|
||||
--hash=sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7 \
|
||||
--hash=sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5 \
|
||||
--hash=sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28 \
|
||||
--hash=sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4 \
|
||||
--hash=sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c \
|
||||
--hash=sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50 \
|
||||
--hash=sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9 \
|
||||
--hash=sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495 \
|
||||
--hash=sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16 \
|
||||
--hash=sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45 \
|
||||
--hash=sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919 \
|
||||
--hash=sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4 \
|
||||
--hash=sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc \
|
||||
--hash=sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec \
|
||||
--hash=sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd \
|
||||
--hash=sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8 \
|
||||
--hash=sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f \
|
||||
--hash=sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940 \
|
||||
--hash=sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72 \
|
||||
--hash=sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366 \
|
||||
--hash=sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814 \
|
||||
--hash=sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690 \
|
||||
--hash=sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13 \
|
||||
--hash=sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a \
|
||||
--hash=sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819 \
|
||||
--hash=sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c \
|
||||
--hash=sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86 \
|
||||
--hash=sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317 \
|
||||
--hash=sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180 \
|
||||
--hash=sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383 \
|
||||
--hash=sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee \
|
||||
--hash=sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe \
|
||||
--hash=sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181 \
|
||||
--hash=sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9 \
|
||||
--hash=sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e \
|
||||
--hash=sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd \
|
||||
--hash=sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3 \
|
||||
--hash=sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d \
|
||||
--hash=sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad \
|
||||
--hash=sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea \
|
||||
--hash=sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24 \
|
||||
--hash=sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d \
|
||||
--hash=sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de \
|
||||
--hash=sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1 \
|
||||
--hash=sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d \
|
||||
--hash=sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11 \
|
||||
--hash=sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9 \
|
||||
--hash=sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2 \
|
||||
--hash=sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776 \
|
||||
--hash=sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f \
|
||||
--hash=sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93 \
|
||||
--hash=sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a \
|
||||
--hash=sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5 \
|
||||
--hash=sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d \
|
||||
--hash=sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d \
|
||||
--hash=sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3 \
|
||||
--hash=sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086 \
|
||||
--hash=sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215
|
||||
lxml==6.1.1 \
|
||||
--hash=sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2 \
|
||||
--hash=sha256:07a4a68e286ee7a1ed7dfb8af83e615757c0ccfe9f18c6b4ea6771388d9ba8c9 \
|
||||
--hash=sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60 \
|
||||
--hash=sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c \
|
||||
--hash=sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7 \
|
||||
--hash=sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a \
|
||||
--hash=sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83 \
|
||||
--hash=sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072 \
|
||||
--hash=sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8 \
|
||||
--hash=sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462 \
|
||||
--hash=sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0 \
|
||||
--hash=sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085 \
|
||||
--hash=sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f \
|
||||
--hash=sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30 \
|
||||
--hash=sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1 \
|
||||
--hash=sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77 \
|
||||
--hash=sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740 \
|
||||
--hash=sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b \
|
||||
--hash=sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c \
|
||||
--hash=sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621 \
|
||||
--hash=sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e \
|
||||
--hash=sha256:32ab449a5486f6c758e849bb86710d0e45edc24a04e250c01555f8f5653958f8 \
|
||||
--hash=sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca \
|
||||
--hash=sha256:34c2d737beabfe35baada43941ed519251e9a12e779031496bcd5d539fcfd730 \
|
||||
--hash=sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245 \
|
||||
--hash=sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1 \
|
||||
--hash=sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004 \
|
||||
--hash=sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d \
|
||||
--hash=sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52 \
|
||||
--hash=sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5 \
|
||||
--hash=sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf \
|
||||
--hash=sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc \
|
||||
--hash=sha256:441dd227fa0690eb9fc81edabc63cdcefc212bba99b906dcf6e32cc1a9d3e533 \
|
||||
--hash=sha256:469e3618338bd7ab5beb412d2439825479fcf0dab99e394ca563dbc4eaf6c834 \
|
||||
--hash=sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947 \
|
||||
--hash=sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a \
|
||||
--hash=sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2 \
|
||||
--hash=sha256:53c909b62a0532183542fed00c5a7218258c56292d409bc789886fe1cb04c438 \
|
||||
--hash=sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc \
|
||||
--hash=sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea \
|
||||
--hash=sha256:55b03549819867ea141c0202242c4816c82e52ec36e7e648db9d8da5a3dc3ed6 \
|
||||
--hash=sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e \
|
||||
--hash=sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c \
|
||||
--hash=sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383 \
|
||||
--hash=sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955 \
|
||||
--hash=sha256:5bec7d03d78d853597d6107854c2310ce3f761fd218fe9fe91d5101fcf6c2efe \
|
||||
--hash=sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074 \
|
||||
--hash=sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c \
|
||||
--hash=sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a \
|
||||
--hash=sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb \
|
||||
--hash=sha256:639f6c857d91d9be29bd7502348d6736dab168b54b5158cd899abf11684dc186 \
|
||||
--hash=sha256:640f97d43d867bcb9c75b3af013b64850756b746cb6bce8ace83b70da3abba9d \
|
||||
--hash=sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1 \
|
||||
--hash=sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f \
|
||||
--hash=sha256:6689e828a94eee4f139408c337bb198e014724bb8a8c26d3cfac49d119ed69a6 \
|
||||
--hash=sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736 \
|
||||
--hash=sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6 \
|
||||
--hash=sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2 \
|
||||
--hash=sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b \
|
||||
--hash=sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7 \
|
||||
--hash=sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14 \
|
||||
--hash=sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009 \
|
||||
--hash=sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca \
|
||||
--hash=sha256:76447f65250ed2501ead1a1552f5ce8edff159a86f308348e6a9c4acb5e1f1b4 \
|
||||
--hash=sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635 \
|
||||
--hash=sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee \
|
||||
--hash=sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e \
|
||||
--hash=sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9 \
|
||||
--hash=sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603 \
|
||||
--hash=sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08 \
|
||||
--hash=sha256:83b6b30eb131da7a75b601f28c5d6971e6ed3e887919bf6b6a1ad3c2df289080 \
|
||||
--hash=sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525 \
|
||||
--hash=sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5 \
|
||||
--hash=sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f \
|
||||
--hash=sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067 \
|
||||
--hash=sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e \
|
||||
--hash=sha256:8be8ad51249698103d24b0571df35a10990fbe93dd043b6c024172189485f5e3 \
|
||||
--hash=sha256:8d43ca737b20e106e4aebc42b2f3ae19f00ba63d7eb731698ee083d72d15646f \
|
||||
--hash=sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485 \
|
||||
--hash=sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13 \
|
||||
--hash=sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383 \
|
||||
--hash=sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315 \
|
||||
--hash=sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e \
|
||||
--hash=sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c \
|
||||
--hash=sha256:9f76acfb5f68ba982635a53fd985a8044be98a35b43232c2a1ee235ffab3e1dd \
|
||||
--hash=sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099 \
|
||||
--hash=sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660 \
|
||||
--hash=sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510 \
|
||||
--hash=sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a \
|
||||
--hash=sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b \
|
||||
--hash=sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5 \
|
||||
--hash=sha256:aae97dfdb60715c164419ac2532a76d013c3918a665eb6cb7288098b5f349aaf \
|
||||
--hash=sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28 \
|
||||
--hash=sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00 \
|
||||
--hash=sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef \
|
||||
--hash=sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1 \
|
||||
--hash=sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955 \
|
||||
--hash=sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590 \
|
||||
--hash=sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137 \
|
||||
--hash=sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf \
|
||||
--hash=sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40 \
|
||||
--hash=sha256:bdebcc8a75d38c7598dfb2c9ed852d7a9eb4a10d6e2d0764b919b802bf32ac88 \
|
||||
--hash=sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e \
|
||||
--hash=sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840 \
|
||||
--hash=sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2 \
|
||||
--hash=sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca \
|
||||
--hash=sha256:c674693f055fa2495de12292cb45e9944199d8eaef5a2dec45175c7c61cb73e3 \
|
||||
--hash=sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465 \
|
||||
--hash=sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc \
|
||||
--hash=sha256:c9a4b821dc7055bf9e05ff5719e18ec501f75c0f0bbfabd573b277559780833d \
|
||||
--hash=sha256:c9f79d5325907f13e1be0b3e4dacc1049d1dffc4aeee3c995284bea5fe0fab7d \
|
||||
--hash=sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa \
|
||||
--hash=sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a \
|
||||
--hash=sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a \
|
||||
--hash=sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206 \
|
||||
--hash=sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e \
|
||||
--hash=sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785 \
|
||||
--hash=sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8 \
|
||||
--hash=sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a \
|
||||
--hash=sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b \
|
||||
--hash=sha256:e07c65f443c887bbcf31cc1771d932ecc192a5273943589b3c7572b749f1ffb2 \
|
||||
--hash=sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6 \
|
||||
--hash=sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6 \
|
||||
--hash=sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354 \
|
||||
--hash=sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818 \
|
||||
--hash=sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84 \
|
||||
--hash=sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909 \
|
||||
--hash=sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038 \
|
||||
--hash=sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d \
|
||||
--hash=sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2 \
|
||||
--hash=sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf \
|
||||
--hash=sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc \
|
||||
--hash=sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d \
|
||||
--hash=sha256:ffecec8eb889b58ba9be5b95fb1cc78e22ea8eedea38e8736a1568fe1979250e
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# python3-saml
|
||||
|
|
@ -1321,9 +1321,9 @@ openpyxl==3.1.5 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# tablib
|
||||
opentelemetry-api==1.41.1 \
|
||||
--hash=sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621 \
|
||||
--hash=sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f
|
||||
opentelemetry-api==1.42.1 \
|
||||
--hash=sha256:51a69edacadbc03a8950ace1c4c21099cacc538820ac2c9e36277e78cebba714 \
|
||||
--hash=sha256:56c63bea9f77b62856be8c47600474acad853b2924b99b1687c4cb6297166716
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
|
|
@ -1341,34 +1341,34 @@ opentelemetry-api==1.41.1 \
|
|||
# opentelemetry-instrumentation-wsgi
|
||||
# opentelemetry-sdk
|
||||
# opentelemetry-semantic-conventions
|
||||
opentelemetry-exporter-otlp==1.41.1 \
|
||||
--hash=sha256:299a2f0541ca175df186f5ac58fd5db177ba1e9b72b0826049062f750d55b47f \
|
||||
--hash=sha256:db276c5a80c02b063994e80950d00ca1bfddcf6520f608335b7dc2db0c0eb9c6
|
||||
opentelemetry-exporter-otlp==1.42.1 \
|
||||
--hash=sha256:2d9ebaed714377a67d224d46795ddcc11d2c877fa5de35fda70b6f3b010729a9 \
|
||||
--hash=sha256:aedd54545bb0587cd45210abdc8be545af9c01413f3307786e276df1e3c83bee
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-exporter-otlp-proto-common==1.41.1 \
|
||||
--hash=sha256:0e253156ea9c36b0bd3d2440c5c9ba7dd1f3fb64ba7a08fc85fbac536b56e1fb \
|
||||
--hash=sha256:10da74dad6a49344b9b7b21b6182e3060373a235fde1528616d5f01f92e66aa9
|
||||
opentelemetry-exporter-otlp-proto-common==1.42.1 \
|
||||
--hash=sha256:04f1f01fb597c4249dfcd7f8b861c902c2102369d376d9d346ff38de4469a2ee \
|
||||
--hash=sha256:f48d395ab815b444da118868977e9798ea354c25737d5cf39578ae894011c140
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-exporter-otlp-proto-grpc==1.41.1 \
|
||||
--hash=sha256:537926dcef951136992479af1d9cd88f25e33d56c530e9f020ed57774dca2f94 \
|
||||
--hash=sha256:b05df8fa1333dc9a3fda36b676b96b5095ab6016d3f0c3296d430d629ba1443b
|
||||
opentelemetry-exporter-otlp-proto-grpc==1.42.1 \
|
||||
--hash=sha256:0ae1177e2038b18a929b3098215243631ef91136cba26b7e2b12790ceb7e87cc \
|
||||
--hash=sha256:975c4461f167dd8ed8857d68d3b6b25f3d272eab896f6a9470d0f5b90e2faf15
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-exporter-otlp
|
||||
opentelemetry-exporter-otlp-proto-http==1.41.1 \
|
||||
--hash=sha256:1a21e8f49c7a946d935551e90947d6c3eb39236723c6624401da0f33d68edcb4 \
|
||||
--hash=sha256:4747a9604c8550ab38c6fd6180e2fcb80de3267060bef2c306bad3cb443302bc
|
||||
opentelemetry-exporter-otlp-proto-http==1.42.1 \
|
||||
--hash=sha256:00a16da1b312a1d6c7233d600d557c91df71125af73020f3b9a7765bd699d59d \
|
||||
--hash=sha256:bf142a21035d7571ac3a09cb2e5639f49886f243972883cfe777ed3bf02b734d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-exporter-otlp
|
||||
opentelemetry-instrumentation==0.62b1 \
|
||||
--hash=sha256:90e92a905ba4f84db06ac3aec96701df6c079b2d66e9379f8739f0a1bdcc7f45 \
|
||||
--hash=sha256:976fc6e640f2006599e97429c949e622c108d0c17c2059347d1e6c93c707f257
|
||||
opentelemetry-instrumentation==0.63b1 \
|
||||
--hash=sha256:32368d6ae52c8de20aa790a6ad86b10a76f09956092337ae37d675773990e541 \
|
||||
--hash=sha256:f1986716d52cc316ea5f60189098726a9071d8ecc0eee96c9ed110be08bade9c
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-instrumentation-dbapi
|
||||
|
|
@ -1380,82 +1380,82 @@ opentelemetry-instrumentation==0.62b1 \
|
|||
# opentelemetry-instrumentation-sqlite3
|
||||
# opentelemetry-instrumentation-system-metrics
|
||||
# opentelemetry-instrumentation-wsgi
|
||||
opentelemetry-instrumentation-dbapi==0.62b1 \
|
||||
--hash=sha256:82755a0f013980b2c000a10452fb91ab5135b937a8afe37c45f34e62ecc7a2b8 \
|
||||
--hash=sha256:dd2cc4085e832a708835218833b839a88ef0ace66851d14debefe6b2ef363a3c
|
||||
opentelemetry-instrumentation-dbapi==0.63b1 \
|
||||
--hash=sha256:1bc842ddcacb7ec3622ef306ffdb3c584bf97df79d381e03604ea6eb23c63781 \
|
||||
--hash=sha256:406978ed56bcfc5fd246fd918e6b36d0f5de26fa396c78cf63326a7b530597c8
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-instrumentation-psycopg
|
||||
# opentelemetry-instrumentation-pymysql
|
||||
# opentelemetry-instrumentation-sqlite3
|
||||
opentelemetry-instrumentation-django==0.62b1 \
|
||||
--hash=sha256:268c9b3d234510ab835acea0524ba65361389f6e2c291b495ba8072c7bb59003 \
|
||||
--hash=sha256:5ac96ef25019fbea5e2739c9b4b7ce17e4379e2b1ec9fdce6b696a5c09ceabbe
|
||||
opentelemetry-instrumentation-django==0.63b1 \
|
||||
--hash=sha256:909ea4afbb18f16eb811d7ac330ed0f6fda7765191d49bccb8cca38c4fbc005f \
|
||||
--hash=sha256:f2071d2f92e4779c5a14dd452b0dfe426343599e6efa9d888304fb639a9f3101
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-psycopg==0.62b1 \
|
||||
--hash=sha256:61c8a1794d6e11c7bca1735c2b87ef8c04b5d7202e962409d66d204f84c01be1 \
|
||||
--hash=sha256:f08e843e81656271ddc8c8194a54a5f3c8ebe0cb137e3166af9a2ff014978b5e
|
||||
opentelemetry-instrumentation-psycopg==0.63b1 \
|
||||
--hash=sha256:4d74ec2dda8e54ead9bd71f134af984792f77e1d8809591ae53edadddd4c8fc0 \
|
||||
--hash=sha256:86819f4cccea21a47920807826495797b7261cc1893c8e855415e76fb7b8e2e8
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-pymysql==0.62b1 \
|
||||
--hash=sha256:12e42f891978a3a41bc564bb81e2299d3654659589f705064a4bb10e93e493f8 \
|
||||
--hash=sha256:50d2efdde1bd8d826cbceffe5b3ce0ffd421349d609200eab0f3e632945cd304
|
||||
opentelemetry-instrumentation-pymysql==0.63b1 \
|
||||
--hash=sha256:2cf6a24e136b5b0c3f6e59675fc44b42ad2b97474b075a82859f9868a9252648 \
|
||||
--hash=sha256:6b54b83c86ac6c2e8dae642bbee4894e2283ceb5da23d571f1abb7060f7b62f4
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-redis==0.62b1 \
|
||||
--hash=sha256:2d3c421d95e05ade075bee5becbe34e743b1cdf5bdee2085cb524f88c4f13dcb \
|
||||
--hash=sha256:9aedd02c1acf631251d1d676634db47da9da04e0a626cd0c7d83fe0eb791d165
|
||||
opentelemetry-instrumentation-redis==0.63b1 \
|
||||
--hash=sha256:28d235159df43cc2bc8779af5c602afad1e08603fff75ac8ca34dd1bf30a9cb9 \
|
||||
--hash=sha256:f0e51c4006f68e340abbf28a7995feff004de78649697cbdf3bac0072cacd082
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-requests==0.62b1 \
|
||||
--hash=sha256:67a79c4b67e2192445c1cf03d62126fa623065688d8bd1a9f87f858b0e5f0286 \
|
||||
--hash=sha256:ca348f2f51b715c21e86d82106d784f7069ae849c3e636ab37e34dc0ba510b8c
|
||||
opentelemetry-instrumentation-requests==0.63b1 \
|
||||
--hash=sha256:513fcaa3d93debbdb359c00ce1a137a34a89ee908c51ac43beb7e8c18ac2b3cd \
|
||||
--hash=sha256:935c980a11e33bfd7ed969c741e4bd7c84077045651469f10e163534368d87f7
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-sqlite3==0.62b1 \
|
||||
--hash=sha256:14ba18aed35a01e1d89bb814e49f7d6dd90bb68b2034ccf047801ca4659dba27 \
|
||||
--hash=sha256:3ab0d614bab9956126ce81a22315bf58d56d653a65675a66e8b525f880ec3016
|
||||
opentelemetry-instrumentation-sqlite3==0.63b1 \
|
||||
--hash=sha256:3d61afda8358dc32135fabd27e5934bd25ea0eed68d64c34508f24ba8d723efc \
|
||||
--hash=sha256:cc11c68cccde061dc8bcc5f80fe00bb0105a0fbb11b390859a23ca91ccd4e3b6
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-system-metrics==0.62b1 \
|
||||
--hash=sha256:260130cb63e3028290305d8f25b744fb3a279677769dd65287ce60086cc11d32 \
|
||||
--hash=sha256:b8097e0d3747102fa545723bb67f50f572a7618b6479359fa6533007d2f621aa
|
||||
opentelemetry-instrumentation-system-metrics==0.63b1 \
|
||||
--hash=sha256:995051f47876d79461aed8b7aa205d4584d90794ef864342cc748929c389bb42 \
|
||||
--hash=sha256:d6d4d7a1a854be4165143cf6420ee5894188762eb367d7bf9da5be4a83a4b632
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-wsgi==0.62b1 \
|
||||
--hash=sha256:02a364fd9c940a46b19c825c5bfe386b007d5292ef91573894164836953fe831 \
|
||||
--hash=sha256:a2df11de0113f504043e2b0fa0288238a93ee49ff607bd5100cb2d3a75bc771f
|
||||
opentelemetry-instrumentation-wsgi==0.63b1 \
|
||||
--hash=sha256:03d61c4678ce82402e7f37b6a3dbd84cb97b85b3cb416a78c2e74c7c6d9451fa \
|
||||
--hash=sha256:86779715262227d3436bdfb16aabd1c524b0f236725a69e8754ceda76c6d79dc
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
# opentelemetry-instrumentation-django
|
||||
opentelemetry-proto==1.41.1 \
|
||||
--hash=sha256:0496713b804d127a4147e32849fbaf5683fac8ee98550e8e7679cd706c289720 \
|
||||
--hash=sha256:4b9d2eb631237ea43b80e16c073af438554e32bc7e9e3f8ca4a9582f900020e5
|
||||
opentelemetry-proto==1.42.1 \
|
||||
--hash=sha256:c6a51e6b4f05ae63565f3a113217f3d2bfaec68f78c02d7a6c85f9010d1cfca6 \
|
||||
--hash=sha256:dedb74cba2886c59c7789b227a7a670613025a07489040050aedff6e5c0fb43c
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-exporter-otlp-proto-common
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-sdk==1.41.1 \
|
||||
--hash=sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6 \
|
||||
--hash=sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d
|
||||
opentelemetry-sdk==1.42.1 \
|
||||
--hash=sha256:083cd4bbfaa5aa7b5a9e552430d9951219967cfb27aa61feb13a77aba1fc839d \
|
||||
--hash=sha256:8c834e8f8c9ba4171d4ec843d0cb8a67e4c7394d3f9e9297e582cbd9456ddbf7
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-semantic-conventions==0.62b1 \
|
||||
--hash=sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802 \
|
||||
--hash=sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c
|
||||
opentelemetry-semantic-conventions==0.63b1 \
|
||||
--hash=sha256:3daf963611334b365e98a57438183eb012d3bfb40b2d931a9af613476b8701a9 \
|
||||
--hash=sha256:dfe5ef4dee82586b746f522b818ceb298d00b3d59f660042bd79404bff8d0682
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-instrumentation
|
||||
|
|
@ -1463,11 +1463,12 @@ opentelemetry-semantic-conventions==0.62b1 \
|
|||
# opentelemetry-instrumentation-django
|
||||
# opentelemetry-instrumentation-redis
|
||||
# opentelemetry-instrumentation-requests
|
||||
# opentelemetry-instrumentation-system-metrics
|
||||
# opentelemetry-instrumentation-wsgi
|
||||
# opentelemetry-sdk
|
||||
opentelemetry-util-http==0.62b1 \
|
||||
--hash=sha256:adf6facbb89aef8f8bc566e2f04624942ba08a7b678b3479a91051a8f4dc70a3 \
|
||||
--hash=sha256:c57e8a6c19fc422c288e6074e882f506f85030b69b7376182f74f9257b9261f0
|
||||
opentelemetry-util-http==0.63b1 \
|
||||
--hash=sha256:6284194028c59cd439f8acfe388145069a6127f11dc077e1344a2094adacc3f8 \
|
||||
--hash=sha256:ba1268f00922ee522dba2ae38458060f99486e7385a8056985901ca9685adfff
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# opentelemetry-instrumentation-django
|
||||
|
|
@ -1681,9 +1682,9 @@ pydyf==0.12.1 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# weasyprint
|
||||
pyjwt[crypto]==2.12.1 \
|
||||
--hash=sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c \
|
||||
--hash=sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b
|
||||
pyjwt[crypto]==2.13.0 \
|
||||
--hash=sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423 \
|
||||
--hash=sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# django-allauth
|
||||
|
|
@ -1717,9 +1718,9 @@ pynacl==1.6.2 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# paramiko
|
||||
pypdf==6.11.0 \
|
||||
--hash=sha256:062b51c81b0910e6d2755e99e1c5547a0a23b7d0a32322af66240d8edcfabe87 \
|
||||
--hash=sha256:769394d5756d5b304c9b6bef88b54b1816b328e7e6fc9254e625529a15ed4ab8
|
||||
pypdf==6.12.1 \
|
||||
--hash=sha256:3953a097b9f26d4e0ead5ff95943d9971377557662a91d8872186053cd71d30a \
|
||||
--hash=sha256:8fa2a2321cf16247ed848bd7c97f193a60c08670d04abed5b0138327e51c43b0
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
|
|
@ -2383,12 +2384,6 @@ xmlsec==1.3.17 \
|
|||
# -c src/backend/requirements.txt
|
||||
# -r src/backend/requirements.in
|
||||
# python3-saml
|
||||
zipp==3.23.1 \
|
||||
--hash=sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc \
|
||||
--hash=sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# importlib-metadata
|
||||
zopfli==0.4.1 \
|
||||
--hash=sha256:02086247dd12fda929f9bfe8b3962b6bcdbfc8c82e99255aebcf367867cf0760 \
|
||||
--hash=sha256:07a5cdc5d1aaa6c288c5d9f5a5383042ba743641abf8e2fd898dcad622d8a38e \
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ build==1.5.0 \
|
|||
--hash=sha256:13f3eecb844759ab66efec90ca17639bbf14dc06cb2fdf37a9010322d9c50a6f \
|
||||
--hash=sha256:302c22c3ba2a0fd5f3911918651341ebb3896176cbdec15bd421f80b1afc7647
|
||||
# via pip-tools
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# -c src/backend/requirements-3.14.txt
|
||||
# -c src/backend/requirements.txt
|
||||
|
|
@ -242,9 +242,9 @@ charset-normalizer==3.4.7 \
|
|||
# -c src/backend/requirements.txt
|
||||
# pdfminer-six
|
||||
# requests
|
||||
click==8.3.3 \
|
||||
--hash=sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2 \
|
||||
--hash=sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613
|
||||
click==8.4.1 \
|
||||
--hash=sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2 \
|
||||
--hash=sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96
|
||||
# via pip-tools
|
||||
coverage[toml]==7.14.0 \
|
||||
--hash=sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74 \
|
||||
|
|
@ -448,9 +448,9 @@ gprof2dot==2025.4.14 \
|
|||
--hash=sha256:0742e4c0b4409a5e8777e739388a11e1ed3750be86895655312ea7c20bd0090e \
|
||||
--hash=sha256:35743e2d2ca027bf48fa7cba37021aaf4a27beeae1ae8e05a50b55f1f921a6ce
|
||||
# via django-silk
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# -c src/backend/requirements-3.14.txt
|
||||
# -c src/backend/requirements.txt
|
||||
|
|
@ -496,24 +496,24 @@ pluggy==1.6.0 \
|
|||
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
|
||||
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
|
||||
# via pytest
|
||||
prek==0.4.0 \
|
||||
--hash=sha256:01d69684306c67917ed69497d0f523216f13f2306723b62e1ace454209477b45 \
|
||||
--hash=sha256:0d19efff4537e4a68b5bd61dcbf5ccb2dd8343df3ea9482aabe37d241ff18ddf \
|
||||
--hash=sha256:0d9483404e5b8bf65111ee6b821e6cf7a5ba9c3a2065e7a0b7a39a17daaffcc9 \
|
||||
--hash=sha256:44e3716a3e2983add2c094775d564536342011e84f770132389819c965513d6d \
|
||||
--hash=sha256:473ce0262e36b8e77b327941ad6d5747ac451b4c441cdc86dab95640b68fff72 \
|
||||
--hash=sha256:47f42477c8453c7440e4e656e5ab0c2a1e4c25daa5ed441a9ac1a2b7634abc12 \
|
||||
--hash=sha256:6e3a0e43d7f345a5e32962736c335b5fc466d499f2556fb6f24028dd08108618 \
|
||||
--hash=sha256:7203bff21e622a5482e956384c43990b0092faab02f72118275839a77a45e939 \
|
||||
--hash=sha256:944670565dfb3800465355f299effa31572822566d10c6210e6f76bf399ddf53 \
|
||||
--hash=sha256:a8272f32e698eae514556086ad73d02026ec00bbd4d26c420f761ea857cfd795 \
|
||||
--hash=sha256:a860fda0f27f872622689358a583e5f2a5771241331848233274f4cfeb8ae9bb \
|
||||
--hash=sha256:b218d92ad5d2ff0b59240d7d837fa9edc61849894958acb3a225efff7a2faa65 \
|
||||
--hash=sha256:b60bd4fdc323896a5bada2708734d16ff59ee5e32b8c390ae2ebe328426964a3 \
|
||||
--hash=sha256:ce2a8feb5dc1f1e748879d0e14c2145353059b830ac5e3f64d92127ab16efc78 \
|
||||
--hash=sha256:e46277b577991ccdc7b13e2cfa7d260ae13e77f5af543e50e188799f649f0ad8 \
|
||||
--hash=sha256:f4cba2132e038349b4b0a00a73b300e4192bae9f78fff8df0365c00bd19140e7 \
|
||||
--hash=sha256:ff1f1fa311023418d40a443bca6928a9f5ce073d0b9130b641954183aa31736d
|
||||
prek==0.4.1 \
|
||||
--hash=sha256:051c442b570b53756225410240577bee1aeace6be52955dfacf45a9783223b36 \
|
||||
--hash=sha256:10e7e78ffe65dfba7d687a8c71b2f473554d1ba60f43c742105da4c0030feed9 \
|
||||
--hash=sha256:17ffa9d8dd40791b9b99cafe558c5cc28e78e5be57607b280b15f0dab90264e9 \
|
||||
--hash=sha256:2ab3460641762edf128b1ec8e833ce7e9ae015d1268a894560cb90d3393a7527 \
|
||||
--hash=sha256:2d1805123ab5d730629de588bf319ea39e7078b589b3288c95740f1b4780a1d4 \
|
||||
--hash=sha256:5b4a348537924b20e208cbd87ef58e96ec37d691c5bec2969209c40de0ecf72e \
|
||||
--hash=sha256:60928d1dad45ff3e491d3083a50643cc213aa2d54f1dbd8d702d7193773c020e \
|
||||
--hash=sha256:622a8812bda87cf4ddcae2dab5ccecc55b88d70c677129dbe25e975d923179f0 \
|
||||
--hash=sha256:6e69a9c02ead38706a5d2a4ae209dccba08ccb5d0026e1d08e723c66ab964750 \
|
||||
--hash=sha256:76663998827a2cbc94f5e209319809655489b5bd1f8e70568a623372e80253f0 \
|
||||
--hash=sha256:7c515492ef3585e6bcd7b83f1bb1cb131038abc88ed2c843de1e4c3ceb865b19 \
|
||||
--hash=sha256:8fa707971465d8ad021c907e43691aad7bb98942943e61e294ece5f95d9fbc78 \
|
||||
--hash=sha256:b25807e0aa57d2118747e127b58e7a1bf41d5d7b3323f5f3f1f3cb10031245cc \
|
||||
--hash=sha256:c0877e82c52359d655fe1072b3a5228639184d1d5f03c6803b6530cd6da1ef20 \
|
||||
--hash=sha256:cdf4503a240369f66321213d9c4bc6f925014b64ff7121de9e9920c9b9838ce2 \
|
||||
--hash=sha256:dc744fedf98df8a00a9e3bcd629b163fee5e9f9e22bce66029d9945241586165 \
|
||||
--hash=sha256:efa95331c4c171a867c0064c19d8a4abc94a1c1c920c8b8092f2d7d87f4b90a8
|
||||
# via -r src/backend/requirements-dev.in
|
||||
pycparser==3.0 \
|
||||
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
|
||||
|
|
@ -540,36 +540,36 @@ pytest==9.0.3 \
|
|||
# via
|
||||
# pytest-codspeed
|
||||
# pytest-django
|
||||
pytest-codspeed==5.0.2 \
|
||||
--hash=sha256:0621a458c52e77aa113c8d6e14037b90ce3cb5a8dd10a7656b71641999baef8c \
|
||||
--hash=sha256:0fd7db3e6fb6bd28abbf0059dd54ee6233f5faf5c08597b1e9624821417e8d99 \
|
||||
--hash=sha256:1b87b6a5e3c0e05ea043790aae08791dd6b3e7f487b18ec1bce145a60c78a130 \
|
||||
--hash=sha256:1ee33ac4c3bd7317b6956c0b6cb250f759e02072bb14fd0324de0df71d5d488f \
|
||||
--hash=sha256:22332fefae895fc80a36ac8a6d5b314663efcad9e833aed8452388441b95c50f \
|
||||
--hash=sha256:33245c1fd96b1a4299604f6791e7fded376605c140ad778db7032dcd46a74d1c \
|
||||
--hash=sha256:3658d3b42a15c6f40fa385629a8a8655dbedadd5d7bb5a01bc342b47f73da252 \
|
||||
--hash=sha256:3799ca9e54d6958d1b388371d00f928fcc4e1e68427d312348dd413a1bba5e0b \
|
||||
--hash=sha256:3a5ce30d2bcfbeb329b61f3435369720ed122caa1dd898464acbcd7edc63cf04 \
|
||||
--hash=sha256:3d15eaa6ca380d0d7cb5b7b8692f362a8aac3832dff6867a0c7068fb8c7a4ef1 \
|
||||
--hash=sha256:40b12cbf88eb69583d7063a4f5c986a7eed14f750a49764ef39a565ffa33d540 \
|
||||
--hash=sha256:439cd9d87ad449b7db327724b8fdc4a1ae79090b166b77c4e5e15102a371f6c7 \
|
||||
--hash=sha256:53473907ee2a7569b5ce6ffbfd2ba1793d284a37ff5c8670ed3149133c3ed37b \
|
||||
--hash=sha256:687e5aa0fd101adbfe98f36dc253cd4e3b77d90ad96260e6e7e78bde4319c357 \
|
||||
--hash=sha256:793d423dc76fd52b67495318681be18c541a7cfe30432ab2f272cd393422c56b \
|
||||
--hash=sha256:7b033d25f40c47733234f29c10629f14d004540c743a5c30718e2aa768d7cbb3 \
|
||||
--hash=sha256:82d3c9db57ccaef5177e1096b4dbbf8f3fde8d25c568e38d31a259474c94e5b4 \
|
||||
--hash=sha256:93fea30b2d7266343dd505a182bdf1eb47f96f5fa2929f1d9aff01d3b60e1589 \
|
||||
--hash=sha256:a14a6515cd315745b4b5b4739a72b287782c00a35f2927e55c310499b79d6bc2 \
|
||||
--hash=sha256:a88fcddd08bdb1afe043ac4f992e032baee92c88990a611111e0c00d77927cfe \
|
||||
--hash=sha256:b42d2aae3ac94192b8843fa7578eae584223bcb6334c50ca9f0e9ebafd40053b \
|
||||
--hash=sha256:c20756925af58ad9d5b584d66a9b8dc709f9b243e6d8fd377e2a1b5a99bf9229 \
|
||||
--hash=sha256:c2c09ec82a2def144816c6ffb311252c6ff0624189b3b5e674d889920b6d926c \
|
||||
--hash=sha256:cd07e12c38f6974c969e76d070aba448c92fad66601cda4fd289afa52c81ef13 \
|
||||
--hash=sha256:d223b0fe74625e633c86934a1da3ed1607f694fb3981a598bcfc02811e54808e \
|
||||
--hash=sha256:d394d0d27ead72d0b00906e3832f4dcb9aadb81887a4f379c534c32c0ab965b7 \
|
||||
--hash=sha256:d6d24532a8fee7018b9a33df51e1a14e27ae6b2b0772e6ad477ce5c561ab06a5 \
|
||||
--hash=sha256:dedc9e4542832a3487aedf0b448217f34fdc794676b9e0daeaf408a343322c2b \
|
||||
--hash=sha256:fbd1e86900e7ebbbf3cdf5a48124412d2b75283ab1378994ac27ba3308e262fc
|
||||
pytest-codspeed==5.0.3 \
|
||||
--hash=sha256:005348ea52ace3ede2e2f595913912ad2564cca7b124211a88dc78a9cb1fca63 \
|
||||
--hash=sha256:0c383c9121deb58a69f174188e9e4488ffc0daced0ed276abf87747182511901 \
|
||||
--hash=sha256:20eba63765be9d1b6cacbbfad84b87d49eb04b357a7045a0899880da181f81e3 \
|
||||
--hash=sha256:25464363c7f9b9bd5022e969c0addba616fa40ac9b8f0fc9e030c4538863b32d \
|
||||
--hash=sha256:2eeb25fb1ac3f73c4de50e739e78fea396b89782bdb740bf2a7cd2df21f8d4ee \
|
||||
--hash=sha256:3a2097247985f5d915a94b80c5552d10979ca858c859fc3edef1bf2baa5c9b7a \
|
||||
--hash=sha256:4c682f6645d4eb472f3bd95dbda1805e3af4243610572cb7d6bf94a88e8a0b6c \
|
||||
--hash=sha256:51e192905a2230f9956e6160732f76577836953a4a1fb2b1e7be74e51ac7b2a0 \
|
||||
--hash=sha256:6524c57fec279a22ffef6112af404036afc71b4704758ae9f0abda429b8478d4 \
|
||||
--hash=sha256:73c5c9d98a3372a42611989ccfa437cce3842431ac6d6b9ab42c4f0e59c070f7 \
|
||||
--hash=sha256:782f9985b6f6b45b8bc20152d206d3a52b56dd088ba81cb70a71f0b39841be9e \
|
||||
--hash=sha256:7ac4344f34bbcdd17f6f8c30dbac3da2f80d223dd112e568fd7f7c2cd4cbc693 \
|
||||
--hash=sha256:85505c96a3477c346ec2d2b7dced8478f4c651e2b1666ee102d53a832b511853 \
|
||||
--hash=sha256:8df77b3409f54f4a268f77f3ff74992fe1d995cdbaf2cecf8ad74d32db217ce7 \
|
||||
--hash=sha256:91afef90e6a96b013495e4702ef5d6358614a449e71008cdc194ef668778b92f \
|
||||
--hash=sha256:9aa0815b90196f3c20d736ea8691381e97f12bbe8c7d87af10a351e434b452cb \
|
||||
--hash=sha256:a2e0ab65df73e837666d12357280ca50ff6d6ac03ea5266703be518b68170edf \
|
||||
--hash=sha256:a4bcdb4b6522738152885ef067e0c8524d5699828d780fb6f464cdb3db44369c \
|
||||
--hash=sha256:a5d8695a227ea1c3a41d25db5b3fe720bf1b4808bd38862be811a4efd902c792 \
|
||||
--hash=sha256:abe793da40f87295d33988673d34f06ea569848b44490b847552cd416816258a \
|
||||
--hash=sha256:bce0a6ea93a5b19658f713312bb67554c19283ab15b454a1e3e55a13e78130f8 \
|
||||
--hash=sha256:bf4cc4178cbace8f4d2bd240408276bc4da3850ac5fcb5fb5f8a74ab417615bb \
|
||||
--hash=sha256:c3a9ed38dfa776443b86f4b49a982e8443d0953db4974bd2673d63cc904ae1ad \
|
||||
--hash=sha256:dbe6a4a00b449b6ba2771f644cbc38bdf55acf5c812e60e5659110e19dd9f510 \
|
||||
--hash=sha256:ec9fa6f0af0a9feb0e0bd517fb59ef28f806fbd50c0c6900ac26cbb4d080eba5 \
|
||||
--hash=sha256:efd43f82ea03ced8488a767ded9473f050791ab7783ea8654107e1e0ac66af40 \
|
||||
--hash=sha256:f56d0339cd98d26f6e561987be25bdd2761a5d53d8f73493b1ebe02d0d451093 \
|
||||
--hash=sha256:f852bee785a7a124cb1720b1915670c6742af87747dc4d838f3ffdbd365ce9d9 \
|
||||
--hash=sha256:fe2ea83c924c2250675b75686c3ee456b8cf0208d83d552e182a195fdf467378
|
||||
# via -r src/backend/requirements-dev.in
|
||||
pytest-django==4.12.0 \
|
||||
--hash=sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85 \
|
||||
|
|
@ -626,13 +626,13 @@ ty==0.0.1a21 \
|
|||
--hash=sha256:e941e9a9d1e54b03eeaf9c3197c26a19cf76009fd5e41e16e5657c1c827bd6d3 \
|
||||
--hash=sha256:ecf41706b803827b0de8717f32a434dad1e67be9f4b8caf403e12013179ea06a
|
||||
# via -r src/backend/requirements-dev.in
|
||||
types-psycopg2==2.9.21.20260509 \
|
||||
--hash=sha256:0422105f691a409e9d8048c2205aca9d694b70823248c6614393444017e9f088 \
|
||||
--hash=sha256:69f6dae384bbea830dff23621936423035db152af901331e6f9c46f7c4f4b24f
|
||||
types-psycopg2==2.9.21.20260518 \
|
||||
--hash=sha256:2fd728a4fa3860db0a4a9813e5f49c30ed329b3d2e60e73530d9db01b2b98420 \
|
||||
--hash=sha256:8b1f80d90d6799a4fcdac12198b382a8feee9ed4340d5f69b56fc5ffa0644143
|
||||
# via django-types
|
||||
types-pyyaml==6.0.12.20260510 \
|
||||
--hash=sha256:09c1f1cb65a6eebea1e2e51ccf4918b8288e152909609a35cdb0d805efd125ad \
|
||||
--hash=sha256:3492eb9ba4d9d833473214c4d5736cccf5f37d93f5854059721e1c84f785309d
|
||||
types-pyyaml==6.0.12.20260518 \
|
||||
--hash=sha256:d2150f75a231c9fe9c7463bd29487d93e60bac90400287351384bc2284eba7cd \
|
||||
--hash=sha256:d917f83fb38462550338c1297faedd860b3ec83912b96b1e3d73255f7473e466
|
||||
# via django-stubs
|
||||
typing-extensions==4.15.0 \
|
||||
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ build==1.5.0 \
|
|||
--hash=sha256:13f3eecb844759ab66efec90ca17639bbf14dc06cb2fdf37a9010322d9c50a6f \
|
||||
--hash=sha256:302c22c3ba2a0fd5f3911918651341ebb3896176cbdec15bd421f80b1afc7647
|
||||
# via pip-tools
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
|
|
@ -104,7 +104,6 @@ cffi==2.0.0 \
|
|||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# cryptography
|
||||
# pytest-codspeed
|
||||
charset-normalizer==3.4.7 \
|
||||
--hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \
|
||||
--hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \
|
||||
|
|
@ -239,9 +238,9 @@ charset-normalizer==3.4.7 \
|
|||
# -c src/backend/requirements.txt
|
||||
# pdfminer-six
|
||||
# requests
|
||||
click==8.3.3 \
|
||||
--hash=sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2 \
|
||||
--hash=sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613
|
||||
click==8.4.1 \
|
||||
--hash=sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2 \
|
||||
--hash=sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96
|
||||
# via pip-tools
|
||||
coverage[toml]==7.13.5 \
|
||||
--hash=sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256 \
|
||||
|
|
@ -443,9 +442,9 @@ gprof2dot==2025.4.14 \
|
|||
--hash=sha256:0742e4c0b4409a5e8777e739388a11e1ed3750be86895655312ea7c20bd0090e \
|
||||
--hash=sha256:35743e2d2ca027bf48fa7cba37021aaf4a27beeae1ae8e05a50b55f1f921a6ce
|
||||
# via django-silk
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# -c src/backend/requirements.txt
|
||||
# requests
|
||||
|
|
@ -489,24 +488,24 @@ pluggy==1.6.0 \
|
|||
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
|
||||
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
|
||||
# via pytest
|
||||
prek==0.3.13 \
|
||||
--hash=sha256:0d89ac712c60e34d1550a606ad5fdfb8ad71d44ced8afa2fa5cbc106be4abd9e \
|
||||
--hash=sha256:326fac2bdce00074ce6c5046b861d310638aee2b9de1ed241ba7eb32bdc83898 \
|
||||
--hash=sha256:64b59a1550780af2bba37297c704b17f81d8e9df6288af1fab4017938e33b1db \
|
||||
--hash=sha256:7ca8c526a23873177fb3b92013500b08ef5f8bedc7263f9f3a44dd2f49645a26 \
|
||||
--hash=sha256:841049f89f5ec9f4035299283d11e566ac5a068e3742ead1055ea04f886831fc \
|
||||
--hash=sha256:9ce6cd8f114ba9bbdbe97422103fd886101949b1c42e588a7543c4436ead2020 \
|
||||
--hash=sha256:a5bbb175478438a871e3281d2c3c3f067288af73ad81707a9bdebfd769766c7d \
|
||||
--hash=sha256:a65327a014d838341af757dfc05a706d10e8e33f039bc32bb3dbe2fa21c440c0 \
|
||||
--hash=sha256:a9fd74e0aec550c6b8d41076fdcdd6ff121cd7d94d743c1338bd794784e3c775 \
|
||||
--hash=sha256:b00d38f01235073c35aa5f48df57fefef45a6cec2ae0884d750345a2c7220370 \
|
||||
--hash=sha256:b6a200843a36a5b0c41764ce7639ccb3471d48b097f1c5e3fc8f034219b42626 \
|
||||
--hash=sha256:bdacaad8f35f343e063d251211fe34db1de9e5cc591795361ad69a6485202258 \
|
||||
--hash=sha256:c48586ee3708bfbf3df80121f55583e9a7d0fa166b08172c091fe5971e92a0ac \
|
||||
--hash=sha256:cc03e924a24d8d961f56195853c8b206cb196be6db4ad8312125dae847d718ac \
|
||||
--hash=sha256:e5530a867bcf5b172b7513a64e71b06a337d1d184696227ae953845867376b8d \
|
||||
--hash=sha256:f00328f1c520d8fefb910ab0d3c6764ee330d227952baa19b7e3de7242bd8b3b \
|
||||
--hash=sha256:f9b5265863d18b5be4ea094fdce4fd6ca61a8c89a70ee3d8ee153b3e0ed6b272
|
||||
prek==0.4.1 \
|
||||
--hash=sha256:051c442b570b53756225410240577bee1aeace6be52955dfacf45a9783223b36 \
|
||||
--hash=sha256:10e7e78ffe65dfba7d687a8c71b2f473554d1ba60f43c742105da4c0030feed9 \
|
||||
--hash=sha256:17ffa9d8dd40791b9b99cafe558c5cc28e78e5be57607b280b15f0dab90264e9 \
|
||||
--hash=sha256:2ab3460641762edf128b1ec8e833ce7e9ae015d1268a894560cb90d3393a7527 \
|
||||
--hash=sha256:2d1805123ab5d730629de588bf319ea39e7078b589b3288c95740f1b4780a1d4 \
|
||||
--hash=sha256:5b4a348537924b20e208cbd87ef58e96ec37d691c5bec2969209c40de0ecf72e \
|
||||
--hash=sha256:60928d1dad45ff3e491d3083a50643cc213aa2d54f1dbd8d702d7193773c020e \
|
||||
--hash=sha256:622a8812bda87cf4ddcae2dab5ccecc55b88d70c677129dbe25e975d923179f0 \
|
||||
--hash=sha256:6e69a9c02ead38706a5d2a4ae209dccba08ccb5d0026e1d08e723c66ab964750 \
|
||||
--hash=sha256:76663998827a2cbc94f5e209319809655489b5bd1f8e70568a623372e80253f0 \
|
||||
--hash=sha256:7c515492ef3585e6bcd7b83f1bb1cb131038abc88ed2c843de1e4c3ceb865b19 \
|
||||
--hash=sha256:8fa707971465d8ad021c907e43691aad7bb98942943e61e294ece5f95d9fbc78 \
|
||||
--hash=sha256:b25807e0aa57d2118747e127b58e7a1bf41d5d7b3323f5f3f1f3cb10031245cc \
|
||||
--hash=sha256:c0877e82c52359d655fe1072b3a5228639184d1d5f03c6803b6530cd6da1ef20 \
|
||||
--hash=sha256:cdf4503a240369f66321213d9c4bc6f925014b64ff7121de9e9920c9b9838ce2 \
|
||||
--hash=sha256:dc744fedf98df8a00a9e3bcd629b163fee5e9f9e22bce66029d9945241586165 \
|
||||
--hash=sha256:efa95331c4c171a867c0064c19d8a4abc94a1c1c920c8b8092f2d7d87f4b90a8
|
||||
# via -r src/backend/requirements-dev.in
|
||||
pycparser==3.0 \
|
||||
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
|
||||
|
|
@ -532,23 +531,36 @@ pytest==9.0.3 \
|
|||
# via
|
||||
# pytest-codspeed
|
||||
# pytest-django
|
||||
pytest-codspeed==4.4.0 \
|
||||
--hash=sha256:06943110e7a8a4b54f4b13aaa3ff8db39caa02b2f61705916887649e36b9713a \
|
||||
--hash=sha256:215170441e57bfcbefd179dfd86ccd54ed0ee235e0602a068ce4448b35f13cb2 \
|
||||
--hash=sha256:29b1bf8a36e18d11641a5e610e23a94036b04185e3099978d81a873a5bd3635c \
|
||||
--hash=sha256:33c38e0e797c74506004f231fc53eab0e412987de281755f714018334381aa3a \
|
||||
--hash=sha256:340dbb1cc5a21434e0e29bd68ab03c7dc7ad9bfde09d1980b7161352c4c2f048 \
|
||||
--hash=sha256:413666266762f9cef1321ba971a9e127b97a1f1dad40ddfd2184c2bc5ac157f9 \
|
||||
--hash=sha256:4afa9455a9b198c5e898224c751182fcf53f67f11fb27c2c3346284da1baa018 \
|
||||
--hash=sha256:56d5dd94dcb69460f916acb9c69865d0171b98acec3ce256645d0c0275b553d7 \
|
||||
--hash=sha256:6a5c1d51e7ca72ffe247c99b9a97a54191185e8f7a27528e2200d7416da2a68b \
|
||||
--hash=sha256:83479a6719598d2910969a60cc410c7283c262c876422a9157dca2f2ab42fa1d \
|
||||
--hash=sha256:98524af4ddd6006ea064791bb15a43957d78fab040cb6f499ca73a369da373e6 \
|
||||
--hash=sha256:a6aab2fa73523f538e7729c20ccf4a1e8e921324c9877a816b05334135950fd9 \
|
||||
--hash=sha256:e258e6c3d5a8a02ae02a64831be3acd44c19210ffbf13321bdbb8c111c5c6fe4 \
|
||||
--hash=sha256:edb7c101d9c50439a42cf02cfa9c0ac92da618841636bbebf87c3fa54669442a \
|
||||
--hash=sha256:ee3e1964446011ca192eebf0350227df231a5b88af57e518f2a4328fc8ca5131 \
|
||||
--hash=sha256:f3ae6f4053042c3a9ae3b05416fb42253c5e514e89391eb25e9c9e3ac8de8677
|
||||
pytest-codspeed==5.0.3 \
|
||||
--hash=sha256:005348ea52ace3ede2e2f595913912ad2564cca7b124211a88dc78a9cb1fca63 \
|
||||
--hash=sha256:0c383c9121deb58a69f174188e9e4488ffc0daced0ed276abf87747182511901 \
|
||||
--hash=sha256:20eba63765be9d1b6cacbbfad84b87d49eb04b357a7045a0899880da181f81e3 \
|
||||
--hash=sha256:25464363c7f9b9bd5022e969c0addba616fa40ac9b8f0fc9e030c4538863b32d \
|
||||
--hash=sha256:2eeb25fb1ac3f73c4de50e739e78fea396b89782bdb740bf2a7cd2df21f8d4ee \
|
||||
--hash=sha256:3a2097247985f5d915a94b80c5552d10979ca858c859fc3edef1bf2baa5c9b7a \
|
||||
--hash=sha256:4c682f6645d4eb472f3bd95dbda1805e3af4243610572cb7d6bf94a88e8a0b6c \
|
||||
--hash=sha256:51e192905a2230f9956e6160732f76577836953a4a1fb2b1e7be74e51ac7b2a0 \
|
||||
--hash=sha256:6524c57fec279a22ffef6112af404036afc71b4704758ae9f0abda429b8478d4 \
|
||||
--hash=sha256:73c5c9d98a3372a42611989ccfa437cce3842431ac6d6b9ab42c4f0e59c070f7 \
|
||||
--hash=sha256:782f9985b6f6b45b8bc20152d206d3a52b56dd088ba81cb70a71f0b39841be9e \
|
||||
--hash=sha256:7ac4344f34bbcdd17f6f8c30dbac3da2f80d223dd112e568fd7f7c2cd4cbc693 \
|
||||
--hash=sha256:85505c96a3477c346ec2d2b7dced8478f4c651e2b1666ee102d53a832b511853 \
|
||||
--hash=sha256:8df77b3409f54f4a268f77f3ff74992fe1d995cdbaf2cecf8ad74d32db217ce7 \
|
||||
--hash=sha256:91afef90e6a96b013495e4702ef5d6358614a449e71008cdc194ef668778b92f \
|
||||
--hash=sha256:9aa0815b90196f3c20d736ea8691381e97f12bbe8c7d87af10a351e434b452cb \
|
||||
--hash=sha256:a2e0ab65df73e837666d12357280ca50ff6d6ac03ea5266703be518b68170edf \
|
||||
--hash=sha256:a4bcdb4b6522738152885ef067e0c8524d5699828d780fb6f464cdb3db44369c \
|
||||
--hash=sha256:a5d8695a227ea1c3a41d25db5b3fe720bf1b4808bd38862be811a4efd902c792 \
|
||||
--hash=sha256:abe793da40f87295d33988673d34f06ea569848b44490b847552cd416816258a \
|
||||
--hash=sha256:bce0a6ea93a5b19658f713312bb67554c19283ab15b454a1e3e55a13e78130f8 \
|
||||
--hash=sha256:bf4cc4178cbace8f4d2bd240408276bc4da3850ac5fcb5fb5f8a74ab417615bb \
|
||||
--hash=sha256:c3a9ed38dfa776443b86f4b49a982e8443d0953db4974bd2673d63cc904ae1ad \
|
||||
--hash=sha256:dbe6a4a00b449b6ba2771f644cbc38bdf55acf5c812e60e5659110e19dd9f510 \
|
||||
--hash=sha256:ec9fa6f0af0a9feb0e0bd517fb59ef28f806fbd50c0c6900ac26cbb4d080eba5 \
|
||||
--hash=sha256:efd43f82ea03ced8488a767ded9473f050791ab7783ea8654107e1e0ac66af40 \
|
||||
--hash=sha256:f56d0339cd98d26f6e561987be25bdd2761a5d53d8f73493b1ebe02d0d451093 \
|
||||
--hash=sha256:f852bee785a7a124cb1720b1915670c6742af87747dc4d838f3ffdbd365ce9d9 \
|
||||
--hash=sha256:fe2ea83c924c2250675b75686c3ee456b8cf0208d83d552e182a195fdf467378
|
||||
# via -r src/backend/requirements-dev.in
|
||||
pytest-django==4.12.0 \
|
||||
--hash=sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85 \
|
||||
|
|
@ -651,13 +663,13 @@ ty==0.0.1a21 \
|
|||
--hash=sha256:e941e9a9d1e54b03eeaf9c3197c26a19cf76009fd5e41e16e5657c1c827bd6d3 \
|
||||
--hash=sha256:ecf41706b803827b0de8717f32a434dad1e67be9f4b8caf403e12013179ea06a
|
||||
# via -r src/backend/requirements-dev.in
|
||||
types-psycopg2==2.9.21.20260422 \
|
||||
--hash=sha256:ad7574fa8e25d9aa96ab96cd280c4dee20872725cd1fe6a6d3facc354f2644d4 \
|
||||
--hash=sha256:e240684ac37946c5a2a058b04ea1f2fd0e4ee2655719b8c3ec9abf37f96da5ba
|
||||
types-psycopg2==2.9.21.20260518 \
|
||||
--hash=sha256:2fd728a4fa3860db0a4a9813e5f49c30ed329b3d2e60e73530d9db01b2b98420 \
|
||||
--hash=sha256:8b1f80d90d6799a4fcdac12198b382a8feee9ed4340d5f69b56fc5ffa0644143
|
||||
# via django-types
|
||||
types-pyyaml==6.0.12.20260408 \
|
||||
--hash=sha256:92a73f2b8d7f39ef392a38131f76b970f8c66e4c42b3125ae872b7c93b556307 \
|
||||
--hash=sha256:fbc42037d12159d9c801ebfcc79ebd28335a7c13b08a4cfbc6916df78fee9384
|
||||
types-pyyaml==6.0.12.20260518 \
|
||||
--hash=sha256:d2150f75a231c9fe9c7463bd29487d93e60bac90400287351384bc2284eba7cd \
|
||||
--hash=sha256:d917f83fb38462550338c1297faedd860b3ec83912b96b1e3d73255f7473e466
|
||||
# via django-stubs
|
||||
typing-extensions==4.15.0 \
|
||||
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
|
||||
|
|
|
|||
|
|
@ -91,19 +91,19 @@ bleach==4.1.0 \
|
|||
--hash=sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da \
|
||||
--hash=sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994
|
||||
# via django-markdownify
|
||||
blessed==1.39.0 \
|
||||
--hash=sha256:666e7e3fd0a4e38c3a262eaaf1e22a4ce2c81337aa17593c3f60ea136ec24fe1 \
|
||||
--hash=sha256:b04fc7141a20a3b2ade6cad741051f1e3ac59cc1e7e90915ed1f9e521332bea4
|
||||
blessed==1.42.0 \
|
||||
--hash=sha256:34b460b77562ed21f807cfd7c527b983b0cc300c98810c8076f283b7bcd45ba7 \
|
||||
--hash=sha256:f96c4a6dc664b48e0b832fa732acc16df67abd30f0ec35babf99025982f21852
|
||||
# via -r src/backend/requirements.in
|
||||
boto3==1.43.8 \
|
||||
--hash=sha256:1894497c383e3cdf50e210f1f57a43e9f4047a5d3accc73ffdb7eacc3b0f011b \
|
||||
--hash=sha256:d1235602d715c727c1923ef4bcdb5612a20575a9a5e4f2db00d571e0ea1f85fc
|
||||
boto3==1.43.14 \
|
||||
--hash=sha256:574335744656cfed0b362a0a0467aaf2eb2bf15526edcd02d31d3c661f4b09e4 \
|
||||
--hash=sha256:5c0a994b3182061ee101812e721100717a4d664f9f4ceaf4a86b6d032ce9fc2d
|
||||
# via
|
||||
# django-anymail
|
||||
# django-storages
|
||||
botocore==1.43.8 \
|
||||
--hash=sha256:611ad8b1f60661373cd39d9391ff16f1eaf8f5cb1d0a691563a4201d1a2603ce \
|
||||
--hash=sha256:6257d2655c3abe75eaa49e218b7d883cdc7cea64652b451e5feb08a6c169da3c
|
||||
botocore==1.43.14 \
|
||||
--hash=sha256:1f4a2a95ea78c10398e78431e98c1fe47adb54a7b10a32975144c1f541186658 \
|
||||
--hash=sha256:b9e500737e43d2f147c9d4e23b54360335e77d4c0ba90a318f51b65e06cb8516
|
||||
# via
|
||||
# boto3
|
||||
# s3transfer
|
||||
|
|
@ -209,9 +209,9 @@ brotli==1.2.0 \
|
|||
--hash=sha256:fc1530af5c3c275b8524f2e24841cbe2599d74462455e9bae5109e9ff42e9361 \
|
||||
--hash=sha256:ff09cd8c5eec3b9d02d2408db41be150d8891c5566addce57513bf546e3d6c6d
|
||||
# via fonttools
|
||||
certifi==2026.4.22 \
|
||||
--hash=sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a \
|
||||
--hash=sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580
|
||||
certifi==2026.5.20 \
|
||||
--hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \
|
||||
--hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d
|
||||
# via
|
||||
# requests
|
||||
# sentry-sdk
|
||||
|
|
@ -673,49 +673,49 @@ drf-spectacular==0.29.0 \
|
|||
--hash=sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc \
|
||||
--hash=sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a
|
||||
# via -r src/backend/requirements.in
|
||||
dulwich==1.2.1 \
|
||||
--hash=sha256:011d37afa0922b500c938d6417317e3e6d29d33a6fbaf12b3696fe2a216aa170 \
|
||||
--hash=sha256:01f43a1b6953c93b4e957c0902f7de80267285e0c59c9b44f4801f7da9f11107 \
|
||||
--hash=sha256:04215befa00c82accda97d0e3ce760d9344a67f081d5b92ade8ad00007fb38d8 \
|
||||
--hash=sha256:09ca37d7a9086f96e535a6474644588e4502f69e2b202c39d92901e3606f6501 \
|
||||
--hash=sha256:0b1181f4ae225bbde373fc16279c4e61fdf04aedd30ec21fab387be642567453 \
|
||||
--hash=sha256:1073c75db1f5da845d219d1b5b601aeaaa7be5f999f3c77f4966f9ca2327bf44 \
|
||||
--hash=sha256:11a51dba8454b4c64bf242a918ca4c4300097f7cec84a13164845e638a26f9de \
|
||||
--hash=sha256:121d2d181407cd7bb051922dc3bc00841ca0959b8299880529525db93dfbdca9 \
|
||||
--hash=sha256:1961e0b6c0b1f2920f4ab05821652d8eb12f19ddb5a4c167c385902391c08dd3 \
|
||||
--hash=sha256:21f48480bb1e6501bdec7f0877639cdfc64a16e0dd97c24947582fbeed3baf21 \
|
||||
--hash=sha256:23560643c1cc85737c87985761666a59b35b06a1cbb06db5ba642fa35c67be93 \
|
||||
--hash=sha256:3183b7db09282842459fbeb37e77e498c8339e6db4d0cb6b5d3685c97ce79dac \
|
||||
--hash=sha256:3412eca24fd79d5413ac7003f8f29b2e01008d7c9d6fce159f77602f70058aea \
|
||||
--hash=sha256:3a95dd2649ef3c6e59095d5bd3de08470b3ba908dc41343f5823666a10a326f8 \
|
||||
--hash=sha256:4198f79ff04b07f6f6dc81047041f341b35e774cf0207f496b35f34dd2e1bb9c \
|
||||
--hash=sha256:41dfe1b1cb0f0202102e90f9f47f54458f27da6b746939a6ed85362b68e3e3a5 \
|
||||
--hash=sha256:4b6cd8104bf4adf2824221ba4f3b399c641a7a6a026dfa193c2f516531971315 \
|
||||
--hash=sha256:55c8415fb19068a5956e0d5bd83b0fb6e06b291d3b096d8fb6a604c105fc6ca0 \
|
||||
--hash=sha256:5a0245dccd69fba9dfe2ed88eff9212bad3e04107bc41676fffbc7f706428cdb \
|
||||
--hash=sha256:5e875729df04991732959f52e29c1de96d00eaf62feddfc60f0b2b08c6e38870 \
|
||||
--hash=sha256:6349b475a1b17b224191a4801687a2486574c9526e00835db2ba9ed081124b11 \
|
||||
--hash=sha256:674b21a9025c00a00495fa03a9bb5f2da67a13ee513c74f16bd91c56678d0a77 \
|
||||
--hash=sha256:74b01505b8e2ba81a715213101c790e0794f5c0b8021f8ce1100131a1e8cfa55 \
|
||||
--hash=sha256:879abd15550b6abcebf97823905a167623f331eeca5e12dc0cac62bcd9e70bcd \
|
||||
--hash=sha256:96846ef600378739a64e347412c22d5f87f1b67d68526c633b465589335e9387 \
|
||||
--hash=sha256:96c160d68173ae55f68bf734e7fddae04ea025f3541996b0b5f28dc2025b42dc \
|
||||
--hash=sha256:9d0ea88273a7ee6fd3b1d75e231cc6fc614774e19bdd7c1de5df274b4b492dde \
|
||||
--hash=sha256:9f7249c1090be7e7e841edda369d843617314092bb05f2a6a8b7f88660bbb2a6 \
|
||||
--hash=sha256:a65527eda5f6a463168c6338d781b05d325ba85dc05c6f8217ddd8454911bb53 \
|
||||
--hash=sha256:ba43bfb3a7cad40d9607170561e8c3be42e7083b4b57af89a5f54e01577ff791 \
|
||||
--hash=sha256:bad94416de9a76ad36dc19f0e65a829b89fc845282bdcc8c43285a4addc1ad2e \
|
||||
--hash=sha256:cedc717cf9ee973df63293bcbaa51bb03ab6f87ff631d1dd329078b3f48712a7 \
|
||||
--hash=sha256:cf3aa983ca4907c96a0b98b357a3cac7381192786495522a65944da1b284bc02 \
|
||||
--hash=sha256:d0ddda4e165ea14c70e1d0531aa97e527332f1133ea0c65eebaa5afb8786029e \
|
||||
--hash=sha256:da2fdcc9e4f178b2b4ec1194d8e17d111d572f111fdaa7c6c5a3f46bbe686eaf \
|
||||
--hash=sha256:e2f14d20aea48dd1d48714d637c70399b140825d930b4f5aa6fbb62199429740 \
|
||||
--hash=sha256:e45a68da922a4abe8fd015ed020ec0123ee58176a6984a34d2a2c74c959e45d3 \
|
||||
--hash=sha256:e88fd960a9327d87556a3bad76ad84b6346d3a07409fe8f081877a775977c86b \
|
||||
--hash=sha256:efd394fcb926ec8e9ed63fe0883784abf8ef7bb1d30a492e950ca8c2f369ce7b \
|
||||
--hash=sha256:f944b742962d9933e60863f577491743328b287251ae57a1e7cd84c289acfc23 \
|
||||
--hash=sha256:fb855620d04d0c286058db941c106cfc60bc1e4882ea20b6dd499f3668a1afbe \
|
||||
--hash=sha256:fd774825510350b614121bfa84d95c6eb08f7e93c0fe7faf8760423a43dbad8b
|
||||
dulwich==1.2.5 \
|
||||
--hash=sha256:00b54a1d56ddbacdd8eadd6d4787a51b3a05fefa30eadbf9165fd283a00b90ed \
|
||||
--hash=sha256:0395b2c8924c3424bafe2d9c1edd5348cc4b21ce9c1d6655bf01f9a5c47164c8 \
|
||||
--hash=sha256:07cb75b58216440e2c170fff4f3d55a5f387358d9489863af8cb11f24ee37121 \
|
||||
--hash=sha256:1679b376433a0fc7f36586afda1d4ed7427afa7a79d4bf17e5014474eea69fa4 \
|
||||
--hash=sha256:1699a4cf8d44c174408325a9594a1498d05786cea34e3004c8732420ee1b8182 \
|
||||
--hash=sha256:1ba83ec3cfb4c506c277400357a51523c8258fa07b841ee06e8e1071da4cfed1 \
|
||||
--hash=sha256:1c151a7f3995ccf9d433a603b747e76141a7ebe7c385c8909e9f7e7a6422c28f \
|
||||
--hash=sha256:2f10dafa1ef5660b1331364bc8d68446448608a8d8f493ed0e260eaf5133e71c \
|
||||
--hash=sha256:2f90d68bfa97c4ca71de7507984365aefe27b6d248cb28dc99644d0f3ae8c60b \
|
||||
--hash=sha256:41ccffb0521f3f9ad73fac78772f321d731607336cee48911e7c26963459481c \
|
||||
--hash=sha256:46db47394ba8a95748ae739f5d3a5a3e1724a2f857bf2437bc71bfc0baaed91d \
|
||||
--hash=sha256:5108acead814d1de8b6262d6d8fb90af7e82f5a4d83788b6b48e39d01800a92f \
|
||||
--hash=sha256:517fb7e20f91d2bd48dc5de9edc90ff8974a5512ce7f243284b191f8be6344c3 \
|
||||
--hash=sha256:53599909d54a2fae49fcd50047f1daf4b8b9eda6a5500a08b71da689f5431c24 \
|
||||
--hash=sha256:556593fd11637f80f6018bee1916b1a84f5b420423b470ebb3f1a782ad6ef081 \
|
||||
--hash=sha256:5e067b7feceb7034bc99e7c7143a704f1d97d4be7027d9a0aa5a83c0657ff091 \
|
||||
--hash=sha256:66aded7d364341b55941973a1562323f25bd205f0809692b687ec36ccd31242c \
|
||||
--hash=sha256:6c683c0f4a062894b6826c61102d415dae86ade61a10003c82ccc2b91858d5fb \
|
||||
--hash=sha256:701a9ecf7a8a44f5e2459e46befa93530cf36a8b1ae3140aefc007db1d7d0207 \
|
||||
--hash=sha256:77d2d2e43ad975459491de1ebf47990c74ff17f12586c8561e9890239bc422db \
|
||||
--hash=sha256:827366331603150de5976d72dd456a3fd5fc91e856471dc1d10fd64758c05f02 \
|
||||
--hash=sha256:8929134acf4ff967203df7600b38535f9b5b590462067a7e30dbce01acb97af9 \
|
||||
--hash=sha256:8e55f36a7f52ba0976dd72100273523908b16fb9dda6ce96d9aa9df9cceed4cc \
|
||||
--hash=sha256:9008ef25cabd379cda4fa86000fc38ca14b72afe17db798a8c85c0b2b7ce4d1e \
|
||||
--hash=sha256:93d2d87acf75d60c5a2b8c5c8a45aff17bbbd00c17bdccb4ba013d3ab590a65f \
|
||||
--hash=sha256:9693d2c9e226b2ea855c1dc3a87e2f4d972f7523fc0f7924e5997e9f4c23d97f \
|
||||
--hash=sha256:9b6d234f1f91335e9f01d9daac42ddc2d2e5c2fdbe285d8eeef50353b283648a \
|
||||
--hash=sha256:9f3c98f5fa90a842c1f545463834f712aa2eed785fc3d5e42836c0df2d691bb6 \
|
||||
--hash=sha256:9fc113c1348c7eb22c4e8790f68b562bb4f42a721fafb813e89a57e9cd632040 \
|
||||
--hash=sha256:a5549f4afc973e0a15ea6b0244d57f848d3f3ee13dac557eb311024aebebf128 \
|
||||
--hash=sha256:a6620963196c49212c511cd909f367dacf771f199a27d116f357cc671ea956c7 \
|
||||
--hash=sha256:a70477c991e96cfe8fdd7c866e7251faf71b38bfeb51d6f27554c9cce1caabf3 \
|
||||
--hash=sha256:ade416833214f3ee13af9b0199fff4de00fa6e0fde3deced776532fd91df5515 \
|
||||
--hash=sha256:c65230abaa52c72093b70d3b499d5689d1d8f9627e88ad3c3b4f8154e86ac0c8 \
|
||||
--hash=sha256:ccc58f26a1b94bef255316311678b03854f7192069bdf11cf501a6c85f61b83c \
|
||||
--hash=sha256:d33bae2b3292ed0235522682316251658187f43b1ebad6cd2b127069b94afb3b \
|
||||
--hash=sha256:d46e35c473646efb3b2ff8032f37ac5b6d48da52a669577187d3796a6d5987a3 \
|
||||
--hash=sha256:d8f7ea8f47e38e5b0de3fab97e07e9c9161ffddc90b3964512cab2b7749df4e6 \
|
||||
--hash=sha256:dd9569bc26174a3437d749114d36c81fc6c7478b55370ae50125e34e9629e4fe \
|
||||
--hash=sha256:df4ac3746099562c8160d78d55bb2fa10c9ada7ef970af3e2536bd133cb7830e \
|
||||
--hash=sha256:e128cddeccae4146b556684a0d5426454fff5bfe7306862e5a8ce6b471568af4 \
|
||||
--hash=sha256:fa37da7ad16c47391016b5f984fb60e175e1ab0b478f04920fd6d1f61123ce4d
|
||||
# via -r src/backend/requirements.in
|
||||
et-xmlfile==2.0.0 \
|
||||
--hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa \
|
||||
|
|
@ -864,20 +864,16 @@ gunicorn==26.0.0 \
|
|||
--hash=sha256:40233d26a5f0d1872916188c276e21641155111c2853f0c2cd55260aec0d24fc \
|
||||
--hash=sha256:ca9346f85e3a4aeeb64d491045c16b9a35647abd37ea15efe53080eb8b090baf
|
||||
# via -r src/backend/requirements.in
|
||||
icalendar==7.1.0 \
|
||||
--hash=sha256:10cd223c792fcc43bee4c3ebe3149d4cf32406c85cfef146624df5a0d414260f \
|
||||
--hash=sha256:6de875370d22fc4aff172ad7c439b39fb109dc2eab9ce358fcb95e8689ad7b56
|
||||
icalendar==7.1.2 \
|
||||
--hash=sha256:01c76243c76c549f58bb51510a8f0a4edb7c539726adda1356dfd0dc04fb7a53 \
|
||||
--hash=sha256:ebc43ebeb357be98984b573d975118008dee3410d8df28b054ef2943cf3e367e
|
||||
# via django-ical
|
||||
idna==3.15 \
|
||||
--hash=sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8 \
|
||||
--hash=sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc
|
||||
idna==3.16 \
|
||||
--hash=sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5 \
|
||||
--hash=sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d
|
||||
# via
|
||||
# django-anymail
|
||||
# requests
|
||||
importlib-metadata==8.7.1 \
|
||||
--hash=sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb \
|
||||
--hash=sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151
|
||||
# via opentelemetry-api
|
||||
inflection==0.5.1 \
|
||||
--hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \
|
||||
--hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
|
||||
|
|
@ -894,6 +890,10 @@ jinja2==3.1.6 \
|
|||
--hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \
|
||||
--hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
|
||||
# via -r src/backend/requirements.in
|
||||
jinxed==2.0.4 \
|
||||
--hash=sha256:58ae0a4a2930b51e9de162208c356b382f5e25b3bc0ad73e2013b02a62d84e8b \
|
||||
--hash=sha256:a92ac48923433c0a88577bb0479191788813fd5055ef17ff2b04a701a1b83f19
|
||||
# via blessed
|
||||
jmespath==1.1.0 \
|
||||
--hash=sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d \
|
||||
--hash=sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64
|
||||
|
|
@ -912,141 +912,141 @@ jwcrypto==1.5.7 \
|
|||
--hash=sha256:70204d7cca406eda8c82352e3c41ba2d946610dafd19e54403f0a1f4f18633c6 \
|
||||
--hash=sha256:729463fefe28b6de5cf1ebfda3e94f1a1b41d2799148ef98a01cb9678ebe2bb0
|
||||
# via django-oauth-toolkit
|
||||
lxml==6.1.0 \
|
||||
--hash=sha256:00750d63ef0031a05331b9223463b1c7c02b9004cef2346a5b2877f0f9494dd2 \
|
||||
--hash=sha256:022981127642fe19866d2907d76241bb07ed21749601f727d5d5dd1ce5d1b773 \
|
||||
--hash=sha256:045e387d1f4f42a418380930fa3f45c73c9b392faf67e495e58902e68e8f44a7 \
|
||||
--hash=sha256:05b9b8787e35bec69e68daf4952b2e6dfcfb0db7ecf1a06f8cdfbbac4eb71aad \
|
||||
--hash=sha256:07f98f5496f96bf724b1e3c933c107f0cbf2745db18c03d2e13a291c3afd2635 \
|
||||
--hash=sha256:08950a23f296b3f83521577274e3d3b0f3d739bf2e68d01a752e4288bc50d286 \
|
||||
--hash=sha256:0d082495c5fcf426e425a6e28daaba1fcb6d8f854a4ff01effb1f1f381203eb9 \
|
||||
--hash=sha256:0f0f08beb0182e3e9a86fae124b3c47a7b41b7b69b225e1377db983802404e54 \
|
||||
--hash=sha256:1081dd10bc6fa437db2500e13993abf7cc30716d0a2f40e65abb935f02ec559c \
|
||||
--hash=sha256:11a873c77a181b4fef9c2e357d08ed399542c2af1390101da66720a19c7c9618 \
|
||||
--hash=sha256:183bfb45a493081943be7ea2b5adfc2b611e1cf377cefa8b8a8be404f45ef9a7 \
|
||||
--hash=sha256:19f4164243fc206d12ed3d866e80e74f5bc3627966520da1a5f97e42c32a3f39 \
|
||||
--hash=sha256:1ae225f66e5938f4fa29d37e009a3bb3b13032ac57eb4eb42afa44f6e4054e69 \
|
||||
--hash=sha256:1bc4cc83fb7f66ffb16f74d6dd0162e144333fc36ebcce32246f80c8735b2551 \
|
||||
--hash=sha256:1dd6a1c3ad4cb674f44525d9957f3e9c209bb6dd9213245195167a281fcc2bdc \
|
||||
--hash=sha256:20cf4d0651987c906a2f5cba4e3a8d6ba4bfdf973cfe2a96c0d6053888ea2ecd \
|
||||
--hash=sha256:2173a7bffe97667bbf0767f8a99e587740a8c56fdf3befac4b09cb29a80276fd \
|
||||
--hash=sha256:21c3302068f50d1e8728c67c87ba92aa87043abee517aa2576cca1855326b405 \
|
||||
--hash=sha256:23a5dc68e08ed13331d61815c08f260f46b4a60fdd1640bbeb82cf89a9d90289 \
|
||||
--hash=sha256:23cad0cc86046d4222f7f418910e46b89971c5a45d3c8abfad0f64b7b05e4a9b \
|
||||
--hash=sha256:2593a0a6621545b9095b71ad74ed4226eba438a7d9fc3712a99bdb15508cf93a \
|
||||
--hash=sha256:264c605ab9c0e4aa1a679636f4582c4d3313700009fac3ec9c3412ed0d8f3e1d \
|
||||
--hash=sha256:26c5272c6a4bf4cf32d3f5a7890c942b0e04438691157d341616d02cca74d4bd \
|
||||
--hash=sha256:26dd9f57ee3bd41e7d35b4c98a2ffd89ed11591649f421f0ec19f67d50ec67ac \
|
||||
--hash=sha256:28902146ffbe5222df411c5d19e5352490122e14447e98cd118907ee3fd6ee62 \
|
||||
--hash=sha256:29f5c00cb7d752bce2c70ebd2d31b0a42f9499ffdd3ecb2f31a5b73ee43031ad \
|
||||
--hash=sha256:30e7b2ed63b6c8e97cca8af048589a788ab5c9c905f36d9cf1c2bb549f450d2f \
|
||||
--hash=sha256:32662519149fd7a9db354175aa5e417d83485a8039b8aaa62f873ceee7ea4cad \
|
||||
--hash=sha256:363e47283bde87051b821826e71dde47f107e08614e1aa312ba0c5711e77738c \
|
||||
--hash=sha256:3648f20d25102a22b6061c688beb3a805099ea4beb0a01ce62975d926944d292 \
|
||||
--hash=sha256:37448bf9c7d7adfc5254763901e2bbd6bb876228dfc1fc7f66e58c06368a7544 \
|
||||
--hash=sha256:37fabd1452852636cf38ecdcc9dd5ca4bba7a35d6c53fa09725deeb894a87491 \
|
||||
--hash=sha256:398443df51c538bd578529aa7e5f7afc6c292644174b47961f3bf87fe5741120 \
|
||||
--hash=sha256:3ae5d8d5427f3cc317e7950f2da7ad276df0cfa37b8de2f5658959e618ea8512 \
|
||||
--hash=sha256:3f00972f84450204cd5d93a5395965e348956aaceaadec693a22ec743f8ae3eb \
|
||||
--hash=sha256:40d9189f80075f2e1f88db21ef815a2b17b28adf8e50aaf5c789bfe737027f32 \
|
||||
--hash=sha256:419c58fc92cc3a2c3fa5f78c63dbf5da70c1fa9c1b25f25727ecee89a96c7de2 \
|
||||
--hash=sha256:41dcc4c7b10484257cbd6c37b83ddb26df2b0e5aff5ac00d095689015af868ec \
|
||||
--hash=sha256:43e4d297f11080ec9d64a4b1ad7ac02b4484c9f0e2179d9c4ef78e886e747b88 \
|
||||
--hash=sha256:45e9dfbd1b661eb64ba0d4dbe762bd210c42d86dd1e5bd2bdf89d634231beb43 \
|
||||
--hash=sha256:4642e04449a1e164b5ff71ffd901ddb772dfabf5c9adf1b7be5dffe1212bc037 \
|
||||
--hash=sha256:468479e52ecf3ec23799c863336d02c05fc2f7ffd1a1424eeeb9a28d4eb69d13 \
|
||||
--hash=sha256:47024feaae386a92a146af0d2aeed65229bf6fff738e6a11dda6b0015fb8fd03 \
|
||||
--hash=sha256:481d6e2104285d9add34f41b42b247b76b61c5b5c26c303c2e9707bbf8bd9a64 \
|
||||
--hash=sha256:4937460dc5df0cdd2f06a86c285c28afda06aefa3af949f9477d3e8df430c485 \
|
||||
--hash=sha256:4a1503c56e4e2b38dc76f2f2da7bae69670c0f1933e27cfa34b2fa5876410b16 \
|
||||
--hash=sha256:4b89b098105b8599dc57adac95d1813409ac476d3c948a498775d3d0c6124bfb \
|
||||
--hash=sha256:4bd1bdb8a9e0e2dd229de19b5f8aebac80e916921b4b2c6ef8a52bc131d0c1f9 \
|
||||
--hash=sha256:4e2c54d6b47361d0f1d3bc8d4e082ad87201e56ccdcca4d3b9ee3644ff595ec8 \
|
||||
--hash=sha256:52b0ac6903cf74ebf997eb8c682d2fbac7d1ab7e4c552413eec55868a9b73f39 \
|
||||
--hash=sha256:546b66c0dd1bb8d9fa89d7123e5fa19a8aff3a1f2141eb22df96112afb17b842 \
|
||||
--hash=sha256:56971379bc5ee8037c5a0f09fa88f66cdb7d37c3e38af3e45cf539f41131ac1f \
|
||||
--hash=sha256:5715e0e28736a070f3f34a7ccc09e2fdcba0e3060abbcf61a1a5718ff6d6b105 \
|
||||
--hash=sha256:5cfa1a34df366d9dc0d5eaf420f4cf2bb1e1bebe1066d1c2fc28c179f8a4004c \
|
||||
--hash=sha256:5d27bbe326c6b539c64b42638b18bc6003a8d88f76213a97ac9ed4f885efeab7 \
|
||||
--hash=sha256:6262b87f9e5c1e5fe501d6c153247289af42eb44ad7660b9b3de17baaf92d6f6 \
|
||||
--hash=sha256:63aeafc26aac0be8aff14af7871249e87ea1319be92090bfd632ec68e03b16a5 \
|
||||
--hash=sha256:690022c7fae793b0489aa68a658822cea83e0d5933781811cabbf5ea3bcfe73d \
|
||||
--hash=sha256:6fd8b1df8254ff4fd93fd31da1fc15770bde23ac045be9bb1f87425702f61cc9 \
|
||||
--hash=sha256:73becf6d8c81d4c76b1014dbd3584cb26d904492dcf73ca85dc8bff08dcd6d2d \
|
||||
--hash=sha256:73d658216fc173cf2c939e90e07b941c5e12736b0bf6a99e7af95459cfe8eabb \
|
||||
--hash=sha256:75c4c7c619a744f972f4451bf5adf6d0fb00992a1ffc9fd78e13b0bc817cc99f \
|
||||
--hash=sha256:76b958b4ea3104483c20f74866d55aa056546e15ebe83dd7aecd63698f43b755 \
|
||||
--hash=sha256:77b9f99b17cbf14026d1e618035077060fc7195dd940d025149f3e2e830fbfcb \
|
||||
--hash=sha256:7ba11752e346bd804ea312ec2eea2532dfa8b8d3261d81a32ef9e6ab16256280 \
|
||||
--hash=sha256:7da13bb6fbadfafb474e0226a30570a3445cfd47c86296f2446dafbd77079ace \
|
||||
--hash=sha256:7e39ab3a28af7784e206d8606ec0e4bcad0190f63a492bca95e94e5a4aef7f6e \
|
||||
--hash=sha256:7f4a77d6f7edf9230cee3e1f7f6764722a41604ee5681844f18db9a81ea0ec33 \
|
||||
--hash=sha256:80410c3a7e3c617af04de17caa9f9f20adaa817093293d69eae7d7d0522836f5 \
|
||||
--hash=sha256:81ff55c70b67d19d52b6fd118a114c0a4c97d799cd3089ff9bd9e2ff4b414ee2 \
|
||||
--hash=sha256:857efde87d365706590847b916baff69c0bc9252dc5af030e378c9800c0b10e3 \
|
||||
--hash=sha256:89e8d73d09ac696a5ba42ec69787913d53284f12092f651506779314f10ba585 \
|
||||
--hash=sha256:8c11b984b5ce6add4dccc7144c7be5d364d298f15b0c6a57da1991baedc750ce \
|
||||
--hash=sha256:8c8984e1d8c4b3949e419158fda14d921ff703a9ed8a47236c6eb7a2b6cb4946 \
|
||||
--hash=sha256:8e369cbd690e788c8d15e56222d91a09c6a417f49cbc543040cba0fe2e25a79e \
|
||||
--hash=sha256:9147d8e386ec3b82c3b15d88927f734f565b0aaadef7def562b853adca45784a \
|
||||
--hash=sha256:920354904d1cb86577d4b3cfe2830c2dbe81d6f4449e57ada428f1609b5985f7 \
|
||||
--hash=sha256:942454ff253da14218f972b23dc72fa4edf6c943f37edd19cd697618b626fac5 \
|
||||
--hash=sha256:972a6451204798675407beaad97b868d0c733d9a74dafefc63120b81b8c2de28 \
|
||||
--hash=sha256:976a6b39b1b13e8c354ad8d3f261f3a4ac6609518af91bdb5094760a08f132c4 \
|
||||
--hash=sha256:97faa0860e13b05b15a51fb4986421ef7a30f0b3334061c416e0981e9450ca4c \
|
||||
--hash=sha256:9c03e048b6ce8e77b09c734e931584894ecd58d08296804ca2d0b184c933ce50 \
|
||||
--hash=sha256:9e7b0a4ca6dcc007a4cef00a761bba2dea959de4bd2df98f926b33c92ca5dfb9 \
|
||||
--hash=sha256:9eb667bf50856c4a58145f8ca2d5e5be160191e79eb9e30855a476191b3c3495 \
|
||||
--hash=sha256:9f93d5b8b07f73e8c77e3c6556a3db269918390c804b5e5fcdd4858232cc8f16 \
|
||||
--hash=sha256:a0092f2b107b69601adf562a57c956fbb596e05e3e6651cabd3054113b007e45 \
|
||||
--hash=sha256:a02ca8fe48815bddcfca3248efe54451abb9dbf2f7d1c5744c8aa4142d476919 \
|
||||
--hash=sha256:a1d9b99e5b2597e4f5aed2484fef835256fa1b68a19e4265c97628ef4bf8bcf4 \
|
||||
--hash=sha256:a2853c8b2170cc6cd54a6b4d50d2c1a8a7aeca201f23804b4898525c7a152cfc \
|
||||
--hash=sha256:a31286dbb5e74c8e9a5344465b77ab4c5bd511a253b355b5ca2fae7e579fafec \
|
||||
--hash=sha256:a86f06f059e22a0d574990ee2df24ede03f7f3c68c1336293eee9536c4c776cd \
|
||||
--hash=sha256:ab863fd37458fed6456525f297d21239d987800c46e67da5ef04fc6b3dd93ac8 \
|
||||
--hash=sha256:ac4db068889f8772a4a698c5980ec302771bb545e10c4b095d4c8be26749616f \
|
||||
--hash=sha256:b6c2f225662bc5ad416bdd06f72ca301b31b39ce4261f0e0097017fc2891b940 \
|
||||
--hash=sha256:bb40648d96157f9081886defe13eac99253e663be969ff938a9289eff6e47b72 \
|
||||
--hash=sha256:bba078de0031c219e5dd06cf3e6bf8fb8e6e64a77819b358f53bb132e3e03366 \
|
||||
--hash=sha256:bc783ee3147e60a25aa0445ea82b3e8aabb83b240f2b95d32cb75587ff781814 \
|
||||
--hash=sha256:be10838781cb3be19251e276910cd508fe127e27c3242e50521521a0f3781690 \
|
||||
--hash=sha256:bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13 \
|
||||
--hash=sha256:c08da09dc003c9e8c70e06b53a11db6fb3b250c21c4236b03c7d7b443c318e7a \
|
||||
--hash=sha256:c3592631e652afa34999a088f98ba7dfc7d6aff0d535c410bea77a71743f3819 \
|
||||
--hash=sha256:c4a699432846df86cc3de502ee85f445ebad748a1c6021d445f3e514d2cd4b1c \
|
||||
--hash=sha256:c4e425db0c5445ef0ad56b0eec54f89b88b2d884656e536a90b2f52aecb4ca86 \
|
||||
--hash=sha256:c53fa3a5a52122d590e847a57ccf955557b9634a7f99ff5a35131321b0a85317 \
|
||||
--hash=sha256:c6854e9cf99c84beb004eecd7d3a3868ef1109bf2b1df92d7bc11e96a36c2180 \
|
||||
--hash=sha256:c748ebcb6877de89f48ab90ca96642ac458fff5dec291a2b9337cd4d0934e383 \
|
||||
--hash=sha256:c871299c595ee004d186f61840f0bfc4941aa3f17c8ba4a565ead7e4f4f820ee \
|
||||
--hash=sha256:cbd7b79cdcb4986ad78a2662625882747f09db5e4cd7b2ae178a88c9c51b3dfe \
|
||||
--hash=sha256:cc16682cc987a3da00aa56a3aa3075b08edb10d9b1e476938cfdbee8f3b67181 \
|
||||
--hash=sha256:cec05be8c876f92a5aa07b01d60bbb4d11cfbdd654cad0561c0d7b5c043a61b9 \
|
||||
--hash=sha256:d036ee7b99d5148072ac7c9b847193decdfeac633db350363f7bce4fff108f0e \
|
||||
--hash=sha256:d0d799ff958655781296ec870d5e2448e75150da2b3d07f13ff5b0c2c35beefd \
|
||||
--hash=sha256:d1392c569c032f78a11a25d1de1c43fff13294c793b39e19d84fade3045cbbc3 \
|
||||
--hash=sha256:d2f17a16cd8751e8eb233a7e41aecdf8e511712e00088bf9be455f604cd0d28d \
|
||||
--hash=sha256:d3829a6e6fd550a219564912d4002c537f65da4c6ae4e093cc34462f4fa027ad \
|
||||
--hash=sha256:d43aa26dcda363f21e79afa0668f5029ed7394b3bb8c92a6927a3d34e8b610ea \
|
||||
--hash=sha256:d6d8efe71429635f0559579092bb5e60560d7b9115ee38c4adbea35632e7fa24 \
|
||||
--hash=sha256:dabecc48db5f42ba348d1f5d5afdc54c6c4cc758e676926c7cd327045749517d \
|
||||
--hash=sha256:db88156fcf544cdbf0d95588051515cfdfd4c876fc66444eb98bceb5d6db76de \
|
||||
--hash=sha256:de550d129f18d8ab819651ffe4f38b1b713c7e116707de3c0c6400d0ef34fbc1 \
|
||||
--hash=sha256:e0af85773850417d994d019741239b901b22c6680206f46a34766926e466141d \
|
||||
--hash=sha256:e3c4f84b24a1fcba435157d111c4b755099c6ff00a3daee1ad281817de75ed11 \
|
||||
--hash=sha256:e3dd5fe19c9e0ac818a9c7f132a5e43c1339ec1cbbfecb1a938bd3a47875b7c9 \
|
||||
--hash=sha256:e69aa6805905807186eb00e66c6d97a935c928275182eb02ee40ba00da9623b2 \
|
||||
--hash=sha256:e80807d72f96b96ad5588cb85c75616e4f2795a7737d4630784c51497beb7776 \
|
||||
--hash=sha256:ebe33f4ec1b2de38ceb225a1749a2965855bffeef435ba93cd2d5d540783bf2f \
|
||||
--hash=sha256:f0cea5b1d3e6e77d71bd2b9972eb2446221a69dc52bb0b9c3c6f6e5700592d93 \
|
||||
--hash=sha256:f15401d8d3dbf239e23c818afc10c7207f7b95f9a307e092122b6f86dd43209a \
|
||||
--hash=sha256:f504d861d9f2a8f94020130adac88d66de93841707a23a86244263d1e54682f5 \
|
||||
--hash=sha256:fc46da94826188ed45cb53bd8e3fc076ae22675aea2087843d4735627f867c6d \
|
||||
--hash=sha256:fc7140d7a7386e6b545d41b7358f4d02b656d4053f5fa6859f92f4b9c2572c4d \
|
||||
--hash=sha256:fcf3da95e93349e0647d48d4b36a12783105bcc74cb0c416952f9988410846a3 \
|
||||
--hash=sha256:fe022f20bc4569ec66b63b3fb275a3d628d9d32da6326b2982584104db6d3086 \
|
||||
--hash=sha256:ffb34ea45a82dd637c2c97ae1bbb920850c1e59bcae79ce1c15af531d83e7215
|
||||
lxml==6.1.1 \
|
||||
--hash=sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2 \
|
||||
--hash=sha256:07a4a68e286ee7a1ed7dfb8af83e615757c0ccfe9f18c6b4ea6771388d9ba8c9 \
|
||||
--hash=sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60 \
|
||||
--hash=sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c \
|
||||
--hash=sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7 \
|
||||
--hash=sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a \
|
||||
--hash=sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83 \
|
||||
--hash=sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072 \
|
||||
--hash=sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8 \
|
||||
--hash=sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462 \
|
||||
--hash=sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0 \
|
||||
--hash=sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085 \
|
||||
--hash=sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f \
|
||||
--hash=sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30 \
|
||||
--hash=sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1 \
|
||||
--hash=sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77 \
|
||||
--hash=sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740 \
|
||||
--hash=sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b \
|
||||
--hash=sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c \
|
||||
--hash=sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621 \
|
||||
--hash=sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e \
|
||||
--hash=sha256:32ab449a5486f6c758e849bb86710d0e45edc24a04e250c01555f8f5653958f8 \
|
||||
--hash=sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca \
|
||||
--hash=sha256:34c2d737beabfe35baada43941ed519251e9a12e779031496bcd5d539fcfd730 \
|
||||
--hash=sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245 \
|
||||
--hash=sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1 \
|
||||
--hash=sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004 \
|
||||
--hash=sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d \
|
||||
--hash=sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52 \
|
||||
--hash=sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5 \
|
||||
--hash=sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf \
|
||||
--hash=sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc \
|
||||
--hash=sha256:441dd227fa0690eb9fc81edabc63cdcefc212bba99b906dcf6e32cc1a9d3e533 \
|
||||
--hash=sha256:469e3618338bd7ab5beb412d2439825479fcf0dab99e394ca563dbc4eaf6c834 \
|
||||
--hash=sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947 \
|
||||
--hash=sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a \
|
||||
--hash=sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2 \
|
||||
--hash=sha256:53c909b62a0532183542fed00c5a7218258c56292d409bc789886fe1cb04c438 \
|
||||
--hash=sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc \
|
||||
--hash=sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea \
|
||||
--hash=sha256:55b03549819867ea141c0202242c4816c82e52ec36e7e648db9d8da5a3dc3ed6 \
|
||||
--hash=sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e \
|
||||
--hash=sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c \
|
||||
--hash=sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383 \
|
||||
--hash=sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955 \
|
||||
--hash=sha256:5bec7d03d78d853597d6107854c2310ce3f761fd218fe9fe91d5101fcf6c2efe \
|
||||
--hash=sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074 \
|
||||
--hash=sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c \
|
||||
--hash=sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a \
|
||||
--hash=sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb \
|
||||
--hash=sha256:639f6c857d91d9be29bd7502348d6736dab168b54b5158cd899abf11684dc186 \
|
||||
--hash=sha256:640f97d43d867bcb9c75b3af013b64850756b746cb6bce8ace83b70da3abba9d \
|
||||
--hash=sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1 \
|
||||
--hash=sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f \
|
||||
--hash=sha256:6689e828a94eee4f139408c337bb198e014724bb8a8c26d3cfac49d119ed69a6 \
|
||||
--hash=sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736 \
|
||||
--hash=sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6 \
|
||||
--hash=sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2 \
|
||||
--hash=sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b \
|
||||
--hash=sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7 \
|
||||
--hash=sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14 \
|
||||
--hash=sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009 \
|
||||
--hash=sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca \
|
||||
--hash=sha256:76447f65250ed2501ead1a1552f5ce8edff159a86f308348e6a9c4acb5e1f1b4 \
|
||||
--hash=sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635 \
|
||||
--hash=sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee \
|
||||
--hash=sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e \
|
||||
--hash=sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9 \
|
||||
--hash=sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603 \
|
||||
--hash=sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08 \
|
||||
--hash=sha256:83b6b30eb131da7a75b601f28c5d6971e6ed3e887919bf6b6a1ad3c2df289080 \
|
||||
--hash=sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525 \
|
||||
--hash=sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5 \
|
||||
--hash=sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f \
|
||||
--hash=sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067 \
|
||||
--hash=sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e \
|
||||
--hash=sha256:8be8ad51249698103d24b0571df35a10990fbe93dd043b6c024172189485f5e3 \
|
||||
--hash=sha256:8d43ca737b20e106e4aebc42b2f3ae19f00ba63d7eb731698ee083d72d15646f \
|
||||
--hash=sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485 \
|
||||
--hash=sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13 \
|
||||
--hash=sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383 \
|
||||
--hash=sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315 \
|
||||
--hash=sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e \
|
||||
--hash=sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c \
|
||||
--hash=sha256:9f76acfb5f68ba982635a53fd985a8044be98a35b43232c2a1ee235ffab3e1dd \
|
||||
--hash=sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099 \
|
||||
--hash=sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660 \
|
||||
--hash=sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510 \
|
||||
--hash=sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a \
|
||||
--hash=sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b \
|
||||
--hash=sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5 \
|
||||
--hash=sha256:aae97dfdb60715c164419ac2532a76d013c3918a665eb6cb7288098b5f349aaf \
|
||||
--hash=sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28 \
|
||||
--hash=sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00 \
|
||||
--hash=sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef \
|
||||
--hash=sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1 \
|
||||
--hash=sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955 \
|
||||
--hash=sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590 \
|
||||
--hash=sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137 \
|
||||
--hash=sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf \
|
||||
--hash=sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40 \
|
||||
--hash=sha256:bdebcc8a75d38c7598dfb2c9ed852d7a9eb4a10d6e2d0764b919b802bf32ac88 \
|
||||
--hash=sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e \
|
||||
--hash=sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840 \
|
||||
--hash=sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2 \
|
||||
--hash=sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca \
|
||||
--hash=sha256:c674693f055fa2495de12292cb45e9944199d8eaef5a2dec45175c7c61cb73e3 \
|
||||
--hash=sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465 \
|
||||
--hash=sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc \
|
||||
--hash=sha256:c9a4b821dc7055bf9e05ff5719e18ec501f75c0f0bbfabd573b277559780833d \
|
||||
--hash=sha256:c9f79d5325907f13e1be0b3e4dacc1049d1dffc4aeee3c995284bea5fe0fab7d \
|
||||
--hash=sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa \
|
||||
--hash=sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a \
|
||||
--hash=sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a \
|
||||
--hash=sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206 \
|
||||
--hash=sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e \
|
||||
--hash=sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785 \
|
||||
--hash=sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8 \
|
||||
--hash=sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a \
|
||||
--hash=sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b \
|
||||
--hash=sha256:e07c65f443c887bbcf31cc1771d932ecc192a5273943589b3c7572b749f1ffb2 \
|
||||
--hash=sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6 \
|
||||
--hash=sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6 \
|
||||
--hash=sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354 \
|
||||
--hash=sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818 \
|
||||
--hash=sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84 \
|
||||
--hash=sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909 \
|
||||
--hash=sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038 \
|
||||
--hash=sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d \
|
||||
--hash=sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2 \
|
||||
--hash=sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf \
|
||||
--hash=sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc \
|
||||
--hash=sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d \
|
||||
--hash=sha256:ffecec8eb889b58ba9be5b95fb1cc78e22ea8eedea38e8736a1568fe1979250e
|
||||
# via
|
||||
# python3-saml
|
||||
# xmlsec
|
||||
|
|
@ -1184,9 +1184,9 @@ openpyxl==3.1.5 \
|
|||
--hash=sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2 \
|
||||
--hash=sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050
|
||||
# via tablib
|
||||
opentelemetry-api==1.41.1 \
|
||||
--hash=sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621 \
|
||||
--hash=sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f
|
||||
opentelemetry-api==1.42.1 \
|
||||
--hash=sha256:51a69edacadbc03a8950ace1c4c21099cacc538820ac2c9e36277e78cebba714 \
|
||||
--hash=sha256:56c63bea9f77b62856be8c47600474acad853b2924b99b1687c4cb6297166716
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
|
|
@ -1203,27 +1203,27 @@ opentelemetry-api==1.41.1 \
|
|||
# opentelemetry-instrumentation-wsgi
|
||||
# opentelemetry-sdk
|
||||
# opentelemetry-semantic-conventions
|
||||
opentelemetry-exporter-otlp==1.41.1 \
|
||||
--hash=sha256:299a2f0541ca175df186f5ac58fd5db177ba1e9b72b0826049062f750d55b47f \
|
||||
--hash=sha256:db276c5a80c02b063994e80950d00ca1bfddcf6520f608335b7dc2db0c0eb9c6
|
||||
opentelemetry-exporter-otlp==1.42.1 \
|
||||
--hash=sha256:2d9ebaed714377a67d224d46795ddcc11d2c877fa5de35fda70b6f3b010729a9 \
|
||||
--hash=sha256:aedd54545bb0587cd45210abdc8be545af9c01413f3307786e276df1e3c83bee
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-exporter-otlp-proto-common==1.41.1 \
|
||||
--hash=sha256:0e253156ea9c36b0bd3d2440c5c9ba7dd1f3fb64ba7a08fc85fbac536b56e1fb \
|
||||
--hash=sha256:10da74dad6a49344b9b7b21b6182e3060373a235fde1528616d5f01f92e66aa9
|
||||
opentelemetry-exporter-otlp-proto-common==1.42.1 \
|
||||
--hash=sha256:04f1f01fb597c4249dfcd7f8b861c902c2102369d376d9d346ff38de4469a2ee \
|
||||
--hash=sha256:f48d395ab815b444da118868977e9798ea354c25737d5cf39578ae894011c140
|
||||
# via
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-exporter-otlp-proto-grpc==1.41.1 \
|
||||
--hash=sha256:537926dcef951136992479af1d9cd88f25e33d56c530e9f020ed57774dca2f94 \
|
||||
--hash=sha256:b05df8fa1333dc9a3fda36b676b96b5095ab6016d3f0c3296d430d629ba1443b
|
||||
opentelemetry-exporter-otlp-proto-grpc==1.42.1 \
|
||||
--hash=sha256:0ae1177e2038b18a929b3098215243631ef91136cba26b7e2b12790ceb7e87cc \
|
||||
--hash=sha256:975c4461f167dd8ed8857d68d3b6b25f3d272eab896f6a9470d0f5b90e2faf15
|
||||
# via opentelemetry-exporter-otlp
|
||||
opentelemetry-exporter-otlp-proto-http==1.41.1 \
|
||||
--hash=sha256:1a21e8f49c7a946d935551e90947d6c3eb39236723c6624401da0f33d68edcb4 \
|
||||
--hash=sha256:4747a9604c8550ab38c6fd6180e2fcb80de3267060bef2c306bad3cb443302bc
|
||||
opentelemetry-exporter-otlp-proto-http==1.42.1 \
|
||||
--hash=sha256:00a16da1b312a1d6c7233d600d557c91df71125af73020f3b9a7765bd699d59d \
|
||||
--hash=sha256:bf142a21035d7571ac3a09cb2e5639f49886f243972883cfe777ed3bf02b734d
|
||||
# via opentelemetry-exporter-otlp
|
||||
opentelemetry-instrumentation==0.62b1 \
|
||||
--hash=sha256:90e92a905ba4f84db06ac3aec96701df6c079b2d66e9379f8739f0a1bdcc7f45 \
|
||||
--hash=sha256:976fc6e640f2006599e97429c949e622c108d0c17c2059347d1e6c93c707f257
|
||||
opentelemetry-instrumentation==0.63b1 \
|
||||
--hash=sha256:32368d6ae52c8de20aa790a6ad86b10a76f09956092337ae37d675773990e541 \
|
||||
--hash=sha256:f1986716d52cc316ea5f60189098726a9071d8ecc0eee96c9ed110be08bade9c
|
||||
# via
|
||||
# opentelemetry-instrumentation-dbapi
|
||||
# opentelemetry-instrumentation-django
|
||||
|
|
@ -1234,75 +1234,76 @@ opentelemetry-instrumentation==0.62b1 \
|
|||
# opentelemetry-instrumentation-sqlite3
|
||||
# opentelemetry-instrumentation-system-metrics
|
||||
# opentelemetry-instrumentation-wsgi
|
||||
opentelemetry-instrumentation-dbapi==0.62b1 \
|
||||
--hash=sha256:82755a0f013980b2c000a10452fb91ab5135b937a8afe37c45f34e62ecc7a2b8 \
|
||||
--hash=sha256:dd2cc4085e832a708835218833b839a88ef0ace66851d14debefe6b2ef363a3c
|
||||
opentelemetry-instrumentation-dbapi==0.63b1 \
|
||||
--hash=sha256:1bc842ddcacb7ec3622ef306ffdb3c584bf97df79d381e03604ea6eb23c63781 \
|
||||
--hash=sha256:406978ed56bcfc5fd246fd918e6b36d0f5de26fa396c78cf63326a7b530597c8
|
||||
# via
|
||||
# opentelemetry-instrumentation-psycopg
|
||||
# opentelemetry-instrumentation-pymysql
|
||||
# opentelemetry-instrumentation-sqlite3
|
||||
opentelemetry-instrumentation-django==0.62b1 \
|
||||
--hash=sha256:268c9b3d234510ab835acea0524ba65361389f6e2c291b495ba8072c7bb59003 \
|
||||
--hash=sha256:5ac96ef25019fbea5e2739c9b4b7ce17e4379e2b1ec9fdce6b696a5c09ceabbe
|
||||
opentelemetry-instrumentation-django==0.63b1 \
|
||||
--hash=sha256:909ea4afbb18f16eb811d7ac330ed0f6fda7765191d49bccb8cca38c4fbc005f \
|
||||
--hash=sha256:f2071d2f92e4779c5a14dd452b0dfe426343599e6efa9d888304fb639a9f3101
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-psycopg==0.62b1 \
|
||||
--hash=sha256:61c8a1794d6e11c7bca1735c2b87ef8c04b5d7202e962409d66d204f84c01be1 \
|
||||
--hash=sha256:f08e843e81656271ddc8c8194a54a5f3c8ebe0cb137e3166af9a2ff014978b5e
|
||||
opentelemetry-instrumentation-psycopg==0.63b1 \
|
||||
--hash=sha256:4d74ec2dda8e54ead9bd71f134af984792f77e1d8809591ae53edadddd4c8fc0 \
|
||||
--hash=sha256:86819f4cccea21a47920807826495797b7261cc1893c8e855415e76fb7b8e2e8
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-pymysql==0.62b1 \
|
||||
--hash=sha256:12e42f891978a3a41bc564bb81e2299d3654659589f705064a4bb10e93e493f8 \
|
||||
--hash=sha256:50d2efdde1bd8d826cbceffe5b3ce0ffd421349d609200eab0f3e632945cd304
|
||||
opentelemetry-instrumentation-pymysql==0.63b1 \
|
||||
--hash=sha256:2cf6a24e136b5b0c3f6e59675fc44b42ad2b97474b075a82859f9868a9252648 \
|
||||
--hash=sha256:6b54b83c86ac6c2e8dae642bbee4894e2283ceb5da23d571f1abb7060f7b62f4
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-redis==0.62b1 \
|
||||
--hash=sha256:2d3c421d95e05ade075bee5becbe34e743b1cdf5bdee2085cb524f88c4f13dcb \
|
||||
--hash=sha256:9aedd02c1acf631251d1d676634db47da9da04e0a626cd0c7d83fe0eb791d165
|
||||
opentelemetry-instrumentation-redis==0.63b1 \
|
||||
--hash=sha256:28d235159df43cc2bc8779af5c602afad1e08603fff75ac8ca34dd1bf30a9cb9 \
|
||||
--hash=sha256:f0e51c4006f68e340abbf28a7995feff004de78649697cbdf3bac0072cacd082
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-requests==0.62b1 \
|
||||
--hash=sha256:67a79c4b67e2192445c1cf03d62126fa623065688d8bd1a9f87f858b0e5f0286 \
|
||||
--hash=sha256:ca348f2f51b715c21e86d82106d784f7069ae849c3e636ab37e34dc0ba510b8c
|
||||
opentelemetry-instrumentation-requests==0.63b1 \
|
||||
--hash=sha256:513fcaa3d93debbdb359c00ce1a137a34a89ee908c51ac43beb7e8c18ac2b3cd \
|
||||
--hash=sha256:935c980a11e33bfd7ed969c741e4bd7c84077045651469f10e163534368d87f7
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-sqlite3==0.62b1 \
|
||||
--hash=sha256:14ba18aed35a01e1d89bb814e49f7d6dd90bb68b2034ccf047801ca4659dba27 \
|
||||
--hash=sha256:3ab0d614bab9956126ce81a22315bf58d56d653a65675a66e8b525f880ec3016
|
||||
opentelemetry-instrumentation-sqlite3==0.63b1 \
|
||||
--hash=sha256:3d61afda8358dc32135fabd27e5934bd25ea0eed68d64c34508f24ba8d723efc \
|
||||
--hash=sha256:cc11c68cccde061dc8bcc5f80fe00bb0105a0fbb11b390859a23ca91ccd4e3b6
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-system-metrics==0.62b1 \
|
||||
--hash=sha256:260130cb63e3028290305d8f25b744fb3a279677769dd65287ce60086cc11d32 \
|
||||
--hash=sha256:b8097e0d3747102fa545723bb67f50f572a7618b6479359fa6533007d2f621aa
|
||||
opentelemetry-instrumentation-system-metrics==0.63b1 \
|
||||
--hash=sha256:995051f47876d79461aed8b7aa205d4584d90794ef864342cc748929c389bb42 \
|
||||
--hash=sha256:d6d4d7a1a854be4165143cf6420ee5894188762eb367d7bf9da5be4a83a4b632
|
||||
# via -r src/backend/requirements.in
|
||||
opentelemetry-instrumentation-wsgi==0.62b1 \
|
||||
--hash=sha256:02a364fd9c940a46b19c825c5bfe386b007d5292ef91573894164836953fe831 \
|
||||
--hash=sha256:a2df11de0113f504043e2b0fa0288238a93ee49ff607bd5100cb2d3a75bc771f
|
||||
opentelemetry-instrumentation-wsgi==0.63b1 \
|
||||
--hash=sha256:03d61c4678ce82402e7f37b6a3dbd84cb97b85b3cb416a78c2e74c7c6d9451fa \
|
||||
--hash=sha256:86779715262227d3436bdfb16aabd1c524b0f236725a69e8754ceda76c6d79dc
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# opentelemetry-instrumentation-django
|
||||
opentelemetry-proto==1.41.1 \
|
||||
--hash=sha256:0496713b804d127a4147e32849fbaf5683fac8ee98550e8e7679cd706c289720 \
|
||||
--hash=sha256:4b9d2eb631237ea43b80e16c073af438554e32bc7e9e3f8ca4a9582f900020e5
|
||||
opentelemetry-proto==1.42.1 \
|
||||
--hash=sha256:c6a51e6b4f05ae63565f3a113217f3d2bfaec68f78c02d7a6c85f9010d1cfca6 \
|
||||
--hash=sha256:dedb74cba2886c59c7789b227a7a670613025a07489040050aedff6e5c0fb43c
|
||||
# via
|
||||
# opentelemetry-exporter-otlp-proto-common
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-sdk==1.41.1 \
|
||||
--hash=sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6 \
|
||||
--hash=sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d
|
||||
opentelemetry-sdk==1.42.1 \
|
||||
--hash=sha256:083cd4bbfaa5aa7b5a9e552430d9951219967cfb27aa61feb13a77aba1fc839d \
|
||||
--hash=sha256:8c834e8f8c9ba4171d4ec843d0cb8a67e4c7394d3f9e9297e582cbd9456ddbf7
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# opentelemetry-exporter-otlp-proto-grpc
|
||||
# opentelemetry-exporter-otlp-proto-http
|
||||
opentelemetry-semantic-conventions==0.62b1 \
|
||||
--hash=sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802 \
|
||||
--hash=sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c
|
||||
opentelemetry-semantic-conventions==0.63b1 \
|
||||
--hash=sha256:3daf963611334b365e98a57438183eb012d3bfb40b2d931a9af613476b8701a9 \
|
||||
--hash=sha256:dfe5ef4dee82586b746f522b818ceb298d00b3d59f660042bd79404bff8d0682
|
||||
# via
|
||||
# opentelemetry-instrumentation
|
||||
# opentelemetry-instrumentation-dbapi
|
||||
# opentelemetry-instrumentation-django
|
||||
# opentelemetry-instrumentation-redis
|
||||
# opentelemetry-instrumentation-requests
|
||||
# opentelemetry-instrumentation-system-metrics
|
||||
# opentelemetry-instrumentation-wsgi
|
||||
# opentelemetry-sdk
|
||||
opentelemetry-util-http==0.62b1 \
|
||||
--hash=sha256:adf6facbb89aef8f8bc566e2f04624942ba08a7b678b3479a91051a8f4dc70a3 \
|
||||
--hash=sha256:c57e8a6c19fc422c288e6074e882f506f85030b69b7376182f74f9257b9261f0
|
||||
opentelemetry-util-http==0.63b1 \
|
||||
--hash=sha256:6284194028c59cd439f8acfe388145069a6127f11dc077e1344a2094adacc3f8 \
|
||||
--hash=sha256:ba1268f00922ee522dba2ae38458060f99486e7385a8056985901ca9685adfff
|
||||
# via
|
||||
# opentelemetry-instrumentation-django
|
||||
# opentelemetry-instrumentation-requests
|
||||
|
|
@ -1490,9 +1491,9 @@ pydyf==0.12.1 \
|
|||
--hash=sha256:ea25b4e1fe7911195cb57067560daaa266639184e8335365cc3ee5214e7eaadc \
|
||||
--hash=sha256:fbd7e759541ac725c29c506612003de393249b94310ea78ae44cb1d04b220095
|
||||
# via weasyprint
|
||||
pyjwt[crypto]==2.12.1 \
|
||||
--hash=sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c \
|
||||
--hash=sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b
|
||||
pyjwt[crypto]==2.13.0 \
|
||||
--hash=sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423 \
|
||||
--hash=sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728
|
||||
# via
|
||||
# django-allauth
|
||||
# djangorestframework-simplejwt
|
||||
|
|
@ -1523,9 +1524,9 @@ pynacl==1.6.2 \
|
|||
--hash=sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2 \
|
||||
--hash=sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9
|
||||
# via paramiko
|
||||
pypdf==6.11.0 \
|
||||
--hash=sha256:062b51c81b0910e6d2755e99e1c5547a0a23b7d0a32322af66240d8edcfabe87 \
|
||||
--hash=sha256:769394d5756d5b304c9b6bef88b54b1816b328e7e6fc9254e625529a15ed4ab8
|
||||
pypdf==6.12.1 \
|
||||
--hash=sha256:3953a097b9f26d4e0ead5ff95943d9971377557662a91d8872186053cd71d30a \
|
||||
--hash=sha256:8fa2a2321cf16247ed848bd7c97f193a60c08670d04abed5b0138327e51c43b0
|
||||
# via -r src/backend/requirements.in
|
||||
pyphen==0.17.2 \
|
||||
--hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \
|
||||
|
|
@ -2130,10 +2131,6 @@ xmlsec==1.3.17 \
|
|||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# python3-saml
|
||||
zipp==3.23.1 \
|
||||
--hash=sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc \
|
||||
--hash=sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110
|
||||
# via importlib-metadata
|
||||
zopfli==0.4.1 \
|
||||
--hash=sha256:02086247dd12fda929f9bfe8b3962b6bcdbfc8c82e99255aebcf367867cf0760 \
|
||||
--hash=sha256:07a5cdc5d1aaa6c288c5d9f5a5383042ba743641abf8e2fd898dcad622d8a38e \
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export interface ModelInformationInterface {
|
|||
url_detail?: string;
|
||||
api_endpoint: ApiEndpoints;
|
||||
admin_url?: string;
|
||||
pk_field?: string;
|
||||
supports_barcode?: boolean;
|
||||
icon: keyof InvenTreeIconType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { DefaultMantineColor, MantineStyleProp } from '@mantine/core';
|
|||
import type { UseFormReturnType } from '@mantine/form';
|
||||
import type { JSX, ReactNode } from 'react';
|
||||
import type { FieldValues, UseFormReturn } from 'react-hook-form';
|
||||
import type { NavigateFunction } from 'react-router-dom';
|
||||
import type { ApiEndpoints } from '../enums/ApiEndpoints';
|
||||
import type { ModelType } from '../enums/ModelType';
|
||||
import type { PathParams, UiSizeType } from './Core';
|
||||
|
|
@ -160,6 +161,7 @@ export type ApiFormFieldSet = Record<string, ApiFormFieldType>;
|
|||
* @param modelType : Define a model type for this form
|
||||
* @param follow : Boolean, follow the result of the form (if possible)
|
||||
* @param table : Table to update on success (if provided)
|
||||
* @param navigate : Optional navigate function to use for following results (if follow is true)
|
||||
*/
|
||||
export interface ApiFormProps {
|
||||
url: ApiEndpoints | string;
|
||||
|
|
@ -189,6 +191,7 @@ export interface ApiFormProps {
|
|||
follow?: boolean;
|
||||
actions?: ApiFormAction[];
|
||||
timeout?: number;
|
||||
navigate?: NavigateFunction;
|
||||
keepOpenOption?: boolean;
|
||||
onKeepOpenChange?: (keepOpen: boolean) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export interface InstanceRenderInterface {
|
|||
link?: boolean;
|
||||
navigate?: any;
|
||||
showSecondary?: boolean;
|
||||
showHover?: boolean;
|
||||
extra?: Record<string, any>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@
|
|||
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
||||
"@lingui/cli": "^5.9.2",
|
||||
"@lingui/macro": "^5.9.2",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@playwright/test": "^1.16.0",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/react": "^19.2.14",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { IconX } from '@tabler/icons-react';
|
|||
import { Boundary } from '@lib/components/Boundary';
|
||||
|
||||
import type { ModelType } from '@lib/index';
|
||||
import type { InvenTreeIconType } from '@lib/types/Icons';
|
||||
import type { JSX } from 'react';
|
||||
|
||||
/**
|
||||
|
|
@ -22,6 +23,7 @@ export interface DashboardWidgetProps {
|
|||
minWidth?: number;
|
||||
minHeight?: number;
|
||||
modelType?: ModelType;
|
||||
icon?: keyof InvenTreeIconType;
|
||||
render: () => JSX.Element;
|
||||
visible?: () => boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ import {
|
|||
Tooltip
|
||||
} from '@mantine/core';
|
||||
import { useDebouncedValue } from '@mantine/hooks';
|
||||
import { IconBackspace, IconLayoutGridAdd } from '@tabler/icons-react';
|
||||
import { IconBackspace } from '@tabler/icons-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { StylishText } from '@lib/components/StylishText';
|
||||
import { InvenTreeIcon } from '../../functions/icons';
|
||||
import { useDashboardItems } from '../../hooks/UseDashboardItems';
|
||||
|
||||
/**
|
||||
|
|
@ -105,7 +106,7 @@ export default function DashboardWidgetDrawer({
|
|||
onAddWidget(widget.label);
|
||||
}}
|
||||
>
|
||||
<IconLayoutGridAdd />
|
||||
<InvenTreeIcon icon={widget.icon ?? 'dashboard'} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Table.Td>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ColorToggleDashboardWidget from './widgets/ColorToggleWidget';
|
|||
import GetStartedWidget from './widgets/GetStartedWidget';
|
||||
import LanguageSelectDashboardWidget from './widgets/LanguageSelectWidget';
|
||||
import NewsWidget from './widgets/NewsWidget';
|
||||
import OrderHistoryWidget from './widgets/OrderHistoryWidget';
|
||||
import QueryCountDashboardWidget from './widgets/QueryCountDashboardWidget';
|
||||
import QueryDashboardWidget from './widgets/QueryDashboardWidget';
|
||||
import StocktakeDashboardWidget from './widgets/StocktakeDashboardWidget';
|
||||
|
|
@ -43,6 +44,7 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
title: t`Invalid BOMs`,
|
||||
description: t`Assemblies requiring bill of materials validation`,
|
||||
modelType: ModelType.part,
|
||||
icon: 'exclamation',
|
||||
params: {
|
||||
active: true, // Only show active parts
|
||||
assembly: true, // Only show parts which are assemblies
|
||||
|
|
@ -94,7 +96,8 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
description: t`Show the number of stock items which have expired`,
|
||||
modelType: ModelType.stockitem,
|
||||
params: { expired: true },
|
||||
enabled: globalSettings.isSet('STOCK_ENABLE_EXPIRY')
|
||||
enabled: globalSettings.isSet('STOCK_ENABLE_EXPIRY'),
|
||||
icon: 'overdue'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Stale Stock Items`,
|
||||
|
|
@ -116,14 +119,16 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
label: 'ovr-bo',
|
||||
description: t`Show the number of build orders which are overdue`,
|
||||
modelType: ModelType.build,
|
||||
params: { overdue: true }
|
||||
params: { overdue: true },
|
||||
icon: 'overdue'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Assigned Build Orders`,
|
||||
label: 'asn-bo',
|
||||
description: t`Show the number of build orders which are assigned to you`,
|
||||
modelType: ModelType.build,
|
||||
params: { assigned_to_me: true, outstanding: true }
|
||||
params: { assigned_to_me: true, outstanding: true },
|
||||
icon: 'responsible'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Active Sales Orders`,
|
||||
|
|
@ -137,14 +142,16 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
label: 'ovr-so',
|
||||
description: t`Show the number of sales orders which are overdue`,
|
||||
modelType: ModelType.salesorder,
|
||||
params: { overdue: true }
|
||||
params: { overdue: true },
|
||||
icon: 'overdue'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Assigned Sales Orders`,
|
||||
label: 'asn-so',
|
||||
description: t`Show the number of sales orders which are assigned to you`,
|
||||
modelType: ModelType.salesorder,
|
||||
params: { assigned_to_me: true, outstanding: true }
|
||||
params: { assigned_to_me: true, outstanding: true },
|
||||
icon: 'responsible'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Pending Shipments`,
|
||||
|
|
@ -165,14 +172,16 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
label: 'ovr-po',
|
||||
description: t`Show the number of purchase orders which are overdue`,
|
||||
modelType: ModelType.purchaseorder,
|
||||
params: { overdue: true }
|
||||
params: { overdue: true },
|
||||
icon: 'overdue'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Assigned Purchase Orders`,
|
||||
label: 'asn-po',
|
||||
description: t`Show the number of purchase orders which are assigned to you`,
|
||||
modelType: ModelType.purchaseorder,
|
||||
params: { assigned_to_me: true, outstanding: true }
|
||||
params: { assigned_to_me: true, outstanding: true },
|
||||
icon: 'responsible'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Active Return Orders`,
|
||||
|
|
@ -186,14 +195,16 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
label: 'ovr-ro',
|
||||
description: t`Show the number of return orders which are overdue`,
|
||||
modelType: ModelType.returnorder,
|
||||
params: { overdue: true }
|
||||
params: { overdue: true },
|
||||
icon: 'overdue'
|
||||
}),
|
||||
QueryCountDashboardWidget({
|
||||
title: t`Assigned Return Orders`,
|
||||
label: 'asn-ro',
|
||||
description: t`Show the number of return orders which are assigned to you`,
|
||||
modelType: ModelType.returnorder,
|
||||
params: { assigned_to_me: true, outstanding: true }
|
||||
params: { assigned_to_me: true, outstanding: true },
|
||||
icon: 'responsible'
|
||||
})
|
||||
];
|
||||
|
||||
|
|
@ -207,6 +218,26 @@ function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
|
|||
});
|
||||
}
|
||||
|
||||
function BuiltinHistoryWidgets(): DashboardWidgetProps[] {
|
||||
return [
|
||||
OrderHistoryWidget({
|
||||
modelType: ModelType.build
|
||||
}),
|
||||
OrderHistoryWidget({
|
||||
modelType: ModelType.salesorder
|
||||
}),
|
||||
OrderHistoryWidget({
|
||||
modelType: ModelType.purchaseorder
|
||||
}),
|
||||
OrderHistoryWidget({
|
||||
modelType: ModelType.returnorder
|
||||
}),
|
||||
OrderHistoryWidget({
|
||||
modelType: ModelType.transferorder
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
function BuiltinGettingStartedWidgets(): DashboardWidgetProps[] {
|
||||
return [
|
||||
{
|
||||
|
|
@ -215,6 +246,7 @@ function BuiltinGettingStartedWidgets(): DashboardWidgetProps[] {
|
|||
description: t`Getting started with InvenTree`,
|
||||
minWidth: 5,
|
||||
minHeight: 4,
|
||||
icon: 'info',
|
||||
render: () => <GetStartedWidget />
|
||||
},
|
||||
{
|
||||
|
|
@ -223,6 +255,7 @@ function BuiltinGettingStartedWidgets(): DashboardWidgetProps[] {
|
|||
description: t`The latest news from InvenTree`,
|
||||
minWidth: 5,
|
||||
minHeight: 4,
|
||||
icon: 'news',
|
||||
render: () => <NewsWidget />
|
||||
}
|
||||
];
|
||||
|
|
@ -243,6 +276,7 @@ function BuiltinActionWidgets(): DashboardWidgetProps[] {
|
|||
export default function DashboardWidgetLibrary(): DashboardWidgetProps[] {
|
||||
return [
|
||||
...BuiltinQueryCountWidgets(),
|
||||
...BuiltinHistoryWidgets(),
|
||||
...BuiltinGettingStartedWidgets(),
|
||||
...BuiltinSettingsWidgets(),
|
||||
...BuiltinActionWidgets()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||
import type { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { StylishText } from '@lib/index';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { BarChart } from '@mantine/charts';
|
||||
import { Stack } from '@mantine/core';
|
||||
import { useDocumentVisibility } from '@mantine/hooks';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { useMemo } from 'react';
|
||||
import { useApi } from '../../../contexts/ApiContext';
|
||||
import { useUserState } from '../../../states/UserState';
|
||||
import type { DashboardWidgetProps } from '../DashboardWidget';
|
||||
|
||||
function OrderHistoryComponent({
|
||||
modelType,
|
||||
title
|
||||
}: {
|
||||
modelType: ModelType;
|
||||
title: string;
|
||||
}) {
|
||||
const modelInfo = useMemo(() => {
|
||||
return ModelInformationDict[modelType];
|
||||
}, [modelType]);
|
||||
|
||||
const url = useMemo(() => {
|
||||
return apiUrl(modelInfo.api_endpoint);
|
||||
}, [modelInfo]);
|
||||
|
||||
const api = useApi();
|
||||
const visibility = useDocumentVisibility();
|
||||
|
||||
const endDate = dayjs().add(1, 'day').format('YYYY-MM-DD');
|
||||
const startDate = dayjs()
|
||||
.subtract(12, 'month')
|
||||
.subtract(1, 'day')
|
||||
.format('YYYY-MM-DD');
|
||||
|
||||
const params = {
|
||||
completed_after: startDate,
|
||||
completed_before: endDate
|
||||
};
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ['dashboard-order-summary', modelType, params, visibility],
|
||||
enabled: visibility === 'visible',
|
||||
refetchOnWindowFocus: true,
|
||||
refetchOnMount: true,
|
||||
refetchInterval: 10 * 60 * 1000, // 10 minute refetch interval
|
||||
staleTime: 5 * 60 * 1000, // 5 minute stale time
|
||||
queryFn: () => {
|
||||
if (visibility !== 'visible') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return api.get(url, { params }).then((res) => {
|
||||
return res.data ?? [];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
const months = Array.from({ length: 13 }, (_, i) => ({
|
||||
month: dayjs()
|
||||
.subtract(12 - i, 'month')
|
||||
.format('MMM YY'),
|
||||
count: 0
|
||||
}));
|
||||
|
||||
for (const order of query.data || []) {
|
||||
// Build orders use `completion_date`; all other order types use `complete_date`
|
||||
const dateStr =
|
||||
order.complete_date ?? order.completion_date ?? order.shipment_date;
|
||||
if (!dateStr) continue;
|
||||
const label = dayjs(dateStr).format('MMM YY');
|
||||
const entry = months.find((m) => m.month === label);
|
||||
if (entry) entry.count++;
|
||||
}
|
||||
|
||||
return months;
|
||||
}, [query.data]);
|
||||
|
||||
return (
|
||||
<Stack gap='xs'>
|
||||
<StylishText size='md'>{title}</StylishText>
|
||||
<BarChart
|
||||
h={200}
|
||||
data={chartData}
|
||||
dataKey='month'
|
||||
series={[{ name: 'count', label: t`Completed`, color: 'blue.6' }]}
|
||||
withYAxis={false}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a simple chart of the number of completed orders per month, for the last 12 months.
|
||||
*/
|
||||
export default function OrderHistoryWidget({
|
||||
modelType
|
||||
}: {
|
||||
modelType: ModelType;
|
||||
}): DashboardWidgetProps {
|
||||
const user = useUserState();
|
||||
|
||||
const modelInfo = useMemo(() => {
|
||||
return ModelInformationDict[modelType];
|
||||
}, [modelType]);
|
||||
|
||||
// Extract translated model labels
|
||||
const models = modelInfo.label_multiple();
|
||||
|
||||
return {
|
||||
label: `${modelType}-history`,
|
||||
title: t`Completed ${models}`,
|
||||
description: t`Display number of completed ${models} per month`,
|
||||
minHeight: 2,
|
||||
minWidth: 3,
|
||||
modelType: modelType,
|
||||
icon: 'chart_bar',
|
||||
visible: () => user.hasViewPermission(modelType),
|
||||
render: () => (
|
||||
<OrderHistoryComponent
|
||||
modelType={modelType}
|
||||
title={t`Completed ${models}`}
|
||||
/>
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
@ -129,6 +129,7 @@ export default function QueryCountDashboardWidget({
|
|||
title,
|
||||
description,
|
||||
modelType,
|
||||
icon,
|
||||
enabled = true,
|
||||
params
|
||||
}: {
|
||||
|
|
@ -136,6 +137,7 @@ export default function QueryCountDashboardWidget({
|
|||
title: string;
|
||||
description: string;
|
||||
modelType: ModelType;
|
||||
icon?: keyof InvenTreeIconType;
|
||||
enabled?: boolean;
|
||||
params: any;
|
||||
}): DashboardWidgetProps {
|
||||
|
|
@ -147,6 +149,7 @@ export default function QueryCountDashboardWidget({
|
|||
modelType: modelType,
|
||||
minWidth: 2,
|
||||
minHeight: 1,
|
||||
icon: icon,
|
||||
render: () => (
|
||||
<QueryCountWidget modelType={modelType} title={title} params={params} />
|
||||
)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export default function StocktakeDashboardWidget(): DashboardWidgetProps {
|
|||
minHeight: 1,
|
||||
minWidth: 2,
|
||||
render: () => <StocktakeWidget />,
|
||||
icon: 'stocktake',
|
||||
enabled: user.hasAddRole(UserRoles.part)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
type SubmitHandler,
|
||||
useForm
|
||||
} from 'react-hook-form';
|
||||
import { type NavigateFunction, useNavigate } from 'react-router-dom';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { Boundary } from '@lib/components/Boundary';
|
||||
import { isTrue } from '@lib/functions/Conversion';
|
||||
|
|
@ -176,14 +176,15 @@ export function ApiForm({
|
|||
props.onKeepOpenChange?.(v);
|
||||
};
|
||||
|
||||
// Accessor for the navigation function (which is used to redirect the user)
|
||||
let navigate: NavigateFunction | null = null;
|
||||
let navigate = props.navigate || null;
|
||||
|
||||
try {
|
||||
navigate = useNavigate();
|
||||
} catch (_error) {
|
||||
// Note: If we launch a form within a plugin context, useNavigate() may not be available
|
||||
navigate = null;
|
||||
if (!navigate) {
|
||||
try {
|
||||
navigate = useNavigate();
|
||||
} catch (_error) {
|
||||
// Note: If we launch a form within a plugin context, useNavigate() may not be available
|
||||
navigate = null;
|
||||
}
|
||||
}
|
||||
|
||||
const [fields, setFields] = useState<ApiFormFieldSet>(
|
||||
|
|
@ -658,6 +659,7 @@ export function ApiForm({
|
|||
definition={field}
|
||||
control={form.control}
|
||||
url={url}
|
||||
navigate={navigate}
|
||||
setFields={setFields}
|
||||
onKeyDown={(value) => {
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { type Control, type FieldValues, useController } from 'react-hook-form';
|
|||
|
||||
import type { ApiFormFieldSet, ApiFormFieldType } from '@lib/types/Forms';
|
||||
import { IconFileUpload } from '@tabler/icons-react';
|
||||
import type { NavigateFunction } from 'react-router-dom';
|
||||
import DateTimeField from '../DateTimeField';
|
||||
import { BooleanField } from './BooleanField';
|
||||
import { ChoiceField } from './ChoiceField';
|
||||
|
|
@ -26,6 +27,7 @@ export function ApiFormField({
|
|||
definition,
|
||||
control,
|
||||
hideLabels,
|
||||
navigate,
|
||||
url,
|
||||
setFields,
|
||||
onKeyDown
|
||||
|
|
@ -34,6 +36,7 @@ export function ApiFormField({
|
|||
definition: ApiFormFieldType;
|
||||
control: Control<FieldValues, any>;
|
||||
hideLabels?: boolean;
|
||||
navigate?: NavigateFunction | null;
|
||||
url?: string;
|
||||
setFields?: React.Dispatch<React.SetStateAction<ApiFormFieldSet>>;
|
||||
onKeyDown?: (value: any) => void;
|
||||
|
|
@ -119,9 +122,10 @@ export function ApiFormField({
|
|||
case 'related field':
|
||||
return (
|
||||
<RelatedModelField
|
||||
controller={controller}
|
||||
definition={fieldDefinition}
|
||||
controller={controller}
|
||||
fieldName={fieldName}
|
||||
navigate={navigate}
|
||||
/>
|
||||
);
|
||||
case 'email':
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import {
|
|||
import { apiUrl } from '@lib/functions/Api';
|
||||
import type { ApiFormFieldType } from '@lib/types/Forms';
|
||||
import { IconPlus } from '@tabler/icons-react';
|
||||
import type { NavigateFunction } from 'react-router-dom';
|
||||
import { useApi } from '../../../contexts/ApiContext';
|
||||
import { useCreateApiFormModal } from '../../../hooks/UseForm';
|
||||
import {
|
||||
|
|
@ -50,11 +51,13 @@ export function RelatedModelField({
|
|||
controller,
|
||||
fieldName,
|
||||
definition,
|
||||
navigate,
|
||||
limit = 10
|
||||
}: Readonly<{
|
||||
controller: UseControllerReturn<FieldValues, any>;
|
||||
definition: ApiFormFieldType;
|
||||
fieldName: string;
|
||||
navigate?: NavigateFunction | null;
|
||||
limit?: number;
|
||||
}>) {
|
||||
const api = useApi();
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ function NavTabs() {
|
|||
|
||||
// static content
|
||||
mainNavTabs.forEach((tab) => {
|
||||
if (tab.role && !user.hasViewRole(tab.role)) {
|
||||
if (tab.visible === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
ActionIcon,
|
||||
Alert,
|
||||
Anchor,
|
||||
Box,
|
||||
Group,
|
||||
HoverCard,
|
||||
type MantineSize,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Space,
|
||||
Stack,
|
||||
Text
|
||||
} from '@mantine/core';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { type ReactNode, useCallback } from 'react';
|
||||
import { type ReactNode, useCallback, useMemo } from 'react';
|
||||
|
||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
|
|
@ -24,9 +28,16 @@ import type {
|
|||
} from '@lib/types/Rendering';
|
||||
|
||||
export type { InstanceRenderInterface } from '@lib/types/Rendering';
|
||||
import { getBaseUrl, navigateToLink, shortenString } from '@lib/index';
|
||||
import {
|
||||
getBaseUrl,
|
||||
getDetailUrl,
|
||||
navigateToLink,
|
||||
shortenString
|
||||
} from '@lib/index';
|
||||
import { IconLink } from '@tabler/icons-react';
|
||||
import { useApi } from '../../contexts/ApiContext';
|
||||
import { usePluginState } from '../../states/PluginState';
|
||||
import { useUserSettingsState } from '../../states/SettingsStates';
|
||||
import { Thumbnail } from '../images/Thumbnail';
|
||||
import { RenderBuildItem, RenderBuildLine, RenderBuildOrder } from './Build';
|
||||
import {
|
||||
|
|
@ -125,11 +136,98 @@ export function RenderInstance(props: RenderInstanceProps): ReactNode {
|
|||
props.custom_model ?? props.model ?? ''
|
||||
);
|
||||
|
||||
// provider component
|
||||
if (!RenderComponent) {
|
||||
return <UnknownRenderer model={props.model} />;
|
||||
}
|
||||
return <RenderComponent {...props} />;
|
||||
const userSettings = useUserSettingsState();
|
||||
|
||||
// Extract model information from the defined model type
|
||||
const modelInfo = useMemo(() => {
|
||||
if (!props.model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return ModelInformationDict[
|
||||
props.model.toString().toLowerCase() as ModelType
|
||||
];
|
||||
}, [props.model]);
|
||||
|
||||
const showHover: boolean = useMemo(() => {
|
||||
if (!modelInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Override with the props.showHover attribute
|
||||
if (props.showHover !== undefined) {
|
||||
return props.showHover;
|
||||
}
|
||||
|
||||
// If not specified, fall back to the user configured setting
|
||||
return userSettings.isSet('SHOW_EXTRA_MODEL_INFO');
|
||||
}, [props.showHover, modelInfo, userSettings]);
|
||||
|
||||
// Extract model ID from the provided instance data, using the defined primary key field (or 'pk' as a fallback)
|
||||
const modelId = useMemo(() => {
|
||||
if (!modelInfo || !props.instance) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return props.instance[modelInfo.pk_field ?? 'pk'];
|
||||
}, [modelInfo, props.instance]);
|
||||
|
||||
const detailUrl = useMemo(() => {
|
||||
if (!props.model) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getDetailUrl(props.model, modelId, true);
|
||||
}, [props.model]);
|
||||
|
||||
return (
|
||||
<HoverCard
|
||||
disabled={!showHover}
|
||||
position='top-end'
|
||||
withinPortal
|
||||
openDelay={500}
|
||||
closeDelay={100}
|
||||
zIndex={99999}
|
||||
>
|
||||
<HoverCard.Target>
|
||||
<Box>
|
||||
{!!RenderComponent ? (
|
||||
<RenderComponent {...props} />
|
||||
) : (
|
||||
<UnknownRenderer model={props.model} />
|
||||
)}
|
||||
</Box>
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown>
|
||||
<Stack gap='xs'>
|
||||
<Group justify='space-between'>
|
||||
<Text size='sm' fw='bold'>
|
||||
{modelInfo?.label()}
|
||||
</Text>
|
||||
{modelId && <Text size='xs'>{`[${t`ID`}: ${modelId}]`}</Text>}
|
||||
</Group>
|
||||
{detailUrl && (
|
||||
<Anchor
|
||||
href={detailUrl}
|
||||
target='_blank'
|
||||
onClick={(event) => {
|
||||
if (props.navigate) {
|
||||
navigateToLink(detailUrl, props.navigate, event);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Group gap='xs' wrap='nowrap'>
|
||||
<ActionIcon variant='transparent' size='xs'>
|
||||
<IconLink />
|
||||
</ActionIcon>
|
||||
<Text size='sm'>{t`View details`}</Text>
|
||||
</Group>
|
||||
</Anchor>
|
||||
)}
|
||||
</Stack>
|
||||
</HoverCard.Dropdown>
|
||||
</HoverCard>
|
||||
);
|
||||
}
|
||||
|
||||
export function RenderRemoteInstance({
|
||||
|
|
|
|||
|
|
@ -124,6 +124,17 @@ export function getActions(navigate: NavigateFunction) {
|
|||
leftSection: <IconLink size='1.2rem' />
|
||||
});
|
||||
|
||||
globalSettings.isSet('TRANSFERORDER_ENABLED') &&
|
||||
user?.hasViewRole(UserRoles.transfer_order) &&
|
||||
_actions.push({
|
||||
id: 'transfer-orders',
|
||||
label: t`Transfer Orders`,
|
||||
description: t`Go to Transfer Orders`,
|
||||
onClick: () =>
|
||||
navigate(ModelInformationDict['transferorder'].url_overview!),
|
||||
leftSection: <IconLink size='1.2rem' />
|
||||
});
|
||||
|
||||
globalSettings.isSet('RETURNORDER_ENABLED') &&
|
||||
user?.hasViewRole(UserRoles.return_order) &&
|
||||
_actions.push({
|
||||
|
|
@ -172,6 +183,17 @@ export function getActions(navigate: NavigateFunction) {
|
|||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.error) &&
|
||||
_actions.push({
|
||||
id: 'error-logs',
|
||||
label: t`Error Logs`,
|
||||
description: t`View error logs for this instance`,
|
||||
onClick: () => navigate('/settings/admin/errors'),
|
||||
leftSection: <IconReport size='1.2rem' />
|
||||
});
|
||||
|
||||
staff &&
|
||||
user?.hasViewPermission(ModelType.pluginconfig) &&
|
||||
_actions.push({
|
||||
id: 'plugin-settings',
|
||||
label: t`Plugins`,
|
||||
|
|
|
|||
|
|
@ -16,15 +16,18 @@ import {
|
|||
} from '@tabler/icons-react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { MenuLinkItem } from '../components/items/MenuLinks';
|
||||
import { useGlobalSettingsState } from '../states/SettingsStates';
|
||||
|
||||
type NavTab = {
|
||||
name: string;
|
||||
title: string;
|
||||
icon: ReactNode;
|
||||
role?: UserRoles;
|
||||
visible?: boolean;
|
||||
};
|
||||
|
||||
export function getNavTabs(user: UserStateProps): NavTab[] {
|
||||
const globalSettings = useGlobalSettingsState.getState();
|
||||
|
||||
const navTabs: NavTab[] = [
|
||||
{
|
||||
name: 'home',
|
||||
|
|
@ -35,37 +38,45 @@ export function getNavTabs(user: UserStateProps): NavTab[] {
|
|||
name: 'part',
|
||||
title: t`Parts`,
|
||||
icon: <IconBox />,
|
||||
role: UserRoles.part
|
||||
visible:
|
||||
user.hasViewRole(UserRoles.part) ||
|
||||
user.hasViewRole(UserRoles.part_category)
|
||||
},
|
||||
{
|
||||
name: 'stock',
|
||||
title: t`Stock`,
|
||||
icon: <IconPackages />,
|
||||
role: UserRoles.stock
|
||||
visible:
|
||||
user.hasViewRole(UserRoles.stock) ||
|
||||
user.hasViewRole(UserRoles.stock_location) ||
|
||||
(globalSettings.isSet('TRANSFERORDER_ENABLED') &&
|
||||
user.hasViewRole(UserRoles.transfer_order))
|
||||
},
|
||||
{
|
||||
name: 'manufacturing',
|
||||
title: t`Manufacturing`,
|
||||
icon: <IconBuildingFactory2 />,
|
||||
role: UserRoles.build
|
||||
visible: user.hasViewRole(UserRoles.build)
|
||||
},
|
||||
{
|
||||
name: 'purchasing',
|
||||
title: t`Purchasing`,
|
||||
icon: <IconShoppingCart />,
|
||||
role: UserRoles.purchase_order
|
||||
visible: user.hasViewRole(UserRoles.purchase_order)
|
||||
},
|
||||
{
|
||||
name: 'sales',
|
||||
title: t`Sales`,
|
||||
icon: <IconTruckDelivery />,
|
||||
role: UserRoles.sales_order
|
||||
visible:
|
||||
user.hasViewRole(UserRoles.sales_order) ||
|
||||
(globalSettings.isSet('RETURNORDER_ENABLED') &&
|
||||
user.hasViewRole(UserRoles.return_order))
|
||||
}
|
||||
];
|
||||
|
||||
return navTabs.filter((tab) => {
|
||||
if (!tab.role) return true;
|
||||
return user.hasViewRole(tab.role);
|
||||
return tab.visible !== false;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconBuildingStore, IconCopy, IconPackages } from '@tabler/icons-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useGlobalSettingsState } from '../states/SettingsStates';
|
||||
|
||||
/**
|
||||
|
|
@ -23,6 +23,12 @@ export function usePartFields({
|
|||
undefined
|
||||
);
|
||||
|
||||
// Set the initial state for the tracked fields based on the global settings
|
||||
useEffect(() => {
|
||||
setVirtual(globalSettings.isSet('PART_VIRTUAL'));
|
||||
setPurchaseable(globalSettings.isSet('PART_PURCHASEABLE'));
|
||||
}, [partId, create]);
|
||||
|
||||
return useMemo(() => {
|
||||
const fields: ApiFormFieldSet = {
|
||||
category: {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
import { ActionButton } from '@lib/components/ActionButton';
|
||||
import { StylishText } from '@lib/components/StylishText';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import type {
|
||||
ApiFormAdjustFilterType,
|
||||
ApiFormFieldChoice,
|
||||
ApiFormFieldSet,
|
||||
ApiFormModalProps,
|
||||
StockOperationProps
|
||||
} from '@lib/types/Forms';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
Alert,
|
||||
|
|
@ -20,27 +33,13 @@ import {
|
|||
IconUsersGroup
|
||||
} from '@tabler/icons-react';
|
||||
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
|
||||
import { type JSX, Suspense, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { ActionButton } from '@lib/components/ActionButton';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import dayjs from 'dayjs';
|
||||
import { type JSX, Suspense, useEffect, useMemo, useState } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { api } from '../App';
|
||||
import RemoveRowButton from '../components/buttons/RemoveRowButton';
|
||||
import { StandaloneField } from '../components/forms/StandaloneField';
|
||||
|
||||
import { StylishText } from '@lib/components/StylishText';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import type {
|
||||
ApiFormAdjustFilterType,
|
||||
ApiFormFieldChoice,
|
||||
ApiFormFieldSet,
|
||||
ApiFormModalProps,
|
||||
StockOperationProps
|
||||
} from '@lib/types/Forms';
|
||||
import {
|
||||
TableFieldExtraRow,
|
||||
type TableFieldRowProps
|
||||
|
|
@ -490,12 +489,31 @@ function StockItemDefaultMove({
|
|||
function moveToDefault(
|
||||
stockItem: any,
|
||||
value: StockItemQuantity,
|
||||
refresh: () => void
|
||||
refresh: () => void,
|
||||
options?: {
|
||||
title?: string;
|
||||
onConfirm?: (location: number) => void;
|
||||
}
|
||||
) {
|
||||
const location =
|
||||
stockItem.part_detail?.default_location ??
|
||||
stockItem.part_detail?.category_default_location;
|
||||
|
||||
modals.openConfirmModal({
|
||||
title: <StylishText>{t`Confirm Stock Transfer`}</StylishText>,
|
||||
title: (
|
||||
<StylishText>{options?.title ?? t`Confirm Stock Transfer`}</StylishText>
|
||||
),
|
||||
children: <StockItemDefaultMove stockItem={stockItem} value={value} />,
|
||||
onConfirm: () => {
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options?.onConfirm) {
|
||||
options.onConfirm(location);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
stockItem.location === stockItem.part_detail?.default_location ||
|
||||
stockItem.location === stockItem.part_detail?.category_default_location
|
||||
|
|
@ -512,9 +530,7 @@ function moveToDefault(
|
|||
status: stockItem.status
|
||||
}
|
||||
],
|
||||
location:
|
||||
stockItem.part_detail?.default_location ??
|
||||
stockItem.part_detail?.category_default_location
|
||||
location: location
|
||||
})
|
||||
.then((response) => {
|
||||
refresh();
|
||||
|
|
@ -548,6 +564,7 @@ function StockOperationsRow({
|
|||
add = false,
|
||||
setMax = false,
|
||||
merge = false,
|
||||
returnStock = false,
|
||||
record
|
||||
}: {
|
||||
props: TableFieldRowProps;
|
||||
|
|
@ -556,8 +573,11 @@ function StockOperationsRow({
|
|||
add?: boolean;
|
||||
setMax?: boolean;
|
||||
merge?: boolean;
|
||||
returnStock?: boolean;
|
||||
record?: any;
|
||||
}) {
|
||||
const form = useFormContext();
|
||||
|
||||
const statusOptions: ApiFormFieldChoice[] = useMemo(() => {
|
||||
return (
|
||||
StatusFilterOptions(ModelType.stockitem)()?.map((choice) => {
|
||||
|
|
@ -676,7 +696,22 @@ function StockOperationsRow({
|
|||
{transfer && (
|
||||
<ActionButton
|
||||
onClick={() =>
|
||||
moveToDefault(record, props.item.quantity, removeAndRefresh)
|
||||
moveToDefault(
|
||||
record,
|
||||
props.item.quantity,
|
||||
removeAndRefresh,
|
||||
returnStock
|
||||
? {
|
||||
title: t`Confirm Stock Return`,
|
||||
onConfirm: (location: number) => {
|
||||
form.setValue('location', location, {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true
|
||||
});
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
}
|
||||
icon={<InvenTreeIcon icon='default_location' />}
|
||||
tooltip={t`Move to default location`}
|
||||
|
|
@ -840,6 +875,7 @@ function stockReturnFields(items: any[]): ApiFormFieldSet {
|
|||
key={record.pk}
|
||||
record={record}
|
||||
transfer
|
||||
returnStock
|
||||
changeStatus
|
||||
/>
|
||||
);
|
||||
|
|
@ -854,12 +890,25 @@ function stockReturnFields(items: any[]): ApiFormFieldSet {
|
|||
]
|
||||
},
|
||||
location: {
|
||||
field_type: 'related field',
|
||||
api_url: apiUrl(ApiEndpoints.stock_location_list),
|
||||
model: ModelType.stocklocation,
|
||||
required: true,
|
||||
filters: {
|
||||
structural: false
|
||||
}
|
||||
},
|
||||
merge: {},
|
||||
notes: {}
|
||||
merge: {
|
||||
field_type: 'boolean',
|
||||
label: t`Merge into existing stock`,
|
||||
description: t`Merge returned items into existing stock items if possible`,
|
||||
value: false
|
||||
},
|
||||
notes: {
|
||||
field_type: 'string',
|
||||
label: t`Notes`,
|
||||
description: t`Stock transaction notes`
|
||||
}
|
||||
};
|
||||
|
||||
return fields;
|
||||
|
|
@ -1593,11 +1642,7 @@ export function useTestResultFields({
|
|||
/**
|
||||
* Modal form for finding a particular stock item by serial number
|
||||
*/
|
||||
export function useFindSerialNumberForm({
|
||||
partId
|
||||
}: {
|
||||
partId: number;
|
||||
}) {
|
||||
export function useFindSerialNumberForm({ partId }: { partId: number }) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return useApiFormModal({
|
||||
|
|
|
|||
|
|
@ -15,10 +15,13 @@ import {
|
|||
IconCalendar,
|
||||
IconCalendarCheck,
|
||||
IconCalendarDot,
|
||||
IconCalendarExclamation,
|
||||
IconCalendarStats,
|
||||
IconCalendarTime,
|
||||
IconCalendarX,
|
||||
IconCancel,
|
||||
IconChartBar,
|
||||
IconChartLine,
|
||||
IconCheck,
|
||||
IconCircleCheck,
|
||||
IconCircleDashedCheck,
|
||||
|
|
@ -63,6 +66,7 @@ import {
|
|||
IconMapPin,
|
||||
IconMapPinHeart,
|
||||
IconMinusVertical,
|
||||
IconNews,
|
||||
IconNotes,
|
||||
IconNumber123,
|
||||
IconNumbers,
|
||||
|
|
@ -158,6 +162,7 @@ const icons: InvenTreeIconType = {
|
|||
transfer_orders: IconTransfer,
|
||||
sales_orders: IconTruckDelivery,
|
||||
scheduling: IconCalendarStats,
|
||||
overdue: IconCalendarExclamation,
|
||||
scrap: IconCircleX,
|
||||
shipment: IconCubeSend,
|
||||
test_templates: IconTestPipe,
|
||||
|
|
@ -267,7 +272,11 @@ const icons: InvenTreeIconType = {
|
|||
plugin: IconPlug,
|
||||
history: IconHistory,
|
||||
dashboard: IconLayoutDashboard,
|
||||
search: IconSearch
|
||||
search: IconSearch,
|
||||
|
||||
chart_bar: IconChartBar,
|
||||
chart_line: IconChartLine,
|
||||
news: IconNews
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue