2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 13:05:42 +00:00

Remove django-allauth-2fa

Fixes #6281
This commit is contained in:
Matthias Mair
2024-04-23 13:09:30 +02:00
47 changed files with 2454 additions and 288 deletions

View File

@ -38,8 +38,8 @@ steps:
- script: | - script: |
python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade pip setuptools wheel
pip install -r requirements.txt pip install --require-hashes -r requirements.txt
pip install -r requirements-dev.txt pip install --require-hashes -r requirements-dev.txt
pip install unittest-xml-reporting coverage invoke pip install unittest-xml-reporting coverage invoke
sudo apt-get install poppler-utils sudo apt-get install poppler-utils
sudo apt-get install libpoppler-dev sudo apt-get install libpoppler-dev

View File

@ -84,7 +84,7 @@ runs:
- name: Install dev requirements - name: Install dev requirements
if: ${{ inputs.dev-install == 'true' ||inputs.install == 'true' }} if: ${{ inputs.dev-install == 'true' ||inputs.install == 'true' }}
shell: bash shell: bash
run: uv pip install -r src/backend/requirements-dev.txt run: uv pip install --require-hashes -r src/backend/requirements-dev.txt
- name: Run invoke install - name: Run invoke install
if: ${{ inputs.install == 'true' }} if: ${{ inputs.install == 'true' }}
shell: bash shell: bash

View File

@ -4,6 +4,10 @@ updates:
directory: / directory: /
schedule: schedule:
interval: weekly interval: weekly
groups:
dependencies:
patterns:
- "*" # Include all dependencies
- package-ecosystem: docker - package-ecosystem: docker
directory: /contrib/container directory: /contrib/container
@ -24,13 +28,25 @@ updates:
directory: /src/backend directory: /src/backend
schedule: schedule:
interval: weekly interval: weekly
groups:
dependencies:
patterns:
- "*" # Include all dependencies
- package-ecosystem: pip - package-ecosystem: pip
directory: /src/backend directory: /src/backend
schedule: schedule:
interval: weekly interval: weekly
groups:
dependencies:
patterns:
- "*" # Include all dependencies
- package-ecosystem: npm - package-ecosystem: npm
directory: /src/frontend directory: /src/frontend
schedule: schedule:
interval: weekly interval: weekly
groups:
dependencies:
patterns:
- "*" # Include all dependencies

3
.github/requirements.in vendored Normal file
View File

@ -0,0 +1,3 @@
# Packages needed for CI
requests==2.31.0
pyyaml==6.0.1

161
.github/requirements.txt vendored Normal file
View File

@ -0,0 +1,161 @@
# This file was autogenerated by uv via the following command:
# uv pip compile .github/requirements.in -o .github/requirements.txt --python-version=3.9 --no-strip-extras --generate-hashes
certifi==2024.2.2 \
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
# via requests
charset-normalizer==3.3.2 \
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via requests
idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
# via requests
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
urllib3==2.2.1 \
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
--hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
# via requests

View File

@ -24,10 +24,6 @@ on:
branches: branches:
- "master" - "master"
env:
requests_version: 2.31.0
pyyaml_version: 6.0.1
permissions: permissions:
contents: read contents: read
@ -80,8 +76,7 @@ jobs:
python-version: ${{ env.python_version }} python-version: ${{ env.python_version }}
- name: Version Check - name: Version Check
run: | run: |
pip install requests==${{ env.requests_version }} pip install --require-hashes -r .github/requirements.txt
pip install pyyaml==${{ env.pyyaml_version }}
python3 .github/scripts/version_check.py python3 .github/scripts/version_check.py
echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV echo "git_commit_hash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV

View File

@ -104,7 +104,7 @@ jobs:
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # pin@v3.0.1 uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # pin@v3.0.1
- name: Check Version - name: Check Version
run: | run: |
pip install requests==${{ env.requests_version }} pip install --require-hashes -r .github/requirements.txt
python3 .github/scripts/version_check.py python3 .github/scripts/version_check.py
mkdocs: mkdocs:
@ -122,7 +122,7 @@ jobs:
python-version: ${{ env.python_version }} python-version: ${{ env.python_version }}
- name: Check Config - name: Check Config
run: | run: |
pip install pyyaml==${{ env.pyyaml_version }} pip install --require-hashes -r .github/requirements.txt
pip install -r docs/requirements.txt pip install -r docs/requirements.txt
python docs/ci/check_mkdocs_config.py python docs/ci/check_mkdocs_config.py
- name: Check Links - name: Check Links
@ -168,7 +168,7 @@ jobs:
- name: Download public schema - name: Download public schema
if: needs.paths-filter.outputs.api == 'false' if: needs.paths-filter.outputs.api == 'false'
run: | run: |
pip install requests==${{ env.requests_version }} >/dev/null 2>&1 pip install --require-hashes -r .github/requirements.txt >/dev/null 2>&1
version="$(python3 .github/scripts/version_check.py only_version 2>&1)" version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
echo "Version: $version" echo "Version: $version"
url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml" url="https://raw.githubusercontent.com/inventree/schema/main/export/${version}/api.yaml"
@ -187,7 +187,7 @@ jobs:
id: version id: version
if: github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true' if: github.ref == 'refs/heads/master' && needs.paths-filter.outputs.api == 'true'
run: | run: |
pip install requests==${{ env.requests_version }} >/dev/null 2>&1 pip install --require-hashes -r .github/requirements.txt >/dev/null 2>&1
version="$(python3 .github/scripts/version_check.py only_version 2>&1)" version="$(python3 .github/scripts/version_check.py only_version 2>&1)"
echo "Version: $version" echo "Version: $version"
echo "version=$version" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT"
@ -290,16 +290,6 @@ jobs:
run: python3 .github/scripts/check_migration_files.py run: python3 .github/scripts/check_migration_files.py
- name: Coverage Tests - name: Coverage Tests
run: invoke test --coverage run: invoke test --coverage
- name: Upload Coverage Report to Coveralls
if: always()
uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 # pin@v2.2.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: backend
file: coverage.xml
git-commit: ${{ github.sha }}
git-branch: ${{ github.ref }}
parallel: true
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # pin@v4.3.0 uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # pin@v4.3.0
if: always() if: always()
@ -432,14 +422,6 @@ jobs:
update: true update: true
- name: Run Tests - name: Run Tests
run: invoke test --migrations --report --coverage run: invoke test --migrations --report --coverage
- name: Upload Coverage Report to Coveralls
if: always()
uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 # pin@v2.2.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: migrations
git-commit: ${{ github.sha }}
git-branch: ${{ github.ref }}
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # pin@v4.3.0 uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # pin@v4.3.0
if: always() if: always()
@ -576,19 +558,3 @@ jobs:
with: with:
name: frontend-build name: frontend-build
path: src/backend/InvenTree/web/static/web path: src/backend/InvenTree/web/static/web
finish_coverage:
name: Finish Coverage
runs-on: ubuntu-20.04
needs: ["platform_ui", "coverage", "migration-tests", "paths-filter"]
if: (needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true') && (needs.platform_ui.result == 'success' || needs.coverage.result == 'success' || needs.migration-tests.result == 'success')
steps:
- name: Finish coverage reporting
uses: coverallsapp/github-action@3dfc5567390f6fa9267c0ee9c251e4c8c3f18949 # pin@v2.2.3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
carryforward: "pui,backend,migrations"
parallel-finished: true
git-commit: ${{ github.sha }}
git-branch: ${{ github.ref }}

View File

@ -5,9 +5,6 @@ on:
release: release:
types: [published] types: [published]
env:
requests_version: 2.31.0
permissions: permissions:
contents: read contents: read
@ -21,7 +18,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
- name: Version Check - name: Version Check
run: | run: |
pip install requests==${{ env.requests_version }} pip install --require-hashes -r .github/requirements.txt
python3 .github/scripts/version_check.py python3 .github/scripts/version_check.py
- name: Push to Stable Branch - name: Push to Stable Branch
uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0 uses: ad-m/github-push-action@d91a481090679876dfc4178fef17f286781251df # pin@v0.8.0

View File

@ -11,7 +11,7 @@ jobs:
steps: steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # pin@v4.1.1
- name: Setup - name: Setup
run: pip install -r requirements-dev.txt run: pip install --require-hashes -r requirements-dev.txt
- name: Update requirements.txt - name: Update requirements.txt
run: pip-compile --output-file=requirements.txt requirements.in -U run: pip-compile --output-file=requirements.txt requirements.in -U
- name: Update requirements-dev.txt - name: Update requirements-dev.txt

View File

@ -10,14 +10,14 @@ exclude: |
)$ )$
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0 rev: v4.6.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer
- id: check-yaml - id: check-yaml
- id: mixed-line-ending - id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.5 rev: v0.4.1
hooks: hooks:
- id: ruff-format - id: ruff-format
args: [--preview] args: [--preview]
@ -27,16 +27,20 @@ repos:
--preview --preview
] ]
- repo: https://github.com/astral-sh/uv-pre-commit - repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.1.29 rev: 0.1.35
hooks: hooks:
- id: pip-compile - id: pip-compile
name: pip-compile requirements-dev.in name: pip-compile requirements-dev.in
args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --python-version=3.9, --no-strip-extras] args: [src/backend/requirements-dev.in, -o, src/backend/requirements-dev.txt, --python-version=3.9, --no-strip-extras, --generate-hashes]
files: src/backend/requirements-dev\.(in|txt)$ files: src/backend/requirements-dev\.(in|txt)$
- id: pip-compile - id: pip-compile
name: pip-compile requirements.txt name: pip-compile requirements.txt
args: [src/backend/requirements.in, -o, src/backend/requirements.txt,--python-version=3.9, --no-strip-extras] args: [src/backend/requirements.in, -o, src/backend/requirements.txt,--python-version=3.9, --no-strip-extras,--generate-hashes]
files: src/backend/requirements\.(in|txt)$ files: src/backend/requirements\.(in|txt)$
- id: pip-compile
name: pip-compile requirements.txt
args: [.github/requirements.in, -o, .github/requirements.txt,--python-version=3.9, --no-strip-extras, --generate-hashes]
files: .github/requirements\.(in|txt)$
- repo: https://github.com/Riverside-Healthcare/djLint - repo: https://github.com/Riverside-Healthcare/djLint
rev: v1.34.1 rev: v1.34.1
hooks: hooks:
@ -61,7 +65,7 @@ repos:
- "prettier@^2.4.1" - "prettier@^2.4.1"
- "@trivago/prettier-plugin-sort-imports" - "@trivago/prettier-plugin-sort-imports"
- repo: https://github.com/pre-commit/mirrors-eslint - repo: https://github.com/pre-commit/mirrors-eslint
rev: "v9.0.0" rev: "v9.1.0"
hooks: hooks:
- id: eslint - id: eslint
additional_dependencies: additional_dependencies:

