Merge commit '4895fbc9fed2c7df28729e3b38929fc26f767ae9' into block-notes
This commit is contained in:
commit
1c4f865b9f
|
|
@ -39,14 +39,14 @@ runs:
|
||||||
using: 'composite'
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
# Python installs
|
# Python installs
|
||||||
- name: Set up Python ${{ env.python_version }}
|
- name: Set up Python ${{ env.python_version }}
|
||||||
if: ${{ inputs.python == 'true' && env.python_version != '3.14' }}
|
if: ${{ inputs.python == 'true' && env.python_version != '3.14' }}
|
||||||
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # pin@v5.0.0
|
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.python_version }}
|
python-version: ${{ env.python_version }}
|
||||||
cache: pip
|
cache: pip
|
||||||
|
|
@ -57,7 +57,7 @@ runs:
|
||||||
contrib/dev_reqs/requirements.txt
|
contrib/dev_reqs/requirements.txt
|
||||||
- name: Setup Python 3.14
|
- name: Setup Python 3.14
|
||||||
if: ${{ inputs.python == 'true' && env.python_version == '3.14' }}
|
if: ${{ inputs.python == 'true' && env.python_version == '3.14' }}
|
||||||
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # pin@v5.0.0
|
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.python_version }}
|
python-version: ${{ env.python_version }}
|
||||||
- name: Install Base Python Dependencies
|
- name: Install Base Python Dependencies
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
)
|
)
|
||||||
steps:
|
steps:
|
||||||
- name: Backport Action
|
- name: Backport Action
|
||||||
uses: sqren/backport-github-action@ad888e978060bc1b2798690dd9d03c4036560947 # pin@v9.2.2
|
uses: sorenlouv/backport-github-action@8a6c0381851f43f9f1fddc7303f0e9015eb57b62 # v12.0.4
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
auto_backport_label_prefix: backport-to-
|
auto_backport_label_prefix: backport-to-
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
|
|
@ -167,7 +167,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set Up Python ${{ env.python_version }}
|
- name: Set Up Python ${{ env.python_version }}
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.python_version }}
|
python-version: ${{ env.python_version }}
|
||||||
- name: Version Check
|
- name: Version Check
|
||||||
|
|
@ -178,13 +178,13 @@ jobs:
|
||||||
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
echo "git_commit_date=$(git show -s --format=%ci)" >> $GITHUB_ENV
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # pin@v4.1.0
|
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # pin@v4.1.0
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||||
- name: Set up cosign
|
- name: Set up cosign
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # pin@v4.1.2
|
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
||||||
- name: Check if Dockerhub login is required
|
- name: Check if Dockerhub login is required
|
||||||
id: docker_login
|
id: docker_login
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -195,14 +195,14 @@ jobs:
|
||||||
fi
|
fi
|
||||||
- name: Login to Dockerhub
|
- name: Login to Dockerhub
|
||||||
if: github.event_name != 'pull_request' && steps.docker_login.outputs.skip_dockerhub_login != 'true'
|
if: github.event_name != 'pull_request' && steps.docker_login.outputs.skip_dockerhub_login != 'true'
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # pin@v4.2.0
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_USERNAME }}
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Log into registry ghcr.io
|
- name: Log into registry ghcr.io
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # pin@v4.2.0
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
|
|
@ -211,16 +211,16 @@ jobs:
|
||||||
- name: Extract Docker metadata
|
- name: Extract Docker metadata
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # pin@v6.1.0
|
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
inventree/inventree
|
inventree/inventree
|
||||||
ghcr.io/${{ github.repository }}
|
ghcr.io/${{ github.repository }}
|
||||||
- uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # pin@v1
|
- uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1
|
||||||
- name: Push Docker Images
|
- name: Push Docker Images
|
||||||
id: push-docker
|
id: push-docker
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: depot/build-push-action@98e78adca7817480b8185f474a400b451d74e287 # pin@v1
|
uses: depot/build-push-action@98e78adca7817480b8185f474a400b451d74e287 # v1
|
||||||
with:
|
with:
|
||||||
project: jczzbjkk68
|
project: jczzbjkk68
|
||||||
context: .
|
context: .
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ name: Frontend
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore: ["l10*"]
|
branches-ignore: ["l10*"]
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ jobs:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
|
|
@ -86,7 +86,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cd src/backend/InvenTree/web/static
|
cd src/backend/InvenTree/web/static
|
||||||
zip -r frontend-build.zip web/ web/.vite
|
zip -r frontend-build.zip web/ web/.vite
|
||||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: frontend-build
|
name: frontend-build
|
||||||
path: src/backend/InvenTree/web/static/web
|
path: src/backend/InvenTree/web/static/web
|
||||||
|
|
@ -141,7 +141,7 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: invoke int.frontend-compile --extract
|
run: invoke int.frontend-compile --extract
|
||||||
- name: Cache Playwright browsers
|
- name: Cache Playwright browsers
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # pin@v5.0.5
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||||
id: playwright-cache
|
id: playwright-cache
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/ms-playwright
|
path: ~/.cache/ms-playwright
|
||||||
|
|
@ -165,7 +165,7 @@ jobs:
|
||||||
cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png
|
cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png
|
||||||
invoke static
|
invoke static
|
||||||
env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox --shard=${{ matrix.shard }}/2
|
env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox --shard=${{ matrix.shard }}/2
|
||||||
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||||
with:
|
with:
|
||||||
name: playwright-report-firefox-${{ matrix.shard }}
|
name: playwright-report-firefox-${{ matrix.shard }}
|
||||||
|
|
@ -223,7 +223,7 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: invoke int.frontend-compile --extract
|
run: invoke int.frontend-compile --extract
|
||||||
- name: Cache Playwright browsers
|
- name: Cache Playwright browsers
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # pin@v5.0.5
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||||
id: playwright-cache
|
id: playwright-cache
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/ms-playwright
|
path: ~/.cache/ms-playwright
|
||||||
|
|
@ -245,7 +245,7 @@ jobs:
|
||||||
cd src/frontend
|
cd src/frontend
|
||||||
npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4
|
npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4
|
||||||
- name: Playwright Report [${{ matrix.shard }} / 4]
|
- name: Playwright Report [${{ matrix.shard }} / 4]
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||||
with:
|
with:
|
||||||
name: playwright-report-chromium-${{ matrix.shard }}
|
name: playwright-report-chromium-${{ matrix.shard }}
|
||||||
|
|
@ -253,7 +253,7 @@ jobs:
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
- name: Upload Coverage Artifact [${{ matrix.shard }} / 4]
|
- name: Upload Coverage Artifact [${{ matrix.shard }} / 4]
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
id: coverage-upload
|
id: coverage-upload
|
||||||
if: ${{ !cancelled() && steps.tests.outcome != 'failure' }}
|
if: ${{ !cancelled() && steps.tests.outcome != 'failure' }}
|
||||||
with:
|
with:
|
||||||
|
|
@ -285,7 +285,7 @@ jobs:
|
||||||
update: false
|
update: false
|
||||||
|
|
||||||
- name: Download Coverage Artifacts
|
- name: Download Coverage Artifacts
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
with:
|
with:
|
||||||
pattern: coverage-*
|
pattern: coverage-*
|
||||||
path: all-coverage/
|
path: all-coverage/
|
||||||
|
|
@ -304,7 +304,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
if: ${{ !cancelled() && github.ref == 'refs/heads/master' }}
|
if: ${{ !cancelled() && github.ref == 'refs/heads/master' }}
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # pin@v7.0.0
|
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
slug: inventree/InvenTree
|
slug: inventree/InvenTree
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ name: Import / Export
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore: ["l10*"]
|
branches-ignore: ["l10*"]
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ jobs:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: QC
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches-ignore: ["l10*"]
|
branches-ignore: ["l10*"]
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ jobs:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1
|
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
|
|
@ -112,12 +112,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Python ${{ env.python_version }}
|
- name: Set up Python ${{ env.python_version }}
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.python_version }}
|
python-version: ${{ env.python_version }}
|
||||||
cache: "pip"
|
cache: "pip"
|
||||||
- name: Run pre commit hook Checks
|
- name: Run pre commit hook Checks
|
||||||
uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # pin@v2
|
uses: j178/prek-action@e98a699c41eb69ab013a45817a0406469a748f8d # v2.0.5
|
||||||
- name: Check Version
|
- name: Check Version
|
||||||
run: |
|
run: |
|
||||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||||
|
|
@ -156,7 +156,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Python ${{ env.python_version }}
|
- name: Set up Python ${{ env.python_version }}
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.python_version }}
|
python-version: ${{ env.python_version }}
|
||||||
- name: Check Config
|
- name: Check Config
|
||||||
|
|
@ -165,7 +165,7 @@ jobs:
|
||||||
pip install --require-hashes -r docs/requirements.txt
|
pip install --require-hashes -r docs/requirements.txt
|
||||||
python docs/ci/check_mkdocs_config.py
|
python docs/ci/check_mkdocs_config.py
|
||||||
- name: Check Links
|
- name: Check Links
|
||||||
uses: tcort/github-action-markdown-link-check@e7c7a18363c842693fadde5d41a3bd3573a7a225 # pin@v1
|
uses: tcort/github-action-markdown-link-check@e7c7a18363c842693fadde5d41a3bd3573a7a225 # v1
|
||||||
with:
|
with:
|
||||||
folder-path: docs
|
folder-path: docs
|
||||||
config-file: docs/mlc_config.json
|
config-file: docs/mlc_config.json
|
||||||
|
|
@ -202,7 +202,7 @@ jobs:
|
||||||
- name: Export API Documentation
|
- name: Export API Documentation
|
||||||
run: invoke dev.schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
run: invoke dev.schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
||||||
- name: Upload schema
|
- name: Upload schema
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: schema.yml
|
name: schema.yml
|
||||||
path: src/backend/InvenTree/schema.yml
|
path: src/backend/InvenTree/schema.yml
|
||||||
|
|
@ -251,17 +251,17 @@ jobs:
|
||||||
- name: Extract settings / tags
|
- name: Extract settings / tags
|
||||||
run: invoke int.export-definitions --basedir docs
|
run: invoke int.export-definitions --basedir docs
|
||||||
- name: Upload settings
|
- name: Upload settings
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: inventree_settings.json
|
name: inventree_settings.json
|
||||||
path: docs/generated/inventree_settings.json
|
path: docs/generated/inventree_settings.json
|
||||||
- name: Upload tags
|
- name: Upload tags
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: inventree_tags.yml
|
name: inventree_tags.yml
|
||||||
path: docs/generated/inventree_tags.yml
|
path: docs/generated/inventree_tags.yml
|
||||||
- name: Upload filters
|
- name: Upload filters
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: inventree_filters.yml
|
name: inventree_filters.yml
|
||||||
path: docs/generated/inventree_filters.yml
|
path: docs/generated/inventree_filters.yml
|
||||||
|
|
@ -284,7 +284,7 @@ jobs:
|
||||||
- name: Create artifact directory
|
- name: Create artifact directory
|
||||||
run: mkdir -p artifact
|
run: mkdir -p artifact
|
||||||
- name: Download schema artifact
|
- name: Download schema artifact
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
with:
|
with:
|
||||||
path: artifact
|
path: artifact
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
@ -301,7 +301,7 @@ jobs:
|
||||||
echo "after move"
|
echo "after move"
|
||||||
ls -la artifact
|
ls -la artifact
|
||||||
rm -rf artifact
|
rm -rf artifact
|
||||||
- uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # pin@v7.1.0
|
- uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
|
||||||
name: Commit schema changes
|
name: Commit schema changes
|
||||||
with:
|
with:
|
||||||
commit_message: "Update API schema for ${{ env.version }} / ${{ github.sha }}"
|
commit_message: "Update API schema for ${{ env.version }} / ${{ github.sha }}"
|
||||||
|
|
@ -409,13 +409,13 @@ jobs:
|
||||||
- name: Coverage Tests
|
- name: Coverage Tests
|
||||||
run: invoke dev.test --check --coverage --translations
|
run: invoke dev.test --check --coverage --translations
|
||||||
- name: Upload raw coverage to artifacts
|
- name: Upload raw coverage to artifacts
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: coverage
|
name: coverage
|
||||||
path: .coverage
|
path: .coverage
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # pin@v7.0.0
|
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
@ -597,7 +597,7 @@ jobs:
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: invoke dev.test --check --migrations --report --coverage --translations
|
run: invoke dev.test --check --migrations --report --coverage --translations
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # pin@v7.0.0
|
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
pip install --require-hashes -r contrib/dev_reqs/requirements.txt
|
||||||
python3 .github/scripts/version_check.py
|
python3 .github/scripts/version_check.py
|
||||||
- name: Push to Stable Branch
|
- name: Push to Stable Branch
|
||||||
uses: ad-m/github-push-action@881a6320fdb16eb5318c5054f31c218aec2b324c # pin@v1.3.0
|
uses: ad-m/github-push-action@881a6320fdb16eb5318c5054f31c218aec2b324c # v1.3.0
|
||||||
if: env.stable_release == 'true'
|
if: env.stable_release == 'true'
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
- name: Build frontend
|
- name: Build frontend
|
||||||
run: cd src/frontend && npm run compile && npm run build
|
run: cd src/frontend && npm run compile && npm run build
|
||||||
- name: Create SBOM for frontend
|
- name: Create SBOM for frontend
|
||||||
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # pin@v0
|
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0
|
||||||
with:
|
with:
|
||||||
artifact-name: frontend-build.spdx
|
artifact-name: frontend-build.spdx
|
||||||
path: src/frontend
|
path: src/frontend
|
||||||
|
|
@ -75,7 +75,7 @@ jobs:
|
||||||
zip -r ../frontend-build.zip * .vite
|
zip -r ../frontend-build.zip * .vite
|
||||||
- name: Attest Build Provenance
|
- name: Attest Build Provenance
|
||||||
id: attest
|
id: attest
|
||||||
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # pin@v4
|
uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1
|
||||||
with:
|
with:
|
||||||
subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip"
|
subject-path: "${{ github.workspace }}/src/backend/InvenTree/web/static/frontend-build.zip"
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ jobs:
|
||||||
REF: ${{ github.ref_name }}
|
REF: ${{ github.ref_name }}
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Upload frontend to artifacts
|
- name: Upload frontend to artifacts
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
with:
|
with:
|
||||||
name: frontend-build
|
name: frontend-build
|
||||||
path: src/backend/InvenTree/web/static/frontend-build.zip
|
path: src/backend/InvenTree/web/static/frontend-build.zip
|
||||||
|
|
@ -161,7 +161,7 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Get frontend artifact
|
- name: Get frontend artifact
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
with:
|
with:
|
||||||
name: frontend-build
|
name: frontend-build
|
||||||
- name: Setup
|
- name: Setup
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ jobs:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # pin@v10.3.0
|
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10.3.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
stale-issue-message: "This issue seems stale. Please react to show this is still important."
|
stale-issue-message: "This issue seems stale. Please react to show this is still important."
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ jobs:
|
||||||
echo "Resetting to HEAD~"
|
echo "Resetting to HEAD~"
|
||||||
git reset HEAD~ || true
|
git reset HEAD~ || true
|
||||||
- name: crowdin action
|
- name: crowdin action
|
||||||
uses: crowdin/github-action@52aa776766211d83d975df51f3b9c53c2f8ba35f # pin@v2
|
uses: crowdin/github-action@52aa776766211d83d975df51f3b9c53c2f8ba35f # v2
|
||||||
with:
|
with:
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # pin@v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Setup
|
- name: Setup
|
||||||
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
run: pip-compile --output-file=requirements.txt requirements.in -U
|
run: pip-compile --output-file=requirements.txt requirements.in -U
|
||||||
- name: Update requirements-dev.txt
|
- name: Update requirements-dev.txt
|
||||||
run: pip-compile --generate-hashes --output-file=requirements-dev.txt requirements-dev.in -U
|
run: pip-compile --generate-hashes --output-file=requirements-dev.txt requirements-dev.in -U
|
||||||
- uses: stefanzweifel/git-auto-commit-action@fd157da78fa13d9383e5580d1fd1184d89554b51 # pin@v4.15.1
|
- uses: stefanzweifel/git-auto-commit-action@fd157da78fa13d9383e5580d1fd1184d89554b51 # v4.15.1
|
||||||
with:
|
with:
|
||||||
commit_message: "[Bot] Updated dependency"
|
commit_message: "[Bot] Updated dependency"
|
||||||
branch: dep-update
|
branch: dep-update
|
||||||
|
|
|
||||||
|
|
@ -53,20 +53,20 @@ To read more about the capabilities of the report templating engine, and how to
|
||||||
|
|
||||||
## Creating Templates
|
## Creating Templates
|
||||||
|
|
||||||
Report and label templates can be created (and edited) via the [admin interface](../settings/admin.md), under the *Report* section.
|
Report and label templates are managed from the [Admin Center](../settings/admin.md#admin-center), which provides dedicated panels (under the *Reporting* group) for each template type:
|
||||||
|
|
||||||
Select the type of template you are wanting to create (a *Report Template* or *Label Template*) and press the *Add* button in the top right corner:
|
- **Label Templates** - Create and edit [label templates](./labels.md)
|
||||||
|
- **Report Templates** - Create and edit [report templates](./report.md)
|
||||||
|
- **Report Snippets** - Manage reusable [snippet](#report-snippets) files
|
||||||
|
- **Report Assets** - Manage uploaded [asset](#report-assets) files
|
||||||
|
|
||||||
{{ image("report/report_template_admin.png", "Report template admin") }}
|
Label and report templates are created and edited using the built-in [template editor](./template_editor.md), which allows templates to be written directly within the browser, with a live preview of the rendered output.
|
||||||
|
|
||||||
!!! tip "Staff Access Only"
|
!!! tip "Staff Access Only"
|
||||||
Only users with staff access can upload or edit report template files.
|
Only users with staff access can create, upload or edit templates, snippets and assets.
|
||||||
|
|
||||||
!!! info "Editing Reports"
|
!!! info "Backend Admin Interface"
|
||||||
Existing reports can be edited from the admin interface, in the same location as described above. To change the contents of the template, re-upload a template file, to override the existing template data.
|
Templates can also be managed at a lower level via the [backend admin interface](../settings/admin.md#backend-admin-interface), under the *Report* section. This is recommended for advanced users only.
|
||||||
|
|
||||||
!!! tip "Template Editor"
|
|
||||||
InvenTree also provides a powerful [template editor](./template_editor.md) which allows for the creation and editing of report templates directly within the browser.
|
|
||||||
|
|
||||||
### Name and Description
|
### Name and Description
|
||||||
|
|
||||||
|
|
@ -147,7 +147,9 @@ Setting the *Debug Mode* option renders the template as raw HTML instead of PDF,
|
||||||
|
|
||||||
## Report Assets
|
## Report Assets
|
||||||
|
|
||||||
User can upload asset files (e.g. images) which can be used when generating reports. For example, you may wish to generate a report with your company logo in the header. Asset files are uploaded via the admin interface.
|
Users can upload asset files (e.g. images) which can be used when generating reports. For example, you may wish to generate a report with your company logo in the header.
|
||||||
|
|
||||||
|
Asset files are managed from the [Admin Center](../settings/admin.md#admin-center), via the *Report Assets* panel. Staff users can upload new asset files, and remove assets which are no longer required.
|
||||||
|
|
||||||
Asset files can be rendered directly into the template as follows
|
Asset files can be rendered directly into the template as follows
|
||||||
|
|
||||||
|
|
@ -181,7 +183,7 @@ Asset files can be rendered directly into the template as follows
|
||||||
If the requested asset name does not match the name of an uploaded asset, the template will continue without loading the image.
|
If the requested asset name does not match the name of an uploaded asset, the template will continue without loading the image.
|
||||||
|
|
||||||
!!! info "Assets location"
|
!!! info "Assets location"
|
||||||
Upload new assets via the [admin interface](../settings/admin.md) to ensure they are uploaded to the correct location on the server.
|
Upload new assets via the *Report Assets* panel in the [Admin Center](../settings/admin.md#admin-center) to ensure they are uploaded to the correct location on the server.
|
||||||
|
|
||||||
|
|
||||||
## Report Snippets
|
## Report Snippets
|
||||||
|
|
@ -190,7 +192,9 @@ A powerful feature provided by the django / WeasyPrint templating framework is t
|
||||||
|
|
||||||
To support this, InvenTree provides report "snippets" - short (or not so short) template files which cannot be rendered by themselves, but can be called from other templates.
|
To support this, InvenTree provides report "snippets" - short (or not so short) template files which cannot be rendered by themselves, but can be called from other templates.
|
||||||
|
|
||||||
Similar to assets files, snippet template files are uploaded via the admin interface.
|
Snippet files are managed from the [Admin Center](../settings/admin.md#admin-center), via the *Report Snippets* panel. Staff users can upload new snippet files, and edit or remove existing snippets.
|
||||||
|
|
||||||
|
Additionally, the content of an existing snippet can be modified directly within the browser - simply select a snippet from the table to open it in the built-in code editor.
|
||||||
|
|
||||||
Snippets are included in a template as follows:
|
Snippets are included in a template as follows:
|
||||||
|
|
||||||
|
|
@ -243,7 +247,7 @@ When WeasyPrint renders a template to PDF it can make outbound requests to load
|
||||||
|---|---|
|
|---|---|
|
||||||
| `data:` URIs | Always permitted — self-contained, no network access |
|
| `data:` URIs | Always permitted — self-contained, no network access |
|
||||||
| `file://` | Always blocked — assets and images must be inlined as `data:` URIs before reaching WeasyPrint |
|
| `file://` | Always blocked — assets and images must be inlined as `data:` URIs before reaching WeasyPrint |
|
||||||
| `http` / `https` | Disabled by default, but can be blocked - see *Remote URL Fetching* below |
|
| `http` / `https` | Disabled by default, but can be enabled - see *Remote URL Fetching* below |
|
||||||
| Any other scheme | Always blocked |
|
| Any other scheme | Always blocked |
|
||||||
|
|
||||||
HTTP redirects are also disabled: a URL that passes validation cannot redirect to an internal address.
|
HTTP redirects are also disabled: a URL that passes validation cannot redirect to an internal address.
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ For example, rendering the name of a part (which is available in the particular
|
||||||
|
|
||||||
## Merging Reports
|
## Merging Reports
|
||||||
|
|
||||||
When rendering reports for multiple items, the default behaviour is that each item is rendered as a separate report. The chosen templeate is rendered multiple times, once for each item selected, and expects a single item in the context variable.
|
When rendering reports for multiple items, the default behaviour is that each item is rendered as a separate report. The chosen template is rendered multiple times, once for each item selected, and expects a single item in the context variable.
|
||||||
|
|
||||||
However, it is possible to merge multiple items into a single report document. This is achieved by enabling the `merge` attribute of the report template:
|
However, it is possible to merge multiple items into a single report document. This is achieved by enabling the `merge` attribute of the report template:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ title: Template editor
|
||||||
|
|
||||||
## Template editor
|
## Template editor
|
||||||
|
|
||||||
The Template Editor is integrated into the [Admin Center](../settings//admin.md#admin-center) of the Web UI. It allows users to create and edit label and report templates directly with a side by side preview for a more productive workflow.
|
The Template Editor is integrated into the [Admin Center](../settings/admin.md#admin-center) of the Web UI. It allows users to create and edit label and report templates directly with a side by side preview for a more productive workflow.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
On the left side (1) are all possible possible template types for labels and reports listed. With the "+" button (2), above the template table (3), new templates for the selected type can be created. To switch to the template editor click on a template.
|
On the left side (1) are all possible template types for labels and reports listed. With the "+" button (2), above the template table (3), new templates for the selected type can be created. To switch to the template editor click on a template.
|
||||||
|
|
||||||
### Editing Templates
|
### Editing Templates
|
||||||
|
|
||||||
|
|
@ -31,3 +31,10 @@ If you don't want to override the template, but just render a preview for a temp
|
||||||
#### Edit template metadata
|
#### Edit template metadata
|
||||||
|
|
||||||
Editing metadata such as name, description, filters and even width/height for labels and orientation/page size for reports can be done from the edit modal accessible when clicking on the three dots (4) and select "Edit" in the dropdown menu.
|
Editing metadata such as name, description, filters and even width/height for labels and orientation/page size for reports can be done from the edit modal accessible when clicking on the three dots (4) and select "Edit" in the dropdown menu.
|
||||||
|
|
||||||
|
### Editing Snippets
|
||||||
|
|
||||||
|
[Report snippets](./index.md#report-snippets) can also be edited directly within the browser, from the *Report Snippets* panel in the Admin Center. Selecting a snippet from the table opens it in the same code editor as used for report and label templates.
|
||||||
|
|
||||||
|
!!! info "No Preview"
|
||||||
|
As snippets cannot be rendered by themselves (they must be included in a report or label template), no preview area is available when editing a snippet.
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 514
|
INVENTREE_API_VERSION = 515
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
|
||||||
v514 -> 2026-06-25 : https://github.com/inventree/InvenTree/pull/11971
|
v516 -> 2026-07-03 : https://github.com/inventree/InvenTree/pull/11971
|
||||||
- Removes direct "notes" field from any models which previously supported markdown notes
|
- Removes direct "notes" field from any models which previously supported markdown notes
|
||||||
- Adds a generic "Note" model which can be attached to any model type via a generic foreign key relationship
|
- Adds a generic "Note" model which can be attached to any model type via a generic foreign key relationship
|
||||||
- Allow multiple notes to be attached to a single object, and for notes to be created / edited / deleted via the API
|
- Allow multiple notes to be attached to a single object, and for notes to be created / edited / deleted via the API
|
||||||
|
|
||||||
|
v514 -> 2026-07-02 : https://github.com/inventree/InvenTree/pull/12294
|
||||||
|
- Adds "duplicate" field to the BuildOrder, Company, ManufacturerPart, SupplierPart and SalesOrderShipment API endpoints
|
||||||
|
- Order duplication options: renames "order_id" field to "original", which now performs primary-key validation
|
||||||
|
- Part duplication options: renames "part" field to "original"
|
||||||
|
|
||||||
v513 -> 2026-06-25 : https://github.com/inventree/InvenTree/pull/12250
|
v513 -> 2026-06-25 : https://github.com/inventree/InvenTree/pull/12250
|
||||||
- Adds "active" field to the ProjectCode model and API endpoints
|
- Adds "active" field to the ProjectCode model and API endpoints
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -599,7 +599,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
Default implementation returns an empty list
|
Default implementation returns an empty list
|
||||||
"""
|
"""
|
||||||
return []
|
return getattr(self, 'SKIP_CREATE_FIELDS', [])
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
"""Catch any django ValidationError thrown at the moment `save` is called, and re-throw as a DRF ValidationError."""
|
"""Catch any django ValidationError thrown at the moment `save` is called, and re-throw as a DRF ValidationError."""
|
||||||
|
|
@ -900,3 +900,104 @@ class ContentTypeField(serializers.ChoiceField):
|
||||||
)
|
)
|
||||||
|
|
||||||
return content_type
|
return content_type
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateOptionsSerializer(serializers.Serializer):
|
||||||
|
"""Generic serializer for specifying copy options when duplicating a model instance.
|
||||||
|
|
||||||
|
Builds its fields dynamically at instantiation time so the same class can be
|
||||||
|
reused for any model without subclassing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Special 'shortcut' fields which are used for multiple models
|
||||||
|
DEFAULT_FIELDS = [
|
||||||
|
(
|
||||||
|
'copy_parameters',
|
||||||
|
_('Copy Parameters'),
|
||||||
|
_('Copy parameters from the original item'),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'copy_lines',
|
||||||
|
_('Copy Lines'),
|
||||||
|
_('Copy line items from the original order'),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'copy_extra_lines',
|
||||||
|
_('Copy Extra Lines'),
|
||||||
|
_('Copy extra line items from the original order'),
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
queryset: QuerySet,
|
||||||
|
*args,
|
||||||
|
copy_fields: Optional[list[dict]] = None,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
"""Initialise the serializer and dynamically attach fields.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
queryset: Queryset used for the `original` PrimaryKeyRelatedField.
|
||||||
|
copy_fields: Optional list of dicts, each describing one boolean copy toggle.
|
||||||
|
Keys:
|
||||||
|
name: (str, required)
|
||||||
|
label: (str, optional)
|
||||||
|
help_text: (str, optional)
|
||||||
|
default: (bool, optional, default True)
|
||||||
|
"""
|
||||||
|
# Enforce certain properties onto this serializer
|
||||||
|
kwargs['label'] = kwargs.get('label', _('Duplication Options'))
|
||||||
|
kwargs['help_text'] = kwargs.get(
|
||||||
|
'help_text', _('Specify options for duplicating this item')
|
||||||
|
)
|
||||||
|
kwargs['required'] = False
|
||||||
|
kwargs['write_only'] = True
|
||||||
|
|
||||||
|
copy_fields = copy_fields or []
|
||||||
|
copy_field_names = [spec['name'] for spec in copy_fields]
|
||||||
|
|
||||||
|
# Apply "default" fields
|
||||||
|
for name, label, help_text, default_value in self.DEFAULT_FIELDS:
|
||||||
|
popped_value = kwargs.pop(name, default_value)
|
||||||
|
|
||||||
|
if name in copy_field_names:
|
||||||
|
# Manually supplied field, continue
|
||||||
|
continue
|
||||||
|
|
||||||
|
if popped_value:
|
||||||
|
copy_fields.append({
|
||||||
|
'name': name,
|
||||||
|
'label': label,
|
||||||
|
'help_text': help_text,
|
||||||
|
'default': True,
|
||||||
|
})
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Re-class the instance with a model-specific subclass,
|
||||||
|
# so that each model generates a unique schema component name
|
||||||
|
if self.__class__ is DuplicateOptionsSerializer:
|
||||||
|
self.__class__ = type(
|
||||||
|
f'{queryset.model.__name__}DuplicateOptionsSerializer',
|
||||||
|
(DuplicateOptionsSerializer,),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.fields['original'] = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=queryset,
|
||||||
|
required=True,
|
||||||
|
label=_('Original'),
|
||||||
|
help_text=_('Select instance to duplicate'),
|
||||||
|
)
|
||||||
|
|
||||||
|
for spec in copy_fields or []:
|
||||||
|
self.fields[spec['name']] = serializers.BooleanField(
|
||||||
|
required=False,
|
||||||
|
default=spec.get('default', True),
|
||||||
|
label=spec.get('label', spec['name']),
|
||||||
|
help_text=spec.get('help_text', ''),
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
CustomStatusSerializerMixin,
|
CustomStatusSerializerMixin,
|
||||||
|
DuplicateOptionsSerializer,
|
||||||
FilterableSerializerMixin,
|
FilterableSerializerMixin,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
|
|
@ -65,6 +66,8 @@ class BuildSerializer(
|
||||||
):
|
):
|
||||||
"""Serializes a Build object."""
|
"""Serializes a Build object."""
|
||||||
|
|
||||||
|
SKIP_CREATE_FIELDS = ['duplicate']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Serializer metaclass."""
|
"""Serializer metaclass."""
|
||||||
|
|
||||||
|
|
@ -78,6 +81,7 @@ class BuildSerializer(
|
||||||
'completed',
|
'completed',
|
||||||
'completion_date',
|
'completion_date',
|
||||||
'destination',
|
'destination',
|
||||||
|
'duplicate',
|
||||||
'external',
|
'external',
|
||||||
'parent',
|
'parent',
|
||||||
'part',
|
'part',
|
||||||
|
|
@ -187,12 +191,29 @@ class BuildSerializer(
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(Build.objects.all(), copy_parameters=True)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Determine if extra serializer fields are required."""
|
"""Determine if extra serializer fields are required."""
|
||||||
kwargs.pop('create', False)
|
kwargs.pop('create', False)
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, validated_data):
|
||||||
|
"""Create a new Build instance, optionally copying data from an existing build."""
|
||||||
|
duplicate = validated_data.pop('duplicate', None)
|
||||||
|
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
|
if duplicate:
|
||||||
|
original = duplicate['original']
|
||||||
|
|
||||||
|
if duplicate.get('copy_parameters', True):
|
||||||
|
instance.copy_parameters_from(original)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
def validate_reference(self, reference):
|
def validate_reference(self, reference):
|
||||||
"""Custom validation for the Build reference field."""
|
"""Custom validation for the Build reference field."""
|
||||||
# Ensure the reference matches the required pattern
|
# Ensure the reference matches the required pattern
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""JSON serializers for Company app."""
|
"""JSON serializers for Company app."""
|
||||||
|
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import Prefetch
|
from django.db.models import Prefetch
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
@ -14,6 +15,7 @@ from importer.registry import register_importer
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.ready import isGeneratingSchema
|
from InvenTree.ready import isGeneratingSchema
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
|
DuplicateOptionsSerializer,
|
||||||
FilterableSerializerMixin,
|
FilterableSerializerMixin,
|
||||||
InvenTreeCurrencySerializer,
|
InvenTreeCurrencySerializer,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
|
|
@ -116,6 +118,8 @@ class CompanySerializer(
|
||||||
|
|
||||||
import_exclude_fields = ['image']
|
import_exclude_fields = ['image']
|
||||||
|
|
||||||
|
SKIP_CREATE_FIELDS = ['duplicate']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
|
|
||||||
|
|
@ -130,6 +134,7 @@ class CompanySerializer(
|
||||||
'email',
|
'email',
|
||||||
'currency',
|
'currency',
|
||||||
'contact',
|
'contact',
|
||||||
|
'duplicate',
|
||||||
'link',
|
'link',
|
||||||
'image',
|
'image',
|
||||||
'active',
|
'active',
|
||||||
|
|
@ -188,6 +193,23 @@ class CompanySerializer(
|
||||||
|
|
||||||
parameters = common.filters.enable_parameters_filter()
|
parameters = common.filters.enable_parameters_filter()
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(Company.objects.all(), copy_parameters=True)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, validated_data):
|
||||||
|
"""Create a new Company instance, optionally copying data from an existing company."""
|
||||||
|
duplicate = validated_data.pop('duplicate', None)
|
||||||
|
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
|
if duplicate:
|
||||||
|
original = duplicate['original']
|
||||||
|
|
||||||
|
if duplicate.get('copy_parameters', True):
|
||||||
|
instance.copy_parameters_from(original)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
@register_importer()
|
@register_importer()
|
||||||
class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerializer):
|
class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerializer):
|
||||||
|
|
@ -213,6 +235,8 @@ class ManufacturerPartSerializer(
|
||||||
):
|
):
|
||||||
"""Serializer for ManufacturerPart object."""
|
"""Serializer for ManufacturerPart object."""
|
||||||
|
|
||||||
|
SKIP_CREATE_FIELDS = ['duplicate']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
|
|
||||||
|
|
@ -225,6 +249,7 @@ class ManufacturerPartSerializer(
|
||||||
'manufacturer',
|
'manufacturer',
|
||||||
'manufacturer_detail',
|
'manufacturer_detail',
|
||||||
'description',
|
'description',
|
||||||
|
'duplicate',
|
||||||
'MPN',
|
'MPN',
|
||||||
'link',
|
'link',
|
||||||
'barcode_hash',
|
'barcode_hash',
|
||||||
|
|
@ -236,6 +261,25 @@ class ManufacturerPartSerializer(
|
||||||
|
|
||||||
parameters = common.filters.enable_parameters_filter()
|
parameters = common.filters.enable_parameters_filter()
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
ManufacturerPart.objects.all(), copy_parameters=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, validated_data):
|
||||||
|
"""Create a new ManufacturerPart instance, optionally copying data from an existing instance."""
|
||||||
|
duplicate = validated_data.pop('duplicate', None)
|
||||||
|
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
|
if duplicate:
|
||||||
|
original = duplicate['original']
|
||||||
|
|
||||||
|
if duplicate.get('copy_parameters', True):
|
||||||
|
instance.copy_parameters_from(original)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
part_detail = OptionalField(
|
part_detail = OptionalField(
|
||||||
serializer_class=part_serializers.PartBriefSerializer,
|
serializer_class=part_serializers.PartBriefSerializer,
|
||||||
serializer_kwargs={
|
serializer_kwargs={
|
||||||
|
|
@ -317,6 +361,8 @@ class SupplierPartSerializer(
|
||||||
|
|
||||||
export_exclude_fields = ['tags']
|
export_exclude_fields = ['tags']
|
||||||
|
|
||||||
|
SKIP_CREATE_FIELDS = ['duplicate']
|
||||||
|
|
||||||
export_child_fields = [
|
export_child_fields = [
|
||||||
'part_detail.name',
|
'part_detail.name',
|
||||||
'part_detail.description',
|
'part_detail.description',
|
||||||
|
|
@ -333,6 +379,7 @@ class SupplierPartSerializer(
|
||||||
'available',
|
'available',
|
||||||
'availability_updated',
|
'availability_updated',
|
||||||
'description',
|
'description',
|
||||||
|
'duplicate',
|
||||||
'in_stock',
|
'in_stock',
|
||||||
'on_order',
|
'on_order',
|
||||||
'link',
|
'link',
|
||||||
|
|
@ -487,6 +534,10 @@ class SupplierPartSerializer(
|
||||||
# Date fields
|
# Date fields
|
||||||
updated = serializers.DateTimeField(allow_null=True, read_only=True)
|
updated = serializers.DateTimeField(allow_null=True, read_only=True)
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
SupplierPart.objects.all(), copy_parameters=True
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Annotate the SupplierPart queryset with extra fields.
|
"""Annotate the SupplierPart queryset with extra fields.
|
||||||
|
|
@ -515,8 +566,11 @@ class SupplierPartSerializer(
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
"""Extract manufacturer data and process ManufacturerPart."""
|
"""Extract manufacturer data and process ManufacturerPart."""
|
||||||
|
duplicate = validated_data.pop('duplicate', None)
|
||||||
|
|
||||||
# Extract 'available' quantity from the serializer
|
# Extract 'available' quantity from the serializer
|
||||||
available = validated_data.pop('available', None)
|
available = validated_data.pop('available', None)
|
||||||
|
|
||||||
|
|
@ -534,6 +588,12 @@ class SupplierPartSerializer(
|
||||||
kwargs = {'manufacturer': manufacturer, 'MPN': MPN}
|
kwargs = {'manufacturer': manufacturer, 'MPN': MPN}
|
||||||
supplier_part.save(**kwargs)
|
supplier_part.save(**kwargs)
|
||||||
|
|
||||||
|
if duplicate:
|
||||||
|
original = duplicate['original']
|
||||||
|
|
||||||
|
if duplicate.get('copy_parameters', True):
|
||||||
|
supplier_part.copy_parameters_from(original)
|
||||||
|
|
||||||
return supplier_part
|
return supplier_part
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ from taggit.serializers import TagListSerializerField
|
||||||
import data_exporter.serializers
|
import data_exporter.serializers
|
||||||
import data_exporter.tasks
|
import data_exporter.tasks
|
||||||
import InvenTree.exceptions
|
import InvenTree.exceptions
|
||||||
|
import InvenTree.serializers
|
||||||
from common.models import DataOutput
|
from common.models import DataOutput
|
||||||
from InvenTree.helpers import str2bool
|
from InvenTree.helpers import str2bool
|
||||||
from InvenTree.tasks import offload_task
|
from InvenTree.tasks import offload_task
|
||||||
|
|
@ -64,6 +65,14 @@ class DataExportSerializerMixin:
|
||||||
# Exclude fields which are not required for data export
|
# Exclude fields which are not required for data export
|
||||||
for field in self.get_export_exclude_fields(**kwargs):
|
for field in self.get_export_exclude_fields(**kwargs):
|
||||||
self.fields.pop(field, None)
|
self.fields.pop(field, None)
|
||||||
|
|
||||||
|
# Duplication options are never used for data export
|
||||||
|
for field in [
|
||||||
|
name
|
||||||
|
for name, field in self.fields.items()
|
||||||
|
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||||
|
]:
|
||||||
|
self.fields.pop(field, None)
|
||||||
else:
|
else:
|
||||||
# Exclude fields which are only used for data export
|
# Exclude fields which are only used for data export
|
||||||
for field in self.get_export_only_fields(**kwargs):
|
for field in self.get_export_only_fields(**kwargs):
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
from rest_framework import fields, serializers
|
from rest_framework import fields, serializers
|
||||||
from taggit.serializers import TagListSerializerField
|
from taggit.serializers import TagListSerializerField
|
||||||
|
|
||||||
|
import InvenTree.serializers
|
||||||
|
|
||||||
|
|
||||||
class DataImportSerializerMixin:
|
class DataImportSerializerMixin:
|
||||||
"""Mixin class for adding data import functionality to a DRF serializer."""
|
"""Mixin class for adding data import functionality to a DRF serializer."""
|
||||||
|
|
@ -41,6 +43,14 @@ class DataImportSerializerMixin:
|
||||||
for field in self.get_import_exclude_fields(**kwargs):
|
for field in self.get_import_exclude_fields(**kwargs):
|
||||||
self.fields.pop(field, None)
|
self.fields.pop(field, None)
|
||||||
|
|
||||||
|
# Duplication options are never used for data import
|
||||||
|
for field in [
|
||||||
|
name
|
||||||
|
for name, field in self.fields.items()
|
||||||
|
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||||
|
]:
|
||||||
|
self.fields.pop(field, None)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Exclude fields which are only used for data import
|
# Exclude fields which are only used for data import
|
||||||
for field in self.get_import_only_fields(**kwargs):
|
for field in self.get_import_only_fields(**kwargs):
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ from InvenTree.helpers import extract_serial_numbers, hash_barcode, normalize, s
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
CustomStatusSerializerMixin,
|
CustomStatusSerializerMixin,
|
||||||
|
DuplicateOptionsSerializer,
|
||||||
FilterableSerializerMixin,
|
FilterableSerializerMixin,
|
||||||
InvenTreeCurrencySerializer,
|
InvenTreeCurrencySerializer,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
|
|
@ -66,40 +67,6 @@ class TotalPriceMixin(serializers.Serializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DuplicateOrderSerializer(serializers.Serializer):
|
|
||||||
"""Serializer for specifying options when duplicating an order."""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Metaclass options."""
|
|
||||||
|
|
||||||
fields = ['order_id', 'copy_lines', 'copy_extra_lines', 'copy_parameters']
|
|
||||||
|
|
||||||
order_id = serializers.IntegerField(
|
|
||||||
required=True, label=_('Order ID'), help_text=_('ID of the order to duplicate')
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_lines = serializers.BooleanField(
|
|
||||||
required=False,
|
|
||||||
default=True,
|
|
||||||
label=_('Copy Lines'),
|
|
||||||
help_text=_('Copy line items from the original order'),
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_extra_lines = serializers.BooleanField(
|
|
||||||
required=False,
|
|
||||||
default=True,
|
|
||||||
label=_('Copy Extra Lines'),
|
|
||||||
help_text=_('Copy extra line items from the original order'),
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_parameters = serializers.BooleanField(
|
|
||||||
required=False,
|
|
||||||
default=True,
|
|
||||||
label=_('Copy Parameters'),
|
|
||||||
help_text=_('Copy order parameters from the original order'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractOrderSerializer(
|
class AbstractOrderSerializer(
|
||||||
CustomStatusSerializerMixin,
|
CustomStatusSerializerMixin,
|
||||||
DataImportExportSerializerMixin,
|
DataImportExportSerializerMixin,
|
||||||
|
|
@ -109,9 +76,8 @@ class AbstractOrderSerializer(
|
||||||
):
|
):
|
||||||
"""Abstract serializer class which provides fields common to all order types."""
|
"""Abstract serializer class which provides fields common to all order types."""
|
||||||
|
|
||||||
export_exclude_fields = ['duplicate']
|
export_exclude_fields = ['notes']
|
||||||
|
import_exclude_fields = ['notes']
|
||||||
import_exclude_fields = ['duplicate']
|
|
||||||
|
|
||||||
# Number of line items in this order
|
# Number of line items in this order
|
||||||
line_items = serializers.IntegerField(
|
line_items = serializers.IntegerField(
|
||||||
|
|
@ -194,12 +160,8 @@ class AbstractOrderSerializer(
|
||||||
|
|
||||||
created_by = UserSerializer(read_only=True)
|
created_by = UserSerializer(read_only=True)
|
||||||
|
|
||||||
duplicate = DuplicateOrderSerializer(
|
# Note: The 'duplicate' field must be defined by each concrete serializer class,
|
||||||
label=_('Duplicate Order'),
|
# as it requires a queryset specific to the order model type
|
||||||
help_text=_('Specify options for duplicating this order'),
|
|
||||||
required=False,
|
|
||||||
write_only=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def validate_reference(self, reference):
|
def validate_reference(self, reference):
|
||||||
"""Custom validation for the reference field."""
|
"""Custom validation for the reference field."""
|
||||||
|
|
@ -291,30 +253,21 @@ class AbstractOrderSerializer(
|
||||||
instance = super().create(validated_data)
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
if duplicate:
|
if duplicate:
|
||||||
order_id = duplicate.get('order_id', None)
|
original = duplicate['original']
|
||||||
copy_lines = duplicate.get('copy_lines', True)
|
|
||||||
copy_extra_lines = duplicate.get('copy_extra_lines', True)
|
|
||||||
copy_parameters = duplicate.get('copy_parameters', True)
|
|
||||||
|
|
||||||
try:
|
if duplicate.get('copy_lines', False):
|
||||||
copy_from = instance.__class__.objects.get(pk=order_id)
|
for line in original.lines.all():
|
||||||
except Exception:
|
|
||||||
# If the order ID is invalid, raise a validation error
|
|
||||||
raise ValidationError(_('Invalid order ID'))
|
|
||||||
|
|
||||||
if copy_lines:
|
|
||||||
for line in copy_from.lines.all():
|
|
||||||
instance.clean_line_item(line)
|
instance.clean_line_item(line)
|
||||||
line.save()
|
line.save()
|
||||||
|
|
||||||
if copy_extra_lines:
|
if duplicate.get('copy_extra_lines', False):
|
||||||
for line in copy_from.extra_lines.all():
|
for line in original.extra_lines.all():
|
||||||
line.pk = None
|
line.pk = None
|
||||||
line.order = instance
|
line.order = instance
|
||||||
line.save()
|
line.save()
|
||||||
|
|
||||||
if copy_parameters:
|
if duplicate.get('copy_parameters', False):
|
||||||
instance.copy_parameters_from(copy_from)
|
instance.copy_parameters_from(original)
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
@ -449,6 +402,13 @@ class PurchaseOrderSerializer(
|
||||||
|
|
||||||
return [*fields, 'duplicate']
|
return [*fields, 'duplicate']
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
order.models.PurchaseOrder.objects.all(),
|
||||||
|
copy_lines=True,
|
||||||
|
copy_extra_lines=True,
|
||||||
|
copy_parameters=True,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add extra information to the queryset.
|
"""Add extra information to the queryset.
|
||||||
|
|
@ -1130,6 +1090,13 @@ class SalesOrderSerializer(
|
||||||
|
|
||||||
return [*fields, 'duplicate']
|
return [*fields, 'duplicate']
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
order.models.SalesOrder.objects.all(),
|
||||||
|
copy_lines=True,
|
||||||
|
copy_extra_lines=True,
|
||||||
|
copy_parameters=True,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add extra information to the queryset.
|
"""Add extra information to the queryset.
|
||||||
|
|
@ -1406,6 +1373,8 @@ class SalesOrderShipmentSerializer(
|
||||||
):
|
):
|
||||||
"""Serializer for the SalesOrderShipment class."""
|
"""Serializer for the SalesOrderShipment class."""
|
||||||
|
|
||||||
|
SKIP_CREATE_FIELDS = ['duplicate']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
|
|
||||||
|
|
@ -1418,6 +1387,7 @@ class SalesOrderShipmentSerializer(
|
||||||
'shipment_address',
|
'shipment_address',
|
||||||
'delivery_date',
|
'delivery_date',
|
||||||
'checked_by',
|
'checked_by',
|
||||||
|
'duplicate',
|
||||||
'reference',
|
'reference',
|
||||||
'tracking_number',
|
'tracking_number',
|
||||||
'invoice_number',
|
'invoice_number',
|
||||||
|
|
@ -1501,6 +1471,25 @@ class SalesOrderShipmentSerializer(
|
||||||
|
|
||||||
tags = common.filters.enable_tags_filter()
|
tags = common.filters.enable_tags_filter()
|
||||||
|
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
order.models.SalesOrderShipment.objects.all(), copy_parameters=True
|
||||||
|
)
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def create(self, validated_data):
|
||||||
|
"""Create a new SalesOrderShipment instance, optionally copying data from an existing shipment."""
|
||||||
|
duplicate = validated_data.pop('duplicate', None)
|
||||||
|
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
|
||||||
|
if duplicate:
|
||||||
|
original = duplicate['original']
|
||||||
|
|
||||||
|
if duplicate.get('copy_parameters', True):
|
||||||
|
instance.copy_parameters_from(original)
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class SalesOrderAllocationSerializer(
|
class SalesOrderAllocationSerializer(
|
||||||
FilterableSerializerMixin, InvenTreeModelSerializer
|
FilterableSerializerMixin, InvenTreeModelSerializer
|
||||||
|
|
@ -2191,6 +2180,14 @@ class ReturnOrderSerializer(
|
||||||
|
|
||||||
return [*fields, 'duplicate']
|
return [*fields, 'duplicate']
|
||||||
|
|
||||||
|
# Note: line items cannot be duplicated from a ReturnOrder,
|
||||||
|
# as they are linked to specific stock items
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
order.models.ReturnOrder.objects.all(),
|
||||||
|
copy_extra_lines=True,
|
||||||
|
copy_parameters=True,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Custom annotation for the serializer queryset."""
|
"""Custom annotation for the serializer queryset."""
|
||||||
|
|
@ -2477,6 +2474,11 @@ class TransferOrderSerializer(
|
||||||
|
|
||||||
return [*fields, 'duplicate']
|
return [*fields, 'duplicate']
|
||||||
|
|
||||||
|
# Note: TransferOrder does not have "extra" line items
|
||||||
|
duplicate = DuplicateOptionsSerializer(
|
||||||
|
order.models.TransferOrder.objects.all(), copy_lines=True, copy_parameters=True
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def annotate_queryset(queryset):
|
def annotate_queryset(queryset):
|
||||||
"""Add extra information to the queryset.
|
"""Add extra information to the queryset.
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,7 @@ class PurchaseOrderTest(OrderTest):
|
||||||
|
|
||||||
# Duplicate with non-existent PK to provoke error
|
# Duplicate with non-existent PK to provoke error
|
||||||
data['duplicate'] = {
|
data['duplicate'] = {
|
||||||
'order_id': 10000001,
|
'original': 10000001,
|
||||||
'copy_lines': True,
|
'copy_lines': True,
|
||||||
'copy_extra_lines': False,
|
'copy_extra_lines': False,
|
||||||
}
|
}
|
||||||
|
|
@ -584,7 +584,7 @@ class PurchaseOrderTest(OrderTest):
|
||||||
response = self.post(reverse('api-po-list'), data, expected_code=400)
|
response = self.post(reverse('api-po-list'), data, expected_code=400)
|
||||||
|
|
||||||
data['duplicate'] = {
|
data['duplicate'] = {
|
||||||
'order_id': 1,
|
'original': 1,
|
||||||
'copy_lines': True,
|
'copy_lines': True,
|
||||||
'copy_extra_lines': False,
|
'copy_extra_lines': False,
|
||||||
}
|
}
|
||||||
|
|
@ -605,7 +605,7 @@ class PurchaseOrderTest(OrderTest):
|
||||||
data['reference'] = 'PO-9998'
|
data['reference'] = 'PO-9998'
|
||||||
|
|
||||||
data['duplicate'] = {
|
data['duplicate'] = {
|
||||||
'order_id': 1,
|
'original': 1,
|
||||||
'copy_lines': False,
|
'copy_lines': False,
|
||||||
'copy_extra_lines': True,
|
'copy_extra_lines': True,
|
||||||
}
|
}
|
||||||
|
|
@ -1792,7 +1792,7 @@ class SalesOrderTest(OrderTest):
|
||||||
{
|
{
|
||||||
'reference': 'SO-12345',
|
'reference': 'SO-12345',
|
||||||
'customer': so.customer.pk,
|
'customer': so.customer.pk,
|
||||||
'duplicate': {'order_id': so.pk, 'copy_parameters': False},
|
'duplicate': {'original': so.pk, 'copy_parameters': False},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1809,7 +1809,7 @@ class SalesOrderTest(OrderTest):
|
||||||
{
|
{
|
||||||
'reference': 'SO-12346',
|
'reference': 'SO-12346',
|
||||||
'customer': so.customer.pk,
|
'customer': so.customer.pk,
|
||||||
'duplicate': {'order_id': so.pk},
|
'duplicate': {'original': so.pk},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -407,67 +407,6 @@ class PartBriefSerializer(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DuplicatePartSerializer(serializers.Serializer):
|
|
||||||
"""Serializer for specifying options when duplicating a Part.
|
|
||||||
|
|
||||||
The fields in this serializer control how the Part is duplicated.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Metaclass options."""
|
|
||||||
|
|
||||||
fields = [
|
|
||||||
'part',
|
|
||||||
'copy_image',
|
|
||||||
'copy_bom',
|
|
||||||
'copy_parameters',
|
|
||||||
'copy_notes',
|
|
||||||
'copy_tests',
|
|
||||||
]
|
|
||||||
|
|
||||||
part = serializers.PrimaryKeyRelatedField(
|
|
||||||
queryset=Part.objects.all(),
|
|
||||||
label=_('Original Part'),
|
|
||||||
help_text=_('Select original part to duplicate'),
|
|
||||||
required=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_image = serializers.BooleanField(
|
|
||||||
label=_('Copy Image'),
|
|
||||||
help_text=_('Copy image from original part'),
|
|
||||||
required=False,
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_bom = serializers.BooleanField(
|
|
||||||
label=_('Copy BOM'),
|
|
||||||
help_text=_('Copy bill of materials from original part'),
|
|
||||||
required=False,
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_parameters = serializers.BooleanField(
|
|
||||||
label=_('Copy Parameters'),
|
|
||||||
help_text=_('Copy parameter data from original part'),
|
|
||||||
required=False,
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_notes = serializers.BooleanField(
|
|
||||||
label=_('Copy Notes'),
|
|
||||||
help_text=_('Copy notes from original part'),
|
|
||||||
required=False,
|
|
||||||
default=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy_tests = serializers.BooleanField(
|
|
||||||
label=_('Copy Tests'),
|
|
||||||
help_text=_('Copy test templates from original part'),
|
|
||||||
required=False,
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class InitialStockSerializer(serializers.Serializer):
|
class InitialStockSerializer(serializers.Serializer):
|
||||||
"""Serializer for creating initial stock quantity."""
|
"""Serializer for creating initial stock quantity."""
|
||||||
|
|
||||||
|
|
@ -600,7 +539,7 @@ class PartSerializer(
|
||||||
Used when displaying all details of a single component.
|
Used when displaying all details of a single component.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import_exclude_fields = ['creation_date', 'creation_user', 'duplicate']
|
import_exclude_fields = ['creation_date', 'creation_user']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass defining serializer fields."""
|
"""Metaclass defining serializer fields."""
|
||||||
|
|
@ -1005,11 +944,37 @@ class PartSerializer(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extra fields used only for creation of a new Part instance
|
# Extra fields used only for creation of a new Part instance
|
||||||
duplicate = DuplicatePartSerializer(
|
duplicate = InvenTree.serializers.DuplicateOptionsSerializer(
|
||||||
|
Part.objects.all(),
|
||||||
label=_('Duplicate Part'),
|
label=_('Duplicate Part'),
|
||||||
help_text=_('Copy initial data from another Part'),
|
help_text=_('Copy initial data from another Part'),
|
||||||
write_only=True,
|
copy_parameters=True,
|
||||||
required=False,
|
copy_fields=[
|
||||||
|
{
|
||||||
|
'name': 'copy_image',
|
||||||
|
'label': _('Copy Image'),
|
||||||
|
'help_text': _('Copy image from original part'),
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'copy_bom',
|
||||||
|
'label': _('Copy BOM'),
|
||||||
|
'help_text': _('Copy bill of materials from original part'),
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'copy_notes',
|
||||||
|
'label': _('Copy Notes'),
|
||||||
|
'help_text': _('Copy notes from original part'),
|
||||||
|
'default': True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'copy_tests',
|
||||||
|
'label': _('Copy Tests'),
|
||||||
|
'help_text': _('Copy test templates from original part'),
|
||||||
|
'default': False,
|
||||||
|
},
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
initial_stock = InitialStockSerializer(
|
initial_stock = InitialStockSerializer(
|
||||||
|
|
@ -1075,7 +1040,7 @@ class PartSerializer(
|
||||||
|
|
||||||
# Copy data from original Part
|
# Copy data from original Part
|
||||||
if duplicate:
|
if duplicate:
|
||||||
original = duplicate['part']
|
original = duplicate['original']
|
||||||
|
|
||||||
if duplicate.get('copy_bom', False):
|
if duplicate.get('copy_bom', False):
|
||||||
instance.copy_bom_from(original)
|
instance.copy_bom_from(original)
|
||||||
|
|
|
||||||
|
|
@ -1649,7 +1649,7 @@ class PartCreationTests(PartAPITestBase):
|
||||||
'testable': do_copy,
|
'testable': do_copy,
|
||||||
'assembly': do_copy,
|
'assembly': do_copy,
|
||||||
'duplicate': {
|
'duplicate': {
|
||||||
'part': 100,
|
'original': 100,
|
||||||
'copy_bom': do_copy,
|
'copy_bom': do_copy,
|
||||||
'copy_notes': do_copy,
|
'copy_notes': do_copy,
|
||||||
'copy_image': do_copy,
|
'copy_image': do_copy,
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class TemplateTagTest(InvenTreeTestCase):
|
||||||
|
|
||||||
shipped_js = resp.split('<script type="module" src="')[1:]
|
shipped_js = resp.split('<script type="module" src="')[1:]
|
||||||
self.assertGreater(len(shipped_js), 0)
|
self.assertGreater(len(shipped_js), 0)
|
||||||
self.assertGreater(len(shipped_js), 3)
|
self.assertGreater(len(shipped_js), 2)
|
||||||
|
|
||||||
manifest_file = Path(__file__).parent.joinpath('static/web/.vite/manifest.json')
|
manifest_file = Path(__file__).parent.joinpath('static/web/.vite/manifest.json')
|
||||||
# Try with removed manifest file
|
# Try with removed manifest file
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,5 @@ export interface SettingsStateProps {
|
||||||
pathParams?: PathParams;
|
pathParams?: PathParams;
|
||||||
getSetting: (key: string, default_value?: string) => string; // Return a raw setting value
|
getSetting: (key: string, default_value?: string) => string; // Return a raw setting value
|
||||||
isSet: (key: string, default_value?: boolean) => boolean; // Check a "boolean" setting
|
isSet: (key: string, default_value?: boolean) => boolean; // Check a "boolean" setting
|
||||||
|
getSettingLength: () => number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,10 +117,10 @@
|
||||||
"zustand": "^5.0.14"
|
"zustand": "^5.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.29.7",
|
"@babel/core": "^8.0.1",
|
||||||
"@babel/preset-react": "^7.29.7",
|
"@babel/preset-react": "^8.0.1",
|
||||||
"@babel/preset-typescript": "^7.29.7",
|
"@babel/preset-typescript": "^8.0.1",
|
||||||
"@babel/runtime": "^7.29.7",
|
"@babel/runtime": "^8.0.0",
|
||||||
"@codecov/vite-plugin": "^2.0.1",
|
"@codecov/vite-plugin": "^2.0.1",
|
||||||
"@flakiness/playwright": "^1.13.0",
|
"@flakiness/playwright": "^1.13.0",
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.9.5",
|
"@lingui/babel-plugin-lingui-macro": "^5.9.5",
|
||||||
|
|
@ -135,7 +135,7 @@
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-window": "^1.8.8",
|
"@types/react-window": "^1.8.8",
|
||||||
"@vanilla-extract/vite-plugin": "^5.2.2",
|
"@vanilla-extract/vite-plugin": "^5.2.2",
|
||||||
"@vitejs/plugin-react": "^5.2.0",
|
"@vitejs/plugin-react": "^5",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"nyc": "^18.0.0",
|
"nyc": "^18.0.0",
|
||||||
"otpauth": "^9.5.1",
|
"otpauth": "^9.5.1",
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
||||||
}
|
}
|
||||||
|
|
||||||
let preview = await api.post(
|
let preview = await api.post(
|
||||||
printingUrl,
|
printingUrl!,
|
||||||
{
|
{
|
||||||
items: [previewItem],
|
items: [previewItem],
|
||||||
template: template.pk
|
template: template.pk
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
|
import { Boundary } from '@lib/components/Boundary';
|
||||||
|
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||||
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
|
Button,
|
||||||
CloseButton,
|
CloseButton,
|
||||||
Group,
|
Group,
|
||||||
List,
|
List,
|
||||||
|
|
@ -24,11 +29,6 @@ import {
|
||||||
import Split from '@uiw/react-split';
|
import Split from '@uiw/react-split';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { Boundary } from '@lib/components/Boundary';
|
|
||||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
|
||||||
import { ModelType } from '@lib/enums/ModelType';
|
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
|
||||||
import { api } from '../../../App';
|
import { api } from '../../../App';
|
||||||
import type { TemplateI } from '../../../tables/settings/TemplateTable';
|
import type { TemplateI } from '../../../tables/settings/TemplateTable';
|
||||||
import { SplitButton } from '../../buttons/SplitButton';
|
import { SplitButton } from '../../buttons/SplitButton';
|
||||||
|
|
@ -78,26 +78,38 @@ export type PreviewArea = {
|
||||||
|
|
||||||
export type TemplateEditorProps = {
|
export type TemplateEditorProps = {
|
||||||
templateUrl: string;
|
templateUrl: string;
|
||||||
printingUrl: string;
|
printingUrl?: string;
|
||||||
editors: Editor[];
|
editors: Editor[];
|
||||||
previewAreas: PreviewArea[];
|
previewAreas: PreviewArea[];
|
||||||
template: TemplateI;
|
template: TemplateI;
|
||||||
|
// Name of the file field on the template model (e.g. 'template' or 'snippet')
|
||||||
|
fileField?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
const { templateUrl, editors, previewAreas, template } = props;
|
const {
|
||||||
|
templateUrl,
|
||||||
|
editors,
|
||||||
|
previewAreas,
|
||||||
|
template,
|
||||||
|
fileField = 'template'
|
||||||
|
} = props;
|
||||||
const editorRef = useRef<EditorRef | null>(null);
|
const editorRef = useRef<EditorRef | null>(null);
|
||||||
const previewRef = useRef<PreviewAreaRef | null>(null);
|
const previewRef = useRef<PreviewAreaRef | null>(null);
|
||||||
|
|
||||||
|
// If no preview areas are provided, the template is saved directly
|
||||||
|
const hasPreview = previewAreas.length > 0;
|
||||||
|
|
||||||
const [hasSaveConfirmed, setHasSaveConfirmed] = useState(false);
|
const [hasSaveConfirmed, setHasSaveConfirmed] = useState(false);
|
||||||
|
|
||||||
const [previewItem, setPreviewItem] = useState<string>('');
|
const [previewItem, setPreviewItem] = useState<string>('');
|
||||||
const [renderingErrors, setRenderingErrors] = useState<string[] | null>(null);
|
const [renderingErrors, setRenderingErrors] = useState<string[] | null>(null);
|
||||||
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
|
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
const [editorValue, setEditorValue] = useState<null | string>(editors[0].key);
|
const [editorValue, setEditorValue] = useState<null | string>(editors[0].key);
|
||||||
const [previewValue, setPreviewValue] = useState<null | string>(
|
const [previewValue, setPreviewValue] = useState<null | string>(
|
||||||
previewAreas[0].key
|
previewAreas[0]?.key ?? null
|
||||||
);
|
);
|
||||||
|
|
||||||
const codeRef = useRef<string | undefined>(undefined);
|
const codeRef = useRef<string | undefined>(undefined);
|
||||||
|
|
@ -131,12 +143,12 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
if (!templateUrl) return;
|
if (!templateUrl) return;
|
||||||
|
|
||||||
api.get(templateUrl).then((response: any) => {
|
api.get(templateUrl).then((response: any) => {
|
||||||
if (response.data?.template) {
|
if (response.data?.[fileField]) {
|
||||||
// Fetch the raw template file from the server
|
// Fetch the raw template file from the server
|
||||||
// Request that it is provided without any caching,
|
// Request that it is provided without any caching,
|
||||||
// to ensure that we always get the latest version
|
// to ensure that we always get the latest version
|
||||||
api
|
api
|
||||||
.get(response.data.template, {
|
.get(response.data[fileField], {
|
||||||
headers: {
|
headers: {
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
Pragma: 'no-cache',
|
Pragma: 'no-cache',
|
||||||
|
|
@ -149,7 +161,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.error(
|
console.error(
|
||||||
`ERR: Could not load template from ${response.data.template}`
|
`ERR: Could not load template from ${response.data[fileField]}`
|
||||||
);
|
);
|
||||||
codeRef.current = undefined;
|
codeRef.current = undefined;
|
||||||
hideNotification('template-load-error');
|
hideNotification('template-load-error');
|
||||||
|
|
@ -244,6 +256,45 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
[previewItem]
|
[previewItem]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Save the template file directly to the server, without any preview
|
||||||
|
const saveTemplate = useCallback(async () => {
|
||||||
|
const code = await getCodeFromEditor();
|
||||||
|
|
||||||
|
if (code === undefined) return;
|
||||||
|
|
||||||
|
const filename =
|
||||||
|
(template as any)[fileField]?.split('/').pop() ?? 'template.html';
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append(fileField, new File([code], filename));
|
||||||
|
|
||||||
|
setIsSaving(true);
|
||||||
|
|
||||||
|
api
|
||||||
|
.patch(templateUrl, formData)
|
||||||
|
.then(() => {
|
||||||
|
hideNotification('template-save');
|
||||||
|
showNotification({
|
||||||
|
id: 'template-save',
|
||||||
|
title: t`Saved`,
|
||||||
|
message: t`Template file has been updated`,
|
||||||
|
color: 'green'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
hideNotification('template-save');
|
||||||
|
showNotification({
|
||||||
|
id: 'template-save',
|
||||||
|
title: t`Error`,
|
||||||
|
message: t`Could not save the template to the server.`,
|
||||||
|
color: 'red'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsSaving(false);
|
||||||
|
});
|
||||||
|
}, [getCodeFromEditor, template, templateUrl, fileField]);
|
||||||
|
|
||||||
const previewApiUrl = useMemo(
|
const previewApiUrl = useMemo(
|
||||||
() =>
|
() =>
|
||||||
ModelInformationDict[template.model_type ?? ModelType.stockitem]
|
ModelInformationDict[template.model_type ?? ModelType.stockitem]
|
||||||
|
|
@ -261,18 +312,20 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
}, [template]);
|
}, [template]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!hasPreview) return;
|
||||||
|
|
||||||
api
|
api
|
||||||
.get(apiUrl(previewApiUrl), { params: { limit: 1, ...templateFilters } })
|
.get(apiUrl(previewApiUrl), { params: { limit: 1, ...templateFilters } })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data.results.length === 0) return;
|
if (res.data.results.length === 0) return;
|
||||||
setPreviewItem(res.data.results[0].pk);
|
setPreviewItem(res.data.results[0].pk);
|
||||||
});
|
});
|
||||||
}, [previewApiUrl, templateFilters]);
|
}, [hasPreview, previewApiUrl, templateFilters]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Boundary label='TemplateEditor'>
|
<Boundary label='TemplateEditor'>
|
||||||
<Stack style={{ height: '100%', flex: '1' }}>
|
<Stack style={{ height: '100%', flex: '1' }}>
|
||||||
<Split visible style={{ flex: 1 }}>
|
<Split visible={hasPreview} style={{ flex: 1 }}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={editorValue}
|
value={editorValue}
|
||||||
onChange={async (v) => {
|
onChange={async (v) => {
|
||||||
|
|
@ -282,7 +335,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
keepMounted={false}
|
keepMounted={false}
|
||||||
style={{
|
style={{
|
||||||
minWidth: '300px',
|
minWidth: '300px',
|
||||||
width: '50%',
|
width: hasPreview ? '50%' : '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column'
|
flexDirection: 'column'
|
||||||
}}
|
}}
|
||||||
|
|
@ -301,29 +354,39 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<Group justify='right' style={{ flex: '1' }} wrap='nowrap'>
|
<Group justify='right' style={{ flex: '1' }} wrap='nowrap'>
|
||||||
<SplitButton
|
{hasPreview ? (
|
||||||
loading={isPreviewLoading}
|
<SplitButton
|
||||||
defaultSelected='preview_save'
|
loading={isPreviewLoading}
|
||||||
name='preview-options'
|
defaultSelected='preview_save'
|
||||||
options={[
|
name='preview-options'
|
||||||
{
|
options={[
|
||||||
key: 'preview',
|
{
|
||||||
name: t`Reload preview`,
|
key: 'preview',
|
||||||
tooltip: t`Use the currently stored template from the server`,
|
name: t`Reload preview`,
|
||||||
icon: IconRefresh,
|
tooltip: t`Use the currently stored template from the server`,
|
||||||
onClick: () => updatePreview(true, false),
|
icon: IconRefresh,
|
||||||
disabled: !previewItem || isPreviewLoading
|
onClick: () => updatePreview(true, false),
|
||||||
},
|
disabled: !previewItem || isPreviewLoading
|
||||||
{
|
},
|
||||||
key: 'preview_save',
|
{
|
||||||
name: t`Save & Reload Preview`,
|
key: 'preview_save',
|
||||||
tooltip: t`Save the current template and reload the preview`,
|
name: t`Save & Reload Preview`,
|
||||||
icon: IconDeviceFloppy,
|
tooltip: t`Save the current template and reload the preview`,
|
||||||
onClick: () => updatePreview(hasSaveConfirmed),
|
icon: IconDeviceFloppy,
|
||||||
disabled: !previewItem || isPreviewLoading
|
onClick: () => updatePreview(hasSaveConfirmed),
|
||||||
}
|
disabled: !previewItem || isPreviewLoading
|
||||||
]}
|
}
|
||||||
/>
|
]}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
leftSection={<IconDeviceFloppy size={18} />}
|
||||||
|
loading={isSaving}
|
||||||
|
onClick={() => saveTemplate()}
|
||||||
|
>
|
||||||
|
{t`Save`}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
|
|
||||||
|
|
@ -342,100 +405,102 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<Tabs
|
{hasPreview && (
|
||||||
value={previewValue}
|
<Tabs
|
||||||
onChange={setPreviewValue}
|
value={previewValue}
|
||||||
keepMounted={false}
|
onChange={setPreviewValue}
|
||||||
style={{
|
keepMounted={false}
|
||||||
minWidth: '200px',
|
|
||||||
width: '50%',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tabs.List>
|
|
||||||
{previewAreas.map((PreviewArea) => (
|
|
||||||
<Tabs.Tab
|
|
||||||
key={PreviewArea.key}
|
|
||||||
value={PreviewArea.key}
|
|
||||||
leftSection={PreviewArea.icon}
|
|
||||||
>
|
|
||||||
{PreviewArea.name}
|
|
||||||
</Tabs.Tab>
|
|
||||||
))}
|
|
||||||
</Tabs.List>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
style={{
|
||||||
minWidth: '100%',
|
minWidth: '200px',
|
||||||
paddingBottom: '10px',
|
width: '50%',
|
||||||
paddingTop: '10px'
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StandaloneField
|
<Tabs.List>
|
||||||
fieldDefinition={{
|
{previewAreas.map((PreviewArea) => (
|
||||||
field_type: 'related field',
|
<Tabs.Tab
|
||||||
api_url: apiUrl(previewApiUrl),
|
key={PreviewArea.key}
|
||||||
description: '',
|
value={PreviewArea.key}
|
||||||
label: t`Select instance to preview`,
|
leftSection={PreviewArea.icon}
|
||||||
model: template.model_type,
|
>
|
||||||
value: previewItem,
|
{PreviewArea.name}
|
||||||
filters: templateFilters,
|
</Tabs.Tab>
|
||||||
onValueChange: (value) => setPreviewItem(value)
|
))}
|
||||||
}}
|
</Tabs.List>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{previewAreas.map((PreviewArea) => (
|
<div
|
||||||
<Tabs.Panel
|
|
||||||
key={PreviewArea.key}
|
|
||||||
value={PreviewArea.key}
|
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
minWidth: '100%',
|
||||||
flex: previewValue === PreviewArea.key ? 1 : 0
|
paddingBottom: '10px',
|
||||||
|
paddingTop: '10px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<StandaloneField
|
||||||
|
fieldDefinition={{
|
||||||
|
field_type: 'related field',
|
||||||
|
api_url: apiUrl(previewApiUrl),
|
||||||
|
description: '',
|
||||||
|
label: t`Select instance to preview`,
|
||||||
|
model: template.model_type,
|
||||||
|
value: previewItem,
|
||||||
|
filters: templateFilters,
|
||||||
|
onValueChange: (value) => setPreviewItem(value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{previewAreas.map((PreviewArea) => (
|
||||||
|
<Tabs.Panel
|
||||||
|
key={PreviewArea.key}
|
||||||
|
value={PreviewArea.key}
|
||||||
style={{
|
style={{
|
||||||
height: '100%',
|
|
||||||
position: 'relative',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flex: '1'
|
flex: previewValue === PreviewArea.key ? 1 : 0
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* @ts-ignore-next-line */}
|
<div
|
||||||
<PreviewArea.component ref={previewRef} />
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
flex: '1'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* @ts-ignore-next-line */}
|
||||||
|
<PreviewArea.component ref={previewRef} />
|
||||||
|
|
||||||
{renderingErrors && (
|
{renderingErrors && (
|
||||||
<Overlay color='red' center blur={0.2}>
|
<Overlay color='red' center blur={0.2}>
|
||||||
<CloseButton
|
<CloseButton
|
||||||
onClick={() => setRenderingErrors(null)}
|
onClick={() => setRenderingErrors(null)}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '10px',
|
top: '10px',
|
||||||
right: '10px',
|
right: '10px',
|
||||||
color: '#fff'
|
color: '#fff'
|
||||||
}}
|
}}
|
||||||
variant='filled'
|
variant='filled'
|
||||||
/>
|
/>
|
||||||
<Alert
|
<Alert
|
||||||
color='red'
|
color='red'
|
||||||
icon={<IconExclamationCircle />}
|
icon={<IconExclamationCircle />}
|
||||||
title={t`Error rendering template`}
|
title={t`Error rendering template`}
|
||||||
mx='10px'
|
mx='10px'
|
||||||
>
|
>
|
||||||
<List>
|
<List>
|
||||||
{renderingErrors.map((error, index) => (
|
{renderingErrors.map((error, index) => (
|
||||||
<ListItem key={index}>{error}</ListItem>
|
<ListItem key={index}>{error}</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Alert>
|
</Alert>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
)}
|
||||||
</Split>
|
</Split>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Boundary>
|
</Boundary>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||||
import type { ModelType } from '@lib/enums/ModelType';
|
import type { ModelType } from '@lib/enums/ModelType';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import { cancelEvent } from '@lib/functions/Events';
|
import { cancelEvent } from '@lib/functions/Events';
|
||||||
import { getDetailUrl, navigateToLink } from '@lib/index';
|
import { getDetailUrl, navigateToLink } from '@lib/functions/Navigation';
|
||||||
import type { ApiFormFieldType } from '@lib/types/Forms';
|
import type { ApiFormFieldType } from '@lib/types/Forms';
|
||||||
import { useApi } from '../../../contexts/ApiContext';
|
import { useApi } from '../../../contexts/ApiContext';
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@ const AboutContent = ({
|
||||||
function fillTable(lookup: AboutLookupRef[], data: any, alwaysLink = false) {
|
function fillTable(lookup: AboutLookupRef[], data: any, alwaysLink = false) {
|
||||||
return lookup
|
return lookup
|
||||||
.filter((entry: AboutLookupRef) => !!data[entry.ref])
|
.filter((entry: AboutLookupRef) => !!data[entry.ref])
|
||||||
.map((entry: AboutLookupRef, idx) => (
|
.map((entry: AboutLookupRef) => (
|
||||||
<Table.Tr key={idx}>
|
<Table.Tr key={entry.ref}>
|
||||||
<Table.Td>{entry.title}</Table.Td>
|
<Table.Td>{entry.title}</Table.Td>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Group justify='space-between' gap='xs'>
|
<Group justify='space-between' gap='xs'>
|
||||||
|
|
|
||||||
|
|
@ -564,9 +564,9 @@ export function SearchDrawer({
|
||||||
multiple
|
multiple
|
||||||
defaultValue={searchQueries.map((q) => q.model)}
|
defaultValue={searchQueries.map((q) => q.model)}
|
||||||
>
|
>
|
||||||
{queryResults.map((query, idx) => (
|
{queryResults.map((query) => (
|
||||||
<QueryResultGroup
|
<QueryResultGroup
|
||||||
key={idx}
|
key={query.model}
|
||||||
searchText={searchText}
|
searchText={searchText}
|
||||||
query={query}
|
query={query}
|
||||||
navigate={navigate}
|
navigate={navigate}
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ export type { InstanceRenderInterface } from '@lib/types/Rendering';
|
||||||
import {
|
import {
|
||||||
getBaseUrl,
|
getBaseUrl,
|
||||||
getDetailUrl,
|
getDetailUrl,
|
||||||
navigateToLink,
|
navigateToLink
|
||||||
shortenString
|
} from '@lib/functions/Navigation';
|
||||||
} from '@lib/index';
|
import { shortenString } from '@lib/functions/String';
|
||||||
import { IconLink } from '@tabler/icons-react';
|
import { IconLink } from '@tabler/icons-react';
|
||||||
import { useApi } from '../../contexts/ApiContext';
|
import { useApi } from '../../contexts/ApiContext';
|
||||||
import { usePluginState } from '../../states/PluginState';
|
import { usePluginState } from '../../states/PluginState';
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import type { NavigateFunction } from 'react-router-dom';
|
||||||
|
|
||||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||||
import type { ModelType } from '@lib/enums/ModelType';
|
import type { ModelType } from '@lib/enums/ModelType';
|
||||||
import { getDetailUrl, navigateToLink } from '@lib/index';
|
import { getDetailUrl, navigateToLink } from '@lib/functions/Navigation';
|
||||||
import { IconLink } from '@tabler/icons-react';
|
import { IconLink } from '@tabler/icons-react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -28,21 +28,34 @@ export function SettingList({
|
||||||
settingsState,
|
settingsState,
|
||||||
keys,
|
keys,
|
||||||
onChange,
|
onChange,
|
||||||
onLoaded
|
onLoaded,
|
||||||
|
doGet
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
heading?: string;
|
heading?: string;
|
||||||
settingsState: SettingsStateProps;
|
settingsState: SettingsStateProps;
|
||||||
keys?: string[];
|
keys?: string[];
|
||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
onLoaded?: (settings: SettingsStateProps) => void;
|
onLoaded?: (settings: SettingsStateProps) => void;
|
||||||
|
doGet?: boolean;
|
||||||
}>) {
|
}>) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (settingsState.loaded) {
|
if (settingsState.loaded === true) {
|
||||||
// Call the onLoaded callback if provided
|
// Call the onLoaded callback if provided
|
||||||
onLoaded?.(settingsState);
|
onLoaded?.(settingsState);
|
||||||
}
|
}
|
||||||
}, [settingsState.loaded, settingsState.settings]);
|
}, [settingsState.loaded, settingsState.settings]);
|
||||||
|
|
||||||
|
// get data if doGet is true to break memos leading to hidden group panels
|
||||||
|
useMemo(() => {
|
||||||
|
if (doGet && !settingsState.loaded) {
|
||||||
|
settingsState.fetchSettings().then((success) => {
|
||||||
|
if (success) {
|
||||||
|
onLoaded?.(settingsState);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [doGet, settingsState]);
|
||||||
|
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
|
|
||||||
const allKeys = useMemo(
|
const allKeys = useMemo(
|
||||||
|
|
@ -226,9 +239,11 @@ export function GlobalSettingList({
|
||||||
|
|
||||||
export function PluginSettingList({
|
export function PluginSettingList({
|
||||||
pluginKey,
|
pluginKey,
|
||||||
|
doGet,
|
||||||
onLoaded
|
onLoaded
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
pluginKey: string;
|
pluginKey: string;
|
||||||
|
doGet?: boolean;
|
||||||
onLoaded?: (settings: SettingsStateProps) => void;
|
onLoaded?: (settings: SettingsStateProps) => void;
|
||||||
}>) {
|
}>) {
|
||||||
const store = useMemo(
|
const store = useMemo(
|
||||||
|
|
@ -246,14 +261,22 @@ export function PluginSettingList({
|
||||||
pluginSettings.fetchSettings();
|
pluginSettings.fetchSettings();
|
||||||
}, [pluginSettings.fetchSettings]);
|
}, [pluginSettings.fetchSettings]);
|
||||||
|
|
||||||
return <SettingList settingsState={pluginSettings} onLoaded={onLoaded} />;
|
return (
|
||||||
|
<SettingList
|
||||||
|
settingsState={pluginSettings}
|
||||||
|
onLoaded={onLoaded}
|
||||||
|
doGet={doGet}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PluginUserSettingList({
|
export function PluginUserSettingList({
|
||||||
pluginKey,
|
pluginKey,
|
||||||
|
doGet,
|
||||||
onLoaded
|
onLoaded
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
pluginKey: string;
|
pluginKey: string;
|
||||||
|
doGet?: boolean;
|
||||||
onLoaded?: (settings: SettingsStateProps) => void;
|
onLoaded?: (settings: SettingsStateProps) => void;
|
||||||
}>) {
|
}>) {
|
||||||
const store = useMemo(
|
const store = useMemo(
|
||||||
|
|
@ -271,7 +294,13 @@ export function PluginUserSettingList({
|
||||||
pluginUserSettings.fetchSettings();
|
pluginUserSettings.fetchSettings();
|
||||||
}, [pluginUserSettings.fetchSettings]);
|
}, [pluginUserSettings.fetchSettings]);
|
||||||
|
|
||||||
return <SettingList settingsState={pluginUserSettings} onLoaded={onLoaded} />;
|
return (
|
||||||
|
<SettingList
|
||||||
|
settingsState={pluginUserSettings}
|
||||||
|
onLoaded={onLoaded}
|
||||||
|
doGet={doGet}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MachineSettingList({
|
export function MachineSettingList({
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,18 @@ import {
|
||||||
} from '../hooks/UseGenerator';
|
} from '../hooks/UseGenerator';
|
||||||
import { useGlobalSettingsState } from '../states/SettingsStates';
|
import { useGlobalSettingsState } from '../states/SettingsStates';
|
||||||
import { RenderPartColumn } from '../tables/ColumnRenderers';
|
import { RenderPartColumn } from '../tables/ColumnRenderers';
|
||||||
import { ProjectCodeField, TagsField } from './CommonFields';
|
import { DuplicateField, ProjectCodeField, TagsField } from './CommonFields';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field set for BuildOrder forms
|
* Field set for BuildOrder forms
|
||||||
*/
|
*/
|
||||||
export function useBuildOrderFields({
|
export function useBuildOrderFields({
|
||||||
create,
|
create,
|
||||||
|
duplicateBuildId,
|
||||||
modalId
|
modalId
|
||||||
}: {
|
}: {
|
||||||
create: boolean;
|
create: boolean;
|
||||||
|
duplicateBuildId?: number | null;
|
||||||
modalId: string;
|
modalId: string;
|
||||||
}): ApiFormFieldSet {
|
}): ApiFormFieldSet {
|
||||||
const [destination, setDestination] = useState<number | null | undefined>(
|
const [destination, setDestination] = useState<number | null | undefined>(
|
||||||
|
|
@ -133,7 +135,13 @@ export function useBuildOrderFields({
|
||||||
is_active: true
|
is_active: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
external: {}
|
external: {},
|
||||||
|
duplicate: DuplicateField({
|
||||||
|
originalId: duplicateBuildId,
|
||||||
|
extraFields: {
|
||||||
|
copy_parameters: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) {
|
if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) {
|
||||||
|
|
@ -144,8 +152,19 @@ export function useBuildOrderFields({
|
||||||
delete fields.external;
|
delete fields.external;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!duplicateBuildId) {
|
||||||
|
delete fields.duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}, [create, destination, batchCode, batchGenerator.result, globalSettings]);
|
}, [
|
||||||
|
create,
|
||||||
|
destination,
|
||||||
|
batchCode,
|
||||||
|
batchGenerator.result,
|
||||||
|
globalSettings,
|
||||||
|
duplicateBuildId
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useBuildOrderOutputFields({
|
export function useBuildOrderOutputFields({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,26 @@ import type { ApiFormFieldType } from '@lib/types/Forms';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { IconList } from '@tabler/icons-react';
|
import { IconList } from '@tabler/icons-react';
|
||||||
|
|
||||||
|
// Generic field for implementing a "duplication options" form field
|
||||||
|
export function DuplicateField({
|
||||||
|
originalId,
|
||||||
|
extraFields
|
||||||
|
}: Readonly<{
|
||||||
|
originalId?: number | null;
|
||||||
|
extraFields?: Record<string, any>;
|
||||||
|
}>): ApiFormFieldType {
|
||||||
|
return {
|
||||||
|
children: {
|
||||||
|
original: {
|
||||||
|
value: originalId,
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
...extraFields
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic field for rendering a list of tags within a form
|
||||||
export function TagsField({
|
export function TagsField({
|
||||||
label,
|
label,
|
||||||
description,
|
description,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
IconPhone
|
IconPhone
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { TagsField } from './CommonFields';
|
import { DuplicateField, TagsField } from './CommonFields';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field set for SupplierPart instance
|
* Field set for SupplierPart instance
|
||||||
|
|
@ -21,11 +21,13 @@ import { TagsField } from './CommonFields';
|
||||||
export function useSupplierPartFields({
|
export function useSupplierPartFields({
|
||||||
manufacturerId,
|
manufacturerId,
|
||||||
manufacturerPartId,
|
manufacturerPartId,
|
||||||
partId
|
partId,
|
||||||
|
duplicateSupplierPartId
|
||||||
}: {
|
}: {
|
||||||
manufacturerId?: number;
|
manufacturerId?: number;
|
||||||
manufacturerPartId?: number;
|
manufacturerPartId?: number;
|
||||||
partId?: number;
|
partId?: number;
|
||||||
|
duplicateSupplierPartId?: number | null;
|
||||||
}) {
|
}) {
|
||||||
const [part, setPart] = useState<any>({});
|
const [part, setPart] = useState<any>({});
|
||||||
|
|
||||||
|
|
@ -95,14 +97,34 @@ export function useSupplierPartFields({
|
||||||
icon: <IconPackage />
|
icon: <IconPackage />
|
||||||
},
|
},
|
||||||
primary: {},
|
primary: {},
|
||||||
active: {}
|
active: {},
|
||||||
|
duplicate: DuplicateField({
|
||||||
|
originalId: duplicateSupplierPartId,
|
||||||
|
extraFields: {
|
||||||
|
copy_parameters: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!duplicateSupplierPartId) {
|
||||||
|
delete fields.duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}, [manufacturerId, manufacturerPartId, partId, part]);
|
}, [
|
||||||
|
manufacturerId,
|
||||||
|
manufacturerPartId,
|
||||||
|
partId,
|
||||||
|
part,
|
||||||
|
duplicateSupplierPartId
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useManufacturerPartFields() {
|
export function useManufacturerPartFields({
|
||||||
|
duplicateManufacturerPartId
|
||||||
|
}: {
|
||||||
|
duplicateManufacturerPartId?: number | null;
|
||||||
|
} = {}) {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const fields: ApiFormFieldSet = {
|
const fields: ApiFormFieldSet = {
|
||||||
part: {},
|
part: {},
|
||||||
|
|
@ -120,18 +142,32 @@ export function useManufacturerPartFields() {
|
||||||
MPN: {},
|
MPN: {},
|
||||||
description: {},
|
description: {},
|
||||||
tags: TagsField({}),
|
tags: TagsField({}),
|
||||||
link: {}
|
link: {},
|
||||||
|
duplicate: DuplicateField({
|
||||||
|
originalId: duplicateManufacturerPartId,
|
||||||
|
extraFields: {
|
||||||
|
copy_parameters: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!duplicateManufacturerPartId) {
|
||||||
|
delete fields.duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}, []);
|
}, [duplicateManufacturerPartId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field set for editing a company instance
|
* Field set for editing a company instance
|
||||||
*/
|
*/
|
||||||
export function companyFields(): ApiFormFieldSet {
|
export function companyFields({
|
||||||
return {
|
duplicateCompanyId
|
||||||
|
}: {
|
||||||
|
duplicateCompanyId?: number | null;
|
||||||
|
} = {}): ApiFormFieldSet {
|
||||||
|
const fields: ApiFormFieldSet = {
|
||||||
name: {},
|
name: {},
|
||||||
description: {},
|
description: {},
|
||||||
website: {
|
website: {
|
||||||
|
|
@ -151,6 +187,18 @@ export function companyFields(): ApiFormFieldSet {
|
||||||
is_supplier: {},
|
is_supplier: {},
|
||||||
is_manufacturer: {},
|
is_manufacturer: {},
|
||||||
is_customer: {},
|
is_customer: {},
|
||||||
active: {}
|
active: {},
|
||||||
|
duplicate: DuplicateField({
|
||||||
|
originalId: duplicateCompanyId,
|
||||||
|
extraFields: {
|
||||||
|
copy_parameters: {}
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!duplicateCompanyId) {
|
||||||
|
delete fields.duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ export function usePartFields({
|
||||||
fields.duplicate = {
|
fields.duplicate = {
|
||||||
icon: <IconCopy />,
|
icon: <IconCopy />,
|
||||||
children: {
|
children: {
|
||||||
part: {
|
original: {
|
||||||
value: duplicatePartInstance?.pk,
|
value: duplicatePartInstance?.pk,
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ export function usePurchaseOrderFields({
|
||||||
if (!!duplicateOrderId) {
|
if (!!duplicateOrderId) {
|
||||||
fields.duplicate = {
|
fields.duplicate = {
|
||||||
children: {
|
children: {
|
||||||
order_id: {
|
original: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
value: duplicateOrderId
|
value: duplicateOrderId
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -84,15 +84,10 @@ export function useReturnOrderFields({
|
||||||
if (!!duplicateOrderId) {
|
if (!!duplicateOrderId) {
|
||||||
fields.duplicate = {
|
fields.duplicate = {
|
||||||
children: {
|
children: {
|
||||||
order_id: {
|
original: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
value: duplicateOrderId
|
value: duplicateOrderId
|
||||||
},
|
},
|
||||||
copy_lines: {
|
|
||||||
// Cannot duplicate lines from a return order!
|
|
||||||
value: false,
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
copy_extra_lines: {},
|
copy_extra_lines: {},
|
||||||
copy_parameters: {}
|
copy_parameters: {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ export function useSalesOrderFields({
|
||||||
if (!!duplicateOrderId) {
|
if (!!duplicateOrderId) {
|
||||||
fields.duplicate = {
|
fields.duplicate = {
|
||||||
children: {
|
children: {
|
||||||
order_id: {
|
original: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
value: duplicateOrderId
|
value: duplicateOrderId
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,12 @@ export function useTransferOrderFields({
|
||||||
if (!!duplicateOrderId) {
|
if (!!duplicateOrderId) {
|
||||||
fields.duplicate = {
|
fields.duplicate = {
|
||||||
children: {
|
children: {
|
||||||
order_id: {
|
original: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
value: duplicateOrderId
|
value: duplicateOrderId
|
||||||
},
|
},
|
||||||
copy_lines: {},
|
copy_lines: {},
|
||||||
// Transfer Orders don't have extra lines for now...
|
copy_parameters: {}
|
||||||
copy_extra_lines: { hidden: true, value: false }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ import 'mantine-datatable/styles.css';
|
||||||
import 'react-grid-layout/css/styles.css';
|
import 'react-grid-layout/css/styles.css';
|
||||||
import 'react-resizable/css/styles.css';
|
import 'react-resizable/css/styles.css';
|
||||||
|
|
||||||
import type * as LinguiCore from '@lingui/core';
|
import * as LinguiCore from '@lingui/core';
|
||||||
import type * as LinguiReact from '@lingui/react';
|
import * as LinguiReact from '@lingui/react';
|
||||||
// Global types to be exported for use in plugins
|
// Global types to be exported for use in plugins
|
||||||
import type * as MantineCore from '@mantine/core';
|
import * as MantineCore from '@mantine/core';
|
||||||
import type * as MantineNotifications from '@mantine/notifications';
|
import * as MantineNotifications from '@mantine/notifications';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import type * as ReactDOM from 'react-dom';
|
import * as ReactDOM from 'react-dom';
|
||||||
import * as ReactDOMClient from 'react-dom/client';
|
import * as ReactDOMClient from 'react-dom/client';
|
||||||
|
|
||||||
import './styles/overrides.css';
|
import './styles/overrides.css';
|
||||||
|
|
@ -24,7 +24,6 @@ import './styles/overrides.css';
|
||||||
import { getBaseUrl } from '@lib/functions/Navigation';
|
import { getBaseUrl } from '@lib/functions/Navigation';
|
||||||
import type { HostList } from '@lib/types/Server';
|
import type { HostList } from '@lib/types/Server';
|
||||||
import MainView from './views/MainView';
|
import MainView from './views/MainView';
|
||||||
import { loadWindowGlobals } from './window';
|
|
||||||
|
|
||||||
// define settings
|
// define settings
|
||||||
declare global {
|
declare global {
|
||||||
|
|
@ -123,5 +122,11 @@ ReactDOMClient.createRoot(
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
// Load globals onto the window object, so that they can be accessed by plugins without requiring direct imports
|
// All window globals assigned here since these modules are already statically bundled
|
||||||
loadWindowGlobals();
|
window.React = React;
|
||||||
|
window.ReactDOM = ReactDOM;
|
||||||
|
window.ReactDOMClient = ReactDOMClient;
|
||||||
|
window.MantineCore = MantineCore;
|
||||||
|
window.MantineNotifications = MantineNotifications;
|
||||||
|
window.LinguiCore = LinguiCore;
|
||||||
|
window.LinguiReact = LinguiReact;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { PluginPanelKey } from '@lib/enums/ModelType';
|
||||||
|
import { UserRoles } from '@lib/enums/Roles';
|
||||||
|
import type { PanelGroupType, PanelType } from '@lib/types/Panel';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { Stack } from '@mantine/core';
|
import { Stack } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
|
|
@ -5,6 +8,7 @@ import {
|
||||||
IconCpu,
|
IconCpu,
|
||||||
IconDevicesPc,
|
IconDevicesPc,
|
||||||
IconExclamationCircle,
|
IconExclamationCircle,
|
||||||
|
IconFileCode,
|
||||||
IconFileDownload,
|
IconFileDownload,
|
||||||
IconFileUpload,
|
IconFileUpload,
|
||||||
IconHome,
|
IconHome,
|
||||||
|
|
@ -13,6 +17,7 @@ import {
|
||||||
IconMail,
|
IconMail,
|
||||||
IconNotes,
|
IconNotes,
|
||||||
IconPackages,
|
IconPackages,
|
||||||
|
IconPhoto,
|
||||||
IconPlugConnected,
|
IconPlugConnected,
|
||||||
IconQrcode,
|
IconQrcode,
|
||||||
IconReport,
|
IconReport,
|
||||||
|
|
@ -22,10 +27,6 @@ import {
|
||||||
IconUsersGroup
|
IconUsersGroup
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { lazy, useMemo } from 'react';
|
import { lazy, useMemo } from 'react';
|
||||||
|
|
||||||
import { PluginPanelKey } from '@lib/enums/ModelType';
|
|
||||||
import { UserRoles } from '@lib/enums/Roles';
|
|
||||||
import type { PanelGroupType, PanelType } from '@lib/types/Panel';
|
|
||||||
import PermissionDenied from '../../../../components/errors/PermissionDenied';
|
import PermissionDenied from '../../../../components/errors/PermissionDenied';
|
||||||
import PageTitle from '../../../../components/nav/PageTitle';
|
import PageTitle from '../../../../components/nav/PageTitle';
|
||||||
import { SettingsHeader } from '../../../../components/nav/SettingsHeader';
|
import { SettingsHeader } from '../../../../components/nav/SettingsHeader';
|
||||||
|
|
@ -106,6 +107,14 @@ const LocationTypesTable = Loadable(
|
||||||
lazy(() => import('../../../../tables/stock/LocationTypesTable'))
|
lazy(() => import('../../../../tables/stock/LocationTypesTable'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const SnippetTable = Loadable(
|
||||||
|
lazy(() => import('../../../../tables/settings/SnippetTable'))
|
||||||
|
);
|
||||||
|
|
||||||
|
const AssetTable = Loadable(
|
||||||
|
lazy(() => import('../../../../tables/settings/AssetTable'))
|
||||||
|
);
|
||||||
|
|
||||||
export default function AdminCenter() {
|
export default function AdminCenter() {
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
|
||||||
|
|
@ -231,6 +240,18 @@ export default function AdminCenter() {
|
||||||
icon: <IconReport />,
|
icon: <IconReport />,
|
||||||
content: <ReportTemplatePanel />
|
content: <ReportTemplatePanel />
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'snippets',
|
||||||
|
label: t`Report Snippets`,
|
||||||
|
icon: <IconFileCode />,
|
||||||
|
content: <SnippetTable />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'assets',
|
||||||
|
label: t`Report Assets`,
|
||||||
|
icon: <IconPhoto />,
|
||||||
|
content: <AssetTable />
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'location-types',
|
name: 'location-types',
|
||||||
label: t`Location Types`,
|
label: t`Location Types`,
|
||||||
|
|
@ -283,7 +304,7 @@ export default function AdminCenter() {
|
||||||
{
|
{
|
||||||
id: 'reporting',
|
id: 'reporting',
|
||||||
label: t`Reporting`,
|
label: t`Reporting`,
|
||||||
panelIDs: ['labels', 'reports']
|
panelIDs: ['labels', 'reports', 'snippets', 'assets']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'plm',
|
id: 'plm',
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,13 @@ function PluginSettingGroupItem({
|
||||||
}) {
|
}) {
|
||||||
// Hide the accordion item if there are no settings for this plugin
|
// Hide the accordion item if there are no settings for this plugin
|
||||||
const [count, setCount] = useState<number>(0);
|
const [count, setCount] = useState<number>(0);
|
||||||
|
const [doGet, setDoGet] = useState<boolean>(true);
|
||||||
|
|
||||||
// Callback once the plugin settings have been loaded
|
// Callback once the plugin settings have been loaded
|
||||||
const onLoaded = useCallback(
|
const onLoaded = useCallback(
|
||||||
(settings: SettingsStateProps) => {
|
(settings: SettingsStateProps) => {
|
||||||
setCount(settings.settings?.length || 0);
|
setCount(settings.getSettingLength());
|
||||||
|
setDoGet(false);
|
||||||
},
|
},
|
||||||
[pluginKey]
|
[pluginKey]
|
||||||
);
|
);
|
||||||
|
|
@ -50,11 +52,20 @@ function PluginSettingGroupItem({
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Accordion.Control>
|
</Accordion.Control>
|
||||||
|
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
{global ? (
|
{global ? (
|
||||||
<PluginSettingList pluginKey={pluginKey} onLoaded={onLoaded} />
|
<PluginSettingList
|
||||||
|
pluginKey={pluginKey}
|
||||||
|
onLoaded={onLoaded}
|
||||||
|
doGet={doGet}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PluginUserSettingList pluginKey={pluginKey} onLoaded={onLoaded} />
|
<PluginUserSettingList
|
||||||
|
pluginKey={pluginKey}
|
||||||
|
onLoaded={onLoaded}
|
||||||
|
doGet={doGet}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Accordion.Panel>
|
</Accordion.Panel>
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@ export default function BuildDetail() {
|
||||||
|
|
||||||
const duplicateBuildOrderFields = useBuildOrderFields({
|
const duplicateBuildOrderFields = useBuildOrderFields({
|
||||||
create: false,
|
create: false,
|
||||||
|
duplicateBuildId: build.pk,
|
||||||
modalId: 'duplicate-build-order'
|
modalId: 'duplicate-build-order'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { DetailsImage } from '../../components/details/DetailsImage';
|
||||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||||
import {
|
import {
|
||||||
DeleteItemAction,
|
DeleteItemAction,
|
||||||
|
DuplicateItemAction,
|
||||||
EditItemAction,
|
EditItemAction,
|
||||||
OptionsActionDropdown
|
OptionsActionDropdown
|
||||||
} from '../../components/items/ActionDropdown';
|
} from '../../components/items/ActionDropdown';
|
||||||
|
|
@ -43,6 +44,7 @@ import { PanelGroup } from '../../components/panels/PanelGroup';
|
||||||
import ParametersPanel from '../../components/panels/ParametersPanel';
|
import ParametersPanel from '../../components/panels/ParametersPanel';
|
||||||
import { companyFields } from '../../forms/CompanyForms';
|
import { companyFields } from '../../forms/CompanyForms';
|
||||||
import {
|
import {
|
||||||
|
useCreateApiFormModal,
|
||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
useEditApiFormModal
|
useEditApiFormModal
|
||||||
} from '../../hooks/UseForm';
|
} from '../../hooks/UseForm';
|
||||||
|
|
@ -293,11 +295,23 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
||||||
url: ApiEndpoints.company_list,
|
url: ApiEndpoints.company_list,
|
||||||
pk: company?.pk,
|
pk: company?.pk,
|
||||||
title: t`Edit Company`,
|
title: t`Edit Company`,
|
||||||
fields: companyFields(),
|
fields: useMemo(() => companyFields({}), []),
|
||||||
queryParams: new URLSearchParams({ tags: 'true' }),
|
queryParams: new URLSearchParams({ tags: 'true' }),
|
||||||
onFormSuccess: refreshInstance
|
onFormSuccess: refreshInstance
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const duplicateCompany = useCreateApiFormModal({
|
||||||
|
url: ApiEndpoints.company_list,
|
||||||
|
title: t`Duplicate Company`,
|
||||||
|
initialData: useMemo(() => ({ ...company }), [company]),
|
||||||
|
fields: useMemo(
|
||||||
|
() => companyFields({ duplicateCompanyId: company?.pk }),
|
||||||
|
[company]
|
||||||
|
),
|
||||||
|
follow: true,
|
||||||
|
modelType: ModelType.company
|
||||||
|
});
|
||||||
|
|
||||||
const deleteCompany = useDeleteApiFormModal({
|
const deleteCompany = useDeleteApiFormModal({
|
||||||
url: ApiEndpoints.company_list,
|
url: ApiEndpoints.company_list,
|
||||||
pk: company?.pk,
|
pk: company?.pk,
|
||||||
|
|
@ -322,6 +336,10 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
||||||
hidden: !user.hasChangeRole(UserRoles.purchase_order),
|
hidden: !user.hasChangeRole(UserRoles.purchase_order),
|
||||||
onClick: () => editCompany.open()
|
onClick: () => editCompany.open()
|
||||||
}),
|
}),
|
||||||
|
DuplicateItemAction({
|
||||||
|
hidden: !user.hasAddRole(UserRoles.purchase_order),
|
||||||
|
onClick: () => duplicateCompany.open()
|
||||||
|
}),
|
||||||
DeleteItemAction({
|
DeleteItemAction({
|
||||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
||||||
onClick: () => deleteCompany.open()
|
onClick: () => deleteCompany.open()
|
||||||
|
|
@ -345,6 +363,7 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
||||||
<>
|
<>
|
||||||
{editCompany.modal}
|
{editCompany.modal}
|
||||||
{deleteCompany.modal}
|
{deleteCompany.modal}
|
||||||
|
{duplicateCompany.modal}
|
||||||
<InstanceDetail
|
<InstanceDetail
|
||||||
query={instanceQuery}
|
query={instanceQuery}
|
||||||
requiredPermission={ModelType.company}
|
requiredPermission={ModelType.company}
|
||||||
|
|
|
||||||
|
|
@ -220,10 +220,14 @@ export default function ManufacturerPartDetail() {
|
||||||
onFormSuccess: refreshInstance
|
onFormSuccess: refreshInstance
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const duplicateManufacturerPartFields = useManufacturerPartFields({
|
||||||
|
duplicateManufacturerPartId: manufacturerPart?.pk
|
||||||
|
});
|
||||||
|
|
||||||
const duplicateManufacturerPart = useCreateApiFormModal({
|
const duplicateManufacturerPart = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.manufacturer_part_list,
|
url: ApiEndpoints.manufacturer_part_list,
|
||||||
title: t`Add Manufacturer Part`,
|
title: t`Add Manufacturer Part`,
|
||||||
fields: editManufacturerPartFields,
|
fields: duplicateManufacturerPartFields,
|
||||||
initialData: {
|
initialData: {
|
||||||
...manufacturerPart
|
...manufacturerPart
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -357,10 +357,14 @@ export default function SupplierPartDetail() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const duplicateSupplierPartFields = useSupplierPartFields({
|
||||||
|
duplicateSupplierPartId: supplierPart?.pk
|
||||||
|
});
|
||||||
|
|
||||||
const duplicateSupplierPart = useCreateApiFormModal({
|
const duplicateSupplierPart = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.supplier_part_list,
|
url: ApiEndpoints.supplier_part_list,
|
||||||
title: t`Add Supplier Part`,
|
title: t`Add Supplier Part`,
|
||||||
fields: supplierPartFields,
|
fields: duplicateSupplierPartFields,
|
||||||
initialData: {
|
initialData: {
|
||||||
...supplierPart
|
...supplierPart
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ export const useGlobalSettingsState = create<SettingsStateProps>(
|
||||||
isSet: (key: string, default_value?: boolean) => {
|
isSet: (key: string, default_value?: boolean) => {
|
||||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||||
return isTrue(value);
|
return isTrue(value);
|
||||||
|
},
|
||||||
|
getSettingLength: () => {
|
||||||
|
return Object.keys(get().lookup).length;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
@ -114,6 +117,9 @@ export const useUserSettingsState = create<SettingsStateProps>((set, get) => ({
|
||||||
isSet: (key: string, default_value?: boolean) => {
|
isSet: (key: string, default_value?: boolean) => {
|
||||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||||
return isTrue(value);
|
return isTrue(value);
|
||||||
|
},
|
||||||
|
getSettingLength: () => {
|
||||||
|
return Object.keys(get().lookup).length;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -185,6 +191,9 @@ export const createPluginSettingsState = ({
|
||||||
isSet: (key: string, default_value?: boolean) => {
|
isSet: (key: string, default_value?: boolean) => {
|
||||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||||
return isTrue(value);
|
return isTrue(value);
|
||||||
|
},
|
||||||
|
getSettingLength: () => {
|
||||||
|
return Object.keys(get().lookup).length;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
@ -246,6 +255,9 @@ export const createMachineSettingsState = ({
|
||||||
isSet: (key: string, default_value?: boolean) => {
|
isSet: (key: string, default_value?: boolean) => {
|
||||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||||
return isTrue(value);
|
return isTrue(value);
|
||||||
|
},
|
||||||
|
getSettingLength: () => {
|
||||||
|
return Object.keys(get().lookup).length;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ import { t } from '@lingui/core/macro';
|
||||||
import { Alert, Divider, Group, Stack, Text } from '@mantine/core';
|
import { Alert, Divider, Group, Stack, Text } from '@mantine/core';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
import { RowEditAction } from '@lib/components/RowActions';
|
||||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import { ActionButton, RowEditAction, UserRoles } from '@lib/index';
|
import { ActionButton, UserRoles } from '@lib/index';
|
||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
||||||
import { IconExclamationCircle, IconReplace } from '@tabler/icons-react';
|
import { IconExclamationCircle, IconReplace } from '@tabler/icons-react';
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
|
import { RowDeleteAction, RowEditAction } from '@lib/components/RowActions';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import {
|
import {
|
||||||
ApiEndpoints,
|
ApiEndpoints,
|
||||||
ModelType,
|
ModelType,
|
||||||
RowDeleteAction,
|
|
||||||
RowEditAction,
|
|
||||||
YesNoButton,
|
YesNoButton,
|
||||||
apiUrl,
|
apiUrl,
|
||||||
formatDecimal
|
formatDecimal
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
import {
|
||||||
|
RowDeleteAction,
|
||||||
|
RowDuplicateAction,
|
||||||
|
RowEditAction
|
||||||
|
} from '@lib/components/RowActions';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import {
|
import {
|
||||||
AddItemButton,
|
AddItemButton,
|
||||||
ApiEndpoints,
|
ApiEndpoints,
|
||||||
type ApiFormFieldSet,
|
type ApiFormFieldSet,
|
||||||
RowDeleteAction,
|
|
||||||
RowDuplicateAction,
|
|
||||||
RowEditAction,
|
|
||||||
UserRoles,
|
UserRoles,
|
||||||
apiUrl
|
apiUrl
|
||||||
} from '@lib/index';
|
} from '@lib/index';
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||||
|
import { RowDeleteAction, RowEditAction } from '@lib/components/RowActions';
|
||||||
import { StylishText } from '@lib/components/StylishText';
|
import { StylishText } from '@lib/components/StylishText';
|
||||||
import { YesNoButton } from '@lib/components/YesNoButton';
|
import { YesNoButton } from '@lib/components/YesNoButton';
|
||||||
import {
|
import {
|
||||||
|
|
@ -32,7 +33,7 @@ import {
|
||||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import { RowDeleteAction, RowEditAction, formatDecimal } from '@lib/index';
|
import { formatDecimal } from '@lib/index';
|
||||||
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
||||||
import type { InvenTreeTableProps } from '@lib/types/Tables';
|
import type { InvenTreeTableProps } from '@lib/types/Tables';
|
||||||
import { Trans } from '@lingui/react/macro';
|
import { Trans } from '@lingui/react/macro';
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { ActionDropdown } from '../../components/items/ActionDropdown';
|
||||||
import ImportPartWizard from '../../components/wizards/ImportPartWizard';
|
import ImportPartWizard from '../../components/wizards/ImportPartWizard';
|
||||||
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
||||||
import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
|
import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
|
||||||
|
import { DuplicateField } from '../../forms/CommonFields';
|
||||||
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||||
import { usePartFields } from '../../forms/PartForms';
|
import { usePartFields } from '../../forms/PartForms';
|
||||||
import { InvenTreeIcon } from '../../functions/icons';
|
import { InvenTreeIcon } from '../../functions/icons';
|
||||||
|
|
@ -312,12 +313,9 @@ export function PartListTable({
|
||||||
const duplicatePartFields: ApiFormFieldSet = useMemo(() => {
|
const duplicatePartFields: ApiFormFieldSet = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...createPartFields,
|
...createPartFields,
|
||||||
duplicate: {
|
duplicate: DuplicateField({
|
||||||
children: {
|
originalId: selectedPart.pk,
|
||||||
part: {
|
extraFields: {
|
||||||
value: selectedPart.pk,
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
copy_image: {
|
copy_image: {
|
||||||
value: true
|
value: true
|
||||||
},
|
},
|
||||||
|
|
@ -337,7 +335,7 @@ export function PartListTable({
|
||||||
hidden: !selectedPart.testable
|
hidden: !selectedPart.testable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
}, [createPartFields, globalSettings, selectedPart]);
|
}, [createPartFields, globalSettings, selectedPart]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,10 +133,14 @@ export function ManufacturerPartTable({
|
||||||
table: table
|
table: table
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const duplicateManufacturerPartFields = useManufacturerPartFields({
|
||||||
|
duplicateManufacturerPartId: selectedPart?.pk
|
||||||
|
});
|
||||||
|
|
||||||
const duplicateManufacturerPart = useCreateApiFormModal({
|
const duplicateManufacturerPart = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.manufacturer_part_list,
|
url: ApiEndpoints.manufacturer_part_list,
|
||||||
title: t`Add Manufacturer Part`,
|
title: t`Add Manufacturer Part`,
|
||||||
fields: useMemo(() => manufacturerPartFields, [manufacturerPartFields]),
|
fields: duplicateManufacturerPartFields,
|
||||||
table: table,
|
table: table,
|
||||||
initialData: {
|
initialData: {
|
||||||
...selectedPart
|
...selectedPart
|
||||||
|
|
|
||||||
|
|
@ -292,10 +292,14 @@ export function SupplierPartTable({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const duplicateSupplierPartFields = useSupplierPartFields({
|
||||||
|
duplicateSupplierPartId: selectedSupplierPart?.pk
|
||||||
|
});
|
||||||
|
|
||||||
const duplicateSupplierPart = useCreateApiFormModal({
|
const duplicateSupplierPart = useCreateApiFormModal({
|
||||||
url: ApiEndpoints.supplier_part_list,
|
url: ApiEndpoints.supplier_part_list,
|
||||||
title: t`Add Supplier Part`,
|
title: t`Add Supplier Part`,
|
||||||
fields: useMemo(() => editSupplierPartFields, [editSupplierPartFields]),
|
fields: duplicateSupplierPartFields,
|
||||||
initialData: {
|
initialData: {
|
||||||
...selectedSupplierPart,
|
...selectedSupplierPart,
|
||||||
primary: false,
|
primary: false,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||||
|
import { type RowAction, RowDeleteAction } from '@lib/components/RowActions';
|
||||||
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
|
import useTable from '@lib/hooks/UseTable';
|
||||||
|
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||||
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { Alert, Text } from '@mantine/core';
|
||||||
|
import { IconInfoCircle } from '@tabler/icons-react';
|
||||||
|
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||||
|
import {
|
||||||
|
useCreateApiFormModal,
|
||||||
|
useDeleteApiFormModal
|
||||||
|
} from '../../hooks/UseForm';
|
||||||
|
import { useUserState } from '../../states/UserState';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
|
export type AssetI = {
|
||||||
|
pk: number;
|
||||||
|
asset: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AssetTable() {
|
||||||
|
const table = useTable('report-asset');
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
|
const columns: TableColumn<AssetI>[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
accessor: 'asset',
|
||||||
|
title: t`Asset`,
|
||||||
|
sortable: false,
|
||||||
|
switchable: false,
|
||||||
|
render: (record: AssetI) => {
|
||||||
|
if (!record.asset) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return <AttachmentLink attachment={record.asset} />;
|
||||||
|
},
|
||||||
|
noContext: true
|
||||||
|
},
|
||||||
|
DescriptionColumn({
|
||||||
|
accessor: 'description',
|
||||||
|
sortable: false,
|
||||||
|
switchable: false
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [selectedAsset, setSelectedAsset] = useState<number>(-1);
|
||||||
|
|
||||||
|
const rowActions = useCallback(
|
||||||
|
(record: AssetI): RowAction[] => {
|
||||||
|
return [
|
||||||
|
RowDeleteAction({
|
||||||
|
hidden: !user.isStaff(),
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedAsset(record.pk);
|
||||||
|
deleteAsset.open();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
|
const newAssetFields: ApiFormFieldSet = useMemo(() => {
|
||||||
|
return {
|
||||||
|
asset: {},
|
||||||
|
description: {}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const deleteAsset = useDeleteApiFormModal({
|
||||||
|
url: ApiEndpoints.report_asset,
|
||||||
|
pk: selectedAsset,
|
||||||
|
title: t`Delete Asset`,
|
||||||
|
table: table
|
||||||
|
});
|
||||||
|
|
||||||
|
const newAsset = useCreateApiFormModal({
|
||||||
|
url: ApiEndpoints.report_asset,
|
||||||
|
title: t`Add Asset`,
|
||||||
|
fields: newAssetFields,
|
||||||
|
table: table
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableActions: ReactNode[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
<AddItemButton
|
||||||
|
key='add-asset'
|
||||||
|
onClick={() => newAsset.open()}
|
||||||
|
tooltip={t`Add asset`}
|
||||||
|
hidden={!user.isStaff()}
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{newAsset.modal}
|
||||||
|
{deleteAsset.modal}
|
||||||
|
<Alert icon={<IconInfoCircle />} title={t`Assets`}>
|
||||||
|
<Text>{t`Assets are files (such as images) which can be used when rendering reports and labels.`}</Text>
|
||||||
|
</Alert>
|
||||||
|
<InvenTreeTable
|
||||||
|
url={apiUrl(ApiEndpoints.report_asset)}
|
||||||
|
tableState={table}
|
||||||
|
columns={columns}
|
||||||
|
props={{
|
||||||
|
rowActions: rowActions,
|
||||||
|
tableActions: tableActions,
|
||||||
|
enableSearch: false,
|
||||||
|
enableFilters: false
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -15,8 +15,9 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
import { UserRoles } from '@lib/enums/Roles';
|
import { UserRoles } from '@lib/enums/Roles';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
|
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import { type ApiFormModalProps, getDetailUrl } from '@lib/index';
|
import type { ApiFormModalProps } from '@lib/index';
|
||||||
import type { TableColumn, TableState } from '@lib/types/Tables';
|
import type { TableColumn, TableState } from '@lib/types/Tables';
|
||||||
import { IconUsersGroup } from '@tabler/icons-react';
|
import { IconUsersGroup } from '@tabler/icons-react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,241 @@
|
||||||
|
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||||
|
import {
|
||||||
|
type RowAction,
|
||||||
|
RowDeleteAction,
|
||||||
|
RowEditAction
|
||||||
|
} from '@lib/components/RowActions';
|
||||||
|
import { DetailDrawer } from '@lib/components/nav/DetailDrawer';
|
||||||
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
|
import useTable from '@lib/hooks/UseTable';
|
||||||
|
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||||
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { Trans } from '@lingui/react/macro';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Group,
|
||||||
|
LoadingOverlay,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
Title
|
||||||
|
} from '@mantine/core';
|
||||||
|
import { IconFileCode, IconInfoCircle } from '@tabler/icons-react';
|
||||||
|
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
CodeEditor,
|
||||||
|
TemplateEditor
|
||||||
|
} from '../../components/editors/TemplateEditor';
|
||||||
|
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||||
|
import {
|
||||||
|
useCreateApiFormModal,
|
||||||
|
useDeleteApiFormModal,
|
||||||
|
useEditApiFormModal
|
||||||
|
} from '../../hooks/UseForm';
|
||||||
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
|
import { useUserState } from '../../states/UserState';
|
||||||
|
import { DescriptionColumn } from '../ColumnRenderers';
|
||||||
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
import type { TemplateI } from './TemplateTable';
|
||||||
|
|
||||||
|
export type SnippetI = {
|
||||||
|
pk: number;
|
||||||
|
snippet: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SnippetDrawer({
|
||||||
|
id
|
||||||
|
}: Readonly<{
|
||||||
|
id: string | number;
|
||||||
|
}>) {
|
||||||
|
const {
|
||||||
|
instance: snippet,
|
||||||
|
instanceQuery: { isFetching, error }
|
||||||
|
} = useInstance<SnippetI>({
|
||||||
|
endpoint: ApiEndpoints.report_snippet,
|
||||||
|
hasPrimaryKey: true,
|
||||||
|
pk: id
|
||||||
|
});
|
||||||
|
|
||||||
|
const filename = useMemo(
|
||||||
|
() => snippet?.snippet?.split('/').pop() ?? '',
|
||||||
|
[snippet]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isFetching) {
|
||||||
|
return <LoadingOverlay visible={true} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error || !snippet) {
|
||||||
|
return (
|
||||||
|
<Text>
|
||||||
|
{(error as any)?.response?.status === 404 ? (
|
||||||
|
<Trans>Snippet not found</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>An error occurred while fetching snippet details</Trans>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap='xs' style={{ display: 'flex', flex: '1' }}>
|
||||||
|
<Group justify='left'>
|
||||||
|
<Title order={4}>{filename}</Title>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<TemplateEditor
|
||||||
|
templateUrl={apiUrl(ApiEndpoints.report_snippet, id)}
|
||||||
|
template={snippet as unknown as TemplateI}
|
||||||
|
fileField='snippet'
|
||||||
|
editors={[CodeEditor]}
|
||||||
|
previewAreas={[]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SnippetTable() {
|
||||||
|
const table = useTable('report-snippet');
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const user = useUserState();
|
||||||
|
|
||||||
|
const openDetailDrawer = useCallback((pk: number) => navigate(`${pk}/`), []);
|
||||||
|
|
||||||
|
const columns: TableColumn<SnippetI>[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
accessor: 'snippet',
|
||||||
|
title: t`Snippet`,
|
||||||
|
sortable: false,
|
||||||
|
switchable: false,
|
||||||
|
render: (record: SnippetI) => {
|
||||||
|
if (!record.snippet) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return <AttachmentLink attachment={record.snippet} />;
|
||||||
|
},
|
||||||
|
noContext: true
|
||||||
|
},
|
||||||
|
DescriptionColumn({
|
||||||
|
accessor: 'description',
|
||||||
|
sortable: false,
|
||||||
|
switchable: false
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [selectedSnippet, setSelectedSnippet] = useState<number>(-1);
|
||||||
|
|
||||||
|
const rowActions = useCallback(
|
||||||
|
(record: SnippetI): RowAction[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: t`Modify`,
|
||||||
|
tooltip: t`Modify snippet file`,
|
||||||
|
icon: <IconFileCode />,
|
||||||
|
onClick: () => openDetailDrawer(record.pk),
|
||||||
|
hidden: !user.isStaff()
|
||||||
|
},
|
||||||
|
RowEditAction({
|
||||||
|
hidden: !user.isStaff(),
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedSnippet(record.pk);
|
||||||
|
editSnippet.open();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RowDeleteAction({
|
||||||
|
hidden: !user.isStaff(),
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedSnippet(record.pk);
|
||||||
|
deleteSnippet.open();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[user]
|
||||||
|
);
|
||||||
|
|
||||||
|
const editSnippetFields: ApiFormFieldSet = useMemo(() => {
|
||||||
|
return {
|
||||||
|
description: {}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const newSnippetFields: ApiFormFieldSet = useMemo(() => {
|
||||||
|
return {
|
||||||
|
snippet: {},
|
||||||
|
description: {}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const editSnippet = useEditApiFormModal({
|
||||||
|
url: ApiEndpoints.report_snippet,
|
||||||
|
pk: selectedSnippet,
|
||||||
|
title: t`Edit Snippet`,
|
||||||
|
fields: editSnippetFields,
|
||||||
|
onFormSuccess: (record: any) => table.updateRecord(record)
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteSnippet = useDeleteApiFormModal({
|
||||||
|
url: ApiEndpoints.report_snippet,
|
||||||
|
pk: selectedSnippet,
|
||||||
|
title: t`Delete Snippet`,
|
||||||
|
table: table
|
||||||
|
});
|
||||||
|
|
||||||
|
const newSnippet = useCreateApiFormModal({
|
||||||
|
url: ApiEndpoints.report_snippet,
|
||||||
|
title: t`Add Snippet`,
|
||||||
|
fields: newSnippetFields,
|
||||||
|
onFormSuccess: (data) => {
|
||||||
|
table.refreshTable();
|
||||||
|
openDetailDrawer(data.pk);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableActions: ReactNode[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
<AddItemButton
|
||||||
|
key='add-snippet'
|
||||||
|
onClick={() => newSnippet.open()}
|
||||||
|
tooltip={t`Add snippet`}
|
||||||
|
hidden={!user.isStaff()}
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{newSnippet.modal}
|
||||||
|
{editSnippet.modal}
|
||||||
|
{deleteSnippet.modal}
|
||||||
|
<DetailDrawer
|
||||||
|
title={t`Edit Snippet`}
|
||||||
|
size={'90%'}
|
||||||
|
closeOnEscape={false}
|
||||||
|
renderContent={(id) => {
|
||||||
|
return <SnippetDrawer id={id ?? ''} />;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Alert icon={<IconInfoCircle />} title={t`Snippets`}>
|
||||||
|
<Text>{t`Snippets are reusable pieces of HTML content that can be inserted into reports and labels.`}</Text>
|
||||||
|
</Alert>
|
||||||
|
<InvenTreeTable
|
||||||
|
url={apiUrl(ApiEndpoints.report_snippet)}
|
||||||
|
tableState={table}
|
||||||
|
columns={columns}
|
||||||
|
props={{
|
||||||
|
rowActions: rowActions,
|
||||||
|
tableActions: tableActions,
|
||||||
|
enableSearch: false,
|
||||||
|
enableFilters: false,
|
||||||
|
onRowClick: (record) => openDetailDrawer(record.pk)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -22,8 +22,9 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
import { UserRoles } from '@lib/enums/Roles';
|
import { UserRoles } from '@lib/enums/Roles';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
|
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
import { type ApiFormModalProps, getDetailUrl } from '@lib/index';
|
import type { ApiFormModalProps } from '@lib/index';
|
||||||
import type { TableFilter } from '@lib/types/Filters';
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { TableColumn, TableState } from '@lib/types/Tables';
|
import type { TableColumn, TableState } from '@lib/types/Tables';
|
||||||
import { showNotification } from '@mantine/notifications';
|
import { showNotification } from '@mantine/notifications';
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,12 @@ import {
|
||||||
} from '../../forms/StockForms';
|
} from '../../forms/StockForms';
|
||||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import { PartColumn, StatusColumn, StockColumn } from '../ColumnRenderers';
|
import {
|
||||||
|
IPNColumn,
|
||||||
|
PartColumn,
|
||||||
|
StatusColumn,
|
||||||
|
StockColumn
|
||||||
|
} from '../ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
|
|
||||||
export default function InstalledItemsTable({
|
export default function InstalledItemsTable({
|
||||||
|
|
@ -61,6 +66,7 @@ export default function InstalledItemsTable({
|
||||||
PartColumn({
|
PartColumn({
|
||||||
part: 'part_detail'
|
part: 'part_detail'
|
||||||
}),
|
}),
|
||||||
|
IPNColumn({}),
|
||||||
StockColumn({
|
StockColumn({
|
||||||
accessor: '',
|
accessor: '',
|
||||||
title: t`Stock Item`,
|
title: t`Stock Item`,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
import {
|
||||||
|
RowDeleteAction,
|
||||||
|
RowDuplicateAction,
|
||||||
|
RowEditAction,
|
||||||
|
RowViewAction
|
||||||
|
} from '@lib/components/RowActions';
|
||||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import useTable from '@lib/hooks/UseTable';
|
import useTable from '@lib/hooks/UseTable';
|
||||||
|
|
@ -6,10 +12,6 @@ import {
|
||||||
AddItemButton,
|
AddItemButton,
|
||||||
ModelType,
|
ModelType,
|
||||||
ProgressBar,
|
ProgressBar,
|
||||||
RowDeleteAction,
|
|
||||||
RowDuplicateAction,
|
|
||||||
RowEditAction,
|
|
||||||
RowViewAction,
|
|
||||||
UserRoles,
|
UserRoles,
|
||||||
formatDecimal
|
formatDecimal
|
||||||
} from '@lib/index';
|
} from '@lib/index';
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/**
|
|
||||||
* Expose certain globals to the window object, so that they can be accessed by plugins,
|
|
||||||
* without requiring plugins to import these dependencies directly.
|
|
||||||
*/
|
|
||||||
export function loadWindowGlobals() {
|
|
||||||
// (window as any).React = React;
|
|
||||||
import('react').then((module) => {
|
|
||||||
window.React = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (window as any).ReactDOM = ReactDOM;
|
|
||||||
import('react-dom').then((module) => {
|
|
||||||
window.ReactDOM = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (window as any).ReactDOMClient = ReactDOMClient;
|
|
||||||
import('react-dom/client').then((module) => {
|
|
||||||
window.ReactDOMClient = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (window as any).MantineCore = MantineCore;
|
|
||||||
import('@mantine/core').then((module) => {
|
|
||||||
window.MantineCore = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
// (window as any).MantineNotifications = MantineNotifications;
|
|
||||||
import('@mantine/notifications').then((module) => {
|
|
||||||
window.MantineNotifications = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
import('@lingui/core').then((module) => {
|
|
||||||
window.LinguiCore = module;
|
|
||||||
});
|
|
||||||
|
|
||||||
import('@lingui/react').then((module) => {
|
|
||||||
window.LinguiReact = module;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -75,8 +75,8 @@ test('Plugins - User Settings', async ({ browser }) => {
|
||||||
await navigate(page, 'settings/user/');
|
await navigate(page, 'settings/user/');
|
||||||
await loadTab(page, 'Plugin Settings');
|
await loadTab(page, 'Plugin Settings');
|
||||||
|
|
||||||
// User settings for the "Sample Plugin" should be visible
|
// User settings for the "SampleIntegrationPlugin" should be visible
|
||||||
await page.getByRole('button', { name: 'Sample Plugin' }).click();
|
await page.getByRole('button', { name: 'SampleIntegrationPlugin' }).click();
|
||||||
|
|
||||||
await page.getByText('User Setting 1').waitFor();
|
await page.getByText('User Setting 1').waitFor();
|
||||||
await page.getByText('User Setting 2').waitFor();
|
await page.getByText('User Setting 2').waitFor();
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,37 @@ test('Settings - Admin', async ({ browser }) => {
|
||||||
await loadTab(page, 'Category Parameters');
|
await loadTab(page, 'Category Parameters');
|
||||||
await loadTab(page, 'Label Templates');
|
await loadTab(page, 'Label Templates');
|
||||||
await loadTab(page, 'Report Templates');
|
await loadTab(page, 'Report Templates');
|
||||||
|
|
||||||
|
// Check the "report snippets" panel
|
||||||
|
await loadTab(page, 'Report Snippets');
|
||||||
|
await page
|
||||||
|
.getByText(
|
||||||
|
'Snippets are reusable pieces of HTML content that can be inserted into reports and labels.'
|
||||||
|
)
|
||||||
|
.waitFor();
|
||||||
|
|
||||||
|
// Launch the dialog to upload a new snippet
|
||||||
|
await page.getByLabel('action-button-add-snippet').click();
|
||||||
|
await page.getByText('Add Snippet', { exact: true }).waitFor();
|
||||||
|
await page.locator('input[type="file"]').waitFor({ state: 'attached' });
|
||||||
|
await page.getByLabel('text-field-description').waitFor();
|
||||||
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
|
// Check the "report assets" panel
|
||||||
|
await loadTab(page, 'Report Assets');
|
||||||
|
await page
|
||||||
|
.getByText(
|
||||||
|
'Assets are files (such as images) which can be used when rendering reports and labels.'
|
||||||
|
)
|
||||||
|
.waitFor();
|
||||||
|
|
||||||
|
// Launch the dialog to upload a new asset
|
||||||
|
await page.getByLabel('action-button-add-asset').click();
|
||||||
|
await page.getByText('Add Asset', { exact: true }).waitFor();
|
||||||
|
await page.locator('input[type="file"]').waitFor({ state: 'attached' });
|
||||||
|
await page.getByLabel('text-field-description').waitFor();
|
||||||
|
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||||
|
|
||||||
await loadTab(page, 'Plugins');
|
await loadTab(page, 'Plugins');
|
||||||
|
|
||||||
// Adjust some "location type" items
|
// Adjust some "location type" items
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,25 @@
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
picocolors "^1.1.1"
|
picocolors "^1.1.1"
|
||||||
|
|
||||||
|
"@babel/code-frame@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-8.0.0.tgz#f374ea9392011ffecf223805dd0d9315606e5bbf"
|
||||||
|
integrity sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^8.0.0"
|
||||||
|
js-tokens "^10.0.0"
|
||||||
|
|
||||||
"@babel/compat-data@^7.29.7":
|
"@babel/compat-data@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
|
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
|
||||||
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
|
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
|
||||||
|
|
||||||
"@babel/core@^7.17.7", "@babel/core@^7.20.12", "@babel/core@^7.21.0", "@babel/core@^7.23.9", "@babel/core@^7.29.0", "@babel/core@^7.29.7":
|
"@babel/compat-data@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-8.0.0.tgz#e780eb6052d8ceeaeadd3a6cd82dda470a945622"
|
||||||
|
integrity sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==
|
||||||
|
|
||||||
|
"@babel/core@^7.17.7", "@babel/core@^7.20.12", "@babel/core@^7.21.0", "@babel/core@^7.23.9", "@babel/core@^7.29.0":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
|
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
|
||||||
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
|
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
|
||||||
|
|
@ -86,6 +99,28 @@
|
||||||
json5 "^2.2.3"
|
json5 "^2.2.3"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
|
"@babel/core@^8.0.1":
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/core/-/core-8.0.1.tgz#dcb133d3ddcfb2b5a6558da03bf240319da0b8c8"
|
||||||
|
integrity sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^8.0.0"
|
||||||
|
"@babel/generator" "^8.0.0"
|
||||||
|
"@babel/helper-compilation-targets" "^8.0.0"
|
||||||
|
"@babel/helpers" "^8.0.0"
|
||||||
|
"@babel/parser" "^8.0.0"
|
||||||
|
"@babel/template" "^8.0.0"
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
"@types/gensync" "^1.0.5"
|
||||||
|
convert-source-map "^2.0.0"
|
||||||
|
empathic "^2.0.1"
|
||||||
|
gensync "^1.0.0-beta.2"
|
||||||
|
import-meta-resolve "^4.2.0"
|
||||||
|
json5 "^2.2.3"
|
||||||
|
obug "^2.1.1"
|
||||||
|
semver "^7.7.3"
|
||||||
|
|
||||||
"@babel/generator@^7.21.1", "@babel/generator@^7.29.7":
|
"@babel/generator@^7.21.1", "@babel/generator@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3"
|
||||||
|
|
@ -97,12 +132,24 @@
|
||||||
"@jridgewell/trace-mapping" "^0.3.28"
|
"@jridgewell/trace-mapping" "^0.3.28"
|
||||||
jsesc "^3.0.2"
|
jsesc "^3.0.2"
|
||||||
|
|
||||||
"@babel/helper-annotate-as-pure@^7.29.7":
|
"@babel/generator@^8.0.0":
|
||||||
version "7.29.7"
|
version "8.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz#c70fe3c6ecbdc3fd2dd1b0f498428b88b82ce47f"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-8.0.0.tgz#24b7b53a74fa8e74cc2377e054fecef4dcdada96"
|
||||||
integrity sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==
|
integrity sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/parser" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
"@jridgewell/gen-mapping" "^0.3.12"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.28"
|
||||||
|
"@types/jsesc" "^2.5.0"
|
||||||
|
jsesc "^3.0.2"
|
||||||
|
|
||||||
|
"@babel/helper-annotate-as-pure@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-8.0.0.tgz#e094d0ea95f319cdc399fe25ec82e4b3dddb8461"
|
||||||
|
integrity sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@^7.29.7":
|
"@babel/helper-compilation-targets@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
|
|
@ -115,31 +162,47 @@
|
||||||
lru-cache "^5.1.1"
|
lru-cache "^5.1.1"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/helper-create-class-features-plugin@^7.29.7":
|
"@babel/helper-compilation-targets@^8.0.0":
|
||||||
version "7.29.7"
|
version "8.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz#6eddf286f2ec418f740c91d60a83347c55838ddd"
|
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz#63f230f427c9ea82323d829c935f6190d93b3736"
|
||||||
integrity sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==
|
integrity sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
"@babel/compat-data" "^8.0.0"
|
||||||
"@babel/helper-member-expression-to-functions" "^7.29.7"
|
"@babel/helper-validator-option" "^8.0.0"
|
||||||
"@babel/helper-optimise-call-expression" "^7.29.7"
|
browserslist "^4.24.0"
|
||||||
"@babel/helper-replace-supers" "^7.29.7"
|
lru-cache "^11.0.0"
|
||||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.29.7"
|
semver "^7.7.3"
|
||||||
"@babel/traverse" "^7.29.7"
|
|
||||||
semver "^6.3.1"
|
"@babel/helper-create-class-features-plugin@^8.0.1":
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-8.0.1.tgz#d8c5f55a3741a5f7d526bb4bfc361805601ef954"
|
||||||
|
integrity sha512-++t3ZktzlLmASAxIlxeXQK9Z2YwUafYGYcvGBFevqOqt16HozVHStUoQvWD09fzAZOb/uJGpUTBuGK41AJAuOA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||||
|
"@babel/helper-member-expression-to-functions" "^8.0.0"
|
||||||
|
"@babel/helper-optimise-call-expression" "^8.0.0"
|
||||||
|
"@babel/helper-replace-supers" "^8.0.1"
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers" "^8.0.0"
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
semver "^7.7.3"
|
||||||
|
|
||||||
"@babel/helper-globals@^7.29.7":
|
"@babel/helper-globals@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
|
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
|
||||||
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
|
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
|
||||||
|
|
||||||
"@babel/helper-member-expression-to-functions@^7.29.7":
|
"@babel/helper-globals@^8.0.0":
|
||||||
version "7.29.7"
|
version "8.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz#8dbdb3ce0b5c487e1aec10e13c9a43a500814df8"
|
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-8.0.0.tgz#c93789d6c1c2f1b65a97a07515c471a049559bf1"
|
||||||
integrity sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==
|
integrity sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==
|
||||||
|
|
||||||
|
"@babel/helper-member-expression-to-functions@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-8.0.0.tgz#c097e24f7aeb60ab08966ef6c2127fc8ee32449e"
|
||||||
|
integrity sha512-xkXrMbtk87Gk7+oKBVmBc6EORg/Qwx++AHESldmHkpvG8wgccdhJJFwrzqlF382Fk8wfXhJHWE/g/43QvEGNPQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/traverse" "^7.29.7"
|
"@babel/traverse" "^8.0.0"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.29.7":
|
"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
|
|
@ -149,6 +212,14 @@
|
||||||
"@babel/traverse" "^7.29.7"
|
"@babel/traverse" "^7.29.7"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^7.29.7"
|
||||||
|
|
||||||
|
"@babel/helper-module-imports@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-8.0.0.tgz#b6b16c75f80616b545f72e842d8224b981fd41d5"
|
||||||
|
integrity sha512-NZ7mSS93o4ndX4KrbD7W8Sf3QT8Qe24PrnFyUcuOPDzK6faqDFKjY9RG7he7+I7FdiQ4llpnosFqzrXa+Vy3Ew==
|
||||||
|
dependencies:
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/helper-module-transforms@^7.29.7":
|
"@babel/helper-module-transforms@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
|
||||||
|
|
@ -158,50 +229,79 @@
|
||||||
"@babel/helper-validator-identifier" "^7.29.7"
|
"@babel/helper-validator-identifier" "^7.29.7"
|
||||||
"@babel/traverse" "^7.29.7"
|
"@babel/traverse" "^7.29.7"
|
||||||
|
|
||||||
"@babel/helper-optimise-call-expression@^7.29.7":
|
"@babel/helper-module-transforms@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz#77b0b5b94f1997fa9d6e3125f445227b1faf9d85"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-8.0.1.tgz#e8cf988892d7d8c774a9072dca0962f94b606bb6"
|
||||||
integrity sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==
|
integrity sha512-UgAhl1kqiW5ciE0yCXqqvnb4H2n3IELJ7lIIQRezwDPilPEZX5i+Rvbja9MFTkwUn2biEiSMeV31aUzR4Lwakw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/helper-module-imports" "^8.0.0"
|
||||||
|
"@babel/helper-validator-identifier" "^8.0.0"
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
|
||||||
|
"@babel/helper-optimise-call-expression@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-8.0.0.tgz#dc1118493494fbfc3bb24b490550673908a99b6c"
|
||||||
|
integrity sha512-3W6satvtPuCUkUx63S2jMoW9EQNYkADgs1HTfufmL7gCmAulHMKupA/12WNz4A0GMMFn/YnWWwqOT9IZrJHQjg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/helper-plugin-utils@^7.29.7":
|
"@babel/helper-plugin-utils@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4"
|
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4"
|
||||||
integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==
|
integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==
|
||||||
|
|
||||||
"@babel/helper-replace-supers@^7.29.7":
|
"@babel/helper-plugin-utils@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz#bc3c3964329043c79112e513c1b198f16589ac21"
|
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.1.tgz#d1c9d8ae225902c597deac8c79ace4227feac8af"
|
||||||
integrity sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==
|
integrity sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==
|
||||||
dependencies:
|
|
||||||
"@babel/helper-member-expression-to-functions" "^7.29.7"
|
|
||||||
"@babel/helper-optimise-call-expression" "^7.29.7"
|
|
||||||
"@babel/traverse" "^7.29.7"
|
|
||||||
|
|
||||||
"@babel/helper-skip-transparent-expression-wrappers@^7.29.7":
|
"@babel/helper-replace-supers@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz#50c95c7e4c4f54936cfa0116428edc559862d551"
|
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-8.0.1.tgz#c9b23aba6b9aff16cacac135052e790cde8d7d5b"
|
||||||
integrity sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==
|
integrity sha512-B1SZADIcy3tmH8CmWvj4SHi/oAPom4UL3uknTc2QRNsPVLFk/sPnZvQL/8kj7Y5omvjMqie0vklvs6XM4OLW5Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/traverse" "^7.29.7"
|
"@babel/helper-member-expression-to-functions" "^8.0.0"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/helper-optimise-call-expression" "^8.0.0"
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-8.0.0.tgz#27a6db3fb4ed17d2b32dbb69c4b30be346d8e8a6"
|
||||||
|
integrity sha512-xmCA9kP3IhySsqhzwIdWGlDN/1A4cCKNBO/uwZx/3YzmDoMePwno2Q5/Bq0q+tYaKbeF940YiKV/kaW8Mzvpjw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/traverse" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/helper-string-parser@^7.29.7":
|
"@babel/helper-string-parser@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
|
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
|
||||||
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
|
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
|
||||||
|
|
||||||
|
"@babel/helper-string-parser@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz#4d47d9ad35d0f5bd7d202b348bf558328a347977"
|
||||||
|
integrity sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@^7.29.7":
|
"@babel/helper-validator-identifier@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
|
||||||
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
|
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^8.0.0":
|
||||||
|
version "8.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz#5527f2e24e5a9f4de7426dca448031749691bb6f"
|
||||||
|
integrity sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==
|
||||||
|
|
||||||
"@babel/helper-validator-option@^7.29.7":
|
"@babel/helper-validator-option@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
|
||||||
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
|
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
|
||||||
|
|
||||||
|
"@babel/helper-validator-option@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz#53307a6882254fa8d940017a701a8f7ec603a1a9"
|
||||||
|
integrity sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==
|
||||||
|
|
||||||
"@babel/helpers@^7.29.7":
|
"@babel/helpers@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
|
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
|
||||||
|
|
@ -210,6 +310,14 @@
|
||||||
"@babel/template" "^7.29.7"
|
"@babel/template" "^7.29.7"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^7.29.7"
|
||||||
|
|
||||||
|
"@babel/helpers@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-8.0.0.tgz#2c612d4b7fdbd5f1d2fa7321015e36b02d1a2d79"
|
||||||
|
integrity sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/template" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.0", "@babel/parser@^7.23.9", "@babel/parser@^7.29.7":
|
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.0", "@babel/parser@^7.23.9", "@babel/parser@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334"
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334"
|
||||||
|
|
@ -217,41 +325,62 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^7.29.7"
|
||||||
|
|
||||||
"@babel/plugin-syntax-jsx@^7.16.7", "@babel/plugin-syntax-jsx@^7.29.7":
|
"@babel/parser@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-8.0.0.tgz#31f6860840277dc1c6d6f8b67bf74e0ccaa5df0a"
|
||||||
|
integrity sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-jsx@^7.16.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz#622c16f9ad63782fe6e83dadc7e40330744b7f1e"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz#622c16f9ad63782fe6e83dadc7e40330744b7f1e"
|
||||||
integrity sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==
|
integrity sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^7.29.7"
|
||||||
|
|
||||||
"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.23.3", "@babel/plugin-syntax-typescript@^7.29.7":
|
"@babel/plugin-syntax-jsx@^8.0.1":
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-8.0.1.tgz#ab457699bd42e3071541fdc2dbade25049f2cc2f"
|
||||||
|
integrity sha512-n0jtCOxEovhU7METqSQjcZO9pX53nu9uNIjMS+hEt+Nt9jA7oOZoBIgbCxhhASmF6T6rPDGge5UAvh6Z4eFz/g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
|
|
||||||
|
"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.23.3":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz#7c29388932313ed58413a0343048d75d92fb5b24"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz#7c29388932313ed58413a0343048d75d92fb5b24"
|
||||||
integrity sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==
|
integrity sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^7.29.7"
|
||||||
|
|
||||||
"@babel/plugin-transform-modules-commonjs@^7.29.7":
|
"@babel/plugin-syntax-typescript@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz#70e6835abf2663dafbe94b8ef1f51de7351ef135"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-8.0.3.tgz#695e5768ff9f2f83289c6dee5b1dc734becd0c59"
|
||||||
integrity sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==
|
integrity sha512-jmTPwps7oSQSZaV1SxkQ3C12UWyufGysGc5OzDpZzvPAIX4mO7dJT3hoqkWVrSImvkcMiknir1iLN1SNV/CZzg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-module-transforms" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
|
||||||
|
|
||||||
"@babel/plugin-transform-react-display-name@^7.29.7":
|
"@babel/plugin-transform-modules-commonjs@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz#bf161a6d750267b79db7ff6f8fb89c3369b02df3"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-8.0.1.tgz#ae8c414da671dc7ac4bb4b502a2714841ab84402"
|
||||||
integrity sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==
|
integrity sha512-PMuzulWrrzFNmY3lXSk/tV9NRb7y0eZZLJY4UEo2TKszroxvUZHAPPi+T9FDyrQhod+TQA+t+8/QYaaMpiEuhA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-module-transforms" "^8.0.1"
|
||||||
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
|
|
||||||
"@babel/plugin-transform-react-jsx-development@^7.29.7":
|
"@babel/plugin-transform-react-display-name@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz#64e6aacb5cb43b9e80d3d5f19ddefc158a624f09"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-8.0.1.tgz#da70220bacd0abcfb3a5fa4af89acde94d891fbc"
|
||||||
integrity sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==
|
integrity sha512-soLishXlkyu6jcICPyO3HEP7A3GCzKEnn7XfvYrImuWEOwFAz93qShmWSYPf5ww0ZkO4By0zsN2bVIDF54fSdA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/plugin-transform-react-jsx" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
|
|
||||||
|
"@babel/plugin-transform-react-jsx-development@^8.0.1":
|
||||||
|
version "8.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-8.0.1.tgz#11fa2b7af26ceaafc47a3cc6e2bd720bba96fc04"
|
||||||
|
integrity sha512-Hb+HUZpV9KFHjm+F+P3aLDMi8QXU9l3ROCQv20z18Me2sGyW5nNNR5YTevNlgHvCpFek3BnAwhDGq/BRndXViw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/plugin-transform-react-jsx" "^8.0.1"
|
||||||
|
|
||||||
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
|
|
@ -267,64 +396,68 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^7.29.7"
|
||||||
|
|
||||||
"@babel/plugin-transform-react-jsx@^7.29.7":
|
"@babel/plugin-transform-react-jsx@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz#3d16a0e5773f079400a8c82a190709cdf92ee204"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-8.0.1.tgz#0b7192bd35e5ca68d1324cd9347f5990f296177f"
|
||||||
integrity sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==
|
integrity sha512-NgkoF7Uq+30TmOPDdNUimT0Nta02uVjqJRFNlVWKrbOCu/CkzfHa4aMnIs0lMpkMmZmWA1e42Va+F04i/pY1zw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||||
"@babel/helper-module-imports" "^7.29.7"
|
"@babel/helper-module-imports" "^8.0.0"
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
"@babel/plugin-syntax-jsx" "^7.29.7"
|
"@babel/plugin-syntax-jsx" "^8.0.1"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/plugin-transform-react-pure-annotations@^7.29.7":
|
"@babel/plugin-transform-react-pure-annotations@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz#76445c90112dd0a7371b63264563bfa9a4fcd6e3"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-8.0.1.tgz#95d5bf8dab5ce0631b320b75ce3c6a6e550c356a"
|
||||||
integrity sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==
|
integrity sha512-7/8UwU8hoPBurXa9tUiTTC8aACTRy5tCqLUtqikHp2eGiWoEB57AduOdbQ71OOMTEvawKrGhv3WfzkDpI+/oSg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
|
|
||||||
"@babel/plugin-transform-typescript@^7.29.7":
|
"@babel/plugin-transform-typescript@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz#f0449c3df7037bbe232043476851c38f5e4a7615"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-8.0.1.tgz#805b11cae5334b4346640286950003c897f24b72"
|
||||||
integrity sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==
|
integrity sha512-0Svqp3413Eg0GElldykF/T7SNsxQO5YVGD70fZyAdZTnX8WRgcopmbiU7GTa5xY5ZnJcEpNbfns8/GjX+/1yeA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||||
"@babel/helper-create-class-features-plugin" "^7.29.7"
|
"@babel/helper-create-class-features-plugin" "^8.0.1"
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.29.7"
|
"@babel/helper-skip-transparent-expression-wrappers" "^8.0.0"
|
||||||
"@babel/plugin-syntax-typescript" "^7.29.7"
|
"@babel/plugin-syntax-typescript" "^8.0.1"
|
||||||
|
|
||||||
"@babel/preset-react@^7.29.7":
|
"@babel/preset-react@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.29.7.tgz#2ed18366e38c2081bbf1760dc01e88fa5674eb17"
|
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-8.0.1.tgz#0cb1802ff37a96faf983b5e781270f2752bb3476"
|
||||||
integrity sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==
|
integrity sha512-jrFuPp/pTddFZbtmWhdLNAYc6UMcpboeUPnw0BBrm4nOmcAko/1TRcFi1PzWCeOFRU+VaSiKmat87W1HvR7mIg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
"@babel/helper-validator-option" "^7.29.7"
|
"@babel/helper-validator-option" "^8.0.0"
|
||||||
"@babel/plugin-transform-react-display-name" "^7.29.7"
|
"@babel/plugin-transform-react-display-name" "^8.0.1"
|
||||||
"@babel/plugin-transform-react-jsx" "^7.29.7"
|
"@babel/plugin-transform-react-jsx" "^8.0.1"
|
||||||
"@babel/plugin-transform-react-jsx-development" "^7.29.7"
|
"@babel/plugin-transform-react-jsx-development" "^8.0.1"
|
||||||
"@babel/plugin-transform-react-pure-annotations" "^7.29.7"
|
"@babel/plugin-transform-react-pure-annotations" "^8.0.1"
|
||||||
|
|
||||||
"@babel/preset-typescript@^7.29.7":
|
"@babel/preset-typescript@^8.0.1":
|
||||||
version "7.29.7"
|
version "8.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz#de9be1f47b785c979ec7b3a71f4cd8bae5267b62"
|
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-8.0.1.tgz#603e709db117e5fafef296de087e8a0a7679a543"
|
||||||
integrity sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==
|
integrity sha512-qrPhQIN1NLrPmzgazF9XKQqXrOcp/WJly+K+6ReFonn24FZqRJO7clxOJo6Ni75L+2vAqI3cHVU2OJLBxoPp5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.29.7"
|
"@babel/helper-plugin-utils" "^8.0.1"
|
||||||
"@babel/helper-validator-option" "^7.29.7"
|
"@babel/helper-validator-option" "^8.0.0"
|
||||||
"@babel/plugin-syntax-jsx" "^7.29.7"
|
"@babel/plugin-transform-modules-commonjs" "^8.0.1"
|
||||||
"@babel/plugin-transform-modules-commonjs" "^7.29.7"
|
"@babel/plugin-transform-typescript" "^8.0.1"
|
||||||
"@babel/plugin-transform-typescript" "^7.29.7"
|
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.29.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
|
"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768"
|
||||||
integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==
|
integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==
|
||||||
|
|
||||||
|
"@babel/runtime@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-8.0.0.tgz#d7bd513e6843662346552c2798ab895716cf97f2"
|
||||||
|
integrity sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw==
|
||||||
|
|
||||||
"@babel/template@^7.29.7":
|
"@babel/template@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
|
||||||
|
|
@ -334,6 +467,15 @@
|
||||||
"@babel/parser" "^7.29.7"
|
"@babel/parser" "^7.29.7"
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^7.29.7"
|
||||||
|
|
||||||
|
"@babel/template@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-8.0.0.tgz#18c12626b0d6d23a0443771655864ed7566a3452"
|
||||||
|
integrity sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^8.0.0"
|
||||||
|
"@babel/parser" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
|
||||||
"@babel/traverse@^7.29.7":
|
"@babel/traverse@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d"
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d"
|
||||||
|
|
@ -347,6 +489,19 @@
|
||||||
"@babel/types" "^7.29.7"
|
"@babel/types" "^7.29.7"
|
||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
|
|
||||||
|
"@babel/traverse@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-8.0.0.tgz#0473589140c796d13e27641ab0783069f0fe7512"
|
||||||
|
integrity sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^8.0.0"
|
||||||
|
"@babel/generator" "^8.0.0"
|
||||||
|
"@babel/helper-globals" "^8.0.0"
|
||||||
|
"@babel/parser" "^8.0.0"
|
||||||
|
"@babel/template" "^8.0.0"
|
||||||
|
"@babel/types" "^8.0.0"
|
||||||
|
obug "^2.1.1"
|
||||||
|
|
||||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.28.2", "@babel/types@^7.29.7":
|
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.28.2", "@babel/types@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
|
||||||
|
|
@ -355,6 +510,14 @@
|
||||||
"@babel/helper-string-parser" "^7.29.7"
|
"@babel/helper-string-parser" "^7.29.7"
|
||||||
"@babel/helper-validator-identifier" "^7.29.7"
|
"@babel/helper-validator-identifier" "^7.29.7"
|
||||||
|
|
||||||
|
"@babel/types@^8.0.0":
|
||||||
|
version "8.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-8.0.0.tgz#b518f1ef7f9838bffdca4e123b449d3f644f4494"
|
||||||
|
integrity sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-string-parser" "^8.0.0"
|
||||||
|
"@babel/helper-validator-identifier" "^8.0.0"
|
||||||
|
|
||||||
"@codecov/bundler-plugin-core@^2.0.1":
|
"@codecov/bundler-plugin-core@^2.0.1":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@codecov/bundler-plugin-core/-/bundler-plugin-core-2.0.1.tgz#bdbeb575339a25b330178154eee6df9dcb01f31e"
|
resolved "https://registry.yarnpkg.com/@codecov/bundler-plugin-core/-/bundler-plugin-core-2.0.1.tgz#bdbeb575339a25b330178154eee6df9dcb01f31e"
|
||||||
|
|
@ -731,9 +894,9 @@
|
||||||
integrity sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==
|
integrity sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==
|
||||||
|
|
||||||
"@flakiness/playwright@^1.13.0":
|
"@flakiness/playwright@^1.13.0":
|
||||||
version "1.16.0"
|
version "1.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/@flakiness/playwright/-/playwright-1.16.0.tgz#55c30aa8a82196615bfb58556a9213c92c28657f"
|
resolved "https://registry.yarnpkg.com/@flakiness/playwright/-/playwright-1.17.0.tgz#37c949cef8a20c7252ea236458bbdf3f672a464a"
|
||||||
integrity sha512-w1mEHd9UyyhfaZtd1ptschPR/C1rUlv1hjJvein9GRsL81vRyObSz7E4t1fNljDrJIymaEQypBLMM1d/Qqm/0A==
|
integrity sha512-RJcCWinnkhJoEPfDZZmUF+v1DP2ZyqEF4TpdoDoHrrpbI1EhcH0qjXd79QU1sxI+ST5+Q+U+e+Vu3H+1CXk9Xg==
|
||||||
|
|
||||||
"@floating-ui/core@^1.7.5":
|
"@floating-ui/core@^1.7.5":
|
||||||
version "1.7.5"
|
version "1.7.5"
|
||||||
|
|
@ -1220,9 +1383,9 @@
|
||||||
"@octokit/types" "^16.0.0"
|
"@octokit/types" "^16.0.0"
|
||||||
|
|
||||||
"@octokit/request@^10.0.6", "@octokit/request@^10.0.7":
|
"@octokit/request@^10.0.6", "@octokit/request@^10.0.7":
|
||||||
version "10.0.10"
|
version "10.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-10.0.10.tgz#45e46934f3d772f006733be6b5ec18f22e54a00c"
|
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-10.0.11.tgz#a11d8b9bae5f6e868efb7dea946edd855ebb2549"
|
||||||
integrity sha512-KxNC2pTqqhszMNrf12ZRd4PonRgyJdsM4F/jySiddQK+DsRcfBtUvqn8t7UsyZhnRJHvX46OohDt5N3VqIWC2w==
|
integrity sha512-+s7HUxjfFqOMS9VlIwDffq0MikjSAK0gSpG73W+meAvVAvX4MBrHYTK5Bj3Uot55qFT4gzUtfzE4mGWY4Br8/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@octokit/endpoint" "^11.0.3"
|
"@octokit/endpoint" "^11.0.3"
|
||||||
"@octokit/request-error" "^7.0.2"
|
"@octokit/request-error" "^7.0.2"
|
||||||
|
|
@ -1401,59 +1564,59 @@
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz#3671ce3f9b928d5c01f879792d5c0b60ae14d4ad"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz#3671ce3f9b928d5c01f879792d5c0b60ae14d4ad"
|
||||||
integrity sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==
|
integrity sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==
|
||||||
|
|
||||||
"@sentry/browser-utils@10.62.0":
|
"@sentry/browser-utils@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/browser-utils/-/browser-utils-10.62.0.tgz#b75ff44f77980744bafd2fa94642c00c23b84c2b"
|
resolved "https://registry.yarnpkg.com/@sentry/browser-utils/-/browser-utils-10.63.0.tgz#1cc79923d35be2213d7f7d872642f3fda9fa5f15"
|
||||||
integrity sha512-mS9HVVuWIdye9o0xUGFmzNOBqktF4n5kugrF8NCOYYDrr5ZV8Cx7BlquHQn5UpCeViVhZtcDlEm4iOK7++Px7A==
|
integrity sha512-DhUGNN+CH8fzAs6qAsueKPU70qShyTX3NxLhIP+l5DbGXDSXpYXBT6s8ubZus0/LhxpLvI0iSyNIDvZRD/gZaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
|
|
||||||
"@sentry/browser@10.62.0":
|
"@sentry/browser@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-10.62.0.tgz#9bf41b5cfaafcdf75970475a72a883c03bde76a7"
|
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-10.63.0.tgz#145400e655bb524561d5503c9f211d32ad3e876e"
|
||||||
integrity sha512-uJi0yPssB3Nt/cZ8/S8opW42gaM59/6IyNtPFYD7C0ciudi/nIo5QMVpCYBBI3jnKFOIQLlsMT4pDlOLuxxNuQ==
|
integrity sha512-0mi56YOkwgyjdLOcN5cB1//EcYzEOt3NZ2GLygE92B3zAAwVM1WgbmibZCXToKFClH7z1uH3VWVfBffmkwIMYw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/browser-utils" "10.62.0"
|
"@sentry/browser-utils" "10.63.0"
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
"@sentry/feedback" "10.62.0"
|
"@sentry/feedback" "10.63.0"
|
||||||
"@sentry/replay" "10.62.0"
|
"@sentry/replay" "10.63.0"
|
||||||
"@sentry/replay-canvas" "10.62.0"
|
"@sentry/replay-canvas" "10.63.0"
|
||||||
|
|
||||||
"@sentry/core@10.62.0":
|
"@sentry/core@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.62.0.tgz#73a4a8bcdded6d741d6cf58bfd055c1b60b3fe10"
|
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.63.0.tgz#8c37016a70c25f22258f7cb3c0f71f931a78fd4e"
|
||||||
integrity sha512-tV69fMg2sS5DUFmQSnS7Jd5qJAp0izxwcsvBVz2ieTM9VMRi99IfOSYW9UYr3p1yfuksk41kefN5PEbeedUE+A==
|
integrity sha512-OtUbsrnbEHffOF2S2+M5zXa3HIM0U2b4CDVLKMY1dgS0J3ivRF8XvkjvyIcEG/y8JXnwXbnprLyjhG+AqMdUZQ==
|
||||||
|
|
||||||
"@sentry/feedback@10.62.0":
|
"@sentry/feedback@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/feedback/-/feedback-10.62.0.tgz#440bfb5690be9c70ec1edb2291a08ed3f98c8d36"
|
resolved "https://registry.yarnpkg.com/@sentry/feedback/-/feedback-10.63.0.tgz#030801b9655fd0d3beadf26e12db286bfab615ff"
|
||||||
integrity sha512-d0BVjJVny6qpBgGJgWL0fbcoQHjtD3z3R8EK/KzTS3RO92JX5n3A536n5D/rh0gZFgcIwiUzBXegmyPOSQn9ng==
|
integrity sha512-If/+72xFg9ylz4twUo3U9gUpZ+Ys+T/3Y09WH7r2gGhWEOF9bp+ta94+Pg7Lb0M2nVD7waz4OxIvB49GEvtLDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
|
|
||||||
"@sentry/react@^10.57.0":
|
"@sentry/react@^10.57.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-10.62.0.tgz#0ea654b9f7080d183b5b223ac2295fe3449b5a0d"
|
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-10.63.0.tgz#f17b6c505ba819d7527ce009543922bf434c6a72"
|
||||||
integrity sha512-PChimVpY0wzs3H/hJqyl87/ITTHwIZWTSY68QoENZyLnp7DvLcFiZYub/gFws1pzDPhtIQXVLU72fbmUjT5PSg==
|
integrity sha512-+/Y0dd4EMqyqYBJ1D3bAYYuG+ccIx5+IFcbTZ9p+XWnW6nNIVjy5zttVftYo6xOmtTQbzRuPT/vO4dqDHKKmfw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/browser" "10.62.0"
|
"@sentry/browser" "10.63.0"
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
|
|
||||||
"@sentry/replay-canvas@10.62.0":
|
"@sentry/replay-canvas@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/replay-canvas/-/replay-canvas-10.62.0.tgz#0ce22ef5786b7d012c3003dc2289d86d12ea1dc0"
|
resolved "https://registry.yarnpkg.com/@sentry/replay-canvas/-/replay-canvas-10.63.0.tgz#754631d8c0773914847f59f97e8fe166ecbe876d"
|
||||||
integrity sha512-CzPAxmpe5US/ABGA1TzpjFKOFZN5uqlzrRh/uM9/daVuzLVKIAQ0XRNxo/PPEXvlDm/PoMdI5L0qIODuIKnyyw==
|
integrity sha512-1Dg6yo+KDNZcE9M6V2EP4DGgTDJMcUgg5ui69w/E96ZZPWErS/bibK2bGj20H3qwpJXlnEwXB5YAJ2fZ620T1A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
"@sentry/replay" "10.62.0"
|
"@sentry/replay" "10.63.0"
|
||||||
|
|
||||||
"@sentry/replay@10.62.0":
|
"@sentry/replay@10.63.0":
|
||||||
version "10.62.0"
|
version "10.63.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-10.62.0.tgz#66455f7c02b227244b02a78523b7578d339531de"
|
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-10.63.0.tgz#014c1be7110eb86d6e6fe148c691130094539460"
|
||||||
integrity sha512-rWp4hBhZOmdQhisxcKzAwTGiRk/LvWnNaElWe7nbRhjsM/usp2095yfjq4iJ47v9MtO7xxY6eUz++fLBycqXKg==
|
integrity sha512-u4fDaLbd4QmJbU0qGzV5g2B2hjw5utdeZzpTrmq565AS5o6mfaZdCz30zF9R2Unkn0g9SJr90piTN2RMwvDrkw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/browser-utils" "10.62.0"
|
"@sentry/browser-utils" "10.63.0"
|
||||||
"@sentry/core" "10.62.0"
|
"@sentry/core" "10.63.0"
|
||||||
|
|
||||||
"@sinclair/typebox@^0.27.8":
|
"@sinclair/typebox@^0.27.8":
|
||||||
version "0.27.10"
|
version "0.27.10"
|
||||||
|
|
@ -1783,6 +1946,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
|
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
|
||||||
integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
|
integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
|
||||||
|
|
||||||
|
"@types/gensync@^1.0.5":
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/gensync/-/gensync-1.0.5.tgz#1819eba537d036dcf4ec7e8c8f15fbfe938e99a0"
|
||||||
|
integrity sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==
|
||||||
|
|
||||||
"@types/history@^4.7.11":
|
"@types/history@^4.7.11":
|
||||||
version "4.7.11"
|
version "4.7.11"
|
||||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
|
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
|
||||||
|
|
@ -1807,10 +1975,15 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
|
"@types/jsesc@^2.5.0":
|
||||||
|
version "2.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/jsesc/-/jsesc-2.5.1.tgz#c34defc608ec94b68dc6a12a581b440942c6d503"
|
||||||
|
integrity sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "26.0.1"
|
version "26.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.0.1.tgz#4a60e2c7a6d68bd261e265f8983bfe1601263ce3"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.1.0.tgz#aa85f0727fc5611347091c478341c63650903439"
|
||||||
integrity sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==
|
integrity sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~8.3.0"
|
undici-types "~8.3.0"
|
||||||
|
|
||||||
|
|
@ -1969,9 +2142,9 @@
|
||||||
vite-node "^3.2.2 || ^5.0.0 || ^6.0.0"
|
vite-node "^3.2.2 || ^5.0.0 || ^6.0.0"
|
||||||
|
|
||||||
"@vanilla-extract/css@^1.20.1":
|
"@vanilla-extract/css@^1.20.1":
|
||||||
version "1.21.0"
|
version "1.21.1"
|
||||||
resolved "https://registry.yarnpkg.com/@vanilla-extract/css/-/css-1.21.0.tgz#cb73abc0b25b7f28cd629b9ae386b010d5b5cf30"
|
resolved "https://registry.yarnpkg.com/@vanilla-extract/css/-/css-1.21.1.tgz#11ddf605b85279511cff801c571ab816cae0681f"
|
||||||
integrity sha512-lqdRtP622Z85RprHlJemV5+ipdi+g48J115LaL8nrI64iixIp4SWPlvAEPf3o9pwEZaZPb5/ZfRwiXLE4p3+kQ==
|
integrity sha512-T6z6oeT+o0OwqukE6kLs9w5ooB75b8NPRadyU9pPTml83l40TPN+mscPt2OQ9P9cYfwEBMfsfivwiJujs2mzmg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/hash" "^0.9.0"
|
"@emotion/hash" "^0.9.0"
|
||||||
"@vanilla-extract/private" "^1.0.9"
|
"@vanilla-extract/private" "^1.0.9"
|
||||||
|
|
@ -2014,7 +2187,7 @@
|
||||||
"@vanilla-extract/compiler" "^0.7.0"
|
"@vanilla-extract/compiler" "^0.7.0"
|
||||||
"@vanilla-extract/integration" "^8.0.10"
|
"@vanilla-extract/integration" "^8.0.10"
|
||||||
|
|
||||||
"@vitejs/plugin-react@^5.2.0":
|
"@vitejs/plugin-react@^5":
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz#108bd0f566f288ce3566982df4eff137ded7b15f"
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz#108bd0f566f288ce3566982df4eff137ded7b15f"
|
||||||
integrity sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==
|
integrity sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==
|
||||||
|
|
@ -2159,9 +2332,9 @@ base64-js@^1.3.1:
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
baseline-browser-mapping@^2.10.38:
|
baseline-browser-mapping@^2.10.38:
|
||||||
version "2.10.40"
|
version "2.10.41"
|
||||||
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz#f372c8eb36ff4ad0b5e7ae467014abef124554ba"
|
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.41.tgz#86738e4aafb4392a32672642ddd092c0c2f80161"
|
||||||
integrity sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==
|
integrity sha512-WwS7MHhqGHHlaVsqRZnhvCEMS0owDX+SxRlve7JkuH7My1Ara3ZriTmCQupPfYjxMZ8I/tgxtJYr2t7taHaH4A==
|
||||||
|
|
||||||
before-after-hook@^4.0.0:
|
before-after-hook@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|
@ -2259,9 +2432,9 @@ camelize@^1.0.0:
|
||||||
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
|
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001799:
|
caniuse-lite@^1.0.30001799:
|
||||||
version "1.0.30001799"
|
version "1.0.30001800"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz#b896c773e1c39400809415162bb5320371291b36"
|
||||||
integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==
|
integrity sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==
|
||||||
|
|
||||||
chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0:
|
chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
|
|
@ -2637,9 +2810,9 @@ dunder-proto@^1.0.1:
|
||||||
gopd "^1.2.0"
|
gopd "^1.2.0"
|
||||||
|
|
||||||
electron-to-chromium@^1.5.376:
|
electron-to-chromium@^1.5.376:
|
||||||
version "1.5.381"
|
version "1.5.385"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.381.tgz#037549001adc80e04834ede96dc52a1fbf6c9fde"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.385.tgz#fbb900d4ddde6fab4651f37de6c1659a070bc68d"
|
||||||
integrity sha512-n9Wa6yB+vDsGuA8AKbl/0z7HbvWqt5jxIdvr1IUicd0ryPrk7/xzwqLv8D9AbbvZ6avVNtXYLTfmgFHkwkyelg==
|
integrity sha512-78sa/M08MNAYHQfjoWMvOlKQqZ0ElhSm/L5HNUc96VZ3b+KvDVnngFm8sYQy0XrhTRgAhggHr5abA7yTvRdo4Q==
|
||||||
|
|
||||||
embla-carousel-react@^8.6.0:
|
embla-carousel-react@^8.6.0:
|
||||||
version "8.6.0"
|
version "8.6.0"
|
||||||
|
|
@ -2664,6 +2837,11 @@ emoji-regex@^8.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||||
|
|
||||||
|
empathic@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/empathic/-/empathic-2.0.1.tgz#37b1bede31093e04a03d2abce95ea323fee8ef49"
|
||||||
|
integrity sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==
|
||||||
|
|
||||||
error-ex@^1.3.1:
|
error-ex@^1.3.1:
|
||||||
version "1.3.4"
|
version "1.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
|
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
|
||||||
|
|
@ -2687,9 +2865,9 @@ es-module-lexer@^0.4.1:
|
||||||
integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==
|
integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==
|
||||||
|
|
||||||
es-module-lexer@^2.0.0:
|
es-module-lexer@^2.0.0:
|
||||||
version "2.2.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.2.0.tgz#fe824f12e3f28bde741bb572b5a182786eaf3764"
|
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.3.0.tgz#fda770234c345064c122eb905e1c4200ffa4ce7e"
|
||||||
integrity sha512-3lGxdTXCLfe1MYfTz1y2ksAAUM4NAOP6rPEjxGJVKO7TZ5+tvHCaQWGpC4Y3IXvW3ece0Cz1cIP4FWBxOnGCTQ==
|
integrity sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==
|
||||||
|
|
||||||
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
|
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
|
|
@ -3064,15 +3242,10 @@ ieee754@^1.1.13:
|
||||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
|
|
||||||
immer@^10.1.1:
|
immer@^11.0.0, immer@^11.1.8:
|
||||||
version "10.2.0"
|
version "11.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/immer/-/immer-10.2.0.tgz#88a4ce06a1af64172d254b70f7cb04df51c871b1"
|
resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.9.tgz#e0ce69359d29cafdb14fc5b6d2cd56f826097966"
|
||||||
integrity sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==
|
integrity sha512-sc/z0Cyti70bZa0ZU4sWfAElfovFb9Ni8tArJZLuklYWxegPiK3pDOql1Rq5H0FIRAW9LSQRG6OX4KqBldbhBA==
|
||||||
|
|
||||||
immer@^11.0.0:
|
|
||||||
version "11.1.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.8.tgz#08a6426f7019dbce8d6dff8c4a43bb25c550a575"
|
|
||||||
integrity sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==
|
|
||||||
|
|
||||||
import-fresh@^3.2.1, import-fresh@^3.3.0:
|
import-fresh@^3.2.1, import-fresh@^3.3.0:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
|
|
@ -3082,6 +3255,11 @@ import-fresh@^3.2.1, import-fresh@^3.3.0:
|
||||||
parent-module "^1.0.0"
|
parent-module "^1.0.0"
|
||||||
resolve-from "^4.0.0"
|
resolve-from "^4.0.0"
|
||||||
|
|
||||||
|
import-meta-resolve@^4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz#08cb85b5bd37ecc8eb1e0f670dc2767002d43734"
|
||||||
|
integrity sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==
|
||||||
|
|
||||||
imurmurhash@^0.1.4:
|
imurmurhash@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||||
|
|
@ -3275,6 +3453,11 @@ js-sha256@^0.10.1:
|
||||||
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.10.1.tgz#b40104ba1368e823fdd5f41b66b104b15a0da60d"
|
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.10.1.tgz#b40104ba1368e823fdd5f41b66b104b15a0da60d"
|
||||||
integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==
|
integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==
|
||||||
|
|
||||||
|
js-tokens@^10.0.0:
|
||||||
|
version "10.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-10.0.0.tgz#dffe7599b4a8bb7fe30aff8d0235234dffb79831"
|
||||||
|
integrity sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
|
@ -3771,9 +3954,9 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
|
||||||
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
|
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
|
||||||
|
|
||||||
picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4:
|
picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4:
|
||||||
version "4.0.4"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.5.tgz#51ea57a17d86f605f81039595fbc40ed06a55fab"
|
||||||
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
|
integrity sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==
|
||||||
|
|
||||||
pkg-dir@^4.1.0:
|
pkg-dir@^4.1.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
|
|
@ -3978,9 +4161,9 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor
|
||||||
prosemirror-model "^1.21.0"
|
prosemirror-model "^1.21.0"
|
||||||
|
|
||||||
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.41.4, prosemirror-view@^1.41.8:
|
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.41.4, prosemirror-view@^1.41.8:
|
||||||
version "1.41.9"
|
version "1.42.0"
|
||||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.41.9.tgz#e756493e7116f7df7c73aaf050f60871cab42100"
|
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.42.0.tgz#82ed0823a1bf971d27cb647f3a23d5e005d04c00"
|
||||||
integrity sha512-clTunTX+eaLbr87L1V1QPheRlEQJyTlL3gXe9x3jQIk3rL0RVWxviDGz8tFaydwIVm+hKhYCyr+R/zBtWr9s6A==
|
integrity sha512-N54DF3OXNWDuP81G1kbfCys8ZzIjuL1VnvJ2mk5STSu/fNxWIcX/EutQLA3s9KR/2wVhgDi4hzBB/1fINVxk0A==
|
||||||
dependencies:
|
dependencies:
|
||||||
prosemirror-model "^1.25.8"
|
prosemirror-model "^1.25.8"
|
||||||
prosemirror-state "^1.0.0"
|
prosemirror-state "^1.0.0"
|
||||||
|
|
@ -4191,16 +4374,16 @@ readdirp@~3.5.0:
|
||||||
picomatch "^2.2.1"
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
recharts@^3.8.1:
|
recharts@^3.8.1:
|
||||||
version "3.9.0"
|
version "3.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/recharts/-/recharts-3.9.0.tgz#b78a4822d1b1805a7529a9e8a82f7a043e94c3c9"
|
resolved "https://registry.yarnpkg.com/recharts/-/recharts-3.9.1.tgz#6fe1b4617147e2016fa6f4cd681c8c818255955e"
|
||||||
integrity sha512-dCEcE9y20c8H2tkVeByrAXhhnBJk6/QLbxKmn+dJUptOfc5NMjwRh1jo0vZPRLD+5dMrHrP+hPEsfbGBMfnf5Q==
|
integrity sha512-WMcwlXcB7l+BbxiEdyClkG+1sxrMHNZpzT577LEvU4+rXPd8oTAy1wXk72hnk2KOOmxuLvw3z5DtXT7HEAydtg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@reduxjs/toolkit" "^1.9.0 || 2.x.x"
|
"@reduxjs/toolkit" "^1.9.0 || 2.x.x"
|
||||||
clsx "^2.1.1"
|
clsx "^2.1.1"
|
||||||
decimal.js-light "^2.5.1"
|
decimal.js-light "^2.5.1"
|
||||||
es-toolkit "^1.39.3"
|
es-toolkit "^1.39.3"
|
||||||
eventemitter3 "^5.0.1"
|
eventemitter3 "^5.0.1"
|
||||||
immer "^10.1.1"
|
immer "^11.1.8"
|
||||||
react-redux "8.x.x || 9.x.x"
|
react-redux "8.x.x || 9.x.x"
|
||||||
reselect "5.2.0"
|
reselect "5.2.0"
|
||||||
tiny-invariant "^1.3.3"
|
tiny-invariant "^1.3.3"
|
||||||
|
|
@ -4353,7 +4536,7 @@ semver@^6.0.0, semver@^6.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||||
|
|
||||||
semver@^7.5.3, semver@^7.5.4:
|
semver@^7.5.3, semver@^7.5.4, semver@^7.7.3:
|
||||||
version "7.8.5"
|
version "7.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
|
||||||
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
|
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
|
||||||
|
|
@ -4654,9 +4837,9 @@ undici@^6.23.0, undici@^6.24.0:
|
||||||
integrity sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==
|
integrity sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==
|
||||||
|
|
||||||
undici@^8.4.1:
|
undici@^8.4.1:
|
||||||
version "8.5.0"
|
version "8.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/undici/-/undici-8.5.0.tgz#31ba9021a3d84c15e61cc5e28be2d7c451e66a66"
|
resolved "https://registry.yarnpkg.com/undici/-/undici-8.6.0.tgz#1595d019e47c8c9c3c62ce22685fb4b6c094f4ea"
|
||||||
integrity sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==
|
integrity sha512-l2FlC6I510GawyEd1qgcE/okihKrzy+BRTEBlu6T0fdbM9m5yxtIH5Oa3ysRsH0zC4EhmWUEaSDsy2QngBeRlw==
|
||||||
|
|
||||||
universal-user-agent@^7.0.0, universal-user-agent@^7.0.2:
|
universal-user-agent@^7.0.0, universal-user-agent@^7.0.2:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue