Merge commit '457fe16f9c31d08fbb6f3493f17105aac2638e86' into preview-panel

This commit is contained in:
Oliver Walters 2026-06-13 23:51:18 +00:00
commit c7eb7b4f2d
126 changed files with 125229 additions and 118841 deletions

View File

@ -115,7 +115,9 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5
permissions:
contents: read # Required for actions/checkout
id-token: write # Required for GitHub OIDC
env:
VITE_COVERAGE: false

View File

@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- [#12142](https://github.com/inventree/InvenTree/pull/12142) prevents users from printing reports or labels against models for which they do not have adequate permissions. This change improves the security of the system by ensuring that users cannot access or print reports or labels for models they do not have permission to view.
- [#11990](https://github.com/inventree/InvenTree/pull/11990) build output operations performed via the API now offload the work to a background task, and now return a task ID which can be used to monitor the progress of the task. This allows for better performance and responsiveness when performing build output operations, as the work is performed asynchronously in the background.
- [#11825](https://github.com/inventree/InvenTree/pull/11825) adds a new "bom" ruleset and associated permissions for BOM management, separate from the "part" ruleset which remains focused on part management. This allows for more granular control over user permissions, allowing users to have different levels of access to part management and BOM management functionality.
- [#11816](https://github.com/inventree/InvenTree/pull/11816) makes the `issued_by` field on the `Build` API read only, and instead sets the `issued_by` field to the current user when a build is created. This change was made to ensure that the `issued_by` field accurately reflects the user who created the build, and to prevent users from setting this field to an arbitrary value when creating or updating a build.

View File

@ -18,6 +18,7 @@ ARG commit_hash=""
ARG commit_date=""
ARG data_dir="data"
ARG NODE_VERSION=24
ENV PYTHONUNBUFFERED=1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
@ -118,15 +119,10 @@ RUN pip install --user --require-hashes -r base_requirements.txt --no-cache-dir
rm -rf /root/.cache/pip
# Install frontend build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
nodejs npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g n yarn --ignore-scripts && \
yarn config set network-timeout 600000 -g
RUN bash -c "n lts"
RUN cd "${INVENTREE_HOME}" && invoke int.frontend-compile --extract
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash && \
bash -c "export NVM_DIR="$HOME/.nvm" && source $HOME/.nvm/nvm.sh && \
nvm install $NODE_VERSION && corepack enable yarn && yarn config set network-timeout 600000 -g"
RUN bash -c "source $HOME/.nvm/nvm.sh && cd '${INVENTREE_HOME}' && invoke int.frontend-compile --extract"
# InvenTree production image:
# - Copies required files from local directory

View File

@ -61,70 +61,70 @@ packaging==26.2 \
# gunicorn
# mariadb
# wheel
psycopg[binary, pool]==3.3.3 \
--hash=sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9 \
--hash=sha256:f96525a72bcfade6584ab17e89de415ff360748c766f0106959144dcbb38c698
psycopg[binary, pool]==3.3.4 \
--hash=sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a \
--hash=sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc
# via -r contrib/container/requirements.in
psycopg-binary==3.3.3 \
--hash=sha256:05f32239aec25c5fb15f7948cffdc2dc0dac098e48b80a140e4ba32b572a2e7d \
--hash=sha256:07c7211f9327d522c9c47560cae00a4ecf6687f4e02d779d035dd3177b41cb12 \
--hash=sha256:0dde92cfde09293fb63b3f547919ba7d73bd2654573c03502b3263dd0218e44e \
--hash=sha256:111c59897a452196116db12e7f608da472fbff000693a21040e35fc978b23430 \
--hash=sha256:162e5675efb4704192411eaf8e00d07f7960b679cd3306e7efb120bb8d9456cc \
--hash=sha256:165f22ab5a9513a3d7425ffb7fcc7955ed8ccaeef6d37e369d6cc1dff1582383 \
--hash=sha256:17bb6600e2455993946385249a3c3d0af52cd70c1c1cdbf712e9d696d0b0bf1b \
--hash=sha256:19f93235ece6dbfc4036b5e4f6d8b13f0b8f2b3eeb8b0bd2936d406991bcdd40 \
--hash=sha256:1bef235a50a80f6aba05147002bc354559657cb6386dbd04d8e1c97d1d7cbe84 \
--hash=sha256:258d1ea53464d29768bf25930f43291949f4c7becc706f6e220c515a63a24edd \
--hash=sha256:263a24f39f26e19ed7fc982d7859a36f17841b05bebad3eb47bb9cd2dd785351 \
--hash=sha256:329ff393441e75f10b673ae99ab45276887993d49e65f141da20d915c05aafd8 \
--hash=sha256:42961609ac07c232a427da7c87a468d3c82fee6762c220f38e37cfdacb2b178d \
--hash=sha256:47f06fcbe8542b4d96d7392c476a74ada521c5aebdb41c3c0155f6595fc14c8d \
--hash=sha256:48e500cf1c0984dacf1f28ea482c3cdbb4c2288d51c336c04bc64198ab21fc51 \
--hash=sha256:497852c5eaf1f0c2d88ab74a64a8097c099deac0c71de1cbcf18659a8a04a4b2 \
--hash=sha256:4d4606c84d04b80f9138d72f1e28c6c02dc5ae0c7b8f3f8aaf89c681ce1cd1b1 \
--hash=sha256:5152d50798c2fa5bd9b68ec68eb68a1b71b95126c1d70adaa1a08cd5eefdc23d \
--hash=sha256:533efe6dc3a7cba5e2a84e38970786bb966306863e45f3db152007e9f48638a6 \
--hash=sha256:56c767007ca959ca32f796b42379fc7e1ae2ed085d29f20b05b3fc394f3715cc \
--hash=sha256:5958dbf28b77ce2033482f6cb9ef04d43f5d8f4b7636e6963d5626f000efb23e \
--hash=sha256:59aa31fe11a0e1d1bcc2ce37ed35fe2ac84cd65bb9036d049b1a1c39064d0f14 \
--hash=sha256:642050398583d61c9856210568eb09a8e4f2fe8224bf3be21b67a370e677eead \
--hash=sha256:6698dbab5bcef8fdb570fc9d35fd9ac52041771bfcfe6fd0fc5f5c4e36f1e99d \
--hash=sha256:73eaaf4bb04709f545606c1db2f65f4000e8a04cdbf3e00d165a23004692093e \
--hash=sha256:74eae563166ebf74e8d950ff359be037b85723d99ca83f57d9b244a871d6c13b \
--hash=sha256:78c9ce98caaf82ac8484d269791c1b403d7598633e0e4e2fa1097baae244e2f1 \
--hash=sha256:7c84f9d214f2d1de2fafebc17fa68ac3f6561a59e291553dfc45ad299f4898c1 \
--hash=sha256:883d68d48ca9ff3cb3d10c5fdebea02c79b48eecacdddbf7cce6e7cdbdc216b8 \
--hash=sha256:8e7e9eca9b363dbedeceeadd8be97149d2499081f3c52d141d7cd1f395a91f83 \
--hash=sha256:90eecd93073922f085967f3ed3a98ba8c325cbbc8c1a204e300282abd2369e13 \
--hash=sha256:97c839717bf8c8df3f6d983a20949c4fb22e2a34ee172e3e427ede363feda27b \
--hash=sha256:9d6a1e56dd267848edb824dbeb08cf5bac649e02ee0b03ba883ba3f4f0bd54f2 \
--hash=sha256:9f7d0cf072c6fbac3795b08c98ef9ea013f11db609659dcfc6b1f6cc31f9e181 \
--hash=sha256:a39f34c9b18e8f6794cca17bfbcd64572ca2482318db644268049f8c738f35a6 \
--hash=sha256:a4aab31bd6d1057f287c96c0effca3a25584eb9cc702f282ecb96ded7814e830 \
--hash=sha256:a6af77b6626ce92b5817bf294b4d45ec1a6161dba80fc2d82cdffdd6814fd023 \
--hash=sha256:a89bb9ee11177b2995d87186b1d9fa892d8ea725e85eab28c6525e4cc14ee048 \
--hash=sha256:ae07a3114313dd91fce686cab2f4c44af094398519af0e0f854bc707e1aeedf1 \
--hash=sha256:b27d3a23c79fa59557d2cc63a7e8bb4c7e022c018558eda36f9d7c4e6b99a6e0 \
--hash=sha256:b3385b58b2fe408a13d084c14b8dcf468cd36cbbe774408250facc128f9fa75c \
--hash=sha256:b62cf8784eb6d35beaee1056d54caf94ec6ecf2b7552395e305518ab61eb8fd2 \
--hash=sha256:cab7bc3d288d37a80aa8c0820033250c95e40b1c2b5c57cf59827b19c2a8b69d \
--hash=sha256:cb85b1d5702877c16f28d7b92ba030c1f49ebcc9b87d03d8c10bf45a2f1c7508 \
--hash=sha256:d257c58d7b36a621dcce1d01476ad8b60f12d80eb1406aee4cf796f88b2ae482 \
--hash=sha256:d593612758d0041cb13cb0003f7f8d3fabb7ad9319e651e78afae49b1cf5860e \
--hash=sha256:da2f331a01af232259a21573a01338530c6016dcfad74626c01330535bcd8628 \
--hash=sha256:dac7ee2f88b4d7bb12837989ca354c38d400eeb21bce3b73dac02622f0a3c8d6 \
--hash=sha256:e77957d2ba17cada11be09a5066d93026cdb61ada7c8893101d7fe1c6e1f3925 \
--hash=sha256:e7800e6c6b5dc4b0ca7cc7370f770f53ac83886b76afda0848065a674231e856 \
--hash=sha256:e7b607f0e14f2a4cf7e78a05ebd13df6144acfba87cb90842e70d3f125d9f53f \
--hash=sha256:eb072949b8ebf4082ae24289a2b0fd724da9adc8f22743409d6fd718ddb379df \
--hash=sha256:eb36a08859b9432d94ea6b26ec41a2f98f83f14868c91321d0c1e11f672eeae7 \
--hash=sha256:f24e8e17035200a465c178e9ea945527ad0738118694184c450f1192a452ff25 \
--hash=sha256:fab6b5e37715885c69f5d091f6ff229be71e235f272ebaa35158d5a46fd548a0
psycopg-binary==3.3.4 \
--hash=sha256:018fbed325936da502feb546642c982dcc4b9ffdea32dfef78dbf3b7f7ad4070 \
--hash=sha256:0579252a1202cd73e4da137a1426e2dae993ae44e757605344282af3a082848c \
--hash=sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc \
--hash=sha256:13a7f380824c35896dcac7fe0f61440f7ca49d6dc73f3c13a9a4471e6a3b302e \
--hash=sha256:17a21953a9e5ff3a16dab692625a3676e2f101db5e40072f39dbee2250194d68 \
--hash=sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae \
--hash=sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829 \
--hash=sha256:22cdbf5f91ef7bb91fe0c5757e1962d3127a8010256eefd9c61fcaf441802097 \
--hash=sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c \
--hash=sha256:276904e3452d6a23d474ef9a21eee19f20eed3d53ddd2576af033827e0ba0992 \
--hash=sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97 \
--hash=sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6 \
--hash=sha256:32a6fbf8481e3a370d0d72b860d35948a693cb01281da217f7b2f307636e591a \
--hash=sha256:41f2ec0fea529832982bcb6c9415de3c86264ebe562b77a467c0fbcd7efbba8d \
--hash=sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228 \
--hash=sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e \
--hash=sha256:494ca54901be8cf9eb7e02c25b731f2317c378efa44f43e8f9bd0e1184ae7be4 \
--hash=sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41 \
--hash=sha256:574ea21a9651958f1535c5a1c649c7409e9168bcbffa29a3f2f961f58b322949 \
--hash=sha256:580ae30a5f95ccd90008ec697d3ed6a4a2047a516407ad904283fa42086936e9 \
--hash=sha256:5ab28a2a7649df3b72e6b674b4c190e448e8e77cf496a65bd846472048de2089 \
--hash=sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf \
--hash=sha256:612a627d733f695b1de1f9b4bd511c15f999a5d8b915d444bbd7dd71cf3370da \
--hash=sha256:6402a9d8146cf4b3974ded3fd28a971e83dc6a0333eb7822524a3aa20b546578 \
--hash=sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014 \
--hash=sha256:71e55ccbdfae79a2ed9c6369c3008a3025817ff9d7e27b32a2d84e2a4267e66e \
--hash=sha256:7465bfe6087d2d5b42d4c53b9b11ca9f218e477317a4a162a10e3c19e984ba8e \
--hash=sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31 \
--hash=sha256:773d573e11f437ce0bdb95b7c18dc58390494f96d43f8b45b9760436114f7652 \
--hash=sha256:77df19583501ea288eaf15ac0fe7ad01e6d8091a91d5c41df5c718f307d8e31b \
--hash=sha256:7f7668f30b9dd5163197e5cbf4e0efd54e00f0a859cc566ce56cfc31f4054839 \
--hash=sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277 \
--hash=sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7 \
--hash=sha256:ab8cca8ef8fb1ccf5b048ae5bd78ba55b9e4b5d472e3ce5ca39ff4d2a9c249e4 \
--hash=sha256:ad3bc94054876155549fdaedf4a46d1ec69d39a5bcee377148afe498e84c4b8e \
--hash=sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70 \
--hash=sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf \
--hash=sha256:b7bfff1ca23732b488cbca3076fc11bc98d520ee122514fdb17a8e20d3338f5a \
--hash=sha256:bdef84570ebbce1d42b4e7ea952d21c414c5f118ad02fee00c5625f35e134429 \
--hash=sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8 \
--hash=sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3 \
--hash=sha256:cf7f73a4a792bc5db58a4b385d8a1467e8d468f7548702fb0ed1e9b7501b1c13 \
--hash=sha256:cffc3408d77a27973f33e5d909b624cce683db5fc25964b02fe0aae7886c1007 \
--hash=sha256:d7b4d40c153fa352ab3cca530f3a0baedf7621b2ebcbd7f084009522c21788fc \
--hash=sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38 \
--hash=sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9 \
--hash=sha256:e2631da29253a98bd496e6c4813b24e09a4fe3fb2a9e88513305d6f8747cce95 \
--hash=sha256:e7510c37550f91a187e3660a8cc50d4b760f8c3b8b2f89ebc5698cd2c7f2c85d \
--hash=sha256:eb05ee1c2b817d27c537333224c9e83c7afb86fe7296ba970990068baf819b16 \
--hash=sha256:eb4eed2079c01a4850bf467deacfab56d356d4225040170af03dc9958321242d \
--hash=sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260 \
--hash=sha256:f80e3f2b5331dbbf0901bcb658056c03eeb2c1ef31d774afb0d61598b242e744 \
--hash=sha256:f9b1c2533af01cd7648378599f82b0b8ae32f293296e6eec5753a625bc97ef28 \
--hash=sha256:fa1cbc10768a796c96d3243656016bf4e337c81c71097270bb7b0ad6210d9765 \
--hash=sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7
# via psycopg
psycopg-pool==3.3.0 \
--hash=sha256:2e44329155c410b5e8666372db44276a8b1ebd8c90f1c3026ebba40d4bc81063 \
--hash=sha256:fa115eb2860bd88fce1717d75611f41490dec6135efb619611142b24da3f6db5
psycopg-pool==3.3.1 \
--hash=sha256:2af5b432941c4c9ad5c87b3fa410aec910ec8f7c122855897983a06c45f2e4b5 \
--hash=sha256:b10b10b7a175d5cc1592147dc5b7eec8a9e0834eb3ed2c4a92c858e2f51eb63c
# via psycopg
pyasn1==0.6.3 \
--hash=sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf \
@ -136,8 +136,8 @@ pyasn1-modules==0.4.2 \
--hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \
--hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6
# via python-ldap
python-ldap==3.4.5 \
--hash=sha256:b2f6ef1c37fe2c6a5a85212efe71311ee21847766a7d45fcb711f3b270a5f79a
python-ldap==3.4.7 \
--hash=sha256:bacd9fb680d20263d8570ade1cf234d90d281149a8beb4f079dd8f33f7613dc8
# via
# -r contrib/container/requirements.in
# django-auth-ldap
@ -236,26 +236,26 @@ typing-extensions==4.15.0 \
# via
# -c src/backend/requirements.txt
# psycopg-pool
uv==0.11.7 \
--hash=sha256:0df59ab0c6a4b14a763e8445e1c303af9abeb53cdfa4428daf9ff9642c0a3cce \
--hash=sha256:162fa961a9a081dcea6e889c79f738a5ae56507047e4672964972e33c301bea9 \
--hash=sha256:23d457d6731ebdb83f1bffebe4894edab2ef43c1ec5488433c74300db4958924 \
--hash=sha256:46d971489b00bdb27e0aa715e4a5cd4ef2c28ea5b6ef78f2b67bf861eb44b405 \
--hash=sha256:4e4d5e31bea86e1b6e0f5a0f95e14e80018e6f6c0129256d2915a4b3d793644d \
--hash=sha256:553e67cc766d013ce24353fecd4ea5533d2aedcfd35f9fac430e07b1d1f23ed4 \
--hash=sha256:5674dfb5944513f4b3735b05c2deba6b1b01151f46729d533d413a9a905f8c5d \
--hash=sha256:5985a15a92bd9a170fc1947abb1fbc3e9828c5a430ad85b5bed8356c20b67a71 \
--hash=sha256:6158b7e39464f1aa1e040daa0186cae4749a78b5cd80ac769f32ca711b8976b1 \
--hash=sha256:750ee5b96959b807cf442b73dd8b55111862d63f258f896787ea5f06b68aaca9 \
--hash=sha256:7d6a17507b8139b8803f445a03fd097f732ce8356b1b7b13cdb4dd8ef7f4b2e0 \
--hash=sha256:8b2fe1ec6775dad10183e3fdce430a5b37b7857d49763c884f3a67eaa8ca6f8a \
--hash=sha256:ceae53b202ea92bc954759bc7c7570cdcd5c3512fce15701198c19fd2dfb8605 \
--hash=sha256:dd48823ca4b505124389f49ae50626ba9f57212b9047738efc95126ed5f3844d \
--hash=sha256:eb91f52ee67e10d5290f2c2897e2171357f1a10966de38d83eefa93d96843b0c \
--hash=sha256:f394331f0507e80ee732cb3df737589de53bed999dd02a6d24682f08c2f8ac4f \
--hash=sha256:f422d39530516b1dfb28bb6e90c32bb7dacd50f6a383cd6e40c1a859419fbc8c \
--hash=sha256:f97e9f4e4d44fb5c4dfaa05e858ef3414a96416a2e4af270ecd88a3e5fb049a9 \
--hash=sha256:fab0bb43fbbc0ee5b5fee212078d2300c371b725faff7cf72eeaafa0bff0606b
uv==0.11.19 \
--hash=sha256:28b0d612a766eb25756dbaa315433b726e93affa467d29a2682cc317547952ba \
--hash=sha256:2d663bacb97e2e8412d1c26eace28c7ebbde9d6f5d7d78760fafd114d693817f \
--hash=sha256:2e0e0b8ad59ec56f1440d6e4313b64a1d8119275dcec73d19eef33c43f99428c \
--hash=sha256:301fd78309fc545c2cec2bfcc61a6bbdde876856c6d2041502737cf44085c178 \
--hash=sha256:32d7988c0dfb6f90941f201c871a4478e96e4f2a32bdb2256d62a78ee20593fc \
--hash=sha256:480fc34a8d0967af6a90b3f99a6e5687cd5c6e29528de96bec04d6e305a59363 \
--hash=sha256:50e4d4796ca1a6da359a4f723a0fea86640c381d3ff4fa759a41badd7cb52dee \
--hash=sha256:574f5dd4f31666661ea6386d3b91c5f0e8b84a8cae98ebba447c4674f2e6a4c7 \
--hash=sha256:62b0b35a51d3034ff30ecd0f381e9bbc20d5b335754f54b098da29424d551ceb \
--hash=sha256:65e932720daed1af1f720a0ff5f9b33ee5f7ad97488dcceceb85154fc1323b82 \
--hash=sha256:7222f45b5541551057bfc2e3021f113800704f665c119fdf3ea700c6c4859b21 \
--hash=sha256:731d9fab8db5d41590af64236d03f8069c8da665fd0f9493b85985f19c86cd90 \
--hash=sha256:7fdd881cd6d80782afcf8c1d446dd15a42985167fd812b763d38ba1e4a8d944d \
--hash=sha256:8f90b6687a480d154595aa619fb836a9a20d00ce37293db8099aad924f2b18f9 \
--hash=sha256:a98495b9dd67287d8c1a0786f98cb037a50f0ee6c3d648572edaa7137aabc277 \
--hash=sha256:aa6a7e8d07b33ad22f4732848ebb1d9486503973c248d6e632c06ce4339fe347 \
--hash=sha256:c729f56ffef9b945053412c839695e8a0b13758aa15b7763e95a7dd539a6f522 \
--hash=sha256:f4aa17ffd719daf37b7a6265efd3ee4922a8ddaabaf0406d2b28c7e5ce2f20ff \
--hash=sha256:f56f5bf853626a30423052d7ee00bf5cc940a08347d6ee7ede96862d084054a5
# via -r contrib/container/requirements.in
wheel==0.47.0 \
--hash=sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced \

View File

@ -139,9 +139,9 @@ charset-normalizer==3.4.7 \
# via
# -c src/backend/requirements.txt
# requests
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# -c src/backend/requirements.txt
# requests

View File

@ -1,7 +1,7 @@
mkdocs==1.6.1
mkdocs-macros-plugin>=0.7,<2.0
mkdocs-material>=9.0,<10.0
mkdocs-git-revision-date-localized-plugin>=1.5.2,<2.0
mkdocs-git-revision-date-localized-plugin>=1.5.3,<2.0
mkdocs-redirects
mkdocs-simple-hooks>=0.1,<1.0
mkdocs-include-markdown-plugin

View File

@ -227,9 +227,9 @@ httpx==0.28.1 \
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
# via neoteroi-mkdocs
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# -c src/backend/requirements.txt
# anyio
@ -398,9 +398,9 @@ mkdocs-get-deps==0.2.2 \
--hash=sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1 \
--hash=sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650
# via mkdocs
mkdocs-git-revision-date-localized-plugin==1.5.2 \
--hash=sha256:0b3d65abdb8b82591d724c1d5ece6af7bb3cd305bdd47e2fadd430886a9a2513 \
--hash=sha256:4f3175e039bc4fe0055cac97d295ce8d0d233a13d65986d42fd5324e4985acc2
mkdocs-git-revision-date-localized-plugin==1.5.3 \
--hash=sha256:873444b54cab4d47c69bd6e85da05ef5fbe81fee27e64508114c46a0e4f81e37 \
--hash=sha256:cd96e432de6a7e59b31c7041574b22f84179c8636835419ff458877ecfaaaf05
# via -r docs/requirements.in
mkdocs-include-markdown-plugin==7.3.0 \
--hash=sha256:2800126746452e31c2e321bbd43c8190b356e0de353e20cbc16a34a3c3d6796c \

View File

@ -1,11 +1,18 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 501
INVENTREE_API_VERSION = 503
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
v503 -> 2026-06-11 : https://github.com/inventree/InvenTree/pull/12155
- Adds additional filtering and sorting options to the LabelTemplate API endpoint
- Adds additional filtering and sorting options to the ReportTemplate API endpoint
v502 -> 2026-06-10 : https://github.com/inventree/InvenTree/pull/12142
- Prevents users from printing reports or labels against models for which they do not have adequate permissions. This change improves the security of the system by ensuring that users cannot access or print reports or labels for models they do not have permission to view.
v501 -> 2026-06-05 : https://github.com/inventree/InvenTree/pull/12093
- Adds "read_only" attribute to PluginSetting API endpoint, which indicates whether a particular plugin setting is read-only (i.e. cannot be modified via the API)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -267,4 +267,4 @@ class LabelPrinterMachine(BaseMachineType):
if not location_pk:
return None
return StockLocation.objects.get(pk=location_pk)
return StockLocation.objects.filter(pk=location_pk).first()

View File

@ -171,6 +171,8 @@ class TestLabelPrinterMachineType(InvenTreeAPITestCase):
fixtures = ['category', 'part', 'location', 'stock']
roles = ['part.view']
def test_registration(self):
"""Test that the machine is correctly registered from the plugin."""
PLG_KEY = 'label-printer-test-plugin'
@ -295,6 +297,14 @@ class TestLabelPrinterMachineType(InvenTreeAPITestCase):
self.assertIn('is not a valid choice', str(response.data['machine']))
def test_location_invalid_pk(self):
"""Test that location property returns None for an invalid PK without raising."""
machine = self.create_machine()
machine.set_setting('LOCATION', 'M', 999999)
self.assertIsNone(machine.location)
class AdminTest(AdminTestCase):
"""Tests for the admin interface integration."""

View File

@ -1027,7 +1027,11 @@ class PluginsRegistry:
data = md5()
# Hash for all loaded plugins
for slug, plug in self.plugins.items():
# Note: Sort by slug, so the hash is independent of discovery order.
# Different processes can discover the same plugins in a different
# order, and the hash must represent the registry *state*, not the
# iteration order of any particular process.
for slug, plug in sorted(self.plugins.items(), key=lambda item: item[0]):
data.update(str(slug).encode())
data.update(str(plug.name).encode())
data.update(str(plug.version).encode())

View File

@ -538,6 +538,30 @@ class RegistryTests(TestQueryMixin, PluginRegistryMixin, TestCase):
registry.registry_hash = 'abc'
self.assertTrue(registry.check_reload())
def test_registry_hash_order_independence(self):
"""Test that the registry hash does not depend on plugin iteration order.
Different processes (gunicorn workers, background worker, shell) can
discover the same set of plugins in a different order. If the hash
depends on iteration order, processes disagree about the hash for the
same registry state, and ping-pong each other into endless reloads
via check_reload.
"""
original_plugins = registry.plugins
# Reversing a dict with fewer than 2 entries would not change anything
self.assertGreater(len(original_plugins), 1)
try:
hash_original = registry.calculate_plugin_hash()
# Simulate a process which discovered the same plugins in reverse order
registry.plugins = dict(reversed(list(original_plugins.items())))
self.assertEqual(hash_original, registry.calculate_plugin_hash())
finally:
registry.plugins = original_plugins
def test_builtin_mandatory_plugins(self):
"""Test that mandatory builtin plugins are always loaded."""
from plugin.models import PluginConfig

View File

@ -7,8 +7,8 @@ from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache
import django_filters.rest_framework.filters as rest_filters
from django_filters.rest_framework import DjangoFilterBackend
from django_filters.rest_framework.filterset import FilterSet
from rest_framework.exceptions import PermissionDenied
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
@ -16,10 +16,11 @@ import InvenTree.permissions
import report.helpers
import report.models
import report.serializers
import users.permissions
from common.models import DataOutput
from common.serializers import DataOutputSerializer
from InvenTree.api import meta_path
from InvenTree.filters import InvenTreeSearchFilter
from InvenTree.filters import SEARCH_ORDER_FILTER
from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI
from plugin import PluginMixinEnum
from plugin.builtin.labels.inventree_label import InvenTreeLabelPlugin
@ -79,7 +80,7 @@ class ReportFilter(ReportFilterBase):
"""Filter options."""
model = report.models.ReportTemplate
fields = ['landscape']
fields = ['landscape', 'merge', 'attach_to_model', 'enabled', 'model_type']
class LabelFilter(ReportFilterBase):
@ -89,7 +90,7 @@ class LabelFilter(ReportFilterBase):
"""Filter options."""
model = report.models.LabelTemplate
fields = []
fields = ['enabled']
class LabelPrint(GenericAPIView):
@ -161,6 +162,14 @@ class LabelPrint(GenericAPIView):
template = serializer.validated_data['template']
model_class = template.get_model()
if model_class and not users.permissions.check_user_permission(
request.user, model_class, 'view'
):
raise PermissionDenied(
_('You do not have permission to view this model type')
)
if template.width <= 0 or template.height <= 0:
raise ValidationError({'template': _('Invalid label dimensions')})
@ -174,7 +183,7 @@ class LabelPrint(GenericAPIView):
plugin = self.get_plugin_class(plugin_key, raise_error=True)
instances = template.get_model().objects.filter(pk__in=items)
instances = model_class.objects.filter(pk__in=items)
# Sort the instances by the order of the provided items
instances = sorted(instances, key=lambda item: items.index(item.pk))
@ -236,9 +245,9 @@ class LabelTemplateList(TemplatePermissionMixin, LabelTemplateMixin, ListCreateA
"""API endpoint for viewing list of LabelTemplate objects."""
filterset_class = LabelFilter
filter_backends = [DjangoFilterBackend, InvenTreeSearchFilter]
filter_backends = SEARCH_ORDER_FILTER
search_fields = ['name', 'description']
ordering_fields = ['name', 'enabled']
ordering_fields = ['name', 'enabled', 'width', 'height']
class LabelTemplateDetail(
@ -261,9 +270,18 @@ class ReportPrint(GenericAPIView):
serializer.is_valid(raise_exception=True)
template = serializer.validated_data['template']
model_class = template.get_model()
if model_class and not users.permissions.check_user_permission(
request.user, model_class, 'view'
):
raise PermissionDenied(
_('You do not have permission to view this model type')
)
items = serializer.validated_data['items']
instances = template.get_model().objects.filter(pk__in=items)
instances = model_class.objects.filter(pk__in=items)
# Sort the instances by the order of the provided items
instances = sorted(instances, key=lambda item: items.index(item.pk))
@ -322,7 +340,7 @@ class ReportTemplateList(TemplatePermissionMixin, ReportTemplateMixin, ListCreat
"""API endpoint for viewing list of ReportTemplate objects."""
filterset_class = ReportFilter
filter_backends = [DjangoFilterBackend, InvenTreeSearchFilter]
filter_backends = SEARCH_ORDER_FILTER
search_fields = ['name', 'description']
ordering_fields = ['name', 'enabled']

View File

@ -110,7 +110,7 @@ class ReportPrintSerializer(serializers.Serializer):
fields = ['template', 'items']
template = serializers.PrimaryKeyRelatedField(
queryset=report.models.ReportTemplate.objects.all(),
queryset=report.models.ReportTemplate.objects.filter(enabled=True),
many=False,
required=True,
allow_null=False,
@ -151,7 +151,7 @@ class LabelPrintSerializer(serializers.Serializer):
super().__init__(*args, **kwargs)
template = serializers.PrimaryKeyRelatedField(
queryset=report.models.LabelTemplate.objects.all(),
queryset=report.models.LabelTemplate.objects.filter(enabled=True),
many=False,
required=True,
allow_null=False,

View File

@ -17,7 +17,7 @@ from build.models import Build
from common.models import Attachment
from common.settings import set_global_setting
from InvenTree.unit_test import AdminTestCase, InvenTreeAPITestCase
from order.models import ReturnOrder, SalesOrder
from order.models import PurchaseOrder, ReturnOrder, SalesOrder
from part.models import Part
from plugin.registry import registry
from report.models import LabelTemplate, ReportTemplate
@ -731,6 +731,140 @@ class TestReportTest(PrintTestMixins, ReportTest):
self.run_print_test(SalesOrder, 'salesorder', label=False)
class ReportPrintPermissionTest(InvenTreeAPITestCase):
"""Test that the report print endpoint checks VIEW permission on the associated model type."""
fixtures = [
'category',
'part',
'company',
'location',
'supplier_part',
'stock',
'order',
]
superuser = False
roles = []
def setUp(self):
"""Setup for permission tests."""
cache.clear()
apps.get_app_config('report').create_default_reports()
return super().setUp()
def test_report_print_model_permission(self):
"""A user without VIEW permission on the model type must receive 403; granting the role allows printing."""
template = ReportTemplate.objects.filter(
enabled=True, model_type='purchaseorder'
).first()
self.assertIsNotNone(template)
items = PurchaseOrder.objects.all()[:2]
self.assertGreater(len(items), 0)
url = reverse('api-report-print')
post_data = {'template': template.pk, 'items': [item.pk for item in items]}
# No roles assigned: expect permission denied
self.post(url, data=post_data, expected_code=403)
# Grant view access to purchase orders
self.assignRole('purchase_order.view')
cache.clear()
# Should now succeed
self.post(url, data=post_data, expected_code=201)
def test_report_print_disabled_template(self):
"""Printing against a disabled report template must be rejected."""
self.assignRole('purchase_order.view')
cache.clear()
template = ReportTemplate.objects.filter(
enabled=True, model_type='purchaseorder'
).first()
self.assertIsNotNone(template)
items = PurchaseOrder.objects.all()[:2]
self.assertGreater(len(items), 0)
url = reverse('api-report-print')
post_data = {'template': template.pk, 'items': [item.pk for item in items]}
# Enabled template: should succeed
self.post(url, data=post_data, expected_code=201)
# Disable the template and retry: should be rejected
template.enabled = False
template.save()
self.post(url, data=post_data, expected_code=400)
class LabelPrintPermissionTest(InvenTreeAPITestCase):
"""Test that the label print endpoint checks VIEW permission on the associated model type."""
fixtures = ['category', 'part', 'company', 'location', 'supplier_part', 'stock']
superuser = False
roles = []
def setUp(self):
"""Setup for permission tests."""
cache.clear()
apps.get_app_config('report').create_default_labels()
return super().setUp()
def test_label_print_model_permission(self):
"""A user without VIEW permission on the model type must receive 403; granting the role allows printing."""
template = LabelTemplate.objects.filter(enabled=True, model_type='part').first()
self.assertIsNotNone(template)
self.assertGreater(template.width, 0)
self.assertGreater(template.height, 0)
items = Part.objects.all()[:2]
self.assertGreater(len(items), 0)
url = reverse('api-label-print')
post_data = {'template': template.pk, 'items': [item.pk for item in items]}
# No roles assigned: expect permission denied
self.post(url, data=post_data, expected_code=403)
# Grant view access to parts
self.assignRole('part.view')
cache.clear()
# Should now succeed
self.post(url, data=post_data, expected_code=201)
def test_label_print_disabled_template(self):
"""Printing against a disabled label template must be rejected."""
self.assignRole('part.view')
cache.clear()
template = LabelTemplate.objects.filter(enabled=True, model_type='part').first()
self.assertIsNotNone(template)
self.assertGreater(template.width, 0)
self.assertGreater(template.height, 0)
items = Part.objects.all()[:2]
self.assertGreater(len(items), 0)
url = reverse('api-label-print')
post_data = {'template': template.pk, 'items': [item.pk for item in items]}
# Enabled template: should succeed
self.post(url, data=post_data, expected_code=201)
# Disable the template and retry: should be rejected
template.enabled = False
template.save()
self.post(url, data=post_data, expected_code=400)
class AdminTest(AdminTestCase):
"""Tests for the admin interface integration."""

View File

@ -101,16 +101,16 @@ blessed==1.44.0 \
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
boto3==1.43.17 \
--hash=sha256:8cf48babdd52ff0e2d891dc661143780b361d3776a3be06cd719da0696995074 \
--hash=sha256:f6b3862a0b14e237f9323223ee76b0563e87a6bbe6d94a42e7b008a901ba8950
boto3==1.43.23 \
--hash=sha256:5d26498702ffd021dc0d57d0eefcc7101cd995ea0ed08c057c9b631efccbaa48 \
--hash=sha256:8afc058924ef8a5c62467fe2e1e2e0304c22018587a044714da89f9c602ba856
# via
# -c src/backend/requirements.txt
# django-anymail
# django-storages
botocore==1.43.17 \
--hash=sha256:27f4ecb80cf1e5be70415fc4a4d3db3907d41ef8178c9df822364f275427d375 \
--hash=sha256:499af7c942ecfd404322974e82c6b5d05a8ea16e9f19320b353e16f401adc5b4
botocore==1.43.23 \
--hash=sha256:69ff3d951cb644d1d84db646663c7eb919dc9c0c47e5768e947c8a71121b3d77 \
--hash=sha256:a6737c598750f330bfa8ef2be2d9fa84b5d2d643b6bbb0d22e129e03b7535df1
# via
# -c src/backend/requirements.txt
# boto3
@ -684,9 +684,9 @@ django-recurrence==1.14 \
# via
# -c src/backend/requirements.txt
# django-ical
django-redis==6.0.0 \
--hash=sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0 \
--hash=sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd
django-redis==7.0.0 \
--hash=sha256:4b23aa6e0cd0937bb1242e9a463809e6004de3ca2150f34e986306bb6220d688 \
--hash=sha256:e48491c862f4350b0747ceb1016700686fb93c4f4e0fb9c490fe6c6658ffd933
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -719,9 +719,9 @@ django-storages[s3, sftp]==1.14.6 \
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
django-structlog==10.0.0 \
--hash=sha256:4e3fa4a930697fb9b649470e389419bb73b916a1ecf4f4bf2f8727f5cbfdb002 \
--hash=sha256:4f9db3cb7b308df6aa4afe1353d9c19d5bac757022ddbbb5c24f3d0d6a91a240
django-structlog==10.1.0 \
--hash=sha256:450842bfb03887fc14469570769e515d22ea67d753848a25cdbd05405382c090 \
--hash=sha256:812f61dea873e559511f42c0f3a7cdc36d4472f6cc15460565a97e5cbe06a76d
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -762,49 +762,49 @@ drf-spectacular==0.29.0 \
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
dulwich==1.2.5 \
--hash=sha256:00b54a1d56ddbacdd8eadd6d4787a51b3a05fefa30eadbf9165fd283a00b90ed \
--hash=sha256:0395b2c8924c3424bafe2d9c1edd5348cc4b21ce9c1d6655bf01f9a5c47164c8 \
--hash=sha256:07cb75b58216440e2c170fff4f3d55a5f387358d9489863af8cb11f24ee37121 \
--hash=sha256:1679b376433a0fc7f36586afda1d4ed7427afa7a79d4bf17e5014474eea69fa4 \
--hash=sha256:1699a4cf8d44c174408325a9594a1498d05786cea34e3004c8732420ee1b8182 \
--hash=sha256:1ba83ec3cfb4c506c277400357a51523c8258fa07b841ee06e8e1071da4cfed1 \
--hash=sha256:1c151a7f3995ccf9d433a603b747e76141a7ebe7c385c8909e9f7e7a6422c28f \
--hash=sha256:2f10dafa1ef5660b1331364bc8d68446448608a8d8f493ed0e260eaf5133e71c \
--hash=sha256:2f90d68bfa97c4ca71de7507984365aefe27b6d248cb28dc99644d0f3ae8c60b \
--hash=sha256:41ccffb0521f3f9ad73fac78772f321d731607336cee48911e7c26963459481c \
--hash=sha256:46db47394ba8a95748ae739f5d3a5a3e1724a2f857bf2437bc71bfc0baaed91d \
--hash=sha256:5108acead814d1de8b6262d6d8fb90af7e82f5a4d83788b6b48e39d01800a92f \
--hash=sha256:517fb7e20f91d2bd48dc5de9edc90ff8974a5512ce7f243284b191f8be6344c3 \
--hash=sha256:53599909d54a2fae49fcd50047f1daf4b8b9eda6a5500a08b71da689f5431c24 \
--hash=sha256:556593fd11637f80f6018bee1916b1a84f5b420423b470ebb3f1a782ad6ef081 \
--hash=sha256:5e067b7feceb7034bc99e7c7143a704f1d97d4be7027d9a0aa5a83c0657ff091 \
--hash=sha256:66aded7d364341b55941973a1562323f25bd205f0809692b687ec36ccd31242c \
--hash=sha256:6c683c0f4a062894b6826c61102d415dae86ade61a10003c82ccc2b91858d5fb \
--hash=sha256:701a9ecf7a8a44f5e2459e46befa93530cf36a8b1ae3140aefc007db1d7d0207 \
--hash=sha256:77d2d2e43ad975459491de1ebf47990c74ff17f12586c8561e9890239bc422db \
--hash=sha256:827366331603150de5976d72dd456a3fd5fc91e856471dc1d10fd64758c05f02 \
--hash=sha256:8929134acf4ff967203df7600b38535f9b5b590462067a7e30dbce01acb97af9 \
--hash=sha256:8e55f36a7f52ba0976dd72100273523908b16fb9dda6ce96d9aa9df9cceed4cc \
--hash=sha256:9008ef25cabd379cda4fa86000fc38ca14b72afe17db798a8c85c0b2b7ce4d1e \
--hash=sha256:93d2d87acf75d60c5a2b8c5c8a45aff17bbbd00c17bdccb4ba013d3ab590a65f \
--hash=sha256:9693d2c9e226b2ea855c1dc3a87e2f4d972f7523fc0f7924e5997e9f4c23d97f \
--hash=sha256:9b6d234f1f91335e9f01d9daac42ddc2d2e5c2fdbe285d8eeef50353b283648a \
--hash=sha256:9f3c98f5fa90a842c1f545463834f712aa2eed785fc3d5e42836c0df2d691bb6 \
--hash=sha256:9fc113c1348c7eb22c4e8790f68b562bb4f42a721fafb813e89a57e9cd632040 \
--hash=sha256:a5549f4afc973e0a15ea6b0244d57f848d3f3ee13dac557eb311024aebebf128 \
--hash=sha256:a6620963196c49212c511cd909f367dacf771f199a27d116f357cc671ea956c7 \
--hash=sha256:a70477c991e96cfe8fdd7c866e7251faf71b38bfeb51d6f27554c9cce1caabf3 \
--hash=sha256:ade416833214f3ee13af9b0199fff4de00fa6e0fde3deced776532fd91df5515 \
--hash=sha256:c65230abaa52c72093b70d3b499d5689d1d8f9627e88ad3c3b4f8154e86ac0c8 \
--hash=sha256:ccc58f26a1b94bef255316311678b03854f7192069bdf11cf501a6c85f61b83c \
--hash=sha256:d33bae2b3292ed0235522682316251658187f43b1ebad6cd2b127069b94afb3b \
--hash=sha256:d46e35c473646efb3b2ff8032f37ac5b6d48da52a669577187d3796a6d5987a3 \
--hash=sha256:d8f7ea8f47e38e5b0de3fab97e07e9c9161ffddc90b3964512cab2b7749df4e6 \
--hash=sha256:dd9569bc26174a3437d749114d36c81fc6c7478b55370ae50125e34e9629e4fe \
--hash=sha256:df4ac3746099562c8160d78d55bb2fa10c9ada7ef970af3e2536bd133cb7830e \
--hash=sha256:e128cddeccae4146b556684a0d5426454fff5bfe7306862e5a8ce6b471568af4 \
--hash=sha256:fa37da7ad16c47391016b5f984fb60e175e1ab0b478f04920fd6d1f61123ce4d
dulwich==1.2.6 \
--hash=sha256:04252b107a1600325f5f0301dde8b5b62f5bb51a0467e360070baddbb4edcea7 \
--hash=sha256:116ac7decb923a473540bf813c1ceb061bef07209fad5fb002d867f1907f9393 \
--hash=sha256:11b1f5a6a6075ab4f906dfb755c1d805c8c898ba4f4816b0fdb6123e113030ac \
--hash=sha256:1c35c294acfc5a0a88d01d5db1abeba550bf6274bcc3fddbf8b365e9eea280da \
--hash=sha256:204d14692fb1dd850ab773690f7530f4065f405e9e7dd3f85bdf92e9330ffa2d \
--hash=sha256:21e2e9b81ab04ad83f2d4101ac515ef56ee08d06fd853c1a7ac255f20bb49963 \
--hash=sha256:27db364f2f3cf5b0dddd44d6c2ae9a20f6021e2bae8b1268fa689076f0192244 \
--hash=sha256:371394e2c6f3f9789cdc0abb965dae9bc62e79984b84f35339e9d466598c9fb0 \
--hash=sha256:405cfd53a99374ff03aacdd7a86d6a07615feca072ed69721f49ae2ebaa3eab4 \
--hash=sha256:493e2ea0f23a8e9aae8e3000a366d1fbf0ed2c13eaf8f41863f050c6392ef138 \
--hash=sha256:4940fbf7cb37870686c63dfc7682e1afdab0e55b663bb614572909b68e775d31 \
--hash=sha256:4cf80217e73a039614dde5ab2c74917833632912b788074bc7158058aafbf3e5 \
--hash=sha256:5ff9f36c95deaf7eb5d6ccde4c68adbcb932a87e03c1b479a8d94d779e7cc5d2 \
--hash=sha256:6993ad48f92dc38a43e3c1bf25efb03a62fc2cf4db86a2e904b6c7176dafc3d5 \
--hash=sha256:6d9720d591052730775dcbf450f0cd5b35162f4eeb4754337a5d763326481b2f \
--hash=sha256:6fcbb3dec5733898be2114476ff5abaa1dbb8a6d28ffbe492b3225a5a556197e \
--hash=sha256:6fd9911fb57ee2d6eefaf895df65e1139fbc911fa560e959b38feabe5f15003f \
--hash=sha256:72512e2a22df6fb65ba7b66f5037046019a12343f6e9e54f42bcc4a68ab3d628 \
--hash=sha256:72ac4f3fc92d54115ba2d812263117d9577b17f4c62ae8f170c177515f62e9d3 \
--hash=sha256:794a85b8b9d4ad57d02c8cb455735419ac50c0f2e3d26d83873e34abee58cb1b \
--hash=sha256:79728d98e0ec184856d71fd0d55abbf5ac7345b5baea9f2d1533a4de9064e13d \
--hash=sha256:7b4a2f497718bfe1a3b21f933ee27c111b9cea560c0b2d8a6d939e1b5f297f79 \
--hash=sha256:7c187efaebb72146245ebcb872b89fdc99314fa37442119c5a5feb18af3f4b8a \
--hash=sha256:824b7f5b22b128c1e1ad7c655e9790e2d75c7ab1ba1e40a708024193f1dc47a3 \
--hash=sha256:82e8810e57f9651a624116e3fede33276f89406cb910f517b944105e284e6755 \
--hash=sha256:8d8175dbe4feaf62bcafc8708448bfe223b4dfc71609be25c0cf2b0962abc36c \
--hash=sha256:9139d0110580a3038048286e761e9be166ec40a2eb19218b41b75541c5d87a86 \
--hash=sha256:9e357d825b82e7fec2b83cd8e50f3c099c14c1070e1df961bfefb83943dc1582 \
--hash=sha256:ad4b6114440f9cf72315b173532ee3284f27a288b8a24bc27e45b2e54593720d \
--hash=sha256:c60ddc8206e04e8e08208eac80130004eff0d587c82d398beeca7330cade061f \
--hash=sha256:c639a8c9fb7e745749f2dcbd5b63a82df2fc99cfe62e2c3654ec025a42d2e51f \
--hash=sha256:cb1f8d658f36b2ac3982715dc3e49f0d741a3e5a8c40136bebb6d8493968aa12 \
--hash=sha256:cdd15b8442b527575d733d90cfd6d3c4cbaebf989e2298b0cb57a7916c66254f \
--hash=sha256:dd2783352917b7cb3ab12b7c3f7757210d93af6df0bd2d876a8e5b53b2feb3eb \
--hash=sha256:dd2b66c915f1b22ca6533b48e8ee435800b25f74f419c40e1a92271666d8b297 \
--hash=sha256:e103584421b7205f022bd413a324ff26905ffa84fcc1536f5787bf554d5d390b \
--hash=sha256:e995ad77b0685747bdb51f7a5cd7e6cb8efe73e29517b0f2c95fc2e6d10d5a90 \
--hash=sha256:eb27a9ebe9029c872abadf4f9dcb18c9f6a4b7a4afe137f79a61df1ae59dc6bf \
--hash=sha256:f682671a2e19b7b4caa572ff3073557de049a153946305e051a4f50bb0e5e1bd \
--hash=sha256:f887643cf1c7a04e898547bd9f0acf6654d772ebd153012433ef950315dcf776 \
--hash=sha256:fa7a089298fcbdaed493dd25c2f13574ccfc708f89a7aae8e3c25fd8393f5c81 \
--hash=sha256:fae59c5e345f5ca234c85d157f1c7d5e0086126b45b5f7cfa66ffe41d049fdd6
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -899,68 +899,58 @@ googleapis-common-protos==1.75.0 \
# -c src/backend/requirements.txt
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
grpcio==1.80.0 \
--hash=sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1 \
--hash=sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9 \
--hash=sha256:05d55e1798756282cddd52d56c896b3e7d673e3a8798c2f1cd05ba249a3bb4de \
--hash=sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab \
--hash=sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921 \
--hash=sha256:1b97cd29a8eda100b559b455331c487a80915b6ea6bd91cf3e89836c4ee8d957 \
--hash=sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f \
--hash=sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257 \
--hash=sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d \
--hash=sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05 \
--hash=sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd \
--hash=sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e \
--hash=sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02 \
--hash=sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae \
--hash=sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f \
--hash=sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21 \
--hash=sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e \
--hash=sha256:43168871f170d1e4ed16ae03d10cd21efa29f190e710a624cee7e5ae07da6f4f \
--hash=sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1 \
--hash=sha256:4560cf0e86514595dbbd330cd65b7afad4b5c4b8c4905c041cfffa138d45e6fd \
--hash=sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069 \
--hash=sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411 \
--hash=sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14 \
--hash=sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9 \
--hash=sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440 \
--hash=sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc \
--hash=sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060 \
--hash=sha256:627fb7312171cdc52828bd6fac8d7028ff2a64b89f1957b6f3416caa2218d141 \
--hash=sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6 \
--hash=sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388 \
--hash=sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106 \
--hash=sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140 \
--hash=sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c \
--hash=sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f \
--hash=sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7 \
--hash=sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0 \
--hash=sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294 \
--hash=sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f \
--hash=sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff \
--hash=sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f \
--hash=sha256:a361c20ec1ccd3c3953d20fb6d7b4125093bdd10dff44c5e2bbb39e58917cedc \
--hash=sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199 \
--hash=sha256:aacdfb4ed3eb919ca997504d27e03d5dba403c85130b8ed450308590a738f7a4 \
--hash=sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2 \
--hash=sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7 \
--hash=sha256:bac1d573dfa84ce59a5547073e28fa7326d53352adda6912e362da0b917fcef4 \
--hash=sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a \
--hash=sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0 \
--hash=sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193 \
--hash=sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6 \
--hash=sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de \
--hash=sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f \
--hash=sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58 \
--hash=sha256:deb10a1528473c11f72a0939eed36d83e847d7cbb63e8cc5611fb7a912d38614 \
--hash=sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a \
--hash=sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50 \
--hash=sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad \
--hash=sha256:ec0a592e926071b4abad50c1495cd0d0d513324b3ff5e7267067c33ba27506e4 \
--hash=sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9 \
--hash=sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2 \
--hash=sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81
grpcio==1.81.0 \
--hash=sha256:0fba53cb96004b2b7fb758b46b2288cb49d0b658316a4e73f3ef67230616ee65 \
--hash=sha256:194eddfacc84d80f50512e9fd4ee851d5f2499f18f299c95aa8fb4748f0537e0 \
--hash=sha256:19f201da7b4e5c0559198abe5a97157e726f3abe6e8f5e832d4a50740f6dcc22 \
--hash=sha256:21ec30b9ea320c8207ea7cd05873ad64aa69fdd0e81b6758b3347983ba20b50a \
--hash=sha256:275144b0115353339dbb8a6f28a9cf8997b5bf40e37f8f66ac0b0ea57e95b43f \
--hash=sha256:300f3337b6425fd16ead9a4f9b2ac25801acb64aa5bc0b99eb69901645b2b1d2 \
--hash=sha256:3755c9669307cad18e7e009860fdea98118978d2300451bd8530a53048e741e7 \
--hash=sha256:3d4e0ce5a40a998cf608c8ba60ecfe18fdf364a9aa193ae4ac3faeecd0e86757 \
--hash=sha256:40edffb4ec3689373825d367c4457727047a6e554f03245265ecc8cc03215f22 \
--hash=sha256:43c121e135ae44d1559b430db2b2dfad7421cbbe40e1deba506c7dc62b439719 \
--hash=sha256:4e032feb3bfb4e2749b140a2302a6baa8ead1b9781ff5cf7094e4402b5e9372e \
--hash=sha256:5192857589f223e5a98ff0e31f6e551b19040e647d17bfe10116c8a2ce3b8696 \
--hash=sha256:57b3b0e73a518fa286959b40c3eddd02703504ca186e8b7b2945954519bd8b2c \
--hash=sha256:5e925a70fe99fe5794f7beca0ea034c75f068afcc356d79047e73f99cdcca34c \
--hash=sha256:62bbe463c9f0f2ff24e31bd25f8dd8b4bae78900e315915a3195a0ef1471a855 \
--hash=sha256:638ccc1b86f7540170a169cb900799b9296a1381e47879ce60b0de9d3db73d33 \
--hash=sha256:725801c7086d7e4cd160e42bb2f54e0aeb976b9568df3cc6f843b15d29b79fb1 \
--hash=sha256:77eb4e9fe61486bd1198cc7236ebb0f70e66234e63c0348f40bc2553ed16a88b \
--hash=sha256:7915a2e63acdc05264a206e1bddfd8e1fb8a29e406c18d72d30f8c124e021374 \
--hash=sha256:794e6aa648e8df47d8f908dc8c3b42347d04ec58438f1dcd4e445f09b4f6b0ce \
--hash=sha256:8226ba097eed660ef14d36c6a69b85038552bb8b6d17b44a5aa6f9abf48b8e08 \
--hash=sha256:87e33b7afcfb3585121b5f007d2c52b8c534104d18f556e840d35193ca2a9141 \
--hash=sha256:8bb1789c94322a13336a2b6c58d9c14d68f8628b6e24205a799c69f5bf8516ce \
--hash=sha256:8c0855a350886f713b9e458e2a10d208009dcaa849f574e39cd6067db1fe1279 \
--hash=sha256:909bb3222b53235498d2c5817a0596d82b0aaea490ba93fdf1b060e2938a543c \
--hash=sha256:97bbd623f7ded558fd4f7cb5a4f600c4d4de65c5dd364c83a5b14b2a10a2d3b5 \
--hash=sha256:98c6240f563178fc5877bd50e6ff274463e53e1472128f4110742450739659fa \
--hash=sha256:9f355384e5543ab77a755a7085225ecc19f32b76032e851cbd8145715d79dec8 \
--hash=sha256:a524cd530900bd24511fcb7f2ed144da4ea37711c4b094475d0bceca7a93a170 \
--hash=sha256:a5acd7efd3b1fe9b4eb0bcaaa1507eed68a0ad0678b654c3f7b464df9ba9dca5 \
--hash=sha256:a9351055f52660b58f3d4890ea66188b5134399f82b11aa0c55bd4b99eff5390 \
--hash=sha256:aa948712c8e5fa40ec250870bda14bc7578e1bb832a8912d9d2a0f720518edbe \
--hash=sha256:aaaa4f7f2057d795952e4eacf3f342be8b5b156992f6ac85023c8b98794ebd47 \
--hash=sha256:b4108e5d9d0f651b7eea749116181fe6c315b145661a80ec31f05ec2dbe21af7 \
--hash=sha256:b76ea9d55cd08fcdbda25d28e0f76679536710acb7fbd5b1f70cb4ac49317265 \
--hash=sha256:b8b025b6af43ee0ad4a70307025d77bcab5adde7c4597786010d802c203e9fc5 \
--hash=sha256:b93cee313cae4e113fbb3a0ce1ea5633db6f63cfde2b2dc1d817429026b2a50b \
--hash=sha256:c197e2ef75a442528072b29e9755da299110e8610e8bcbb59a6b4cf55384f005 \
--hash=sha256:c36f5d5e97944cbda2d4096b4ae262e6e68506246b61582acf1b8591607f3ccc \
--hash=sha256:c4fe218c5a35e1d87a5a26544237f1fa41dfd9cbd3c856b0810a30061f8b0aaf \
--hash=sha256:c6ff087cb1f563f47b504b4e29e684129fc5ae4863faf3ebca08a327764ee6cb \
--hash=sha256:cd78145b7f7784661c524624f3526c9c6f891b30a4b54cb93a40806d0d0d61e9 \
--hash=sha256:db217c2e52931719f9937bd12082cd4d7b495b35803d5760686975c285924bf8 \
--hash=sha256:dbdb99986548a7e87f8343805ef315fd4eb50ffaabf4fb1206e42f2542bb805d \
--hash=sha256:e4d053900a0d24b75d7521139a3872150301b3d6bde3bed5e12318fb25791e4d \
--hash=sha256:e7746ba3e6efc9e2b748eff59470a2b8684d5a9ec607c6580bcaa5be175820bc \
--hash=sha256:f345de40ef2e65f63645d53d251824e6070e07804827c5b00ec2e44555f9f901 \
--hash=sha256:f750a091fff3a3991731abc1f818bdc64874bb3528162732cb4d45f2e07821a6 \
--hash=sha256:f85570a016d794c29b1e76cf22f67af4486ddbe779e0f30674f138fa4e1769ec \
--hash=sha256:fbbe81314a9d92156abce8b62c09364eb8bafc0ca2a19919a45ec64b5c6cb664 \
--hash=sha256:ff83d889e3ebf6341c8c7864ad8031591ad5ca61599072fc511644d1eb962d2b
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -977,9 +967,9 @@ icalendar==7.1.2 \
# via
# -c src/backend/requirements.txt
# django-ical
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# -c src/backend/requirements.txt
# django-anymail
@ -1717,9 +1707,9 @@ pynacl==1.6.2 \
# via
# -c src/backend/requirements.txt
# paramiko
pypdf==6.12.2 \
--hash=sha256:111669eb6680c04495ae0c113a1476e3bf93a95761d23c7406b591c80a6490b1 \
--hash=sha256:67b2699357a1f3f4c945940ea80826349ee507c9e2577724a14b4941982c104d
pypdf==6.13.0 \
--hash=sha256:558683ec9daf6b91c280c322c84c32f5cc216afd3eaa3a37de5ae88ae0c3b787 \
--hash=sha256:de1294ae49d6956edb4e5c41527fb9e8716ddd2b120f2185c68aab784d4ffe60
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -2110,9 +2100,9 @@ s3transfer==0.18.0 \
# via
# -c src/backend/requirements.txt
# boto3
sentry-sdk==2.61.0 \
--hash=sha256:1ca9b4bb777eb5be67004edab7eb894f21c6301f1d05ed64966719ad5d1764ce \
--hash=sha256:ec4d30273909cb1d198e03208b16ee70e2bc5d90a16fd9f1fb2fc6a72e1f03dc
sentry-sdk==2.61.1 \
--hash=sha256:9c6adccb3feefa9ba032c8d295ca477575c2f11896046a2b0ad686c47c4af555 \
--hash=sha256:fa36eaf4b8ad708f718500d4bdcc1532637526a22beb874d88cbc0a46458b5ae
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -2167,9 +2157,9 @@ tinyhtml5==2.1.0 \
# via
# -c src/backend/requirements.txt
# weasyprint
tqdm==4.67.3 \
--hash=sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb \
--hash=sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf
tqdm==4.68.1 \
--hash=sha256:fc163d96b287bd031e1aa24421ce4411b25559bd0a1be4fe649bdaa4d2c02bf5 \
--hash=sha256:fea4a90e4023f764914569f7802a297277c5ab1a66be5144143e142e1a4031d8
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in
@ -2218,9 +2208,9 @@ wcwidth==0.7.0 \
# -c src/backend/requirements.txt
# blessed
# prettytable
weasyprint==68.1 \
--hash=sha256:4dc3ba63c68bbbce3e9617cb2226251c372f5ee90a8a484503b1c099da9cf5be \
--hash=sha256:d3b752049b453a5c95edb27ce78d69e9319af5a34f257fa0f4c738c701b4184e
weasyprint==69.0 \
--hash=sha256:475951cfd917014de6d4d005caff48c6aa867e7e42b80cd5b16a0484a1609ee6 \
--hash=sha256:a7a32f39ca16bd82ef11de99c92ea4b5f14951c9033af035e451ce4f4ee0a88c
# via
# -c src/backend/requirements.txt
# -r src/backend/requirements.in

View File

@ -448,9 +448,9 @@ gprof2dot==2025.4.14 \
--hash=sha256:0742e4c0b4409a5e8777e739388a11e1ed3750be86895655312ea7c20bd0090e \
--hash=sha256:35743e2d2ca027bf48fa7cba37021aaf4a27beeae1ae8e05a50b55f1f921a6ce
# via django-silk
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# -c src/backend/requirements-3.14.txt
# -c src/backend/requirements.txt
@ -484,9 +484,9 @@ pdfminer-six==20260107 \
--hash=sha256:366585ba97e80dffa8f00cebe303d2f381884d8637af4ce422f1df3ef38111a9 \
--hash=sha256:96bfd431e3577a55a0efd25676968ca4ce8fd5b53f14565f85716ff363889602
# via -r src/backend/requirements-dev.in
pip==26.1.1 \
--hash=sha256:99cb1c2899893b075ff56e4ed0af55669a955b49ad7fb8d8603ecdaf4ed653fb \
--hash=sha256:d36762751d156a4ee895de8af39aa0abeeeb577f93a2eca6ab62467bbf0f8a78
pip==26.1.2 \
--hash=sha256:382ff9f685ee3bc25864f820aa50505825f10f5458ffff07e30a6d96e5715cab \
--hash=sha256:f49cd134c61cf2fd75e0ce2676db03e4054504a5a4986d00f8299ae632dc4605
# via pip-tools
pip-tools==7.5.3 \
--hash=sha256:3aac0c473240ae90db7213c033401f345b05197293ccbdd2704e52e7a783785e \
@ -496,24 +496,24 @@ pluggy==1.6.0 \
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
# via pytest
prek==0.4.3 \
--hash=sha256:03a4ac3c3023a76faa52ad7775720599b10241930be8902c471085b22572b4b0 \
--hash=sha256:1b8d99ee3277f8f3a3453a953120ee5c6c52f7ad89e459a25425cf62135f47b1 \
--hash=sha256:2d2b0c12e3d1c6d90646f9faa2d4c66f9861f3c6e577d7dbd25e733ed095ac56 \
--hash=sha256:40173425ab82bf0a7267d672b3e3aae9dd425eaee3a3641c6a5f040da3ff95e4 \
--hash=sha256:70d9da5fc14ef41565ff7ba9f476fb53166bf719a954339b2e9f42ed494a2f71 \
--hash=sha256:798d04437d30d6b4e6c1d520fe6ca800c340c9246f0dc8900d8b365df54b71b6 \
--hash=sha256:8607d636ef9232675507d97d252e1dcca5628bff79cb069fa945fff09d7bbb43 \
--hash=sha256:89484765304a779780f83489eb3aed5de5366f47fce7713fa5a917ebc281baa0 \
--hash=sha256:a46862d81078d2c8caa286c392f965ed72fb72eb1fed171910ba54fe8d546ed0 \
--hash=sha256:b43a85f5ddf7827a75491e79ca068a49c5e4efde8dbac844ecb89622a78458e4 \
--hash=sha256:c67109de8d9766c2afd6e7e64feb9e1a0d3eceb3b4123280c28344660c1a97cd \
--hash=sha256:ca6802eaf191acb6166e9e013dd277ea193ba27c1dca896ab7debf6dca758b6d \
--hash=sha256:e08595fe96d24c1fe13486b00d55ce73a7b37040a16e82365942606594c67a6b \
--hash=sha256:e486307ea649e7300b3535fac52fe0ba0b80aebe23143b662659d16e6a7c8b47 \
--hash=sha256:e99ee90a7b6e84dabef891ff7521eb59dae38953467bdb482f004ea522d3a64c \
--hash=sha256:f514ec0d95cd4578d74d4601058bd259f5baf91c937f2aaae942d4b070b8077f \
--hash=sha256:f78e343584cfff106fc3c361109b87949ad8028dc5aa667e0fccd26db8170d7d
prek==0.4.4 \
--hash=sha256:0b04a0f36d07474f2a9fc5b1ba1197a1b326b2b211f39cd74cf0d4613545f7f4 \
--hash=sha256:143154b329c05b2f9fa3230e604d02d9c4297dd43f96135a8ba166772e8ecd60 \
--hash=sha256:23cfd96a25de1c93e3c43c746643b80489e3b2fa49ca9c0ffd6022e51535c900 \
--hash=sha256:3efa28fb37b9ddbafb7759da8d497f0d36cf02a05816e15d6541f5669d5d2114 \
--hash=sha256:3f3a25041733de987a47e5a7bace47182a6f0e2ae5f960cb54c1d4630afd2591 \
--hash=sha256:4058638532c6dcbf0076d23b9264cbdd9f0f0e320762e237a6b9e4e4b854a766 \
--hash=sha256:4ec5771153d158a0e4473933b7fd9b51e1b1f57f2df50aeb7560ea6812226dc5 \
--hash=sha256:619bab14071670249777deea0cc0b29d904c4a514cf33b20e583900a544f0399 \
--hash=sha256:9cebca8c15da4f1d6e3a25e6ae0611425c8596e926222050f2588c390e42df8a \
--hash=sha256:a2b7c8710546a1e894afa7ab022030cd4e21f1ee7ffb301b4360773d22f1f00f \
--hash=sha256:a427b792c4436f49732b1f6ebccf221fdcc6390c148474280da9c2c6eaabc9c4 \
--hash=sha256:b998038fc92c990e03147eb5b95b0f2c394517f8857ab911aac8e092f1b9b3ab \
--hash=sha256:bad3586fcea3e913f0edf2e8f132f97889e03976b7ee3d120fd294ad4e89a5eb \
--hash=sha256:c38c5140ae2ea55ebb02e6ca590a416664ea1af287cdd21f54daeec53a81015a \
--hash=sha256:c8742ac26363e74c855df6215a709d5db183204d00ac0f1a722b13aed4da3cd0 \
--hash=sha256:e02bd4d5e05c500e4d9f70f024e30d13aa361dc490724b7f476d2e35542c239f \
--hash=sha256:f032ccbe2d6edc345f81a6d772c18cc169d63c27b5a8292bfe416b352bdfee57
# via -r src/backend/requirements-dev.in
pycparser==3.0 \
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \

View File

@ -442,9 +442,9 @@ gprof2dot==2025.4.14 \
--hash=sha256:0742e4c0b4409a5e8777e739388a11e1ed3750be86895655312ea7c20bd0090e \
--hash=sha256:35743e2d2ca027bf48fa7cba37021aaf4a27beeae1ae8e05a50b55f1f921a6ce
# via django-silk
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# -c src/backend/requirements.txt
# requests

View File

@ -16,7 +16,7 @@ django-mailbox # Email scraping
django-markdownify # Markdown rendering
django-money # Django app for currency management
django-mptt # Modified Preorder Tree Traversal
django-redis>=5.0.0 # Redis integration
django-redis>=7.0.0 # Redis integration
django-q2 # Background task scheduling
django-q-sentry # sentry.io integration for django-q
django-sesame # Magic link authentication

View File

@ -95,15 +95,15 @@ blessed==1.44.0 \
--hash=sha256:d3b5037f0143eb7c80b2000be5bcdf86161af68aed231b91deadbce4e7379785 \
--hash=sha256:e1d2ed93d3d90d0a1494a8b134d188c83fb89ae25590af638b921e8c1c8fa223
# via -r src/backend/requirements.in
boto3==1.43.17 \
--hash=sha256:8cf48babdd52ff0e2d891dc661143780b361d3776a3be06cd719da0696995074 \
--hash=sha256:f6b3862a0b14e237f9323223ee76b0563e87a6bbe6d94a42e7b008a901ba8950
boto3==1.43.23 \
--hash=sha256:5d26498702ffd021dc0d57d0eefcc7101cd995ea0ed08c057c9b631efccbaa48 \
--hash=sha256:8afc058924ef8a5c62467fe2e1e2e0304c22018587a044714da89f9c602ba856
# via
# django-anymail
# django-storages
botocore==1.43.17 \
--hash=sha256:27f4ecb80cf1e5be70415fc4a4d3db3907d41ef8178c9df822364f275427d375 \
--hash=sha256:499af7c942ecfd404322974e82c6b5d05a8ea16e9f19320b353e16f401adc5b4
botocore==1.43.23 \
--hash=sha256:69ff3d951cb644d1d84db646663c7eb919dc9c0c47e5768e947c8a71121b3d77 \
--hash=sha256:a6737c598750f330bfa8ef2be2d9fa84b5d2d643b6bbb0d22e129e03b7535df1
# via
# boto3
# s3transfer
@ -620,9 +620,9 @@ django-recurrence==1.14 \
--hash=sha256:154a6221bd6667c35250d9fa89bbc4792b3f1ec5dc8dff0f5872186b6df3cf76 \
--hash=sha256:3e7420a38c7fa2f5073598e2a4236c65a983213f30f4413618448b43514649cd
# via django-ical
django-redis==6.0.0 \
--hash=sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0 \
--hash=sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd
django-redis==7.0.0 \
--hash=sha256:4b23aa6e0cd0937bb1242e9a463809e6004de3ca2150f34e986306bb6220d688 \
--hash=sha256:e48491c862f4350b0747ceb1016700686fb93c4f4e0fb9c490fe6c6658ffd933
# via -r src/backend/requirements.in
django-sesame==3.2.3 \
--hash=sha256:09977a1c55bdbcce0a024c712c4d683e1a69543a217626ffa1d5f7ef7ebffc58 \
@ -643,9 +643,9 @@ django-storages[s3, sftp]==1.14.6 \
--hash=sha256:11b7b6200e1cb5ffcd9962bd3673a39c7d6a6109e8096f0e03d46fab3d3aabd9 \
--hash=sha256:7a25ce8f4214f69ac9c7ce87e2603887f7ae99326c316bc8d2d75375e09341c9
# via -r src/backend/requirements.in
django-structlog==10.0.0 \
--hash=sha256:4e3fa4a930697fb9b649470e389419bb73b916a1ecf4f4bf2f8727f5cbfdb002 \
--hash=sha256:4f9db3cb7b308df6aa4afe1353d9c19d5bac757022ddbbb5c24f3d0d6a91a240
django-structlog==10.1.0 \
--hash=sha256:450842bfb03887fc14469570769e515d22ea67d753848a25cdbd05405382c090 \
--hash=sha256:812f61dea873e559511f42c0f3a7cdc36d4472f6cc15460565a97e5cbe06a76d
# via -r src/backend/requirements.in
django-taggit==6.1.0 \
--hash=sha256:ab776264bbc76cb3d7e49e1bf9054962457831bd21c3a42db9138b41956e4cf0 \
@ -673,49 +673,49 @@ drf-spectacular==0.29.0 \
--hash=sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc \
--hash=sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a
# via -r src/backend/requirements.in
dulwich==1.2.5 \
--hash=sha256:00b54a1d56ddbacdd8eadd6d4787a51b3a05fefa30eadbf9165fd283a00b90ed \
--hash=sha256:0395b2c8924c3424bafe2d9c1edd5348cc4b21ce9c1d6655bf01f9a5c47164c8 \
--hash=sha256:07cb75b58216440e2c170fff4f3d55a5f387358d9489863af8cb11f24ee37121 \
--hash=sha256:1679b376433a0fc7f36586afda1d4ed7427afa7a79d4bf17e5014474eea69fa4 \
--hash=sha256:1699a4cf8d44c174408325a9594a1498d05786cea34e3004c8732420ee1b8182 \
--hash=sha256:1ba83ec3cfb4c506c277400357a51523c8258fa07b841ee06e8e1071da4cfed1 \
--hash=sha256:1c151a7f3995ccf9d433a603b747e76141a7ebe7c385c8909e9f7e7a6422c28f \
--hash=sha256:2f10dafa1ef5660b1331364bc8d68446448608a8d8f493ed0e260eaf5133e71c \
--hash=sha256:2f90d68bfa97c4ca71de7507984365aefe27b6d248cb28dc99644d0f3ae8c60b \
--hash=sha256:41ccffb0521f3f9ad73fac78772f321d731607336cee48911e7c26963459481c \
--hash=sha256:46db47394ba8a95748ae739f5d3a5a3e1724a2f857bf2437bc71bfc0baaed91d \
--hash=sha256:5108acead814d1de8b6262d6d8fb90af7e82f5a4d83788b6b48e39d01800a92f \
--hash=sha256:517fb7e20f91d2bd48dc5de9edc90ff8974a5512ce7f243284b191f8be6344c3 \
--hash=sha256:53599909d54a2fae49fcd50047f1daf4b8b9eda6a5500a08b71da689f5431c24 \
--hash=sha256:556593fd11637f80f6018bee1916b1a84f5b420423b470ebb3f1a782ad6ef081 \
--hash=sha256:5e067b7feceb7034bc99e7c7143a704f1d97d4be7027d9a0aa5a83c0657ff091 \
--hash=sha256:66aded7d364341b55941973a1562323f25bd205f0809692b687ec36ccd31242c \
--hash=sha256:6c683c0f4a062894b6826c61102d415dae86ade61a10003c82ccc2b91858d5fb \
--hash=sha256:701a9ecf7a8a44f5e2459e46befa93530cf36a8b1ae3140aefc007db1d7d0207 \
--hash=sha256:77d2d2e43ad975459491de1ebf47990c74ff17f12586c8561e9890239bc422db \
--hash=sha256:827366331603150de5976d72dd456a3fd5fc91e856471dc1d10fd64758c05f02 \
--hash=sha256:8929134acf4ff967203df7600b38535f9b5b590462067a7e30dbce01acb97af9 \
--hash=sha256:8e55f36a7f52ba0976dd72100273523908b16fb9dda6ce96d9aa9df9cceed4cc \
--hash=sha256:9008ef25cabd379cda4fa86000fc38ca14b72afe17db798a8c85c0b2b7ce4d1e \
--hash=sha256:93d2d87acf75d60c5a2b8c5c8a45aff17bbbd00c17bdccb4ba013d3ab590a65f \
--hash=sha256:9693d2c9e226b2ea855c1dc3a87e2f4d972f7523fc0f7924e5997e9f4c23d97f \
--hash=sha256:9b6d234f1f91335e9f01d9daac42ddc2d2e5c2fdbe285d8eeef50353b283648a \
--hash=sha256:9f3c98f5fa90a842c1f545463834f712aa2eed785fc3d5e42836c0df2d691bb6 \
--hash=sha256:9fc113c1348c7eb22c4e8790f68b562bb4f42a721fafb813e89a57e9cd632040 \
--hash=sha256:a5549f4afc973e0a15ea6b0244d57f848d3f3ee13dac557eb311024aebebf128 \
--hash=sha256:a6620963196c49212c511cd909f367dacf771f199a27d116f357cc671ea956c7 \
--hash=sha256:a70477c991e96cfe8fdd7c866e7251faf71b38bfeb51d6f27554c9cce1caabf3 \
--hash=sha256:ade416833214f3ee13af9b0199fff4de00fa6e0fde3deced776532fd91df5515 \
--hash=sha256:c65230abaa52c72093b70d3b499d5689d1d8f9627e88ad3c3b4f8154e86ac0c8 \
--hash=sha256:ccc58f26a1b94bef255316311678b03854f7192069bdf11cf501a6c85f61b83c \
--hash=sha256:d33bae2b3292ed0235522682316251658187f43b1ebad6cd2b127069b94afb3b \
--hash=sha256:d46e35c473646efb3b2ff8032f37ac5b6d48da52a669577187d3796a6d5987a3 \
--hash=sha256:d8f7ea8f47e38e5b0de3fab97e07e9c9161ffddc90b3964512cab2b7749df4e6 \
--hash=sha256:dd9569bc26174a3437d749114d36c81fc6c7478b55370ae50125e34e9629e4fe \
--hash=sha256:df4ac3746099562c8160d78d55bb2fa10c9ada7ef970af3e2536bd133cb7830e \
--hash=sha256:e128cddeccae4146b556684a0d5426454fff5bfe7306862e5a8ce6b471568af4 \
--hash=sha256:fa37da7ad16c47391016b5f984fb60e175e1ab0b478f04920fd6d1f61123ce4d
dulwich==1.2.6 \
--hash=sha256:04252b107a1600325f5f0301dde8b5b62f5bb51a0467e360070baddbb4edcea7 \
--hash=sha256:116ac7decb923a473540bf813c1ceb061bef07209fad5fb002d867f1907f9393 \
--hash=sha256:11b1f5a6a6075ab4f906dfb755c1d805c8c898ba4f4816b0fdb6123e113030ac \
--hash=sha256:1c35c294acfc5a0a88d01d5db1abeba550bf6274bcc3fddbf8b365e9eea280da \
--hash=sha256:204d14692fb1dd850ab773690f7530f4065f405e9e7dd3f85bdf92e9330ffa2d \
--hash=sha256:21e2e9b81ab04ad83f2d4101ac515ef56ee08d06fd853c1a7ac255f20bb49963 \
--hash=sha256:27db364f2f3cf5b0dddd44d6c2ae9a20f6021e2bae8b1268fa689076f0192244 \
--hash=sha256:371394e2c6f3f9789cdc0abb965dae9bc62e79984b84f35339e9d466598c9fb0 \
--hash=sha256:405cfd53a99374ff03aacdd7a86d6a07615feca072ed69721f49ae2ebaa3eab4 \
--hash=sha256:493e2ea0f23a8e9aae8e3000a366d1fbf0ed2c13eaf8f41863f050c6392ef138 \
--hash=sha256:4940fbf7cb37870686c63dfc7682e1afdab0e55b663bb614572909b68e775d31 \
--hash=sha256:4cf80217e73a039614dde5ab2c74917833632912b788074bc7158058aafbf3e5 \
--hash=sha256:5ff9f36c95deaf7eb5d6ccde4c68adbcb932a87e03c1b479a8d94d779e7cc5d2 \
--hash=sha256:6993ad48f92dc38a43e3c1bf25efb03a62fc2cf4db86a2e904b6c7176dafc3d5 \
--hash=sha256:6d9720d591052730775dcbf450f0cd5b35162f4eeb4754337a5d763326481b2f \
--hash=sha256:6fcbb3dec5733898be2114476ff5abaa1dbb8a6d28ffbe492b3225a5a556197e \
--hash=sha256:6fd9911fb57ee2d6eefaf895df65e1139fbc911fa560e959b38feabe5f15003f \
--hash=sha256:72512e2a22df6fb65ba7b66f5037046019a12343f6e9e54f42bcc4a68ab3d628 \
--hash=sha256:72ac4f3fc92d54115ba2d812263117d9577b17f4c62ae8f170c177515f62e9d3 \
--hash=sha256:794a85b8b9d4ad57d02c8cb455735419ac50c0f2e3d26d83873e34abee58cb1b \
--hash=sha256:79728d98e0ec184856d71fd0d55abbf5ac7345b5baea9f2d1533a4de9064e13d \
--hash=sha256:7b4a2f497718bfe1a3b21f933ee27c111b9cea560c0b2d8a6d939e1b5f297f79 \
--hash=sha256:7c187efaebb72146245ebcb872b89fdc99314fa37442119c5a5feb18af3f4b8a \
--hash=sha256:824b7f5b22b128c1e1ad7c655e9790e2d75c7ab1ba1e40a708024193f1dc47a3 \
--hash=sha256:82e8810e57f9651a624116e3fede33276f89406cb910f517b944105e284e6755 \
--hash=sha256:8d8175dbe4feaf62bcafc8708448bfe223b4dfc71609be25c0cf2b0962abc36c \
--hash=sha256:9139d0110580a3038048286e761e9be166ec40a2eb19218b41b75541c5d87a86 \
--hash=sha256:9e357d825b82e7fec2b83cd8e50f3c099c14c1070e1df961bfefb83943dc1582 \
--hash=sha256:ad4b6114440f9cf72315b173532ee3284f27a288b8a24bc27e45b2e54593720d \
--hash=sha256:c60ddc8206e04e8e08208eac80130004eff0d587c82d398beeca7330cade061f \
--hash=sha256:c639a8c9fb7e745749f2dcbd5b63a82df2fc99cfe62e2c3654ec025a42d2e51f \
--hash=sha256:cb1f8d658f36b2ac3982715dc3e49f0d741a3e5a8c40136bebb6d8493968aa12 \
--hash=sha256:cdd15b8442b527575d733d90cfd6d3c4cbaebf989e2298b0cb57a7916c66254f \
--hash=sha256:dd2783352917b7cb3ab12b7c3f7757210d93af6df0bd2d876a8e5b53b2feb3eb \
--hash=sha256:dd2b66c915f1b22ca6533b48e8ee435800b25f74f419c40e1a92271666d8b297 \
--hash=sha256:e103584421b7205f022bd413a324ff26905ffa84fcc1536f5787bf554d5d390b \
--hash=sha256:e995ad77b0685747bdb51f7a5cd7e6cb8efe73e29517b0f2c95fc2e6d10d5a90 \
--hash=sha256:eb27a9ebe9029c872abadf4f9dcb18c9f6a4b7a4afe137f79a61df1ae59dc6bf \
--hash=sha256:f682671a2e19b7b4caa572ff3073557de049a153946305e051a4f50bb0e5e1bd \
--hash=sha256:f887643cf1c7a04e898547bd9f0acf6654d772ebd153012433ef950315dcf776 \
--hash=sha256:fa7a089298fcbdaed493dd25c2f13574ccfc708f89a7aae8e3c25fd8393f5c81 \
--hash=sha256:fae59c5e345f5ca234c85d157f1c7d5e0086126b45b5f7cfa66ffe41d049fdd6
# via -r src/backend/requirements.in
et-xmlfile==2.0.0 \
--hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa \
@ -795,68 +795,58 @@ googleapis-common-protos==1.75.0 \
# via
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
grpcio==1.80.0 \
--hash=sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1 \
--hash=sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9 \
--hash=sha256:05d55e1798756282cddd52d56c896b3e7d673e3a8798c2f1cd05ba249a3bb4de \
--hash=sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab \
--hash=sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921 \
--hash=sha256:1b97cd29a8eda100b559b455331c487a80915b6ea6bd91cf3e89836c4ee8d957 \
--hash=sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f \
--hash=sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257 \
--hash=sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d \
--hash=sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05 \
--hash=sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd \
--hash=sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e \
--hash=sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02 \
--hash=sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae \
--hash=sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f \
--hash=sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21 \
--hash=sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e \
--hash=sha256:43168871f170d1e4ed16ae03d10cd21efa29f190e710a624cee7e5ae07da6f4f \
--hash=sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1 \
--hash=sha256:4560cf0e86514595dbbd330cd65b7afad4b5c4b8c4905c041cfffa138d45e6fd \
--hash=sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069 \
--hash=sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411 \
--hash=sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14 \
--hash=sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9 \
--hash=sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440 \
--hash=sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc \
--hash=sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060 \
--hash=sha256:627fb7312171cdc52828bd6fac8d7028ff2a64b89f1957b6f3416caa2218d141 \
--hash=sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6 \
--hash=sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388 \
--hash=sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106 \
--hash=sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140 \
--hash=sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c \
--hash=sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f \
--hash=sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7 \
--hash=sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0 \
--hash=sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294 \
--hash=sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f \
--hash=sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff \
--hash=sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f \
--hash=sha256:a361c20ec1ccd3c3953d20fb6d7b4125093bdd10dff44c5e2bbb39e58917cedc \
--hash=sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199 \
--hash=sha256:aacdfb4ed3eb919ca997504d27e03d5dba403c85130b8ed450308590a738f7a4 \
--hash=sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2 \
--hash=sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7 \
--hash=sha256:bac1d573dfa84ce59a5547073e28fa7326d53352adda6912e362da0b917fcef4 \
--hash=sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a \
--hash=sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0 \
--hash=sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193 \
--hash=sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6 \
--hash=sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de \
--hash=sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f \
--hash=sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58 \
--hash=sha256:deb10a1528473c11f72a0939eed36d83e847d7cbb63e8cc5611fb7a912d38614 \
--hash=sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a \
--hash=sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50 \
--hash=sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad \
--hash=sha256:ec0a592e926071b4abad50c1495cd0d0d513324b3ff5e7267067c33ba27506e4 \
--hash=sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9 \
--hash=sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2 \
--hash=sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81
grpcio==1.81.0 \
--hash=sha256:0fba53cb96004b2b7fb758b46b2288cb49d0b658316a4e73f3ef67230616ee65 \
--hash=sha256:194eddfacc84d80f50512e9fd4ee851d5f2499f18f299c95aa8fb4748f0537e0 \
--hash=sha256:19f201da7b4e5c0559198abe5a97157e726f3abe6e8f5e832d4a50740f6dcc22 \
--hash=sha256:21ec30b9ea320c8207ea7cd05873ad64aa69fdd0e81b6758b3347983ba20b50a \
--hash=sha256:275144b0115353339dbb8a6f28a9cf8997b5bf40e37f8f66ac0b0ea57e95b43f \
--hash=sha256:300f3337b6425fd16ead9a4f9b2ac25801acb64aa5bc0b99eb69901645b2b1d2 \
--hash=sha256:3755c9669307cad18e7e009860fdea98118978d2300451bd8530a53048e741e7 \
--hash=sha256:3d4e0ce5a40a998cf608c8ba60ecfe18fdf364a9aa193ae4ac3faeecd0e86757 \
--hash=sha256:40edffb4ec3689373825d367c4457727047a6e554f03245265ecc8cc03215f22 \
--hash=sha256:43c121e135ae44d1559b430db2b2dfad7421cbbe40e1deba506c7dc62b439719 \
--hash=sha256:4e032feb3bfb4e2749b140a2302a6baa8ead1b9781ff5cf7094e4402b5e9372e \
--hash=sha256:5192857589f223e5a98ff0e31f6e551b19040e647d17bfe10116c8a2ce3b8696 \
--hash=sha256:57b3b0e73a518fa286959b40c3eddd02703504ca186e8b7b2945954519bd8b2c \
--hash=sha256:5e925a70fe99fe5794f7beca0ea034c75f068afcc356d79047e73f99cdcca34c \
--hash=sha256:62bbe463c9f0f2ff24e31bd25f8dd8b4bae78900e315915a3195a0ef1471a855 \
--hash=sha256:638ccc1b86f7540170a169cb900799b9296a1381e47879ce60b0de9d3db73d33 \
--hash=sha256:725801c7086d7e4cd160e42bb2f54e0aeb976b9568df3cc6f843b15d29b79fb1 \
--hash=sha256:77eb4e9fe61486bd1198cc7236ebb0f70e66234e63c0348f40bc2553ed16a88b \
--hash=sha256:7915a2e63acdc05264a206e1bddfd8e1fb8a29e406c18d72d30f8c124e021374 \
--hash=sha256:794e6aa648e8df47d8f908dc8c3b42347d04ec58438f1dcd4e445f09b4f6b0ce \
--hash=sha256:8226ba097eed660ef14d36c6a69b85038552bb8b6d17b44a5aa6f9abf48b8e08 \
--hash=sha256:87e33b7afcfb3585121b5f007d2c52b8c534104d18f556e840d35193ca2a9141 \
--hash=sha256:8bb1789c94322a13336a2b6c58d9c14d68f8628b6e24205a799c69f5bf8516ce \
--hash=sha256:8c0855a350886f713b9e458e2a10d208009dcaa849f574e39cd6067db1fe1279 \
--hash=sha256:909bb3222b53235498d2c5817a0596d82b0aaea490ba93fdf1b060e2938a543c \
--hash=sha256:97bbd623f7ded558fd4f7cb5a4f600c4d4de65c5dd364c83a5b14b2a10a2d3b5 \
--hash=sha256:98c6240f563178fc5877bd50e6ff274463e53e1472128f4110742450739659fa \
--hash=sha256:9f355384e5543ab77a755a7085225ecc19f32b76032e851cbd8145715d79dec8 \
--hash=sha256:a524cd530900bd24511fcb7f2ed144da4ea37711c4b094475d0bceca7a93a170 \
--hash=sha256:a5acd7efd3b1fe9b4eb0bcaaa1507eed68a0ad0678b654c3f7b464df9ba9dca5 \
--hash=sha256:a9351055f52660b58f3d4890ea66188b5134399f82b11aa0c55bd4b99eff5390 \
--hash=sha256:aa948712c8e5fa40ec250870bda14bc7578e1bb832a8912d9d2a0f720518edbe \
--hash=sha256:aaaa4f7f2057d795952e4eacf3f342be8b5b156992f6ac85023c8b98794ebd47 \
--hash=sha256:b4108e5d9d0f651b7eea749116181fe6c315b145661a80ec31f05ec2dbe21af7 \
--hash=sha256:b76ea9d55cd08fcdbda25d28e0f76679536710acb7fbd5b1f70cb4ac49317265 \
--hash=sha256:b8b025b6af43ee0ad4a70307025d77bcab5adde7c4597786010d802c203e9fc5 \
--hash=sha256:b93cee313cae4e113fbb3a0ce1ea5633db6f63cfde2b2dc1d817429026b2a50b \
--hash=sha256:c197e2ef75a442528072b29e9755da299110e8610e8bcbb59a6b4cf55384f005 \
--hash=sha256:c36f5d5e97944cbda2d4096b4ae262e6e68506246b61582acf1b8591607f3ccc \
--hash=sha256:c4fe218c5a35e1d87a5a26544237f1fa41dfd9cbd3c856b0810a30061f8b0aaf \
--hash=sha256:c6ff087cb1f563f47b504b4e29e684129fc5ae4863faf3ebca08a327764ee6cb \
--hash=sha256:cd78145b7f7784661c524624f3526c9c6f891b30a4b54cb93a40806d0d0d61e9 \
--hash=sha256:db217c2e52931719f9937bd12082cd4d7b495b35803d5760686975c285924bf8 \
--hash=sha256:dbdb99986548a7e87f8343805ef315fd4eb50ffaabf4fb1206e42f2542bb805d \
--hash=sha256:e4d053900a0d24b75d7521139a3872150301b3d6bde3bed5e12318fb25791e4d \
--hash=sha256:e7746ba3e6efc9e2b748eff59470a2b8684d5a9ec607c6580bcaa5be175820bc \
--hash=sha256:f345de40ef2e65f63645d53d251824e6070e07804827c5b00ec2e44555f9f901 \
--hash=sha256:f750a091fff3a3991731abc1f818bdc64874bb3528162732cb4d45f2e07821a6 \
--hash=sha256:f85570a016d794c29b1e76cf22f67af4486ddbe779e0f30674f138fa4e1769ec \
--hash=sha256:fbbe81314a9d92156abce8b62c09364eb8bafc0ca2a19919a45ec64b5c6cb664 \
--hash=sha256:ff83d889e3ebf6341c8c7864ad8031591ad5ca61599072fc511644d1eb962d2b
# via
# -r src/backend/requirements.in
# opentelemetry-exporter-otlp-proto-grpc
@ -868,9 +858,9 @@ icalendar==7.1.2 \
--hash=sha256:01c76243c76c549f58bb51510a8f0a4edb7c539726adda1356dfd0dc04fb7a53 \
--hash=sha256:ebc43ebeb357be98984b573d975118008dee3410d8df28b054ef2943cf3e367e
# via django-ical
idna==3.17 \
--hash=sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c \
--hash=sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# django-anymail
# requests
@ -1523,9 +1513,9 @@ pynacl==1.6.2 \
--hash=sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2 \
--hash=sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9
# via paramiko
pypdf==6.12.2 \
--hash=sha256:111669eb6680c04495ae0c113a1476e3bf93a95761d23c7406b591c80a6490b1 \
--hash=sha256:67b2699357a1f3f4c945940ea80826349ee507c9e2577724a14b4941982c104d
pypdf==6.13.0 \
--hash=sha256:558683ec9daf6b91c280c322c84c32f5cc216afd3eaa3a37de5ae88ae0c3b787 \
--hash=sha256:de1294ae49d6956edb4e5c41527fb9e8716ddd2b120f2185c68aab784d4ffe60
# via -r src/backend/requirements.in
pyphen==0.17.2 \
--hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \
@ -1888,9 +1878,9 @@ s3transfer==0.18.0 \
--hash=sha256:239c13b09e65ad0346e1be7348b8a202dcad44ac7ea7c6eb858fc881dce739b6 \
--hash=sha256:3760b8b7ec1315da54048b2d626276732bee4300d054d492d4e1d43e20d4ecbd
# via boto3
sentry-sdk==2.61.0 \
--hash=sha256:1ca9b4bb777eb5be67004edab7eb894f21c6301f1d05ed64966719ad5d1764ce \
--hash=sha256:ec4d30273909cb1d198e03208b16ee70e2bc5d90a16fd9f1fb2fc6a72e1f03dc
sentry-sdk==2.61.1 \
--hash=sha256:9c6adccb3feefa9ba032c8d295ca477575c2f11896046a2b0ad686c47c4af555 \
--hash=sha256:fa36eaf4b8ad708f718500d4bdcc1532637526a22beb874d88cbc0a46458b5ae
# via
# -r src/backend/requirements.in
# django-q-sentry
@ -1930,14 +1920,15 @@ tinyhtml5==2.1.0 \
--hash=sha256:60a50ec3d938a37e491efa01af895853060943dcebb5627de5b10d188b338a67 \
--hash=sha256:6e11cfff38515834268daf89d5f85bbde0b6dd02e8d9e212d1385c2289b89f0a
# via weasyprint
tqdm==4.67.3 \
--hash=sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb \
--hash=sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf
tqdm==4.68.1 \
--hash=sha256:fc163d96b287bd031e1aa24421ce4411b25559bd0a1be4fe649bdaa4d2c02bf5 \
--hash=sha256:fea4a90e4023f764914569f7802a297277c5ab1a66be5144143e142e1a4031d8
# via -r src/backend/requirements.in
typing-extensions==4.15.0 \
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
--hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
# via
# django-redis
# dulwich
# flexcache
# flexparser
@ -1975,9 +1966,9 @@ wcwidth==0.7.0 \
# via
# blessed
# prettytable
weasyprint==68.1 \
--hash=sha256:4dc3ba63c68bbbce3e9617cb2226251c372f5ee90a8a484503b1c099da9cf5be \
--hash=sha256:d3b752049b453a5c95edb27ce78d69e9319af5a34f257fa0f4c738c701b4184e
weasyprint==69.0 \
--hash=sha256:475951cfd917014de6d4d005caff48c6aa867e7e42b80cd5b16a0484a1609ee6 \
--hash=sha256:a7a32f39ca16bd82ef11de99c92ea4b5f14951c9033af035e451ce4f4ee0a88c
# via -r src/backend/requirements.in
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \

View File

@ -17,18 +17,22 @@ export type InvenTreeHotkeyItem = [
HotkeyItemOptions?
];
export function useInvenTreeHotkeys(hotkeys: InvenTreeHotkeyItem[]) {
// Register the hotkeys using the Mantine hook
useHotkeys(
hotkeys.map(([key, _, handler, options]) => [key, handler, options])
);
// register to helper state to store hotkeys
// This allows us to display the hotkeys in the UI
const keyelems: [string, string][] = hotkeys.map(([key, description]) => [
export function useInvenTreeHotkeys(_keys: InvenTreeHotkeyItem[]) {
const keyelems: [string, string][] = _keys.map(([key, description]) => [
key,
description
]);
const mappedHotkeys: [
string,
(event: KeyboardEvent) => void,
HotkeyItemOptions?
][] = _keys.map(([key, _, handler, options]) => [key, handler, options]);
// Register the hotkeys using the Mantine hook
useHotkeys(mappedHotkeys);
// register to helper state to store hotkeys
// This allows us to display the hotkeys in the UI
useEffect(() => {
useLocalLibState.getState().addHotkeys(keyelems);
return () =>

View File

@ -17,6 +17,7 @@ export type PanelType = {
disabled?: boolean;
showHeadline?: boolean;
supportsDirty?: boolean;
hotkey?: string;
};
/**

View File

@ -70,6 +70,11 @@ export type TableState = {
idAccessor?: string;
};
export type TableColumnFilterType =
| string
| string[]
| (({ close }: { close: () => void }) => ReactNode);
/**
* Table column properties
*
@ -109,10 +114,7 @@ export type TableColumnProps<T = any> = {
editable?: boolean;
definition?: ApiFormFieldType;
render?: (record: T, index?: number) => any;
filter?:
| string
| string[]
| (({ close }: { close: () => void }) => ReactNode);
filter?: TableColumnFilterType;
filtering?: boolean;
width?: number;
minWidth?: string | number;

View File

@ -113,6 +113,7 @@
"@babel/preset-typescript": "^7.28.5",
"@babel/runtime": "^7.28.6",
"@codecov/vite-plugin": "^1.9.1",
"@flakiness/playwright": "^1.13.0",
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
"@lingui/cli": "^5.9.2",
"@lingui/macro": "^5.9.2",

View File

@ -43,7 +43,12 @@ export default defineConfig({
retries: MAX_RETRIES,
workers: MAX_WORKERS,
reporter: IS_CI
? [['html', { open: 'never' }], ['blob'], ['github']]
? [
['html', { open: 'never' }],
['blob'],
['github'],
['@flakiness/playwright', { flakinessProject: 'InvenTree/InvenTree' }]
]
: 'list',
/* Configure projects for major browsers */

View File

@ -11,6 +11,7 @@ import { api } from '../../App';
import { extractAvailableFields } from '../../functions/forms';
import useDataOutput from '../../hooks/UseDataOutput';
import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useLocalState } from '../../states/LocalState';
import {
useGlobalSettingsState,
useUserSettingsState
@ -32,6 +33,11 @@ export function PrintingActions({
}) {
const userSettings = useUserSettingsState();
const globalSettings = useGlobalSettingsState();
const localState = useLocalState();
const lastUsedPrinting = useMemo(() => {
return modelType ? localState.lastUsedPrinting[modelType] : undefined;
}, [localState.lastUsedPrinting, modelType]);
const enabled = useMemo(() => items.length > 0, [items]);
@ -118,6 +124,7 @@ export function PrintingActions({
fields.template = {
...fields.template,
autoFill: true,
value: lastUsedPrinting?.template,
filters: {
enabled: true,
model_type: modelType,
@ -147,7 +154,14 @@ export function PrintingActions({
};
return fields;
}, [defaultLabelPlugin, pluginKey, printingFields.data, itemIdList]);
}, [
defaultLabelPlugin,
pluginKey,
printingFields.data,
itemIdList,
lastUsedPrinting,
modelType
]);
const labelModal = useCreateApiFormModal({
url: apiUrl(ApiEndpoints.label_print),
@ -158,15 +172,21 @@ export function PrintingActions({
onOpen: () => {
setLabelDialogOpen(true);
setItemIdList(items);
setPluginKey(lastUsedPrinting?.plugin ?? null);
},
onClose: () => {
setLabelDialogOpen(false);
setPluginKey('');
},
submitText: t`Print`,
successMessage: null,
onFormSuccess: (response: any) => {
setPluginKey('');
onFormSuccess: (response: any, form: any) => {
if (modelType) {
const values = form?.getValues?.();
localState.setLastUsedPrinting(modelType, {
plugin: pluginKey || undefined,
template: values?.template ? Number(values.template) : undefined
});
}
setLabelId(response.pk);
}
});

View File

@ -28,7 +28,7 @@ export function ScanButton({
if (hotkey) {
useInvenTreeHotkeys([
[
'mod+b',
'mod+Shift+B',
t`Open barcode scanner`,
() => {
open();

View File

@ -1,6 +1,7 @@
import type {
CalendarOptions,
DatesSetArg,
DayCellContentArg,
EventContentArg
} from '@fullcalendar/core';
import allLocales from '@fullcalendar/core/locales-all';
@ -182,6 +183,25 @@ export default function Calendar({
[calendarProps.eventContent, eventTooltipContent]
);
const monthDayCellClassNames = useCallback(
(arg: DayCellContentArg): string[] => {
const monthClass =
arg.date.getMonth() % 2 === 0
? 'fc-day-month-even'
: 'fc-day-month-odd';
const existing = calendarProps.dayCellClassNames;
if (!existing) return [monthClass];
if (typeof existing === 'function') {
const result = existing(arg);
const arr = Array.isArray(result) ? result : result ? [result] : [];
return [monthClass, ...arr];
}
if (Array.isArray(existing)) return [monthClass, ...existing];
return [monthClass, existing as string];
},
[calendarProps.dayCellClassNames]
);
return (
<>
{state.exportModal.modal}
@ -309,6 +329,11 @@ export default function Calendar({
{...calendarProps}
datesSet={datesSet}
eventContent={wrappedEventContent}
dayCellClassNames={
isScrollView
? monthDayCellClassNames
: calendarProps.dayCellClassNames
}
/>
</Box>
</Stack>

View File

@ -34,6 +34,7 @@ export type ActionDropdownItem = {
hidden?: boolean;
onClick: (event?: any) => void;
indicator?: Omit<IndicatorProps, 'children'>;
hotkey?: string;
};
/**
@ -184,7 +185,8 @@ export function BarcodeActionDropdown({
title: t`Link Barcode`,
icon: <IconLink />,
tooltip: t`Link a custom barcode to this item`,
ChildItem: QRCodeLink
ChildItem: QRCodeLink,
hotkey: 'mod+L'
}),
GeneralBarcodeAction({
hidden: hidden || !hash || !permission,
@ -220,6 +222,7 @@ function GeneralBarcodeAction({
icon: ReactNode;
tooltip: string;
ChildItem: any;
hotkey?: string;
}): ActionDropdownItem {
const onClick = () => {
modals.open({
@ -255,7 +258,8 @@ export function DeleteItemAction(
...props,
icon: <IconTrash color='red' />,
name: t`Delete`,
tooltip: props.tooltip ?? t`Delete item`
tooltip: props.tooltip ?? t`Delete item`,
hotkey: 'mod+X'
};
}
@ -275,7 +279,8 @@ export function CancelItemAction(
...props,
icon: <InvenTreeIcon icon='cancel' iconProps={{ color: 'red' }} />,
name: t`Cancel`,
tooltip: props.tooltip ?? t`Cancel`
tooltip: props.tooltip ?? t`Cancel`,
hotkey: 'mod+X'
};
}
@ -287,6 +292,7 @@ export function DuplicateItemAction(
...props,
icon: <IconCopy color='green' />,
name: t`Duplicate`,
tooltip: props.tooltip ?? t`Duplicate item`
tooltip: props.tooltip ?? t`Duplicate item`,
hotkey: 'mod+D'
};
}

View File

@ -45,7 +45,8 @@ export function HotkeyModal({
);
keys.sort((a, b) => a.key.localeCompare(b.key));
return keys;
}, []);
}, [context, id]);
const data = useMemo(() => {
return {
head: ['Hotkey', 'Action'],

View File

@ -57,7 +57,7 @@ export function PageDetail({
useInvenTreeHotkeys([
[
'mod+E',
title ? t`Edit ${title}` : t`Edit`,
t`Edit`,
(event) => {
if (event.repeat) {
return;
@ -68,6 +68,7 @@ export function PageDetail({
}
]
]);
useActionHotkeys(actions);
const pageTitleString = useMemo(
() =>
@ -196,3 +197,74 @@ export function PageDetail({
</>
);
}
function useActionHotkeys(actions: ReactNode[] = []) {
const hotkeys = useMemo(() => extractHotkeys(actions), [actions]);
useInvenTreeHotkeys(
hotkeys.map(({ hotkey, onClick, name }) => [
hotkey,
name,
(event) => {
if (event.repeat) {
return;
}
onClick();
}
])
);
}
function extractHotkeys(actions: ReactNode[]) {
const calcActions = actions
.filter(
(action) =>
action &&
typeof action === 'object' &&
'hotkey' in action &&
action.hotkey
)
.map((action: any) => {
return {
hotkey: action?.hotkey,
name: action?.name,
onClick: action?.onClick
};
})
.filter((action) => action !== null);
let primaryActionHotkeyAdded = false;
// now iterate over the actions to extract more possible hotkeys
actions.forEach((action: any) => {
const typeName = action?.type?.name;
// dropdowns - nested actions
if (typeName === 'ActionDropdown' || typeName === 'OptionsActionDropdown') {
const dropdownActions = action?.props?.actions as any[];
dropdownActions.forEach((dropdownAction: any) => {
if (dropdownAction.hotkey) {
calcActions.push({
hotkey: dropdownAction.hotkey,
name: dropdownAction.name,
onClick: dropdownAction.onClick
});
}
});
}
// PrimaryActionButton - use the 'mod+A' hotkey if it is enabled
if (typeName === 'PrimaryActionButton' && action?.props?.hidden !== true) {
if (primaryActionHotkeyAdded) return;
const hotkey = action?.props?.hotkey ?? 'mod+A';
calcActions.push({
hotkey,
name:
action?.props?.tooltip ?? action?.props?.title ?? t`Primary Action`,
onClick: action?.props?.onClick
});
primaryActionHotkeyAdded = true;
}
});
return calcActions;
}

View File

@ -19,6 +19,7 @@ export default function AttachmentPanel({
name: 'attachments',
label: t`Attachments`,
icon: <IconPaperclip />,
hotkey: 'mod+Shift+A',
notification_dot: async () => {
if (!model_type || !model_id) {
return null;

View File

@ -26,6 +26,7 @@ export default function NotesPanel({
name: 'notes',
label: t`Notes`,
icon: <IconNotes />,
hotkey: 'mod+Shift+N',
notification_dot: has_note ? 'info' : null,
content:
model_type && model_id ? (

View File

@ -37,7 +37,11 @@ import { Boundary } from '@lib/components/Boundary';
import { StylishText } from '@lib/components/StylishText';
import type { ModelType, PluginPanelKey } from '@lib/enums/ModelType';
import { identifierString } from '@lib/functions/Conversion';
import { cancelEvent } from '@lib/functions/Events';
import {
type InvenTreeHotkeyItem,
cancelEvent,
useInvenTreeHotkeys
} from '@lib/functions/Events';
import { eventModified, getBaseUrl } from '@lib/functions/Navigation';
import { navigateToLink } from '@lib/functions/Navigation';
import type {
@ -335,6 +339,22 @@ function BasePanelGroup({
}
}, [activePanels, panel]);
// hotkeys
const hotkeys = useMemo(() => {
const keys: InvenTreeHotkeyItem[] = [];
activePanels.forEach((panel) => {
if (panel.hotkey) {
keys.push([
panel.hotkey,
t`Navigate to panel ${panel.name}`,
() => handlePanelChange(panel.name)
]);
}
});
return keys;
}, [activePanels]);
useInvenTreeHotkeys(hotkeys);
const [isDirty, setIsDirty] = useState(false);
useWindowEvent('beforeunload', (event) => {
if (isDirty) {

View File

@ -23,6 +23,7 @@ export default function ParametersPanel({
name: 'parameters',
label: t`Parameters`,
icon: <IconListDetails />,
hotkey: 'mod+Shift+P',
hidden: hidden ?? false,
notification_dot: async () => {
if (!model_type || !model_id) {

View File

@ -2,6 +2,7 @@ import { t } from '@lingui/core/macro';
import type { SpotlightActionData } from '@mantine/spotlight';
import {
IconBarcode,
IconDevicesPc,
IconLink,
IconPlug,
IconPointer,
@ -9,7 +10,8 @@ import {
IconSettings,
IconTags,
IconUserBolt,
IconUserCog
IconUserCog,
IconUsers
} from '@tabler/icons-react';
import type { NavigateFunction } from 'react-router-dom';
@ -213,6 +215,16 @@ export function getActions(navigate: NavigateFunction) {
leftSection: <IconReport size='1.2rem' />
});
staff &&
user?.hasViewPermission(ModelType.user) &&
_actions.push({
id: 'users',
label: t`Users`,
description: t`Manage user accounts`,
onClick: () => navigate('/settings/admin/user'),
leftSection: <IconUsers size='1.2rem' />
});
staff &&
user?.hasViewPermission(ModelType.pluginconfig) &&
_actions.push({
@ -223,6 +235,16 @@ export function getActions(navigate: NavigateFunction) {
leftSection: <IconPlug size='1.2rem' />
});
staff &&
user?.hasViewPermission(ModelType.pluginconfig) &&
_actions.push({
id: 'machine-management',
label: t`Machines`,
description: t`Manage machines and machine types`,
onClick: () => navigate('/settings/admin/machine'),
leftSection: <IconDevicesPc size='1.2rem' />
});
staff &&
user?.hasViewPermission(ModelType.reporttemplate) &&
_actions.push({

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More