View File

@ -13,7 +13,6 @@
[![Netlify Status](https://api.netlify.com/api/v1/badges/9bbb2101-0a4d-41e7-ad56-b63fb6053094/deploy-status)](https://app.netlify.com/sites/inventree/deploys) [![Netlify Status](https://api.netlify.com/api/v1/badges/9bbb2101-0a4d-41e7-ad56-b63fb6053094/deploy-status)](https://app.netlify.com/sites/inventree/deploys)
[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=inventree_InvenTree&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=inventree_InvenTree) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=inventree_InvenTree&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=inventree_InvenTree)
[![Coveralls](https://img.shields.io/coveralls/github/inventree/InvenTree)](https://coveralls.io/github/inventree/InvenTree)
[![codecov](https://codecov.io/gh/inventree/InvenTree/graph/badge.svg?token=9DZRGUUV7B)](https://codecov.io/gh/inventree/InvenTree) [![codecov](https://codecov.io/gh/inventree/InvenTree/graph/badge.svg?token=9DZRGUUV7B)](https://codecov.io/gh/inventree/InvenTree)
[![Crowdin](https://badges.crowdin.net/inventree/localized.svg)](https://crowdin.com/project/inventree) [![Crowdin](https://badges.crowdin.net/inventree/localized.svg)](https://crowdin.com/project/inventree)
![GitHub commit activity](https://img.shields.io/github/commit-activity/m/inventree/inventree) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/inventree/inventree)
@ -95,7 +94,7 @@ InvenTree is designed to be **extensible**, and provides multiple options for **
<ul> <ul>
<li><a href="https://hub.docker.com/r/inventree/inventree">Docker</a></li> <li><a href="https://hub.docker.com/r/inventree/inventree">Docker</a></li>
<li><a href="https://crowdin.com/project/inventree">Crowdin</a></li> <li><a href="https://crowdin.com/project/inventree">Crowdin</a></li>
<li><a href="https://coveralls.io/github/inventree/InvenTree">Coveralls</a></li> <li><a href="https://app.codecov.io/gh/inventree/InvenTree">Codecov</a></li>
<li><a href="https://app.deepsource.com/gh/inventree/InvenTree">DeepSource</a></li> <li><a href="https://app.deepsource.com/gh/inventree/InvenTree">DeepSource</a></li>
<li><a href="https://packager.io/gh/inventree/InvenTree">Packager.io</a></li> <li><a href="https://packager.io/gh/inventree/InvenTree">Packager.io</a></li>
</ul> </ul>

View File

@ -97,7 +97,8 @@ FROM inventree_base AS prebuild
ENV PATH=/root/.local/bin:$PATH ENV PATH=/root/.local/bin:$PATH
RUN ./install_build_packages.sh --no-cache --virtual .build-deps && \ RUN ./install_build_packages.sh --no-cache --virtual .build-deps && \
pip install --user -r base_requirements.txt -r requirements.txt --no-cache && \ pip install --user -r base_requirements.txt --no-cache && \
pip install --user --require-hashes -r requirements.txt --no-cache && \
apk --purge del .build-deps apk --purge del .build-deps
# Frontend builder image: # Frontend builder image:

View File

@ -39,7 +39,6 @@ InvenTree relies on the following Python libraries:
| [flake8](https://pypi.org/project/flake8/) | MIT | style checking | | [flake8](https://pypi.org/project/flake8/) | MIT | style checking |
| [pep8-naming](https://pypi.org/project/pep8-naming/) | Expat | name checking | | [pep8-naming](https://pypi.org/project/pep8-naming/) | Expat | name checking |
| [coverage](https://pypi.org/project/coverage/) | Apache-2.0 | coverage checking | | [coverage](https://pypi.org/project/coverage/) | Apache-2.0 | coverage checking |
| [coveralls](https://pypi.org/project/coveralls/) | MIT | coverage uploader |
| [django-formtools](https://pypi.org/project/django-formtools/) | MIT | better forms / wizards | | [django-formtools](https://pypi.org/project/django-formtools/) | MIT | better forms / wizards |
| [django-allauth](https://pypi.org/project/django-allauth/) | MIT | SSO for django | | [django-allauth](https://pypi.org/project/django-allauth/) | MIT | SSO for django |
| [pint](https://pint.readthedocs.io/en/stable/) | [licence](https://github.com/hgrecco/pint/blob/master/LICENSE) | Physical unit conversion | | [pint](https://pint.readthedocs.io/en/stable/) | [licence](https://github.com/hgrecco/pint/blob/master/LICENSE) | Physical unit conversion |

View File

@ -19,7 +19,7 @@ If the `invoke` command does not work, it means that the [invoke](https://pypi.o
Update the installed python packages with PIP: Update the installed python packages with PIP:
``` ```
pip3 install -U -r requirements.txt pip3 install -U --require-hashes -r requirements.txt
``` ```
### Invoke Version ### Invoke Version

View File

@ -37,7 +37,7 @@ InvenTree is built using the Django framework, which has a strong focus on secur
### Test coverage ### Test coverage
We run coverage tests on our codebase to ensure that we have a high level of test coverage above 90%. This is public and can be found [here](https://coveralls.io/github/inventree/InvenTree). We run coverage tests on our codebase to ensure that we have a high level of test coverage above 90%. This is public and can be found [here](https://app.codecov.io/gh/inventree/InvenTree).
### Pinning dependencies ### Pinning dependencies

View File

@ -324,6 +324,7 @@ The logo and custom messages can be changed/set:
| INVENTREE_CUSTOM_SPLASH | customize.splash | Path to custom splash screen in the static files directory | *Not specified* | | INVENTREE_CUSTOM_SPLASH | customize.splash | Path to custom splash screen in the static files directory | *Not specified* |
| INVENTREE_CUSTOMIZE | customize.login_message | Custom message for login page | *Not specified* | | INVENTREE_CUSTOMIZE | customize.login_message | Custom message for login page | *Not specified* |
| INVENTREE_CUSTOMIZE | customize.navbar_message | Custom message for navbar | *Not specified* | | INVENTREE_CUSTOMIZE | customize.navbar_message | Custom message for navbar | *Not specified* |
| INVENTREE_CUSTOMIZE | customize.hide_pui_banner | Disable PUI banner | False |
If you want to remove the InvenTree branding as far as possible from your end-user also check the [global server settings](../settings/global.md#server-settings). If you want to remove the InvenTree branding as far as possible from your end-user also check the [global server settings](../settings/global.md#server-settings).

View File

@ -1,11 +1,17 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 190 INVENTREE_API_VERSION = 192
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v192 - 2024-04-23 : https://github.com/inventree/InvenTree/pull/7106
- Adds 'trackable' ordering option to BuildLineLabel API endpoint
v191 - 2024-04-22 : https://github.com/inventree/InvenTree/pull/7079
- Adds API endpoints for Contenttype model
v190 - 2024-04-19 : https://github.com/inventree/InvenTree/pull/7024 v190 - 2024-04-19 : https://github.com/inventree/InvenTree/pull/7024
- Adds "active" field to the Company API endpoints - Adds "active" field to the Company API endpoints
- Allow company list to be filtered by "active" status - Allow company list to be filtered by "active" status

View File

@ -280,6 +280,8 @@ class InvenTreeMetadata(SimpleMetadata):
# Special case for 'user' model # Special case for 'user' model
if field_info['model'] == 'user': if field_info['model'] == 'user':
field_info['api_url'] = '/api/user/' field_info['api_url'] = '/api/user/'
elif field_info['model'] == 'contenttype':
field_info['api_url'] = '/api/contenttype/'
else: else:
field_info['api_url'] = model.get_api_url() field_info['api_url'] = model.get_api_url()

View File

@ -349,6 +349,7 @@ class BuildLineList(BuildLineEndpoint, ListCreateAPI):
'optional', 'optional',
'unit_quantity', 'unit_quantity',
'available_stock', 'available_stock',
'trackable',
] ]
ordering_field_aliases = { ordering_field_aliases = {
@ -357,6 +358,7 @@ class BuildLineList(BuildLineEndpoint, ListCreateAPI):
'unit_quantity': 'bom_item__quantity', 'unit_quantity': 'bom_item__quantity',
'consumable': 'bom_item__consumable', 'consumable': 'bom_item__consumable',
'optional': 'bom_item__optional', 'optional': 'bom_item__optional',
'trackable': 'bom_item__sub_part__trackable',
} }
search_fields = [ search_fields = [

View File

@ -3,6 +3,7 @@
import json import json
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.http.response import HttpResponse from django.http.response import HttpResponse
from django.urls import include, path, re_path from django.urls import include, path, re_path
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
@ -619,6 +620,38 @@ class FlagDetail(RetrieveAPI):
return {key: value} return {key: value}
class ContentTypeList(ListAPI):
"""List view for ContentTypes."""
queryset = ContentType.objects.all()
serializer_class = common.serializers.ContentTypeSerializer
permission_classes = [permissions.IsAuthenticated]
class ContentTypeDetail(RetrieveAPI):
"""Detail view for a ContentType model."""
queryset = ContentType.objects.all()
serializer_class = common.serializers.ContentTypeSerializer
permission_classes = [permissions.IsAuthenticated]
@extend_schema(operation_id='contenttype_retrieve_model')
class ContentTypeModelDetail(ContentTypeDetail):
"""Detail view for a ContentType model."""
def get_object(self):
"""Attempt to find a ContentType object with the provided key."""
model_ref = self.kwargs.get('model', None)
if model_ref:
qs = self.filter_queryset(self.get_queryset())
try:
return qs.get(model=model_ref)
except ContentType.DoesNotExist:
raise NotFound()
raise NotFound()
settings_api_urls = [ settings_api_urls = [
# User settings # User settings
path( path(
@ -799,6 +832,21 @@ common_api_urls = [
path('', AllStatusViews.as_view(), name='api-status-all'), path('', AllStatusViews.as_view(), name='api-status-all'),
]), ]),
), ),
# Contenttype
path(
'contenttype/',
include([
path(
'<int:pk>/', ContentTypeDetail.as_view(), name='api-contenttype-detail'
),
path(
'<str:model>/',
ContentTypeModelDetail.as_view(),
name='api-contenttype-detail-modelname',
),
path('', ContentTypeList.as_view(), name='api-contenttype-list'),
]),
),
] ]
admin_api_urls = [ admin_api_urls = [

View File

@ -1,5 +1,6 @@
"""JSON serializers for common components.""" """JSON serializers for common components."""
from django.contrib.contenttypes.models import ContentType
from django.db.models import OuterRef, Subquery from django.db.models import OuterRef, Subquery
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -16,6 +17,7 @@ from InvenTree.serializers import (
InvenTreeImageSerializerField, InvenTreeImageSerializerField,
InvenTreeModelSerializer, InvenTreeModelSerializer,
) )
from plugin import registry as plugin_registry
from users.serializers import OwnerSerializer from users.serializers import OwnerSerializer
@ -303,6 +305,26 @@ class FlagSerializer(serializers.Serializer):
return data return data
class ContentTypeSerializer(serializers.Serializer):
"""Serializer for ContentType models."""
pk = serializers.IntegerField(read_only=True)
app_label = serializers.CharField(read_only=True)
model = serializers.CharField(read_only=True)
app_labeled_name = serializers.CharField(read_only=True)
is_plugin = serializers.SerializerMethodField('get_is_plugin', read_only=True)
class Meta:
"""Meta options for ContentTypeSerializer."""
model = ContentType
fields = ['pk', 'app_label', 'model', 'app_labeled_name', 'is_plugin']
def get_is_plugin(self, obj) -> bool:
"""Return True if the model is a plugin model."""
return obj.app_label in plugin_registry.installed_apps
class CustomUnitSerializer(InvenTreeModelSerializer): class CustomUnitSerializer(InvenTreeModelSerializer):
"""DRF serializer for CustomUnit model.""" """DRF serializer for CustomUnit model."""

View File

@ -8,6 +8,7 @@ from http import HTTPStatus
from unittest import mock from unittest import mock
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
@ -1339,3 +1340,46 @@ class CustomUnitAPITest(InvenTreeAPITestCase):
for name in invalid_name_values: for name in invalid_name_values:
self.patch(url, {'name': name}, expected_code=400) self.patch(url, {'name': name}, expected_code=400)
class ContentTypeAPITest(InvenTreeAPITestCase):
"""Unit tests for the ContentType API."""
def test_list(self):
"""Test API list functionality."""
response = self.get(reverse('api-contenttype-list'), expected_code=200)
self.assertEqual(len(response.data), ContentType.objects.count())
def test_detail(self):
"""Test API detail functionality."""
ct = ContentType.objects.first()
assert ct
response = self.get(
reverse('api-contenttype-detail', kwargs={'pk': ct.pk}), expected_code=200
)
self.assertEqual(response.data['app_label'], ct.app_label)
self.assertEqual(response.data['model'], ct.model)
# Test with model name
response = self.get(
reverse('api-contenttype-detail-modelname', kwargs={'model': ct.model}),
expected_code=200,
)
self.assertEqual(response.data['app_label'], ct.app_label)
self.assertEqual(response.data['model'], ct.model)
# Test non-existent model
self.get(
reverse(
'api-contenttype-detail-modelname', kwargs={'model': 'nonexistent'}
),
expected_code=404,
)
# PK should not work on model name endpoint
self.get(
reverse('api-contenttype-detail-modelname', kwargs={'model': None}),
expected_code=404,
)

View File

@ -300,6 +300,7 @@ remote_login_header: HTTP_REMOTE_USER
# hide_password_reset: true # hide_password_reset: true
# logo: img/custom_logo.png # logo: img/custom_logo.png
# splash: img/custom_splash.jpg # splash: img/custom_splash.jpg
# hide_pui_banner: true
# Set enabled frontends # Set enabled frontends
# Use the environment variable INVENTREE_CLASSIC_FRONTEND # Use the environment variable INVENTREE_CLASSIC_FRONTEND

View File

@ -10,6 +10,8 @@
{% block content %} {% block content %}
{% include "pui_banner.html" with mode='admin' %}
<table class='table table-striped table-condensed'> <table class='table table-striped table-condensed'>
<tbody> <tbody>
{% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" icon="fa-building" %} {% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" icon="fa-building" %}

View File

@ -16,6 +16,8 @@
</div> </div>
{% endif %} {% endif %}
{% include "pui_banner.html" with mode='admin' %}
<table class='table table-striped table-condensed'> <table class='table table-striped table-condensed'>
<tbody> <tbody>
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_PWD_FORGOT" icon="fa-user-lock" %} {% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_PWD_FORGOT" icon="fa-user-lock" %}

View File

@ -15,6 +15,8 @@
{% trans "Changing the settings below require you to immediately restart the server. Do not change this while under active usage." %} {% trans "Changing the settings below require you to immediately restart the server. Do not change this while under active usage." %}
</div> </div>
{% include "pui_banner.html" with mode='admin' %}
<div class='table-responsive'> <div class='table-responsive'>
<table class='table table-striped table-condensed'> <table class='table table-striped table-condensed'>
<tbody> <tbody>

View File

@ -10,6 +10,8 @@
{% block content %} {% block content %}
{% include "pui_banner.html" with mode='admin' %}
<table class='table table-striped table-condensed'> <table class='table table-striped table-condensed'>
<tbody> <tbody>
{% include "InvenTree/settings/setting.html" with key="REPORT_ENABLE" icon="fa-file-pdf" %} {% include "InvenTree/settings/setting.html" with key="REPORT_ENABLE" icon="fa-file-pdf" %}

View File

@ -13,6 +13,8 @@
{% inventree_customize 'login_message' as login_message %} {% inventree_customize 'login_message' as login_message %}
{% mail_configured as mail_conf %} {% mail_configured as mail_conf %}
{% include "pui_banner.html" with mode='user' %}
<div class='d-flex flex-wrap'> <div class='d-flex flex-wrap'>
<h3>{% trans "Sign In" %}</h3> <h3>{% trans "Sign In" %}</h3>
{% include "spacer.html" %} {% include "spacer.html" %}

View File

@ -2436,11 +2436,9 @@ function loadBuildLineTable(table, build_id, options={}) {
params.build = build_id; params.build = build_id;
if (output) { if (output) {
params.tracked = true;
params.output = output; params.output = output;
name += `-${output}`; name += `-${output}`;
} else {
// Default to untracked parts for the build
params.tracked = false;
} }
let filters = loadTableFilters('buildlines', params); let filters = loadTableFilters('buildlines', params);
@ -2649,7 +2647,11 @@ function loadBuildLineTable(table, build_id, options={}) {
if (row.part_detail.trackable && !options.output) { if (row.part_detail.trackable && !options.output) {
// Tracked parts must be allocated to a specific build output // Tracked parts must be allocated to a specific build output
return `<em>{% trans "Tracked item" %}</em>`; return `
<div>
<em>{% trans "Tracked item" %}</em>
<span title='{% trans "Allocate tracked items against individual build outputs" %}' class='fas fa-info-circle icon-blue' />
</div>`;
} }
if (row.allocated < row.quantity) { if (row.allocated < row.quantity) {

View File

@ -0,0 +1,17 @@
{% load inventree_extras %}
{% load i18n %}
{% inventree_customize 'hide_pui_banner' as hidden %}
{% if not hidden %}
<div class='alert alert-block alert-warning'>
{% if mode == 'admin' %}
{% trans "Platform UI - the new UI for InvenTree - provides more modern administration options." %}
{% endif %}
{% if mode == 'user' %}
{% trans "Platform UI - the new UI for InvenTree - is ready to be tested." %}
{% endif %}
<br>
{% trans "Try it out now" %} <a href="{% url 'platform' %}"/>{% trans "here" %}</a>.
</div>
{% endif %}

View File

@ -1,7 +1,6 @@
# Dev requirements for InvenTree # Dev requirements for InvenTree
-c requirements.txt -c requirements.txt
coverage[toml] # Unit test coverage coverage[toml] # Unit test coverage
coveralls==2.1.2 # Coveralls linking (for tracking coverage) # PINNED 2022-06-28 - Old version needed for correct upload
django-admin-shell # Remote shell access django-admin-shell # Remote shell access
django-querycount # Display number of URL queries for requests django-querycount # Display number of URL queries for requests
django-slowtests # Show which unit tests are running slowly django-slowtests # Show which unit tests are running slowly

View File

@ -1,90 +1,413 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# uv pip compile src/backend/requirements-dev.in -o src/backend/requirements-dev.txt --python-version=3.9 --no-strip-extras # uv pip compile src/backend/requirements-dev.in -o src/backend/requirements-dev.txt --python-version=3.9 --no-strip-extras --generate-hashes
asgiref==3.8.1 asgiref==3.8.1 \
--hash=sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47 \
--hash=sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590
# via django # via django
build==1.2.1 build==1.2.1 \
--hash=sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d \
--hash=sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4
# via pip-tools # via pip-tools
certifi==2024.2.2 cffi==1.16.0 \
# via requests --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
cffi==1.16.0 --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
--hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
--hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
--hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
--hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
--hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
--hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
--hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
--hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
--hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
--hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
--hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
--hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
--hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
--hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
--hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
--hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
--hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
# via cryptography # via cryptography
cfgv==3.4.0 cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
# via pre-commit # via pre-commit
charset-normalizer==3.3.2 charset-normalizer==3.3.2 \
# via --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
# pdfminer-six --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
# requests --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
click==8.1.7 --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
# via pip-tools --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
coverage[toml]==5.5 --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
# via coveralls --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
coveralls==2.1.2 --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
cryptography==42.0.5 --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via pdfminer-six # via pdfminer-six
distlib==0.3.8 click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
# via pip-tools
coverage[toml]==5.5 \
--hash=sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c \
--hash=sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6 \
--hash=sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45 \
--hash=sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a \
--hash=sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03 \
--hash=sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529 \
--hash=sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a \
--hash=sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a \
--hash=sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2 \
--hash=sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6 \
--hash=sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759 \
--hash=sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53 \
--hash=sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a \
--hash=sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4 \
--hash=sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff \
--hash=sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502 \
--hash=sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793 \
--hash=sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb \
--hash=sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905 \
--hash=sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821 \
--hash=sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b \
--hash=sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81 \
--hash=sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0 \
--hash=sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b \
--hash=sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3 \
--hash=sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184 \
--hash=sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701 \
--hash=sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a \
--hash=sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82 \
--hash=sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638 \
--hash=sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5 \
--hash=sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083 \
--hash=sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6 \
--hash=sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90 \
--hash=sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465 \
--hash=sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a \
--hash=sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3 \
--hash=sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e \
--hash=sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066 \
--hash=sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf \
--hash=sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b \
--hash=sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae \
--hash=sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669 \
--hash=sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873 \
--hash=sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b \
--hash=sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6 \
--hash=sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb \
--hash=sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160 \
--hash=sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c \
--hash=sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079 \
--hash=sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d \
--hash=sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6
cryptography==42.0.5 \
--hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \
--hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \
--hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \
--hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \
--hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \
--hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \
--hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \
--hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \
--hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \
--hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \
--hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \
--hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \
--hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \
--hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \
--hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \
--hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \
--hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \
--hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \
--hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \
--hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \
--hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \
--hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \
--hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \
--hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \
--hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \
--hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \
--hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \
--hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \
--hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \
--hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \
--hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \
--hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7
# via pdfminer-six
distlib==0.3.8 \
--hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \
--hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64
# via virtualenv # via virtualenv
django==4.2.11 django==4.2.11 \
--hash=sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4 \
--hash=sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3
# via # via
# django-admin-shell # django-admin-shell
# django-slowtests # django-slowtests
django-admin-shell==2.0.1 django-admin-shell==2.0.1 \
django-querycount==0.8.3 --hash=sha256:334a651e53ae4f59d0d279d7ede7dc5ed7a7733d4d093765b447dca5274c7b30 \
django-slowtests==1.1.1 --hash=sha256:b129e282ebd581c2099c0504edf081259728b3a504b40c5784d0457b8cb41470
django-test-migrations==1.3.0 django-querycount==0.8.3 \
docopt==0.6.2 --hash=sha256:0782484e8a1bd29498fa0195a67106e47cdcc98fafe80cebb1991964077cb694
# via coveralls django-slowtests==1.1.1 \
filelock==3.13.3 --hash=sha256:3c6936d420c9df444ac03625b41d97de043c662bbde61fbcd33e4cd407d0c247
django-test-migrations==1.3.0 \
--hash=sha256:b42edb1af481e08c9d91c95aa9b373e76e905a931bc19c086ec00a6cb936876e \
--hash=sha256:b52b29475f9a1bcaa4512f2ec8fad08b5f470cf1cf522e86b7d950252fb6fbf1
filelock==3.13.3 \
--hash=sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb \
--hash=sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546
# via virtualenv # via virtualenv
identify==2.5.35 identify==2.5.35 \
--hash=sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791 \
--hash=sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e
# via pre-commit # via pre-commit
idna==3.6 importlib-metadata==7.0.0 \
# via requests --hash=sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7 \
importlib-metadata==7.0.0 --hash=sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67
# via build # via build
isort==5.13.2 isort==5.13.2 \
nodeenv==1.8.0 --hash=sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109 \
--hash=sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6
nodeenv==1.8.0 \
--hash=sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2 \
--hash=sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec
# via pre-commit # via pre-commit
packaging==24.0 packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
# via build # via build
pdfminer-six==20231228 pdfminer-six==20231228 \
pip==24.0 --hash=sha256:6004da3ad1a7a4d45930cb950393df89b068e73be365a6ff64a838d37bcb08c4 \
--hash=sha256:e8d3c3310e6fbc1fe414090123ab01351634b4ecb021232206c4c9a8ca3e3b8f
pip==24.0 \
--hash=sha256:ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc \
--hash=sha256:ea9bd1a847e8c5774a5777bb398c19e80bcd4e2aa16a4b301b718fe6f593aba2
# via pip-tools # via pip-tools
pip-tools==7.4.1 pip-tools==7.4.1 \
platformdirs==4.2.0 --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \
--hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9
platformdirs==4.2.0 \
--hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \
--hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768
# via virtualenv # via virtualenv
pre-commit==3.7.0 pre-commit==3.7.0 \
pycparser==2.22 --hash=sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab \
--hash=sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi # via cffi
pyproject-hooks==1.0.0 pyproject-hooks==1.0.0 \
--hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \
--hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5
# via # via
# build # build
# pip-tools # pip-tools
pyyaml==6.0.1 pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
--hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
--hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
--hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
--hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
--hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
# via pre-commit # via pre-commit
requests==2.31.0 setuptools==69.5.1 \
# via coveralls --hash=sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987 \
setuptools==69.5.1 --hash=sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32
# via # via
# nodeenv # nodeenv
# pip-tools # pip-tools
sqlparse==0.4.4 sqlparse==0.4.4 \
--hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
--hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
# via django # via django
toml==0.10.2 toml==0.10.2 \
--hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
--hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
# via coverage # via coverage
tomli==2.0.1 tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
# via # via
# build # build
# pip-tools # pip-tools
# pyproject-hooks # pyproject-hooks
typing-extensions==4.11.0 typing-extensions==4.11.0 \
--hash=sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0 \
--hash=sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a
# via # via
# asgiref # asgiref
# django-test-migrations # django-test-migrations
urllib3==2.2.1 virtualenv==20.25.1 \
# via requests --hash=sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a \
virtualenv==20.25.1 --hash=sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197
# via pre-commit # via pre-commit
wheel==0.43.0 wheel==0.43.0 \
--hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \
--hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81
# via pip-tools # via pip-tools
zipp==3.18.1 zipp==3.18.1 \
--hash=sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b \
--hash=sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715
# via importlib-metadata # via importlib-metadata

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,9 @@ export default defineConfig({
}, },
{ {
command: 'invoke server -a 127.0.0.1:8000', command: 'invoke server -a 127.0.0.1:8000',
env: {
INVENTREE_DEBUG: 'True'
},
url: 'http://127.0.0.1:8000/api/', url: 'http://127.0.0.1:8000/api/',
reuseExistingServer: !process.env.CI, reuseExistingServer: !process.env.CI,
stdout: 'pipe', stdout: 'pipe',

View File

@ -19,3 +19,16 @@ export function isTrue(value: any): boolean {
return ['true', 'yes', '1', 'on', 't', 'y'].includes(s); return ['true', 'yes', '1', 'on', 't', 'y'].includes(s);
} }
/*
* Resolve a nested item in an object.
* Returns the resolved item, if it exists.
*
* e.g. resolveItem(data, "sub.key.accessor")
*
* Allows for retrieval of nested items in an object.
*/
export function resolveItem(obj: any, path: string): any {
let properties = path.split('.');
return properties.reduce((prev, curr) => prev?.[curr], obj);
}

View File

@ -203,8 +203,7 @@ export default function BuildDetail() {
content: build?.pk ? ( content: build?.pk ? (
<BuildLineTable <BuildLineTable
params={{ params={{
build: id, build: id
tracked: false
}} }}
/> />
) : ( ) : (

View File

@ -37,7 +37,13 @@ import { InvenTreeTable } from '../../../tables/InvenTreeTable';
import { NoPricingData } from './PricingPanel'; import { NoPricingData } from './PricingPanel';
// Display BOM data as a pie chart // Display BOM data as a pie chart
function BomPieChart({ data, currency }: { data: any[]; currency: string }) { function BomPieChart({
data,
currency
}: {
readonly data: any[];
readonly currency: string;
}) {
return ( return (
<ResponsiveContainer width="100%" height={500}> <ResponsiveContainer width="100%" height={500}>
<PieChart> <PieChart>
@ -78,7 +84,13 @@ function BomPieChart({ data, currency }: { data: any[]; currency: string }) {
} }
// Display BOM data as a bar chart // Display BOM data as a bar chart
function BomBarChart({ data, currency }: { data: any[]; currency: string }) { function BomBarChart({
data,
currency
}: {
readonly data: any[];
readonly currency: string;
}) {
return ( return (
<ResponsiveContainer width="100%" height={500}> <ResponsiveContainer width="100%" height={500}>
<BarChart data={data}> <BarChart data={data}>
@ -113,8 +125,8 @@ export default function BomPricingPanel({
part, part,
pricing pricing
}: { }: {
part: any; readonly part: any;
pricing: any; readonly pricing: any;
}): ReactNode { }): ReactNode {
const table = useTable('pricing-bom'); const table = useTable('pricing-bom');

View File

@ -189,7 +189,7 @@ export default function PricingOverviewPanel({
<DataTable records={overviewData} columns={columns} /> <DataTable records={overviewData} columns={columns} />
</Stack> </Stack>
<ResponsiveContainer width="100%" height={500}> <ResponsiveContainer width="100%" height={500}>
<BarChart data={overviewData}> <BarChart data={overviewData} id="pricing-overview-chart">
<XAxis dataKey="title" /> <XAxis dataKey="title" />
<YAxis <YAxis
tickFormatter={(value, index) => tickFormatter={(value, index) =>

View File

@ -43,9 +43,9 @@ export default function PricingPanel({
label: panelOptions; label: panelOptions;
title: string; title: string;
visible: boolean; visible: boolean;
disabled?: boolean | undefined; disabled?: boolean;
}): ReactNode { }): ReactNode {
const is_disabled = disabled === undefined ? false : disabled; const is_disabled = disabled ?? false;
return ( return (
visible && ( visible && (
<Accordion.Item value={label} id={label}> <Accordion.Item value={label} id={label}>

View File

@ -3,6 +3,7 @@
*/ */
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Anchor } from '@mantine/core'; import { Anchor } from '@mantine/core';
import { access } from 'fs';
import { YesNoButton } from '../components/buttons/YesNoButton'; import { YesNoButton } from '../components/buttons/YesNoButton';
import { Thumbnail } from '../components/images/Thumbnail'; import { Thumbnail } from '../components/images/Thumbnail';
@ -11,6 +12,7 @@ import { TableStatusRenderer } from '../components/render/StatusRenderer';
import { RenderOwner } from '../components/render/User'; import { RenderOwner } from '../components/render/User';
import { formatCurrency, renderDate } from '../defaults/formatters'; import { formatCurrency, renderDate } from '../defaults/formatters';
import { ModelType } from '../enums/ModelType'; import { ModelType } from '../enums/ModelType';
import { resolveItem } from '../functions/conversion';
import { cancelEvent } from '../functions/events'; import { cancelEvent } from '../functions/events';
import { TableColumn } from './Column'; import { TableColumn } from './Column';
import { ProjectCodeHoverCard } from './TableHoverCard'; import { ProjectCodeHoverCard } from './TableHoverCard';
@ -29,19 +31,24 @@ export function BooleanColumn({
accessor, accessor,
title, title,
sortable, sortable,
switchable switchable,
ordering
}: { }: {
accessor: string; accessor: string;
title?: string; title?: string;
ordering?: string;
sortable?: boolean; sortable?: boolean;
switchable?: boolean; switchable?: boolean;
}): TableColumn { }): TableColumn {
return { return {
accessor: accessor, accessor: accessor,
title: title, title: title,
ordering: ordering,
sortable: sortable ?? true, sortable: sortable ?? true,
switchable: switchable ?? true, switchable: switchable ?? true,
render: (record: any) => <YesNoButton value={record[accessor]} /> render: (record: any) => (
<YesNoButton value={resolveItem(record, accessor)} />
)
}; };
} }
@ -71,7 +78,7 @@ export function LinkColumn({
accessor: accessor, accessor: accessor,
sortable: false, sortable: false,
render: (record: any) => { render: (record: any) => {
let url = record[accessor]; let url = resolveItem(record, accessor);
if (!url) { if (!url) {
return '-'; return '-';

View File

@ -28,6 +28,7 @@ import { ActionButton } from '../components/buttons/ActionButton';
import { ButtonMenu } from '../components/buttons/ButtonMenu'; import { ButtonMenu } from '../components/buttons/ButtonMenu';
import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField'; import { ApiFormFieldSet } from '../components/forms/fields/ApiFormField';
import { ModelType } from '../enums/ModelType'; import { ModelType } from '../enums/ModelType';
import { resolveItem } from '../functions/conversion';
import { extractAvailableFields, mapFields } from '../functions/forms'; import { extractAvailableFields, mapFields } from '../functions/forms';
import { getDetailUrl } from '../functions/urls'; import { getDetailUrl } from '../functions/urls';
import { TableState } from '../hooks/UseTable'; import { TableState } from '../hooks/UseTable';
@ -519,7 +520,8 @@ export function InvenTreeTable<T = any>({
// If a custom row click handler is provided, use that // If a custom row click handler is provided, use that
props.onRowClick(record, index, event); props.onRowClick(record, index, event);
} else if (tableProps.modelType) { } else if (tableProps.modelType) {
const pk = record?.[tableProps.modelField ?? 'pk']; const accessor = tableProps.modelField ?? 'pk';
const pk = resolveItem(record, accessor);
if (pk) { if (pk) {
// If a model type is provided, navigate to the detail view for that model // If a model type is provided, navigate to the detail view for that model

View File

@ -6,13 +6,11 @@ import {
IconTool IconTool
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { PartHoverCard } from '../../components/images/Thumbnail'; import { PartHoverCard } from '../../components/images/Thumbnail';
import { ProgressBar } from '../../components/items/ProgressBar'; import { ProgressBar } from '../../components/items/ProgressBar';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { ModelType } from '../../enums/ModelType'; import { ModelType } from '../../enums/ModelType';
import { getDetailUrl } from '../../functions/urls';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
@ -25,7 +23,6 @@ import { TableHoverCard } from '../TableHoverCard';
export default function BuildLineTable({ params = {} }: { params?: any }) { export default function BuildLineTable({ params = {} }: { params?: any }) {
const table = useTable('buildline'); const table = useTable('buildline');
const user = useUserState(); const user = useUserState();
const navigate = useNavigate();
const tableFilters: TableFilter[] = useMemo(() => { const tableFilters: TableFilter[] = useMemo(() => {
return [ return [
@ -47,6 +44,11 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
name: 'optional', name: 'optional',
label: t`Optional`, label: t`Optional`,
description: t`Show optional lines` description: t`Show optional lines`
},
{
name: 'tracked',
label: t`Tracked`,
description: t`Show tracked lines`
} }
]; ];
}, []); }, []);
@ -122,18 +124,28 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
return [ return [
{ {
accessor: 'bom_item', accessor: 'bom_item',
ordering: 'part',
sortable: true, sortable: true,
switchable: false, switchable: false,
render: (record: any) => <PartHoverCard part={record.part_detail} /> render: (record: any) => <PartHoverCard part={record.part_detail} />
}, },
{ {
accessor: 'bom_item_detail.reference' accessor: 'bom_item_detail.reference',
ordering: 'reference',
sortable: true,
title: t`Reference`
}, },
BooleanColumn({ BooleanColumn({
accessor: 'bom_item_detail.consumable' accessor: 'bom_item_detail.consumable',
ordering: 'consumable'
}), }),
BooleanColumn({ BooleanColumn({
accessor: 'bom_item_detail.optional' accessor: 'bom_item_detail.optional',
ordering: 'optional'
}),
BooleanColumn({
accessor: 'part_detail.trackable',
ordering: 'trackable'
}), }),
{ {
accessor: 'bom_item_detail.quantity', accessor: 'bom_item_detail.quantity',
@ -198,6 +210,11 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
return []; return [];
} }
// Tracked items must be allocated to a particular output
if (record?.part_detail?.trackable) {
return [];
}
return [ return [
{ {
icon: <IconArrowRight />, icon: <IconArrowRight />,
@ -234,11 +251,8 @@ export default function BuildLineTable({ params = {} }: { params?: any }) {
}, },
tableFilters: tableFilters, tableFilters: tableFilters,
rowActions: rowActions, rowActions: rowActions,
onRowClick: (row: any) => { modelType: ModelType.part,
if (row?.part_detail?.pk) { modelField: 'part_detail.pk'
navigate(getDetailUrl(ModelType.part, row.part_detail.pk));
}
}
}} }}
/> />
); );

View File

@ -1,6 +1,6 @@
export const classicUrl = 'http://127.0.0.1:8000'; export const classicUrl = 'http://127.0.0.1:8000';
export const baseUrl = `${classicUrl}/platform`; export const baseUrl = './platform';
export const loginUrl = `${baseUrl}/login`; export const loginUrl = `${baseUrl}/login`;
export const logoutUrl = `${baseUrl}/logout`; export const logoutUrl = `${baseUrl}/logout`;
export const homeUrl = `${baseUrl}/home`; export const homeUrl = `${baseUrl}/home`;

View File

@ -25,13 +25,15 @@ export const doLogin = async (page, username?: string, password?: string) => {
export const doQuickLogin = async ( export const doQuickLogin = async (
page, page,
username?: string, username?: string,
password?: string password?: string,
url?: string
) => { ) => {
username = username ?? user.username; username = username ?? user.username;
password = password ?? user.password; password = password ?? user.password;
url = url ?? baseUrl;
// await page.goto(logoutUrl); // await page.goto(logoutUrl);
await page.goto(`${baseUrl}/login/?login=${username}&password=${password}`); await page.goto(`${url}/login/?login=${username}&password=${password}`);
await page.waitForURL('**/platform/home'); await page.waitForURL('**/platform/home');
await page.waitForTimeout(250); await page.waitForTimeout(250);
}; };

View File

@ -0,0 +1,88 @@
import { test } from '../baseFixtures.js';
import { baseUrl } from '../defaults.js';
import { doQuickLogin } from '../login.js';
const newPartName = 'UITESTIN123';
test('PUI - Pages - Index - Playground', async ({ page }) => {
await doQuickLogin(page);
await page.goto('./');
// Playground
await page.getByRole('tab', { name: 'Playground' }).click();
await page.getByRole('button', { name: 'API Forms' }).click();
// New Part
await page.getByRole('button', { name: 'Create New Part' }).click();
await page.locator('#react-select-3-input').fill('category 0');
await page
.getByRole('option', { name: 'Category 0' })
.locator('div')
.first()
.click();
await page.getByLabel('Name *').fill(newPartName);
await page.getByLabel('Initial Stock Quantity *').fill('1');
await page
.getByLabel('Create Part')
.getByRole('button', { name: 'Cancel' })
.click();
// Edit Part
await page.getByRole('button', { name: 'Edit Part' }).click();
await page.getByLabel('IPN').click();
await page.getByLabel('IPN').fill(newPartName);
await page
.getByLabel('Edit Part')
.getByRole('button', { name: 'Cancel' })
.click();
// Create Stock Item
await page.getByRole('button', { name: 'Create Stock Item' }).click();
await page.locator('#react-select-25-input').fill('R_1K_0402_1');
await page.getByText('R_1K_0402_1%').click();
await page
.getByLabel('Add Stock Item')
.getByRole('button', { name: 'Cancel' })
.click();
// EditCategory
await page.getByRole('button', { name: 'Edit Category' }).click();
await page.locator('.css-1xvbfjt-Input2').first().click();
await page.getByText('Category 0').click();
await page
.getByLabel('Edit Category')
.getByRole('button', { name: 'Cancel' })
.click();
// Create Attachment
await page.getByRole('button', { name: 'Create Attachment' }).click();
await page.getByLabel('Attachment *').waitFor();
await page.getByRole('button', { name: 'Cancel' }).click();
// TODO: actually create an attachment
// Create Part new Modal
await page.getByRole('button', { name: 'Create Part new Modal' }).click();
await page.locator('.css-1xvbfjt-Input2').first().click();
await page.getByText('Category 0').click();
await page
.getByLabel('Create part')
.getByRole('button', { name: 'Cancel' })
.click();
// Status Label
await page.getByRole('button', { name: 'Status labels' }).click();
await page.getByRole('textbox').dblclick();
await page.getByRole('textbox').fill('50');
await page.getByText('Attention needed').waitFor();
});
test('PUI - Pages - Index - Dashboard', async ({ page }) => {
await doQuickLogin(page);
// Dashboard auto update
await page.getByRole('tab', { name: 'Dashboard' }).click();
await page.getByText('Autoupdate').click();
await page.waitForTimeout(500);
await page.getByText('Autoupdate').click();
await page.getByText('This page is a replacement').waitFor();
});

View File

@ -0,0 +1,154 @@
import { test } from '@playwright/test';
import { baseUrl } from '../defaults';
import { doQuickLogin } from '../login';
test('PUI - Pages - Part - Pricing (Nothing, BOM)', async ({ page }) => {
await doQuickLogin(page);
// Part with no history
await page.goto(`${baseUrl}/part/82/pricing`);
await page.getByText('1551ABK').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Purchase History' }).isDisabled();
await page.getByRole('button', { name: 'Internal Pricing' }).isDisabled();
await page.getByRole('button', { name: 'Supplier Pricing' }).isDisabled();
// Part with history
await page.goto(`${baseUrl}/part/108/pricing`);
await page.getByText('Part: Blue Chair').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Internal Pricing' }).isDisabled();
await page.getByRole('button', { name: 'Sale History' }).isDisabled();
await page.getByRole('button', { name: 'Sale Pricing' }).isDisabled();
await page.getByRole('button', { name: 'BOM Pricing' }).isEnabled();
// Overview Graph
let graph = page.locator('#pricing-overview-chart');
await graph.waitFor();
await graph.getByText('$60').waitFor();
await graph.getByText('BOM Pricing').waitFor();
await graph.getByText('Overall Pricing').waitFor();
await graph.locator('path').nth(1).hover();
await page.getByText('min_value : $50').waitFor();
// BOM Pricing
await page.getByRole('button', { name: 'BOM Pricing' }).click();
await page.getByText('Bar Chart').click();
await page.getByText('total_price_min').waitFor();
await page.getByText('Pie Chart').click();
await page.getByRole('button', { name: 'Quantity Not sorted' }).waitFor();
await page.getByRole('button', { name: 'Unit Price Not sorted' }).waitFor();
// BOM Pricing - linkjumping
await page.getByText('Wood Screw').waitFor();
await page.getByText('Wood Screw').click();
await page.waitForURL('**/part/98/pricing');
});
test('PUI - Pages - Part - Pricing (Supplier)', async ({ page }) => {
await doQuickLogin(page);
// Part
await page.goto(`${baseUrl}/part/55/pricing`);
await page.getByText('Part: C_100nF_0603').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Purchase History' }).isEnabled();
await page.getByRole('button', { name: 'Internal Pricing' }).isDisabled();
await page.getByRole('button', { name: 'Supplier Pricing' }).isEnabled();
// Supplier Pricing
await page.getByRole('button', { name: 'Supplier Pricing' }).click();
await page.waitForTimeout(500);
await page.getByRole('button', { name: 'SKU Not sorted' }).waitFor();
// Supplier Pricing - linkjumping
let target = page.getByText('ARR-26041-LPC').first();
await target.waitFor();
await target.click();
// await page.waitForURL('**/purchasing/supplier-part/697/');
});
test('PUI - Pages - Part - Pricing (Variant)', async ({ page }) => {
await doQuickLogin(page);
// Part
await page.goto(`${baseUrl}/part/106/pricing`);
await page.getByText('Part: Chair').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Internal Pricing' }).isDisabled();
await page.getByRole('button', { name: 'BOM Pricing' }).isEnabled();
await page.getByRole('button', { name: 'Variant Pricing' }).isEnabled();
await page.getByRole('button', { name: 'Sale Pricing' }).isDisabled();
await page.getByRole('button', { name: 'Sale History' }).isDisabled();
// Variant Pricing
await page.getByRole('button', { name: 'Variant Pricing' }).click();
await page.waitForTimeout(500);
await page.getByRole('button', { name: 'Variant Part Not sorted' }).click();
// Variant Pricing - linkjumping
let target = page.getByText('Green Chair').first();
await target.waitFor();
await target.click();
await page.waitForURL('**/part/109/pricing');
});
test('PUI - Pages - Part - Pricing (Internal)', async ({ page }) => {
await doQuickLogin(page);
// Part
await page.goto(`${baseUrl}/part/65/pricing`);
await page.getByText('Part: M2x4 SHCS').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Purchase History' }).isDisabled();
await page.getByRole('button', { name: 'Internal Pricing' }).isEnabled();
await page.getByRole('button', { name: 'Supplier Pricing' }).isDisabled();
// Internal Pricing
await page.getByRole('button', { name: 'Internal Pricing' }).click();
await page.getByRole('button', { name: 'Price Break Not sorted' }).waitFor();
// Internal Pricing - editing
await page.getByRole('row', { name: '1 NZ$' }).getByRole('button').click();
await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByText('Part *M2x4 SHCSSocket head').click();
await page.getByText('Part *M2x4 SHCSSocket head').click();
});
test('PUI - Pages - Part - Pricing (Purchase)', async ({ page }) => {
await doQuickLogin(page);
// Part
await page.goto(`${baseUrl}/part/69/pricing`);
await page.getByText('Part: 530470210').waitFor();
await page.getByRole('tab', { name: 'Part Pricing' }).click();
await page.getByLabel('Part Pricing').getByText('Part Pricing').waitFor();
await page.getByRole('button', { name: 'Pricing Overview' }).waitFor();
await page.getByText('Last Updated').waitFor();
await page.getByRole('button', { name: 'Purchase History' }).isEnabled();
await page.getByRole('button', { name: 'Internal Pricing' }).isDisabled();
await page.getByRole('button', { name: 'Supplier Pricing' }).isDisabled();
// Purchase History
await page.getByRole('button', { name: 'Purchase History' }).click();
await page
.getByRole('button', { name: 'Purchase Order Not sorted' })
.waitFor();
await page.getByText('2022-04-29').waitFor();
});

View File

@ -237,12 +237,12 @@ def install(c, uv=False):
c.run('pip3 install --upgrade pip') c.run('pip3 install --upgrade pip')
c.run('pip3 install --upgrade setuptools') c.run('pip3 install --upgrade setuptools')
c.run( c.run(
'pip3 install --no-cache-dir --disable-pip-version-check -U -r src/backend/requirements.txt' 'pip3 install --no-cache-dir --disable-pip-version-check -U --require-hashes -r src/backend/requirements.txt'
) )
else: else:
c.run('pip3 install --upgrade uv') c.run('pip3 install --upgrade uv')
c.run('uv pip install --upgrade setuptools') c.run('uv pip install --upgrade setuptools')
c.run('uv pip install -U -r src/backend/requirements.txt') c.run('uv pip install -U --require-hashes -r src/backend/requirements.txt')
# Run plugins install # Run plugins install
plugins(c, uv=uv) plugins(c, uv=uv)
@ -260,7 +260,7 @@ def setup_dev(c, tests=False):
print("Installing required python packages from 'src/backend/requirements-dev.txt'") print("Installing required python packages from 'src/backend/requirements-dev.txt'")
# Install required Python packages with PIP # Install required Python packages with PIP
c.run('pip3 install -U -r src/backend/requirements-dev.txt') c.run('pip3 install -U --require-hashes -r src/backend/requirements-dev.txt')
# Install pre-commit hook # Install pre-commit hook
print('Installing pre-commit for checks before git commits...') print('Installing pre-commit for checks before git commits...')