Merge remote-tracking branch 'upstream/master' into barcode-generation

This commit is contained in:
wolflu05 2024-07-18 08:50:29 +02:00
commit a6b3f4aa5c
No known key found for this signature in database
GPG Key ID: 9099EFC7C5EB963C
98 changed files with 125603 additions and 107391 deletions

View File

@ -567,6 +567,8 @@ jobs:
run: cd src/frontend && yarn install
- name: Build frontend
run: cd src/frontend && yarn run compile && yarn run build
- name: Write version file - SHA
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
- name: Zip frontend
run: |
cd src/backend/InvenTree/web/static

View File

@ -43,6 +43,10 @@ jobs:
run: cd src/frontend && yarn install
- name: Build frontend
run: cd src/frontend && npm run compile && npm run build
- name: Write version file - SHA
run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt
- name: Write version file - TAG
run: cd src/backend/InvenTree/web/static/web/.vite && echo "${{ github.ref_name }}" > tag.txt
- name: Zip frontend
run: |
cd src/backend/InvenTree/web/static/web

View File

@ -17,7 +17,7 @@ repos:
- id: check-yaml
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.1
rev: v0.5.1
hooks:
- id: ruff-format
args: [--preview]
@ -27,23 +27,23 @@ repos:
--preview
]
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.1.35
rev: 0.2.13
hooks:
- id: pip-compile
name: pip-compile requirements-dev.in
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt]
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --no-strip-extras, --generate-hashes]
files: src/backend/requirements-dev\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [src/backend/requirements.in, -o, src/backend/requirements.txt]
args: [src/backend/requirements.in, -o, src/backend/requirements.txt, --no-strip-extras, --generate-hashes]
files: src/backend/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt]
args: [contrib/dev_reqs/requirements.in, -o, contrib/dev_reqs/requirements.txt, --no-strip-extras, --generate-hashes]
files: contrib/dev_reqs/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [docs/requirements.in, -o, docs/requirements.txt]
args: [docs/requirements.in, -o, docs/requirements.txt, --no-strip-extras, --generate-hashes]
files: docs/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
@ -54,9 +54,11 @@ repos:
hooks:
- id: djlint-django
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies:
- tomli
exclude: >
(?x)^(
docs/docs/stylesheets/.*|
@ -75,7 +77,7 @@ repos:
- "prettier@^2.4.1"
- "@trivago/prettier-plugin-sort-imports"
- repo: https://github.com/pre-commit/mirrors-eslint
rev: "v9.4.0"
rev: "v9.6.0"
hooks:
- id: eslint
additional_dependencies:
@ -87,7 +89,7 @@ repos:
- "@typescript-eslint/parser"
files: ^src/frontend/.*\.(js|jsx|ts|tsx)$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.3
rev: v8.18.4
hooks:
- id: gitleaks
#- repo: https://github.com/jumanjihouse/pre-commit-hooks

View File

@ -11,12 +11,15 @@ django==4.2.14 \
django-auth-ldap==4.8.0 \
--hash=sha256:4b4b944f3c28bce362f33fb6e8db68429ed8fd8f12f0c0c4b1a4344a7ef225ce \
--hash=sha256:604250938ddc9fda619f247c7a59b0b2f06e53a7d3f46a156f28aa30dd71a738
# via -r contrib/container/requirements.in
gunicorn==22.0.0 \
--hash=sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9 \
--hash=sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63
# via -r contrib/container/requirements.in
invoke==2.2.0 \
--hash=sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820 \
--hash=sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5
# via -r contrib/container/requirements.in
mariadb==1.1.10 \
--hash=sha256:03d6284ef713d1cad40146576a4cc2d6cbc1662060f2a0e59b174e1694521698 \
--hash=sha256:1ce87971c02375236ff8933e6c593c748e7b2f2950b86eabfab4289fd250ea63 \
@ -29,6 +32,7 @@ mariadb==1.1.10 \
--hash=sha256:a332893e3ef7ceb7970ab4bd7c844bcb4bd68a051ca51313566f9808d7411f2d \
--hash=sha256:d7b09ec4abd02ed235257feb769f90cd4066e8f536b55b92f5166103d5b66a63 \
--hash=sha256:dff8b28ce4044574870d7bdd2d9f9f5da8e5f95a7ff6d226185db733060d1a93
# via -r contrib/container/requirements.in
mysqlclient==2.2.4 \
--hash=sha256:329e4eec086a2336fe3541f1ce095d87a6f169d1cc8ba7b04ac68bcb234c9711 \
--hash=sha256:33bc9fb3464e7d7c10b1eaf7336c5ff8f2a3d3b88bab432116ad2490beb3bf41 \
@ -39,6 +43,7 @@ mysqlclient==2.2.4 \
--hash=sha256:ac44777eab0a66c14cb0d38965572f762e193ec2e5c0723bcd11319cc5b693c5 \
--hash=sha256:d43987bb9626096a302ca6ddcdd81feaeca65ced1d5fe892a6a66b808326aa54 \
--hash=sha256:e1ebe3f41d152d7cb7c265349fdb7f1eca86ccb0ca24a90036cde48e00ceb2ab
# via -r contrib/container/requirements.in
packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
@ -48,6 +53,7 @@ packaging==24.0 \
psycopg[binary, pool]==3.1.18 \
--hash=sha256:31144d3fb4c17d78094d9e579826f047d4af1da6a10427d91dfcfb6ecdf6f12b \
--hash=sha256:4d5a0a5a8590906daa58ebd5f3cfc34091377354a1acced269dd10faf55da60e
# via -r contrib/container/requirements.in
psycopg-binary==3.1.18 \
--hash=sha256:02bd4da45d5ee9941432e2e9bf36fa71a3ac21c6536fe7366d1bd3dd70d6b1e7 \
--hash=sha256:0f68ac2364a50d4cf9bb803b4341e83678668f1881a253e1224574921c69868c \
@ -131,7 +137,9 @@ pyasn1-modules==0.4.0 \
# via python-ldap
python-ldap==3.4.4 \
--hash=sha256:7edb0accec4e037797705f3a05cbf36a9fde50d08c8f67f2aef99a2628fab828
# via django-auth-ldap
# via
# -r contrib/container/requirements.in
# django-auth-ldap
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
@ -184,9 +192,11 @@ pyyaml==6.0.1 \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
# via -r contrib/container/requirements.in
setuptools==70.3.0 \
--hash=sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5 \
--hash=sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc
# via -r contrib/container/requirements.in
sqlparse==0.5.0 \
--hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
--hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
@ -215,6 +225,8 @@ uv==0.1.38 \
--hash=sha256:b0b15e51a0f8240969bc412ed0dd60cfe3f664b30173139ef263d71c596d631f \
--hash=sha256:ea44c07605d1359a7d82bf42706dd86d341f15f4ca2e1f36e51626a7111c2ad5 \
--hash=sha256:f87c9711493c53d32012a96b49c4d53aabdf7ed666cbf2c3fb55dd402a6b31a8
# via -r contrib/container/requirements.in
wheel==0.43.0 \
--hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \
--hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81
# via -r contrib/container/requirements.in

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt
# uv pip compile contrib/dev_reqs/requirements.in -o contrib/dev_reqs/requirements.txt --no-strip-extras --generate-hashes
certifi==2024.7.4 \
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
@ -103,6 +103,7 @@ idna==3.7 \
jc==1.25.2 \
--hash=sha256:26e412a65a478f9da3097653db6277f915cfae5c0f0a3f42026b405936abd358 \
--hash=sha256:97ada193495f79550f06fe0cbfb119ff470bcca57c1cc593a5cdb0008720e0b3
# via -r contrib/dev_reqs/requirements.in
pygments==2.17.2 \
--hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
--hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
@ -159,9 +160,11 @@ pyyaml==6.0.1 \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
# via -r contrib/dev_reqs/requirements.in
requests==2.32.2 \
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
# via -r contrib/dev_reqs/requirements.in
ruamel-yaml==0.18.6 \
--hash=sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636 \
--hash=sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b

View File

@ -5,33 +5,41 @@
set -eu
VERSION="$APP_PKG_VERSION-$APP_PKG_ITERATION"
echo "Setting VERSION information to $VERSION"
echo "$VERSION" > VERSION
# The sha is the second element in APP_PKG_ITERATION
REPO="inventree/InvenTree"
VERSION="$APP_PKG_VERSION-$APP_PKG_ITERATION"
SHA=$(echo $APP_PKG_ITERATION | cut -d'.' -f2)
# Download info
echo "Getting info from github for commit $SHA"
curl -L \
echo "INFO collection | Getting info from github for commit $SHA"
curl -L -s -f \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA > commit.json
curl -L \
https://api.github.com/repos/$REPO/commits/$SHA > commit.json
echo "INFO collection | Got commit.json with size $(wc -c commit.json)"
curl -L -s -f \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/InvenTree/InvenTree/commits/$SHA/branches-where-head > branches.json
https://api.github.com/repos/$REPO/commits/$SHA/branches-where-head > branches.json
echo "INFO collection | Got branches.json with size $(wc -c branches.json)"
curl -L -s -f \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/$REPO/commits/$APP_PKG_VERSION > tag.json
echo "INFO collection | Got tag.json with size $(wc -c tag.json)"
# Extract info
echo "Extracting info from github"
echo "INFO extract | Extracting info from github"
DATE=$(jq -r '.commit.committer.date' commit.json)
BRANCH=$(jq -r '.[].name' branches.json)
NODE_ID=$(jq -r '.node_id' commit.json)
SIGNATURE=$(jq -r '.commit.verification.signature' commit.json)
FULL_SHA=$(jq -r '.sha' commit.json)
echo "Write VERSION information"
echo "INFO write | Write VERSION information"
echo "$VERSION" > VERSION
echo "INVENTREE_COMMIT_HASH='$SHA'" >> VERSION
echo "INVENTREE_COMMIT_SHA='$FULL_SHA'" >> VERSION
echo "INVENTREE_COMMIT_DATE='$DATE'" >> VERSION
echo "INVENTREE_PKG_INSTALLER='PKG'" >> VERSION
echo "INVENTREE_PKG_BRANCH='$BRANCH'" >> VERSION
@ -39,5 +47,22 @@ echo "INVENTREE_PKG_TARGET='$TARGET'" >> VERSION
echo "NODE_ID='$NODE_ID'" >> VERSION
echo "SIGNATURE='$SIGNATURE'" >> VERSION
echo "Written VERSION information"
echo "INFO write | Written VERSION information"
echo "### VERSION ###"
cat VERSION
echo "### VERSION ###"
# Try to get frontend
echo "INFO frontend | Trying to get frontend"
# Check if tag sha is the same as the commit sha
TAG_SHA=$(jq -r '.sha' tag.json)
if [ "$TAG_SHA" != "$FULL_SHA" ]; then
echo "INFO frontend | Tag sha '$TAG_SHA' is not the same as commit sha $FULL_SHA, can not download frontend"
else
echo "INFO frontend | Getting frontend from github via tag"
curl https://github.com/$REPO/releases/download/$APP_PKG_VERSION/frontend-build.zip -L -O -f
mkdir -p src/backend/InvenTree/web/static
echo "INFO frontend | Unzipping frontend"
unzip -qq frontend-build.zip -d src/backend/InvenTree/web/static/web
echo "INFO frontend | Unzipped frontend"
fi

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile docs/requirements.in -o docs/requirements.txt
# uv pip compile docs/requirements.in -o docs/requirements.txt --no-strip-extras --generate-hashes
anyio==4.3.0 \
--hash=sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 \
--hash=sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6
@ -284,6 +284,7 @@ mkdocs==1.6.0 \
--hash=sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7 \
--hash=sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512
# via
# -r docs/requirements.in
# mkdocs-autorefs
# mkdocs-git-revision-date-localized-plugin
# mkdocs-include-markdown-plugin
@ -303,15 +304,19 @@ mkdocs-get-deps==0.2.0 \
mkdocs-git-revision-date-localized-plugin==1.2.5 \
--hash=sha256:0c439816d9d0dba48e027d9d074b2b9f1d7cd179f74ba46b51e4da7bb3dc4b9b \
--hash=sha256:d796a18b07cfcdb154c133e3ec099d2bb5f38389e4fd54d3eb516a8a736815b8
# via -r docs/requirements.in
mkdocs-include-markdown-plugin==6.0.6 \
--hash=sha256:7c80258b2928563c75cc057a7b9a0014701c40804b1b6aa290f3b4032518b43c \
--hash=sha256:7ccafbaa412c1e5d3510c4aff46d1fe64c7a810c01dace4c636253d1aa5bc193
# via -r docs/requirements.in
mkdocs-macros-plugin==1.0.5 \
--hash=sha256:f60e26f711f5a830ddf1e7980865bf5c0f1180db56109803cdd280073c1a050a \
--hash=sha256:fe348d75f01c911f362b6d998c57b3d85b505876dde69db924f2c512c395c328
# via -r docs/requirements.in
mkdocs-material==9.5.24 \
--hash=sha256:02d5aaba0ee755e707c3ef6e748f9acb7b3011187c0ea766db31af8905078a34 \
--hash=sha256:e12cd75954c535b61e716f359cf2a5056bf4514889d17161fdebd5df4b0153c6
# via -r docs/requirements.in
mkdocs-material-extensions==1.3.1 \
--hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \
--hash=sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31
@ -319,10 +324,13 @@ mkdocs-material-extensions==1.3.1 \
mkdocs-simple-hooks==0.1.5 \
--hash=sha256:dddbdf151a18723c9302a133e5cf79538be8eb9d274e8e07d2ac3ac34890837c \
--hash=sha256:efeabdbb98b0850a909adee285f3404535117159d5cb3a34f541d6eaa644d50a
# via -r docs/requirements.in
mkdocstrings[python]==0.25.1 \
--hash=sha256:c3a2515f31577f311a9ee58d089e4c51fc6046dbd9e9b4c3de4c3194667fe9bf \
--hash=sha256:da01fcc2670ad61888e8fe5b60afe9fee5781017d67431996832d63e887c2e51
# via mkdocstrings-python
# via
# -r docs/requirements.in
# mkdocstrings-python
mkdocstrings-python==1.10.2 \
--hash=sha256:38a4fd41953defb458a107033440c229c7e9f98f35a24e84d888789c97da5a63 \
--hash=sha256:e8e596b37f45c09b67bec253e035fe18988af5bbbbf44e0ccd711742eed750e5
@ -330,6 +338,7 @@ mkdocstrings-python==1.10.2 \
neoteroi-mkdocs==1.0.5 \
--hash=sha256:1f3b372dee79269157361733c0f45b3a89189077078e0e3224d829a144ef3579 \
--hash=sha256:29875ef444b08aec5619a384142e16f1b4e851465cab4e380fb2b8ae730fe046
# via -r docs/requirements.in
packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9

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

View File

@ -170,6 +170,18 @@ def uploaded_image(
width = kwargs.get('width', None)
height = kwargs.get('height', None)
if width is not None:
try:
width = int(width)
except ValueError:
width = None
if height is not None:
try:
height = int(height)
except ValueError:
height = None
if width is not None and height is not None:
# Resize the image, width *and* height are provided
img = img.resize((width, height))
@ -185,10 +197,12 @@ def uploaded_image(
img = img.resize((wsize, height))
# Optionally rotate the image
rotate = kwargs.get('rotate', None)
if rotate is not None:
img = img.rotate(rotate)
if rotate := kwargs.get('rotate', None):
try:
rotate = int(rotate)
img = img.rotate(rotate)
except ValueError:
pass
# Return a base-64 encoded image
img_data = report.helpers.encode_image_base64(img)

View File

@ -163,7 +163,13 @@ function generateTreeStructure(data, options) {
const nodes = {};
const roots = [];
for (let node of data) {
if (!data || !Array.isArray(data) || data.length == 0) {
return [];
}
for (let ii = 0; ii < data.length; ii++) {
let node = data[ii];
nodes[node.pk] = node;
node.selectable = false;
@ -173,12 +179,16 @@ function generateTreeStructure(data, options) {
};
if (options.processNode) {
data[data.indexOf(node)] = options.processNode(node);
node = options.processNode(node);
data[ii] = node;
}
}
for (let node of data) {
if (node.parent != null) {
for (let ii = 0; ii < data.length; ii++) {
let node = data[ii];
if (!!node.parent) {
if (nodes[node.parent].nodes) {
nodes[node.parent].nodes.push(node);
} else {
@ -186,9 +196,9 @@ function generateTreeStructure(data, options) {
}
if (node.state.expanded) {
while (node.parent != null) {
while (!!node.parent) {
nodes[node.parent].state.expanded = true;
data[data.indexOf(node)] = nodes[node.parent];
node = nodes[node.parent];
}
}

View File

@ -1,9 +1,11 @@
# This file was autogenerated by uv via the following command:
# uv pip compile src/backend/requirements-dev.in -o src/backend/requirements-dev.txt
# uv pip compile src/backend/requirements-dev.in -o src/backend/requirements-dev.txt --no-strip-extras --generate-hashes
asgiref==3.8.1 \
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
# via django
# via
# -c src/backend/requirements.txt
# django
build==1.2.1 \
--hash=sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d \
--hash=sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4
@ -61,7 +63,9 @@ cffi==1.16.0 \
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
# via cryptography
# via
# -c src/backend/requirements.txt
# cryptography
cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
@ -157,7 +161,9 @@ charset-normalizer==3.3.2 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via pdfminer-six
# via
# -c src/backend/requirements.txt
# pdfminer-six
click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
@ -215,6 +221,7 @@ coverage[toml]==7.5.4 \
--hash=sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633 \
--hash=sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9 \
--hash=sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c
# via -r src/backend/requirements-dev.in
cryptography==42.0.8 \
--hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \
--hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \
@ -248,7 +255,9 @@ cryptography==42.0.8 \
--hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \
--hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \
--hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e
# via pdfminer-six
# via
# -c src/backend/requirements.txt
# pdfminer-six
distlib==0.3.8 \
--hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \
--hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64
@ -257,18 +266,23 @@ django==4.2.14 \
--hash=sha256:3ec32bc2c616ab02834b9cac93143a7dc1cdcd5b822d78ac95fc20a38c534240 \
--hash=sha256:fc6919875a6226c7ffcae1a7d51e0f2ceaf6f160393180818f6c95f51b1e7b96
# via
# -c src/backend/requirements.txt
# django-admin-shell
# django-slowtests
django-admin-shell==2.0.1 \
--hash=sha256:334a651e53ae4f59d0d279d7ede7dc5ed7a7733d4d093765b447dca5274c7b30 \
--hash=sha256:b129e282ebd581c2099c0504edf081259728b3a504b40c5784d0457b8cb41470
# via -r src/backend/requirements-dev.in
django-querycount==0.8.3 \
--hash=sha256:0782484e8a1bd29498fa0195a67106e47cdcc98fafe80cebb1991964077cb694
# via -r src/backend/requirements-dev.in
django-slowtests==1.1.1 \
--hash=sha256:3c6936d420c9df444ac03625b41d97de043c662bbde61fbcd33e4cd407d0c247
# via -r src/backend/requirements-dev.in
django-test-migrations==1.3.0 \
--hash=sha256:b42edb1af481e08c9d91c95aa9b373e76e905a931bc19c086ec00a6cb936876e \
--hash=sha256:b52b29475f9a1bcaa4512f2ec8fad08b5f470cf1cf522e86b7d950252fb6fbf1
# via -r src/backend/requirements-dev.in
filelock==3.15.4 \
--hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \
--hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7
@ -280,10 +294,13 @@ identify==2.5.36 \
importlib-metadata==7.1.0 \
--hash=sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570 \
--hash=sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2
# via build
# via
# -c src/backend/requirements.txt
# build
isort==5.13.2 \
--hash=sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109 \
--hash=sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6
# via -r src/backend/requirements-dev.in
nodeenv==1.9.1 \
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
--hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
@ -291,10 +308,13 @@ nodeenv==1.9.1 \
packaging==24.1 \
--hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
--hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
# via build
# via
# -c src/backend/requirements.txt
# build
pdfminer-six==20231228 \
--hash=sha256:6004da3ad1a7a4d45930cb950393df89b068e73be365a6ff64a838d37bcb08c4 \
--hash=sha256:e8d3c3310e6fbc1fe414090123ab01351634b4ecb021232206c4c9a8ca3e3b8f
# via -r src/backend/requirements-dev.in
pip==24.1 \
--hash=sha256:a775837439bf5da2c1a0c2fa43d5744854497c689ddbd9344cf3ea6d00598540 \
--hash=sha256:bdae551038c0ce6a83030b4aedef27fc95f0daa683593fea22fa05e55ed8e317
@ -302,6 +322,7 @@ pip==24.1 \
pip-tools==7.4.1 \
--hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \
--hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9
# via -r src/backend/requirements-dev.in
platformdirs==4.2.2 \
--hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \
--hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3
@ -309,10 +330,13 @@ platformdirs==4.2.2 \
pre-commit==3.7.1 \
--hash=sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a \
--hash=sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5
# via -r src/backend/requirements-dev.in
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
# via
# -c src/backend/requirements.txt
# cffi
pyproject-hooks==1.1.0 \
--hash=sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965 \
--hash=sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2
@ -371,15 +395,22 @@ pyyaml==6.0.1 \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
# via pre-commit
# via
# -c src/backend/requirements.txt
# pre-commit
setuptools==70.3.0 \
--hash=sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5 \
--hash=sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc
# via pip-tools
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements-dev.in
# pip-tools
sqlparse==0.5.0 \
--hash=sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93 \
--hash=sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663
# via django
# via
# -c src/backend/requirements.txt
# django
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
@ -391,6 +422,7 @@ typing-extensions==4.12.2 \
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
# via
# -c src/backend/requirements.txt
# asgiref
# django-test-migrations
virtualenv==20.26.3 \
@ -404,4 +436,6 @@ wheel==0.43.0 \
zipp==3.19.2 \
--hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \
--hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c
# via importlib-metadata
# via
# -c src/backend/requirements.txt
# importlib-metadata

View File

@ -1,5 +1,5 @@
# This file was autogenerated by uv via the following command:
# uv pip compile src/backend/requirements.in -o src/backend/requirements.txt
# uv pip compile src/backend/requirements.in -o src/backend/requirements.txt --no-strip-extras --generate-hashes
asgiref==3.8.1 \
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
@ -266,6 +266,7 @@ charset-normalizer==3.3.2 \
coreapi==2.3.3 \
--hash=sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb \
--hash=sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3
# via -r src/backend/requirements.in
coreschema==0.0.4 \
--hash=sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f \
--hash=sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607
@ -303,7 +304,9 @@ cryptography==42.0.8 \
--hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \
--hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \
--hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e
# via djangorestframework-simplejwt
# via
# -r src/backend/requirements.in
# djangorestframework-simplejwt
cssselect2==0.7.0 \
--hash=sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a \
--hash=sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969
@ -327,10 +330,12 @@ diff-match-patch==20230430 \
# via django-import-export
dj-rest-auth==6.0.0 \
--hash=sha256:760b45f3a07cd6182e6a20fe07d0c55230c5f950167df724d7914d0dd8c50133
# via -r src/backend/requirements.in
django==4.2.14 \
--hash=sha256:3ec32bc2c616ab02834b9cac93143a7dc1cdcd5b822d78ac95fc20a38c534240 \
--hash=sha256:fc6919875a6226c7ffcae1a7d51e0f2ceaf6f160393180818f6c95f51b1e7b96
# via
# -r src/backend/requirements.in
# dj-rest-auth
# django-allauth
# django-allauth-2fa
@ -363,40 +368,53 @@ django==4.2.14 \
# drf-spectacular
django-allauth[openid, saml]==0.63.3 \
--hash=sha256:2374164c468a309e6badf70bc3405136df6036f24a20a13387f2a063066bdaa9
# via django-allauth-2fa
# via
# -r src/backend/requirements.in
# django-allauth-2fa
django-allauth-2fa==0.11.1 \
--hash=sha256:02ffdf1025836f072c2f6ec0964494589cf1d52362f663f9ff6d9ca61a7b6962 \
--hash=sha256:2f2d61dd488f66ad45e59780b061f5abe96caea9c3466e3ee4ea50ea1faebef6
# via -r src/backend/requirements.in
django-cleanup==8.1.0 \
--hash=sha256:70df905076a44e7a111b31198199af633dee08876e199e6dce36ca8dd6b8b10f \
--hash=sha256:7903873ea73b3f7e61e055340d27dba49b70634f60c87a573ad748e172836458
# via -r src/backend/requirements.in
django-cors-headers==4.4.0 \
--hash=sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6 \
--hash=sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2
# via -r src/backend/requirements.in
django-crispy-forms==1.14.0 \
--hash=sha256:35887b8851a931374dd697207a8f56c57a9c5cb9dbf0b9fa54314da5666cea5b \
--hash=sha256:bc4d2037f6de602d39c0bc452ac3029d1f5d65e88458872cc4dbc01c3a400604
# via -r src/backend/requirements.in
django-dbbackup==4.1.0 \
--hash=sha256:c411d38d0f8e60ab3254017278c14ebd75d4001b5634fc73be7fbe8a5260583b \
--hash=sha256:c539b5246b429a22a8efadbab3719ee6b8eda45c66c4ff6592056c590d51c782
# via -r src/backend/requirements.in
django-error-report-2==0.4.2 \
--hash=sha256:1dd99c497af09b7ea99f5fbaf910501838150a9d5390796ea00e187bc62f6c1b \
--hash=sha256:603e1e3b24d01bbfeab6379af948893b2b034031c80fa8b45cf1c4735341c04b
# via -r src/backend/requirements.in
django-filter==24.2 \
--hash=sha256:48e5fc1da3ccd6ca0d5f9bb550973518ce977a4edde9d2a8a154a7f4f0b9f96e \
--hash=sha256:df2ee9857e18d38bed203c8745f62a803fa0f31688c9fe6f8e868120b1848e48
# via -r src/backend/requirements.in
django-flags==5.0.13 \
--hash=sha256:52df74b86d93f5cb402190ad26b68a5ba0f127e9e016189f1a6f2e8ba3c06a42 \
--hash=sha256:ff6940cf37e07d6d0c4ac28c5420c8cfc478b62541473dba4aa02d600f7db9fc
# via -r src/backend/requirements.in
django-formtools==2.5.1 \
--hash=sha256:47cb34552c6efca088863d693284d04fc36eaaf350eb21e1a1d935e0df523c93 \
--hash=sha256:bce9b64eda52cc1eef6961cc649cf75aacd1a707c2fff08d6c3efcbc8e7e761a
# via -r src/backend/requirements.in
django-ical==1.9.2 \
--hash=sha256:44c9b6fa90d09f25e9ebaa91ed9eb007f079afbc23d6aac909cfc18188a8e90c \
--hash=sha256:74a16bca05735f91a00120cad7250f3c3aa292a9f698a6cfdc544a922c11de70
# via -r src/backend/requirements.in
django-import-export==3.3.9 \
--hash=sha256:16797965e93a8001fe812c61e3b71fb858c57c1bd16da195fe276d6de685348e \
--hash=sha256:dd6cabc08ed6d1bd37a392e7fb542bd7d196b615c800168f5c69f0f55f49b103
# via -r src/backend/requirements.in
django-js-asset==2.2.0 \
--hash=sha256:0c57a82cae2317e83951d956110ce847f58ff0cdc24e314dbc18b35033917e94 \
--hash=sha256:7ef3e858e13d06f10799b56eea62b1e76706f42cf4e709be4e13356bc0ae30d8
@ -404,15 +422,19 @@ django-js-asset==2.2.0 \
django-maintenance-mode==0.21.1 \
--hash=sha256:b79afddb671c59972ae542e4fafbc99117d2d37991843eaaa837e328eed12b1b \
--hash=sha256:c02fff0e386b7f8b2ab54479d3a0d336ae34014da22a7a2365ca96d5a2c1db94
# via -r src/backend/requirements.in
django-markdownify==0.9.5 \
--hash=sha256:2c4ae44e386c209453caf5e9ea1b74f64535985d338ad2d5ad5e7089cc94be86 \
--hash=sha256:34c34eba4a797282a5c5bd97b13cec84d6a4c0673ad47ce1c1d000d74dd8d4ab
# via -r src/backend/requirements.in
django-money==3.2.0 \
--hash=sha256:2e4174b47993780bf4b61ad3fa0a66ebe140da42fdbe68b628c7ba9788287214 \
--hash=sha256:3099f906407175af06b56ef3ff5c250e2fc525ff00f50d42f77b98597e625459
# via -r src/backend/requirements.in
django-mptt==0.16.0 \
--hash=sha256:56c9606bf0b329b5f5afd55dd8bfd073612ea1d5999b10903b09de62bee84c8e \
--hash=sha256:8716849ba3318d94e2e100ed0923a05c1ffdf8195f8472b690dbaf737d2af3b5
# via -r src/backend/requirements.in
django-otp==1.5.0 \
--hash=sha256:e7142139f1e9686be5f396669a3d3d61178cd9b3e9de9de5933888668908b46b \
--hash=sha256:e88871d2d3b333a86c2cd0cb721be8098d4d6344cb220315a500e5a5c8254295
@ -423,9 +445,11 @@ django-picklefield==3.2 \
# via django-q2
django-q-sentry==0.1.6 \
--hash=sha256:9b8b4d7fad253a7d9a47f2c2ab0d9dea83078b7ef45c8849dbb1e4176ef8d050
# via -r src/backend/requirements.in
django-q2==1.6.2 \
--hash=sha256:c2d75552c80b83ca0d8c0b0db7db4f17e9f43ee131a46d0ddd514c5f5fc603cb \
--hash=sha256:cd83c16b5791cd99f83a8d106d2447305d73c6c8ed8ec22c7cb954fe0e814284
# via -r src/backend/requirements.in
django-recurrence==1.11.1 \
--hash=sha256:0c65f30872599b5813a9bab6952dada23c55894f28674490a753ada559f14bc5 \
--hash=sha256:9c89444e651a78c587f352c5f63eda48ab2f53996347b9fcdff2d248f4fcff70
@ -433,41 +457,53 @@ django-recurrence==1.11.1 \
django-redis==5.4.0 \
--hash=sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42 \
--hash=sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b
# via -r src/backend/requirements.in
django-sesame==3.2.2 \
--hash=sha256:523ebd4d04e28c897c262f25b78b6fd8f37e11cdca6e277fdc8bf496bd686cf5 \
--hash=sha256:5d753a309166356b6a0d7fc047690943b9e80b4aa7952f1a6400fe6ce60d573c
# via -r src/backend/requirements.in
django-sql-utils==0.7.0 \
--hash=sha256:9371ff28eaf326836a7c52887259123cdd3fbffb7b738e42ae1a21258be0feb6 \
--hash=sha256:fefc40c826896b60fcf33e35b6e30b523fc958955a16006438cd3ba6d795a532
# via -r src/backend/requirements.in
django-sslserver==0.22 \
--hash=sha256:c598a363d2ccdc2421c08ddb3d8b0973f80e8e47a3a5b74e4a2896f21c2947c5
# via -r src/backend/requirements.in
django-stdimage==6.0.2 \
--hash=sha256:880ab14828be56b53f711c3afae83c219ddd5d9af00850626736feb48382bf7f \
--hash=sha256:9a73f7da48c48074580e2b032d5bdb7164935dbe4b9dc4fb88a7e112f3d521c8
# via -r src/backend/requirements.in
django-taggit==5.0.1 \
--hash=sha256:a0ca8a28b03c4b26c2630fd762cb76ec39b5e41abf727a7b66f897a625c5e647 \
--hash=sha256:edcd7db1e0f35c304e082a2f631ddac2e16ef5296029524eb792af7430cab4cc
# via -r src/backend/requirements.in
django-user-sessions==2.0.0 \
--hash=sha256:0965554279f556b47062965609fa08b3ae45bbc581001dbe84b2ea599cc67748 \
--hash=sha256:41b8b1ebeb4736065efbc96437c9cfbf491c39e10fd547a76b98f2312e11fa3e
# via -r src/backend/requirements.in
django-weasyprint==2.3.0 \
--hash=sha256:2f849e15bfd6c1b2a58512097b9042eddf3533651d37d2e096cd6f7d8be6442b \
--hash=sha256:807cb3b16332123d97c8bbe2ac9c70286103fe353235351803ffd33b67284735
# via -r src/backend/requirements.in
django-xforwardedfor-middleware==2.0 \
--hash=sha256:16fd1cb27f33a5541b6f3e0b43afb1b7334a76f27a1255b69e14ec5c440f0b24
# via -r src/backend/requirements.in
djangorestframework==3.14.0 \
--hash=sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8 \
--hash=sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08
# via
# -r src/backend/requirements.in
# dj-rest-auth
# djangorestframework-simplejwt
# drf-spectacular
djangorestframework-simplejwt[crypto]==5.3.1 \
--hash=sha256:381bc966aa46913905629d472cd72ad45faa265509764e20ffd440164c88d220 \
--hash=sha256:6c4bd37537440bc439564ebf7d6085e74c5411485197073f508ebdfa34bc9fae
# via -r src/backend/requirements.in
drf-spectacular==0.27.2 \
--hash=sha256:a199492f2163c4101055075ebdbb037d59c6e0030692fc83a1a8c0fc65929981 \
--hash=sha256:b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b
# via -r src/backend/requirements.in
dulwich==0.22.1 \
--hash=sha256:0d72a88c7af8fafa14c8743e8923c8d46bd0b850a0b7f5e34eb49201f1ead88e \
--hash=sha256:0ea4c5feedd35e8bde175a9ab91ef6705c3cef5ee209eeb2f67dd0b59ff1825f \
@ -516,6 +552,7 @@ dulwich==0.22.1 \
--hash=sha256:e90b8a2f24149c5803b733a24f1a016a2943b1f5a9ab2360db545e4638354c35 \
--hash=sha256:f9e10678fe0692c5167553981d97cbe342ed055c49016aef10da336e2962b1f2 \
--hash=sha256:fd51e77ff1b4ca08bc9b09b85646a3e77f275827b7b30180d76d769ce608e64d
# via -r src/backend/requirements.in
et-xmlfile==1.1.0 \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada
@ -523,6 +560,7 @@ et-xmlfile==1.1.0 \
feedparser==6.0.11 \
--hash=sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45 \
--hash=sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5
# via -r src/backend/requirements.in
fonttools[woff]==4.53.0 \
--hash=sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d \
--hash=sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64 \
@ -620,10 +658,13 @@ grpcio==1.64.1 \
--hash=sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd \
--hash=sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22 \
--hash=sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309
# via opentelemetry-exporter-otlp-proto-grpc
# via
# -r src/backend/requirements.in
# opentelemetry-exporter-otlp-proto-grpc
gunicorn==22.0.0 \
--hash=sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9 \
--hash=sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63
# via -r src/backend/requirements.in
html5lib==1.1 \
--hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \
--hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f
@ -893,6 +934,7 @@ opentelemetry-api==1.25.0 \
--hash=sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737 \
--hash=sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869
# via
# -r src/backend/requirements.in
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
# opentelemetry-instrumentation
@ -905,6 +947,7 @@ opentelemetry-api==1.25.0 \
opentelemetry-exporter-otlp==1.25.0 \
--hash=sha256:ce03199c1680a845f82e12c0a6a8f61036048c07ec7a0bd943142aca8fa6ced0 \
--hash=sha256:d67a831757014a3bc3174e4cd629ae1493b7ba8d189e8a007003cacb9f1a6b60
# via -r src/backend/requirements.in
opentelemetry-exporter-otlp-proto-common==1.25.0 \
--hash=sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693 \
--hash=sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3
@ -930,12 +973,15 @@ opentelemetry-instrumentation==0.46b0 \
opentelemetry-instrumentation-django==0.46b0 \
--hash=sha256:cc11b2e24f9bdd20759570390ed8619d9c5acbf788b4a5401e36e280dfc20feb \
--hash=sha256:ecc85941263122f99dbd96463a981b2d1eeea618ca287a58abe0af9fd67631ee
# via -r src/backend/requirements.in
opentelemetry-instrumentation-redis==0.46b0 \
--hash=sha256:8b4639fe52edb6ccdc633c54c01630005ab63faeffd97754cddbf6bdc1f04c5e \
--hash=sha256:e796530808829a9c32f19eaf470f0b01caef13bd89f1d964f536198de881e460
# via -r src/backend/requirements.in
opentelemetry-instrumentation-requests==0.46b0 \
--hash=sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81 \
--hash=sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4
# via -r src/backend/requirements.in
opentelemetry-instrumentation-wsgi==0.46b0 \
--hash=sha256:2386014b026f5307c802417eeab74265785ae3dd6eee8c5581a830e3b2d3435b \
--hash=sha256:f4e1001e8477eb546cac7c13cff0b0cf127812b1188a37bcaa3e43eb741451e2
@ -951,6 +997,7 @@ opentelemetry-sdk==1.25.0 \
--hash=sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7 \
--hash=sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9
# via
# -r src/backend/requirements.in
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
opentelemetry-semantic-conventions==0.46b0 \
@ -976,6 +1023,7 @@ packaging==24.1 \
pdf2image==1.17.0 \
--hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \
--hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2
# via -r src/backend/requirements.in
pillow==10.3.0 \
--hash=sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c \
--hash=sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2 \
@ -1047,6 +1095,7 @@ pillow==10.3.0 \
--hash=sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27 \
--hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a
# via
# -r src/backend/requirements.in
# django-stdimage
# pdf2image
# python-barcode
@ -1055,9 +1104,11 @@ pillow==10.3.0 \
pint==0.21 \
--hash=sha256:3e98bdf01f4dcf840cc0207c0b6f7510d4e0c6288efc1bf470626e875c831172 \
--hash=sha256:998b695e84a34d11702da4a8b9457a39bb5c7ab5ec68db90e948e30878e421f1
# via -r src/backend/requirements.in
pip-licenses==4.4.0 \
--hash=sha256:996817118375445243a34faafe23c06f6b2d250247c4046571b5a6722d45be69 \
--hash=sha256:dbad2ac5a25f574cabe2716f2f031a0c5fa359bed9b3ef615301f4e546893b46
# via -r src/backend/requirements.in
prettytable==3.10.0 \
--hash=sha256:6536efaf0757fdaa7d22e78b3aac3b69ea1b7200538c2c6995d649365bddab92 \
--hash=sha256:9665594d137fb08a1117518c25551e0ede1687197cf353a4fdc78d27e1073568
@ -1104,6 +1155,7 @@ pypng==0.20220715.0 \
python-barcode[images]==0.15.1 \
--hash=sha256:057636fba37369c22852410c8535b36adfbeb965ddfd4e5b6924455d692e0886 \
--hash=sha256:3b1825fbdb11e597466dff4286b4ea9b1e86a57717b59e563ae679726fc854de
# via -r src/backend/requirements.in
python-dateutil==2.9.0.post0 \
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
@ -1113,6 +1165,7 @@ python-dateutil==2.9.0.post0 \
python-dotenv==1.0.1 \
--hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
--hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
# via -r src/backend/requirements.in
python-fsutil==0.14.1 \
--hash=sha256:0d45e623f0f4403f674bdd8ae7aa7d24a4b3132ea45c65416bd2865e6b20b035 \
--hash=sha256:8fb204fa8059f37bdeee8a1dc0fff010170202ea47c4225ee71bb3c26f3997be
@ -1186,12 +1239,15 @@ pyyaml==6.0.1 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
# via
# -r src/backend/requirements.in
# drf-spectacular
# tablib
qrcode[pil]==7.4.2 \
--hash=sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a \
--hash=sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845
# via django-allauth-2fa
# via
# -r src/backend/requirements.in
# django-allauth-2fa
rapidfuzz==3.9.3 \
--hash=sha256:05ee0696ebf0dfe8f7c17f364d70617616afc7dafe366532730ca34056065b8a \
--hash=sha256:0c34139df09a61b1b557ab65782ada971b4a3bce7081d1b2bee45b0a52231adb \
@ -1286,6 +1342,7 @@ rapidfuzz==3.9.3 \
--hash=sha256:f50fed4a9b0c9825ff37cf0bccafd51ff5792090618f7846a7650f21f85579c9 \
--hash=sha256:f57e8305c281e8c8bc720515540e0580355100c0a7a541105c6cafc5de71daae \
--hash=sha256:fd84b7f652a5610733400307dc732f57c4a907080bef9520412e6d9b55bc9adc
# via -r src/backend/requirements.in
redis==5.0.7 \
--hash=sha256:0e479e24da960c690be5d9b96d21f7b918a98c0cf49af3b6fafaa0753f93a0db \
--hash=sha256:8f611490b93c8109b50adc317b31bfd84fff31def3475b92e7e80bf39f48175b
@ -1376,6 +1433,7 @@ regex==2024.4.28 \
--hash=sha256:fd24fd140b69f0b0bcc9165c397e9b2e89ecbeda83303abf2a072609f60239e2 \
--hash=sha256:fdae0120cddc839eb8e3c15faa8ad541cc6d906d3eb24d82fb041cfe2807bc1e \
--hash=sha256:fe00f4fe11c8a521b173e6324d862ee7ee3412bf7107570c9b564fe1119b56fb
# via -r src/backend/requirements.in
requests==2.32.3 \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
@ -1488,11 +1546,14 @@ rpds-py==0.18.1 \
sentry-sdk==2.7.0 \
--hash=sha256:d846a211d4a0378b289ced3c434480945f110d0ede00450ba631fc2852e7a0d4 \
--hash=sha256:db9594c27a4d21c1ebad09908b1f0dc808ef65c2b89c1c8e7e455143262e37c1
# via django-q-sentry
# via
# -r src/backend/requirements.in
# django-q-sentry
setuptools==70.3.0 \
--hash=sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5 \
--hash=sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc
# via
# -r src/backend/requirements.in
# django-money
# opentelemetry-instrumentation
sgmllib3k==1.0.0 \
@ -1515,7 +1576,9 @@ sqlparse==0.5.0 \
tablib[html, ods, xls, xlsx, yaml]==3.5.0 \
--hash=sha256:9821caa9eca6062ff7299fa645e737aecff982e6b2b42046928a6413c8dabfd9 \
--hash=sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33
# via django-import-export
# via
# -r src/backend/requirements.in
# django-import-export
tinycss2==1.2.1 \
--hash=sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847 \
--hash=sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627
@ -1552,7 +1615,9 @@ wcwidth==0.2.13 \
weasyprint==61.2 \
--hash=sha256:47df6cfeeff8c6c28cf2e4caf837cde17715efe462708ada74baa2eb391b6059 \
--hash=sha256:76c6dc0e75e09182d5645d92c66ddf86b1b992c9420235b723fb374b584e5bf4
# via django-weasyprint
# via
# -r src/backend/requirements.in
# django-weasyprint
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
@ -1564,6 +1629,7 @@ webencodings==0.5.1 \
whitenoise==6.7.0 \
--hash=sha256:58c7a6cd811e275a6c91af22e96e87da0b1109e9a53bb7464116ef4c963bf636 \
--hash=sha256:a1ae85e01fdc9815d12fa33f17765bc132ed2c54fa76daf9e39e879dd93566f6
# via -r src/backend/requirements.in
wrapt==1.16.0 \
--hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \
--hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \

View File

@ -139,6 +139,7 @@ export function OptionsApiForm({
if (!props.ignorePermissionCheck) {
fields = extractAvailableFields(response, props.method);
}
return fields;
},
throwOnError: (error: any) => {
@ -183,7 +184,7 @@ export function OptionsApiForm({
<ApiForm
id={id}
props={formProps}
optionsLoading={optionsQuery.isFetching}
optionsLoading={optionsQuery.isFetching || !optionsQuery.data}
/>
);
}
@ -206,9 +207,6 @@ export function ApiForm({
const [fields, setFields] = useState<ApiFormFieldSet>(
() => props.fields ?? {}
);
useEffect(() => {
setFields(props.fields ?? {});
}, [props.fields]);
const defaultValues: FieldValues = useMemo(() => {
let defaultValuesMap = mapFields(fields ?? {}, (_path, field) => {
@ -314,11 +312,24 @@ export function ApiForm({
} catch (error) {
console.error('ERR: Error fetching initial data:', error);
// Re-throw error to allow react-query to handle error
throw error;
return {};
}
}
});
useEffect(() => {
let _fields = props.fields ?? {};
// Ensure default values override initial field spec
for (const k of Object.keys(_fields)) {
if (defaultValues[k]) {
_fields[k].value = defaultValues[k];
}
}
setFields(_fields);
}, [props.fields, defaultValues, initialDataQuery.data]);
// Fetch initial data on form load
useEffect(() => {
// Fetch initial data if the fetchInitialData property is set
@ -559,21 +570,23 @@ export function ApiForm({
)}
</Boundary>
<Boundary label={`ApiForm-${id}-FormContent`}>
<FormProvider {...form}>
<Stack gap="xs">
{!optionsLoading &&
Object.entries(fields).map(([fieldName, field]) => (
<ApiFormField
key={fieldName}
fieldName={fieldName}
definition={field}
control={form.control}
url={url}
setFields={setFields}
/>
))}
</Stack>
</FormProvider>
{!isLoading && (
<FormProvider {...form}>
<Stack gap="xs">
{!optionsLoading &&
Object.entries(fields).map(([fieldName, field]) => (
<ApiFormField
key={fieldName}
fieldName={fieldName}
definition={field}
control={form.control}
url={url}
setFields={setFields}
/>
))}
</Stack>
</FormProvider>
)}
</Boundary>
<Boundary label={`ApiForm-${id}-PostFormContent`}>
{props.postFormContent}

View File

@ -149,7 +149,7 @@ export function ApiFormField({
label: hideLabels ? undefined : definition.label,
description: hideLabels ? undefined : definition.description
};
}, [definition]);
}, [hideLabels, definition]);
// pull out onValueChange as this can cause strange errors when passing the
// definition to the input components via spread syntax
@ -202,7 +202,7 @@ export function ApiFormField({
}
return val;
}, [value]);
}, [definition.field_type, value]);
// Coerce the value to a (stringified) boolean value
const booleanValue: boolean = useMemo(() => {

View File

@ -41,7 +41,8 @@ export function useSupplierPartFields() {
},
supplier: {
filters: {
active: true
active: true,
is_supplier: true
}
},
SKU: {
@ -69,7 +70,12 @@ export function useManufacturerPartFields() {
return useMemo(() => {
const fields: ApiFormFieldSet = {
part: {},
manufacturer: {},
manufacturer: {
filters: {
active: true,
is_manufacturer: true
}
},
MPN: {},
description: {},
link: {}

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

File diff suppressed because it is too large Load Diff

View File

@ -167,7 +167,7 @@ export default function AdminCenter() {
},
{
name: 'location-types',
label: t`Location types`,
label: t`Location Types`,
icon: <IconPackages />,
content: <LocationTypesTable />
},

View File

@ -168,12 +168,6 @@ export default function SystemSettings() {
/>
)
},
{
name: 'categories',
label: t`Part Categories`,
icon: <IconSitemap />,
content: <PlaceholderPanel />
},
{
name: 'parts',
label: t`Parts`,

View File

@ -9,7 +9,7 @@ import {
IconPaperclip
} from '@tabler/icons-react';
import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import AdminButton from '../../components/buttons/AdminButton';
import { DetailsField, DetailsTable } from '../../components/details/Details';
@ -29,8 +29,10 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles';
import { useManufacturerPartFields } from '../../forms/CompanyForms';
import { getDetailUrl } from '../../functions/urls';
import {
useCreateApiFormModal,
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance';
@ -43,6 +45,7 @@ import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
export default function ManufacturerPartDetail() {
const { id } = useParams();
const user = useUserState();
const navigate = useNavigate();
const {
instance: manufacturerPart,
@ -218,6 +221,15 @@ export default function ManufacturerPartDetail() {
modelType: ModelType.manufacturerpart
});
const deleteManufacturerPart = useDeleteApiFormModal({
url: ApiEndpoints.manufacturer_part_list,
pk: manufacturerPart?.pk,
title: t`Delete Manufacturer Part`,
onFormSuccess: () => {
navigate(getDetailUrl(ModelType.part, manufacturerPart.part));
}
});
const manufacturerPartActions = useMemo(() => {
return [
<AdminButton
@ -237,7 +249,8 @@ export default function ManufacturerPartDetail() {
onClick: () => editManufacturerPart.open()
}),
DeleteItemAction({
hidden: !user.hasDeleteRole(UserRoles.purchase_order)
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
onClick: () => deleteManufacturerPart.open()
})
]}
/>
@ -259,6 +272,8 @@ export default function ManufacturerPartDetail() {
return (
<>
{deleteManufacturerPart.modal}
{duplicateManufacturerPart.modal}
{editManufacturerPart.modal}
<InstanceDetail status={requestStatus} loading={instanceQuery.isFetching}>
<Stack gap="xs">

View File

@ -9,7 +9,7 @@ import {
IconShoppingCart
} from '@tabler/icons-react';
import { ReactNode, useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import AdminButton from '../../components/buttons/AdminButton';
import { DetailsField, DetailsTable } from '../../components/details/Details';
@ -30,8 +30,10 @@ import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType';
import { UserRoles } from '../../enums/Roles';
import { useSupplierPartFields } from '../../forms/CompanyForms';
import { getDetailUrl } from '../../functions/urls';
import {
useCreateApiFormModal,
useDeleteApiFormModal,
useEditApiFormModal
} from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance';
@ -46,6 +48,8 @@ export default function SupplierPartDetail() {
const user = useUserState();
const navigate = useNavigate();
const {
instance: supplierPart,
instanceQuery,
@ -271,10 +275,11 @@ export default function SupplierPartDetail() {
}),
EditItemAction({
hidden: !user.hasChangeRole(UserRoles.purchase_order),
onClick: () => editSuppliertPart.open()
onClick: () => editSupplierPart.open()
}),
DeleteItemAction({
hidden: !user.hasDeleteRole(UserRoles.purchase_order)
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
onClick: () => deleteSupplierPart.open()
})
]}
/>
@ -283,7 +288,7 @@ export default function SupplierPartDetail() {
const supplierPartFields = useSupplierPartFields();
const editSuppliertPart = useEditApiFormModal({
const editSupplierPart = useEditApiFormModal({
url: ApiEndpoints.supplier_part_list,
pk: supplierPart?.pk,
title: t`Edit Supplier Part`,
@ -291,6 +296,15 @@ export default function SupplierPartDetail() {
onFormSuccess: refreshInstance
});
const deleteSupplierPart = useDeleteApiFormModal({
url: ApiEndpoints.supplier_part_list,
pk: supplierPart?.pk,
title: t`Delete Supplier Part`,
onFormSuccess: () => {
navigate(getDetailUrl(ModelType.part, supplierPart.part));
}
});
const duplicateSupplierPart = useCreateApiFormModal({
url: ApiEndpoints.supplier_part_list,
title: t`Add Supplier Part`,
@ -327,7 +341,9 @@ export default function SupplierPartDetail() {
return (
<>
{editSuppliertPart.modal}
{deleteSupplierPart.modal}
{duplicateSupplierPart.modal}
{editSupplierPart.modal}
<InstanceDetail status={requestStatus} loading={instanceQuery.isFetching}>
<Stack gap="xs">
<PageDetail

View File

@ -45,6 +45,7 @@ import { cancelEvent } from '../functions/events';
import { extractAvailableFields, mapFields } from '../functions/forms';
import { navigateToLink } from '../functions/navigation';
import { getDetailUrl } from '../functions/urls';
import { useDeleteApiFormModal } from '../hooks/UseForm';
import { TableState } from '../hooks/UseTable';
import { useLocalState } from '../states/LocalState';
import { TableColumn } from './Column';
@ -495,66 +496,34 @@ export function InvenTreeTable<T = any>({
tableState.setRecords(data ?? []);
}, [data]);
// Callback function to delete the selected records in the table
const deleteSelectedRecords = useCallback((ids: number[]) => {
if (ids.length == 0) {
// Ignore if no records are selected
return;
}
modals.openConfirmModal({
title: t`Delete selected records`,
children: (
<Alert
color="red"
title={t`Are you sure you want to delete the selected records?`}
>
{t`This action cannot be undone!`}
</Alert>
),
labels: {
confirm: t`Delete`,
cancel: t`Cancel`
},
confirmProps: {
color: 'red'
},
onConfirm: () => {
api
.delete(url, {
data: {
items: ids
}
})
.then((_response) => {
// Refresh the table
refetch();
// Show notification
showNotification({
title: t`Deleted records`,
message: t`Records were deleted successfully`,
color: 'green'
});
})
.catch((_error) => {
console.warn(`Bulk delete operation failed at ${url}`);
showNotification({
title: t`Error`,
message: t`Failed to delete records`,
color: 'red'
});
})
.finally(() => {
tableState.clearSelectedRecords();
if (props.afterBulkDelete) {
props.afterBulkDelete();
}
});
const deleteRecords = useDeleteApiFormModal({
url: url,
title: t`Delete Selected Items`,
preFormContent: (
<Alert
color="red"
title={t`Are you sure you want to delete the selected items?`}
>
{t`This action cannot be undone!`}
</Alert>
),
initialData: {
items: tableState.selectedIds
},
fields: {
items: {
hidden: true
}
});
}, []);
},
onFormSuccess: () => {
tableState.clearSelectedRecords();
tableState.refreshTable();
if (props.afterBulkDelete) {
props.afterBulkDelete();
}
}
});
// Callback when a row is clicked
const handleRowClick = useCallback(
@ -587,6 +556,7 @@ export function InvenTreeTable<T = any>({
return (
<>
{deleteRecords.modal}
{tableProps.enableFilters && (filters.length ?? 0) > 0 && (
<Boundary label="table-filter-drawer">
<FilterSelectDrawer
@ -623,7 +593,9 @@ export function InvenTreeTable<T = any>({
icon={<IconTrash />}
color="red"
tooltip={t`Delete selected records`}
onClick={() => deleteSelectedRecords(tableState.selectedIds)}
onClick={() => {
deleteRecords.open();
}}
/>
)}
{tableProps.tableActions?.map((group, idx) => (

View File

@ -28,7 +28,6 @@ test('PUI - Admin', async ({ page }) => {
await page.getByRole('tab', { name: 'Pricing' }).click();
await page.getByRole('tab', { name: 'Labels' }).click();
await page.getByRole('tab', { name: 'Reporting' }).click();
await page.getByRole('tab', { name: 'Part Categories' }).click();
await page.getByRole('tab', { name: 'Stocktake' }).click();
await page.getByRole('tab', { name: 'Build Orders' }).click();

View File

@ -1272,6 +1272,34 @@ def frontend_download(
handle_extract(dst.name)
def check_already_current(tag=None, sha=None):
"""Check if the currently available frontend is already the requested one."""
ref = 'tag' if tag else 'commit'
if tag:
current = managePyDir().joinpath('web', 'static', 'web', '.vite', 'tag.txt')
elif sha:
current = managePyDir().joinpath('web', 'static', 'web', '.vite', 'sha.txt')
else:
raise ValueError('Either tag or sha needs to be set')
if not current.exists():
print(
f'Current frontend information for {ref} is not available - this is expected in some cases'
)
return False
current_content = current.read_text().strip()
ref_value = tag or sha
if current_content == ref_value:
print(f'Frontend {ref} is already `{ref_value}`')
return True
else:
print(
f'Frontend {ref} is not expected `{ref_value}` but `{current_content}` - new version will be downloaded'
)
return False
# if zip file is specified, try to extract it directly
if file:
handle_extract(file)
@ -1288,8 +1316,24 @@ def frontend_download(
['git', 'rev-parse', 'HEAD'], encoding='utf-8'
).strip()
except Exception:
print("[ERROR] Cannot get current ref via 'git rev-parse HEAD'")
return
# .deb Packages contain extra information in the VERSION file
version_file = localDir().joinpath('VERSION')
if not version_file.exists():
return
from dotenv import dotenv_values # noqa: WPS433
content = dotenv_values(version_file)
if (
'INVENTREE_PKG_INSTALLER' in content
and content['INVENTREE_PKG_INSTALLER'] == 'PKG'
):
ref = content.get('INVENTREE_COMMIT_SHA')
print(
f'[INFO] Running in package environment, got commit "{ref}" from VERSION file'
)
else:
print("[ERROR] Cannot get current ref via 'git rev-parse HEAD'")
return
if ref is None and tag is None:
print('[ERROR] Either ref or tag needs to be set.')
@ -1297,6 +1341,8 @@ def frontend_download(
if tag:
tag = tag.lstrip('v')
try:
if check_already_current(tag=tag):
return
handle_download(
f'https://github.com/{repo}/releases/download/{tag}/frontend-build.zip'
)
@ -1312,6 +1358,8 @@ Then try continuing by running: invoke frontend-download --file <path-to-downloa
return
if ref:
if check_already_current(sha=ref):
return
# get workflow run from all workflow runs on that particular ref
workflow_runs = requests.get(
f'https://api.github.com/repos/{repo}/actions/runs?head_sha={ref}',