diff --git a/package-lock.json b/package-lock.json
index cea77cb..c5b7c7c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,12 +16,12 @@
"@mui/material": "^9.4.0",
"@shopify/draggable": "^1.2.1",
"dashgui": "file:../dashgui",
- "eslint": "^10.11.0",
"jsbarcode": "^3.12.3",
"notistack": "^3.0.2",
"pdfconvert-wasm": "^0.3.0",
"react": "^19.3.0",
"react-automat": "file:../automat",
+ "react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor",
"react-dom": "^19.3.0",
"react-router-dom": "^7.18.4",
"sortablejs": "^1.15.7",
@@ -30,6 +30,7 @@
"devDependencies": {
"@eslint/js": "^10.0.1",
"@vitejs/plugin-react": "6.1.1",
+ "eslint": "^10.11.0",
"eslint-plugin-react-hooks": "^7.1.1",
"globals": "^17.12.0",
"qrcode": "^1.5.4",
@@ -1620,6 +1621,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz",
"integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@cacheable/utils": "^2.5.0",
@@ -1632,12 +1634,23 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz",
"integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"hashery": "^1.5.1",
"keyv": "^5.6.0"
}
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz",
+ "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
@@ -1788,6 +1801,7 @@
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz",
"integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.4.3"
@@ -1806,6 +1820,7 @@
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -1818,6 +1833,7 @@
"version": "4.12.2",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
"integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
@@ -1827,6 +1843,7 @@
"version": "0.23.5",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
"integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/object-schema": "^3.0.5",
@@ -1841,6 +1858,7 @@
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz",
"integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^1.2.1"
@@ -1853,6 +1871,7 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
"integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
@@ -1886,6 +1905,7 @@
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
"integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
@@ -1895,6 +1915,7 @@
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz",
"integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^1.2.1",
@@ -1908,6 +1929,7 @@
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
"integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanfs/types": "^0.15.0"
@@ -1920,6 +1942,7 @@
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
"integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanfs/core": "^0.19.2",
@@ -1934,6 +1957,7 @@
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
"integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
@@ -1943,6 +1967,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=12.22"
@@ -1956,6 +1981,7 @@
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
"integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
@@ -1965,6 +1991,554 @@
"url": "https://github.com/sponsors/nzakas"
}
},
+ "node_modules/@img/colour": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
+ "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz",
+ "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz",
+ "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-freebsd-wasm32": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz",
+ "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.5"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz",
+ "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz",
+ "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz",
+ "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz",
+ "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz",
+ "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz",
+ "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz",
+ "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz",
+ "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz",
+ "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz",
+ "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz",
+ "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==",
+ "cpu": [
+ "arm"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz",
+ "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz",
+ "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-riscv64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz",
+ "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-riscv64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz",
+ "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz",
+ "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz",
+ "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz",
+ "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz",
+ "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==",
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.11.3"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-webcontainers-wasm32": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz",
+ "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@img/sharp-wasm32": "0.35.5"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz",
+ "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz",
+ "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz",
+ "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
@@ -2051,6 +2625,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz",
"integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"hashery": "^1.4.0",
@@ -2067,6 +2642,7 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz",
"integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@mui/core-downloads-tracker": {
@@ -3157,18 +3733,21 @@
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
"integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/parse-json": {
@@ -3250,6 +3829,7 @@
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
"integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
+ "dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -3262,6 +3842,7 @@
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -3271,6 +3852,7 @@
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
"integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
@@ -3287,7 +3869,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -3297,7 +3878,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
@@ -3452,11 +4032,32 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/baseline-browser-mapping": {
"version": "2.11.25",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz",
@@ -3470,10 +4071,22 @@
"node": ">=6.0.0"
}
},
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@@ -3516,6 +4129,30 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -3527,6 +4164,7 @@
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz",
"integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@cacheable/memory": "^2.2.0",
@@ -3599,7 +4237,6 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -3626,11 +4263,30 @@
],
"license": "CC-BY-4.0"
},
+ "node_modules/canvas": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.2.3.tgz",
+ "integrity": "sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "node-addon-api": "^7.0.0",
+ "prebuild-install": "^7.1.3"
+ },
+ "engines": {
+ "node": "^18.12.0 || >= 20.9.0"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "license": "ISC"
+ },
"node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
@@ -3651,7 +4307,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
@@ -3664,7 +4319,6 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
"license": "MIT"
},
"node_modules/commander": {
@@ -3749,6 +4403,7 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -3854,16 +4509,40 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
"license": "MIT"
},
"node_modules/deepmerge": {
@@ -3916,7 +4595,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -3926,7 +4604,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
- "dev": true,
"license": "MIT"
},
"node_modules/dom-helpers": {
@@ -3981,9 +4658,17 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
@@ -4176,6 +4861,7 @@
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.11.0.tgz",
"integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==",
+ "dev": true,
"license": "MIT",
"workspaces": [
"packages/*"
@@ -4254,6 +4940,7 @@
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
"integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
+ "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@types/esrecurse": "^4.3.1",
@@ -4272,6 +4959,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
"integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
@@ -4284,6 +4972,7 @@
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
"integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
+ "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.16.0",
@@ -4301,6 +4990,7 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
@@ -4313,6 +5003,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
@@ -4325,6 +5016,7 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
@@ -4341,6 +5033,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
@@ -4359,22 +5052,34 @@
"url": "https://github.com/bgub/eta?sponsor=1"
}
},
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "license": "(MIT OR WTFPL)",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
"license": "MIT"
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
@@ -4416,6 +5121,7 @@
"version": "11.1.5",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz",
"integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"flat-cache": "^6.1.23"
@@ -4471,6 +5177,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"locate-path": "^6.0.0",
@@ -4487,6 +5194,7 @@
"version": "6.1.23",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz",
"integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"cacheable": "^2.5.0",
@@ -4498,6 +5206,7 @@
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
"integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
+ "dev": true,
"license": "ISC"
},
"node_modules/for-each": {
@@ -4533,6 +5242,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "license": "MIT"
+ },
"node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
@@ -4631,7 +5346,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
@@ -4701,6 +5415,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+ "license": "MIT"
+ },
"node_modules/glob": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
@@ -4730,6 +5450,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
@@ -4872,6 +5593,7 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz",
"integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"hookified": "^1.15.0"
@@ -4928,6 +5650,7 @@
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz",
"integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/idb": {
@@ -4937,10 +5660,31 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
@@ -4966,11 +5710,24 @@
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.19"
}
},
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -5146,6 +5903,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5171,7 +5929,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5201,6 +5958,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -5448,6 +6206,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
"license": "ISC"
},
"node_modules/jackspeak": {
@@ -5518,12 +6277,14 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
"license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/json5": {
@@ -5566,6 +6327,7 @@
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
"integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@keyv/serialize": "^1.1.1"
@@ -5585,6 +6347,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1",
@@ -5877,6 +6640,7 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"p-locate": "^5.0.0"
@@ -5937,10 +6701,23 @@
"node": ">= 0.4"
}
},
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/minimatch": {
"version": "10.2.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
"integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.8"
@@ -5952,6 +6729,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@@ -5962,6 +6748,12 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -5987,10 +6779,47 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/napi-build-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+ "license": "MIT"
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-abi": {
+ "version": "3.96.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.96.0.tgz",
+ "integrity": "sha512-rebQ/lz7i0EkoLzUVSrKRzA69zMkwLp95kKMWoMDkkM00Suxz0D7zEQPwRml5fQum24mj7bPvmlgLAmu2JCiYg==",
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-abi/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"license": "MIT"
},
"node_modules/node-releases": {
@@ -6087,10 +6916,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"deep-is": "^0.1.3",
@@ -6127,6 +6966,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
@@ -6142,6 +6982,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"p-limit": "^3.0.2"
@@ -6157,7 +6998,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6213,6 +7053,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6289,7 +7130,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10.13.0"
@@ -6334,10 +7174,38 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/prebuild-install": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+ "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+ "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^2.0.0",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.8.0"
@@ -6373,10 +7241,21 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -6386,6 +7265,7 @@
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz",
"integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"hookified": "^2.1.1"
@@ -6398,13 +7278,13 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz",
"integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
@@ -6418,6 +7298,21 @@
"node": ">=10.13.0"
}
},
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
"node_modules/react": {
"version": "19.3.0",
"resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz",
@@ -6431,6 +7326,20 @@
"resolved": "../automat",
"link": true
},
+ "node_modules/react-canvas-label-editor": {
+ "version": "18.0.0",
+ "resolved": "git+ssh://git@github.com/sebseb7/react-canvas-label-editor.git#7f0e31b66ff22da011e872b201017398b14e9dd9",
+ "dependencies": {
+ "canvas": "^3.2.3",
+ "jsbarcode": "^3.12.3",
+ "qrcode": "^1.5.4",
+ "sharp": "^0.35.3"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/react-dom": {
"version": "19.3.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz",
@@ -6503,6 +7412,20 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -6609,7 +7532,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6629,7 +7551,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true,
"license": "ISC"
},
"node_modules/resolve": {
@@ -6762,6 +7683,26 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/safe-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@@ -6827,7 +7768,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
- "dev": true,
"license": "ISC"
},
"node_modules/set-cookie-parser": {
@@ -6885,10 +7825,72 @@
"node": ">= 0.4"
}
},
+ "node_modules/sharp": {
+ "version": "0.35.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz",
+ "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@img/colour": "^1.1.0",
+ "detect-libc": "^2.1.2",
+ "semver": "^7.8.5"
+ },
+ "engines": {
+ "node": ">=20.9.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.35.5",
+ "@img/sharp-darwin-x64": "0.35.5",
+ "@img/sharp-freebsd-wasm32": "0.35.5",
+ "@img/sharp-libvips-darwin-arm64": "1.3.4",
+ "@img/sharp-libvips-darwin-x64": "1.3.4",
+ "@img/sharp-libvips-linux-arm": "1.3.4",
+ "@img/sharp-libvips-linux-arm64": "1.3.4",
+ "@img/sharp-libvips-linux-ppc64": "1.3.4",
+ "@img/sharp-libvips-linux-riscv64": "1.3.4",
+ "@img/sharp-libvips-linux-s390x": "1.3.4",
+ "@img/sharp-libvips-linux-x64": "1.3.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.3.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.3.4",
+ "@img/sharp-linux-arm": "0.35.5",
+ "@img/sharp-linux-arm64": "0.35.5",
+ "@img/sharp-linux-ppc64": "0.35.5",
+ "@img/sharp-linux-riscv64": "0.35.5",
+ "@img/sharp-linux-s390x": "0.35.5",
+ "@img/sharp-linux-x64": "0.35.5",
+ "@img/sharp-linuxmusl-arm64": "0.35.5",
+ "@img/sharp-linuxmusl-x64": "0.35.5",
+ "@img/sharp-webcontainers-wasm32": "0.35.5",
+ "@img/sharp-win32-arm64": "0.35.5",
+ "@img/sharp-win32-ia32": "0.35.5",
+ "@img/sharp-win32-x64": "0.35.5"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sharp/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -6901,6 +7903,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6995,6 +7998,51 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
"node_modules/smob": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz",
@@ -7065,11 +8113,19 @@
"node": ">= 0.4"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -7187,7 +8243,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
@@ -7206,6 +8261,15 @@
"node": ">=10"
}
},
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
@@ -7224,6 +8288,34 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tar-fs": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
+ "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
+ "license": "MIT",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/temp-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
@@ -7295,10 +8387,30 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD",
+ "optional": true
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1"
@@ -7529,11 +8641,18 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
"node_modules/vite": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz",
@@ -7653,6 +8772,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -7735,7 +8855,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/which-typed-array": {
@@ -7764,6 +8883,7 @@
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -8044,7 +9164,6 @@
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
@@ -8055,11 +9174,16 @@
"node": ">=8"
}
},
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
"node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/yallist": {
@@ -8073,7 +9197,6 @@
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
@@ -8096,7 +9219,6 @@
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
@@ -8110,7 +9232,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
@@ -8124,7 +9245,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
@@ -8137,7 +9257,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
@@ -8153,7 +9272,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
@@ -8166,6 +9284,7 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
diff --git a/package.json b/package.json
index 2d6d24b..e246e56 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"pdfconvert-wasm": "^0.3.0",
"react": "^19.3.0",
"react-automat": "file:../automat",
+ "react-canvas-label-editor": "github:sebseb7/react-canvas-label-editor",
"react-dom": "^19.3.0",
"react-router-dom": "^7.18.4",
"sortablejs": "^1.15.7",
@@ -42,5 +43,9 @@
"qrcode": "^1.5.4",
"vite": "^8.3.1",
"vite-plugin-pwa": "^1.3.0"
+ },
+ "allowScripts": {
+ "canvas@3.2.3": true,
+ "github:sebseb7/react-canvas-label-editor#7f0e31b66ff22da011e872b201017398b14e9dd9": true
}
}
diff --git a/src/api/ApiClient.js b/src/api/ApiClient.js
index 10954d1..6934640 100644
--- a/src/api/ApiClient.js
+++ b/src/api/ApiClient.js
@@ -103,6 +103,8 @@ export class ApiClient {
create: (body) => this.#json('POST', '/api/warehouse', { body }),
/** PATCH /api/warehouse/{id} → 200 { warehouse: Warehouse } */
update: (id, body) => this.#json('PATCH', `/api/warehouse/${enc(id)}`, { body }),
+ /** PUT /api/warehouse/order → 200 { warehouseIds: number[] } */
+ order: (body) => this.#json('PUT', '/api/warehouse/order', { body }),
/** DELETE /api/warehouse/{id} → 204 */
delete: (id) => this.#empty('DELETE', `/api/warehouse/${enc(id)}`),
};
@@ -353,7 +355,7 @@ export class ApiClient {
* `onHistory(history, total)` — returns `{ unwatch, setSkipAndOffset }`.
*/
historyWatch: (sku, onHistory) => this.watchArticleHistory(sku, onHistory),
- /** PATCH /api/article/{sku} — body: at least one of { name, unitamount, unitSi } */
+ /** PATCH /api/article/{sku} — body: at least one of { name, unitamount, unitSi, track_stock } */
update: async (sku, body) => {
const nameChange = body != null && Object.hasOwn(body, 'name');
if (nameChange) {
@@ -400,6 +402,15 @@ export class ApiClient {
/** PUT /api/article/{sku}/categories */
setCategories: (sku, body) =>
this.#json('PUT', `/api/article/${enc(sku)}/categories`, { body }),
+ /** PUT /api/article/{sku}/track_stock */
+ setTrackStock: async (sku, body) => {
+ const payload = typeof body === 'boolean' ? { track_stock: body } : body;
+ const res = await this.#json('PUT', `/api/article/${enc(sku)}/track_stock`, { body: payload });
+ if (res?.article) {
+ this.setArticle(res.article);
+ }
+ return res;
+ },
/** GET /api/article/{sku}/supplier */
getSuppliers: (sku) => this.#json('GET', `/api/article/${enc(sku)}/supplier`),
/** POST /api/article/{sku}/supplier */
diff --git a/src/api/index.js b/src/api/index.js
index 302bb9d..d64ddb5 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -216,16 +216,20 @@ export const article = {
},
/** POST /api/article → 201 { article } */
- create({ parentId, name }) {
+ create({ parentId, name, track_stock }) {
return http('/api/article', {
method: 'POST',
- body: { parentId, name },
+ body: {
+ parentId,
+ name,
+ ...(track_stock !== undefined ? { track_stock } : {}),
+ },
});
},
/**
* PATCH /api/article/:sku
- * Body: at least one of { name, unitamount, unitSi }
+ * Body: at least one of { name, unitamount, unitSi, track_stock }
* unitSi must exist for selected company → 404 Unit not found
* → 200 { article } (same detail shape as GET)
*/
@@ -236,6 +240,19 @@ export const article = {
});
},
+ /**
+ * PUT /api/article/:sku/track_stock
+ * Body: { track_stock: boolean }
+ * → 200 { article }
+ */
+ setTrackStock(sku, body) {
+ const payload = typeof body === 'boolean' ? { track_stock: body } : body;
+ return http(`/api/article/${encodeURIComponent(sku)}/track_stock`, {
+ method: 'PUT',
+ body: payload,
+ });
+ },
+
/**
* DELETE /api/article/:sku → 204
* Errors: 400 Article has children, 401, 403, 404 Article not found
@@ -404,6 +421,56 @@ export const article = {
const qs = params.toString();
return httpGetBinary(`/api/article/export.zip${qs ? `?${qs}` : ''}`);
},
+ /**
+ * POST /api/article/:sku/print
+ * Body: { printerId, templateId, quantity }
+ * Prints the given template to the specified printer for this article.
+ */
+ printLabel(sku, body) {
+ return http(`/api/article/${encodeURIComponent(sku)}/print`, {
+ method: 'POST',
+ body,
+ });
+ },
+};
+
+/**
+ * Company-scoped printers (selectedCompanyId from session).
+ * Shape: Printer = { id, address, type, model, serial, sort, desc }
+ */
+export const printer = {
+ /** GET /api/printer → { printers: Printer[] } */
+ list() {
+ return http('/api/printer');
+ },
+
+ /** GET /api/printer/:id → { printer: Printer } */
+ getById(id) {
+ return http(`/api/printer/${id}`);
+ },
+
+ /**
+ * POST /api/printer
+ * Body: { address, type, model, serial, sort, desc }
+ * → 201 { printer: Printer }
+ */
+ create(body) {
+ return http('/api/printer', { method: 'POST', body });
+ },
+
+ /**
+ * PATCH /api/printer/:id
+ * Body: partial printer fields
+ * → 200 { printer: Printer }
+ */
+ update(id, body) {
+ return http(`/api/printer/${id}`, { method: 'PATCH', body });
+ },
+
+ /** DELETE /api/printer/:id → 204 */
+ delete(id) {
+ return http(`/api/printer/${id}`, { method: 'DELETE' });
+ },
};
/**
@@ -679,7 +746,7 @@ export const warehouse = {
/**
* POST /api/warehouse
- * Body: { name } — empty name ⇒ 400 Name required.
+ * Body: { name, sort? } — empty name ⇒ 400 Name required.
* → 201 { warehouse: Warehouse }
*/
create(body) {
@@ -688,13 +755,22 @@ export const warehouse = {
/**
* PATCH /api/warehouse/:id
- * Body: { name } — empty name ⇒ 400 Name required.
+ * Body: { name?, sort? }
* → 200 { warehouse: Warehouse }
*/
update(id, body) {
return http(`/api/warehouse/${id}`, { method: 'PATCH', body });
},
+ /**
+ * PUT /api/warehouse/order
+ * Body: { warehouseIds: number[] }
+ * → 200 { warehouseIds: number[] }
+ */
+ order(body) {
+ return http('/api/warehouse/order', { method: 'PUT', body });
+ },
+
/** DELETE /api/warehouse/:id → 204 */
delete(id) {
return http(`/api/warehouse/${id}`, { method: 'DELETE' });
@@ -1466,6 +1542,47 @@ export const auth = {
},
};
+/**
+ * Company-scoped ZPL label templates (selectedCompanyId from session).
+ * Shape: LabelTemplate = { id, company_id, name, width, height, dpi, type, content, thumb }
+ */
+export const labeltemplate = {
+ /** GET /api/labeltemplate → { labeltemplates: LabelTemplate[] } */
+ list() {
+ return http('/api/labeltemplate');
+ },
+
+ /** GET /api/labeltemplate/:id → { labeltemplate: LabelTemplate } */
+ get(id) {
+ return http(`/api/labeltemplate/${encodeURIComponent(id)}`);
+ },
+
+ /**
+ * POST /api/labeltemplate
+ * Body: { name, width, height, dpi, type, content }
+ * → 201 { labeltemplate: LabelTemplate }
+ */
+ create(body) {
+ return http('/api/labeltemplate', { method: 'POST', body });
+ },
+
+ /**
+ * PATCH /api/labeltemplate/:id
+ * Body: partial { name?, width?, height?, dpi?, type?, content? }
+ * → 200 { labeltemplate: LabelTemplate }
+ */
+ update(id, body) {
+ return http(`/api/labeltemplate/${encodeURIComponent(id)}`, { method: 'PATCH', body });
+ },
+
+ /** DELETE /api/labeltemplate/:id → 204 */
+ delete(id) {
+ return http(`/api/labeltemplate/${encodeURIComponent(id)}`, { method: 'DELETE' });
+ },
+
+ // thumb is returned inline as a base64 string in list/get responses
+};
+
export default {
auth,
article,
@@ -1476,10 +1593,12 @@ export default {
customergroup,
delivery,
entity,
+ labeltemplate,
ledger,
number,
order,
posterminal,
+ printer,
quote,
supplier,
thumb,
diff --git a/src/appRouter.jsx b/src/appRouter.jsx
index 835b4cd..8823a39 100644
--- a/src/appRouter.jsx
+++ b/src/appRouter.jsx
@@ -8,6 +8,7 @@ const ArtikelKategorienPage = lazy(() => import('./pages/artikel/kategorien'));
const RedirectArtikelKategorien = lazy(() => import('./pages/artikel/RedirectArtikelKategorien'));
const ArtikelLagerPage = lazy(() => import('./pages/artikel/lager'));
const ArtikelMarkenPage = lazy(() => import('./pages/artikel/marken'));
+const ArtikelVorlagenPage = lazy(() => import('./pages/artikel/vorlagen'));
const ArtikelSkuPage = lazy(() => import('./pages/artikel/sku'));
const LieferungListePage = lazy(() => import('./pages/lieferung/index'));
const LieferungNeuPage = lazy(() => import('./pages/lieferung/neu'));
@@ -55,6 +56,7 @@ const routes = [
{ path: 'kategorien/*', element: },
{ path: 'lager', element: },
{ path: 'marken', element: },
+ { path: 'vorlagen', element: },
{ path: ':sku/:tab?', element: },
],
},
diff --git a/src/automats/warehouseAutomat.js b/src/automats/warehouseAutomat.js
index 488b16b..baf43f7 100644
--- a/src/automats/warehouseAutomat.js
+++ b/src/automats/warehouseAutomat.js
@@ -130,6 +130,17 @@ const actions = {
await warehouseAutomat.actions.reload();
},
+ /**
+ * Persists a new sort order for all warehouses.
+ *
+ * @param {Array} warehouseIds IDs in the desired order.
+ * @returns {Promise}
+ */
+ async reorder(warehouseIds) {
+ await warehouseApi.order({ warehouseIds });
+ await warehouseAutomat.actions.reload();
+ },
+
/**
* Replaces the cached list without a round-trip.
*
diff --git a/src/components/article/ArticleStockAdjustDialog.jsx b/src/components/article/ArticleStockAdjustDialog.jsx
index f1a18a0..a4505db 100644
--- a/src/components/article/ArticleStockAdjustDialog.jsx
+++ b/src/components/article/ArticleStockAdjustDialog.jsx
@@ -25,8 +25,10 @@ import WarehouseIcon from '@mui/icons-material/Warehouse';
import TrendingUpIcon from '@mui/icons-material/TrendingUp';
import TrendingDownIcon from '@mui/icons-material/TrendingDown';
import TuneIcon from '@mui/icons-material/Tune';
+import Switch from '@mui/material/Switch';
import { enqueueSnackbar } from 'notistack';
-import { stock } from '../../api';
+import { stock, article as articleApi } from '../../api';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import { formatStock } from '../../pages/artikel/searchFormat';
import { notifyError } from '../../utils/notify';
import artikelAutomat from '../../automats/artikelAutomat';
@@ -41,9 +43,13 @@ const REASON_PRESETS = [
];
export default class ArticleStockAdjustDialog extends PureComponent {
+ static contextType = StorageManagerContext;
+
constructor(props) {
super(props);
const initialWhId = this.resolveInitialWarehouseId(props);
+ const isTrackStock =
+ props.article?.track_stock !== false && props.article?.track_stock !== 0;
this.state = {
mode: 'diff', // 'diff' | 'target'
warehouseId: initialWhId,
@@ -53,6 +59,8 @@ export default class ArticleStockAdjustDialog extends PureComponent {
submitting: false,
error: null,
warehouses: warehouseAutomat.state.warehouses || [],
+ trackStock: isTrackStock,
+ initialTrackStock: isTrackStock,
};
this.handleWarehouseChange = this.handleWarehouseChange.bind(this);
@@ -60,6 +68,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
this.handleDiffChange = this.handleDiffChange.bind(this);
this.handleTargetChange = this.handleTargetChange.bind(this);
this.handleReasonChange = this.handleReasonChange.bind(this);
+ this.handleTrackStockToggle = this.handleTrackStockToggle.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
@@ -82,6 +91,8 @@ export default class ArticleStockAdjustDialog extends PureComponent {
if (this.props.open && !prevProps.open) {
void warehouseAutomat.actions.load().catch(() => {});
const initialWhId = this.resolveInitialWarehouseId(this.props);
+ const isTrackStock =
+ this.props.article?.track_stock !== false && this.props.article?.track_stock !== 0;
this.setState({
mode: 'diff',
warehouseId: initialWhId,
@@ -91,6 +102,8 @@ export default class ArticleStockAdjustDialog extends PureComponent {
submitting: false,
error: null,
warehouses: warehouseAutomat.state.warehouses || [],
+ trackStock: isTrackStock,
+ initialTrackStock: isTrackStock,
});
}
}
@@ -134,8 +147,15 @@ export default class ArticleStockAdjustDialog extends PureComponent {
this.setState({ reason: event.target.value });
}
+ handleTrackStockToggle(event) {
+ this.setState({ trackStock: event.target.checked, error: null });
+ }
+
calculateAdjustment() {
- const { mode, warehouseId, diffValue, targetValue } = this.state;
+ const { mode, warehouseId, diffValue, targetValue, trackStock } = this.state;
+ if (!trackStock) {
+ return { valid: false, amount: 0, newStock: 0 };
+ }
const currentStock = this.getCurrentStock(warehouseId);
if (mode === 'diff') {
@@ -167,43 +187,77 @@ export default class ArticleStockAdjustDialog extends PureComponent {
async handleSubmit(event) {
event?.preventDefault();
- const { article, onClose, onAdjustSuccess } = this.props;
- const { warehouseId, reason, submitting } = this.state;
+ const { article, onClose, onAdjustSuccess, onArticleUpdated } = this.props;
+ const { warehouseId, reason, submitting, trackStock, initialTrackStock } = this.state;
if (submitting) return;
- if (!warehouseId) {
- this.setState({ error: 'Bitte wählen Sie ein Lager aus.' });
+ const trackStockChanged = trackStock !== initialTrackStock;
+ const { valid, amount } = this.calculateAdjustment();
+ const hasAdjustment = trackStock && valid && amount !== 0;
+
+ if (!trackStockChanged && !hasAdjustment) {
+ if (trackStock && (!valid || amount === 0)) {
+ this.setState({ error: 'Bitte geben Sie eine gültige Bestandsänderung ein (ungleich 0).' });
+ }
return;
}
- const { valid, amount } = this.calculateAdjustment();
- if (!valid || amount === 0) {
- this.setState({ error: 'Bitte geben Sie eine gültige Bestandsänderung ein (ungleich 0).' });
+ if (hasAdjustment && !warehouseId) {
+ this.setState({ error: 'Bitte wählen Sie ein Lager aus.' });
return;
}
this.setState({ submitting: true, error: null });
try {
- const payload = {
- sku: article.sku,
- warehouseId: Number(warehouseId),
- amount,
- text: reason.trim() || undefined,
- };
+ let updatedArticle = null;
- const result = await stock.adjust(payload);
+ // 1. Update track_stock if changed
+ if (trackStockChanged) {
+ const store = this.context;
+ const setFn = store?.article?.setTrackStock ?? articleApi.setTrackStock;
+ const trackRes = await setFn(article.sku, { track_stock: trackStock });
+ updatedArticle = trackRes?.article || null;
+ }
- enqueueSnackbar(
- `Bestand für „${article.name || article.sku}“ erfolgreich angepasst (${amount > 0 ? `+${amount}` : amount}).`,
- { variant: 'success' }
- );
+ // 2. Adjust stock if an adjustment was entered and stock is tracked
+ let adjustResult = null;
+ if (hasAdjustment) {
+ const payload = {
+ sku: article.sku,
+ warehouseId: Number(warehouseId),
+ amount,
+ text: reason.trim() || undefined,
+ };
+ adjustResult = await stock.adjust(payload);
+ }
- // Reload article to update UI
+ // User feedback
+ if (trackStockChanged && hasAdjustment) {
+ enqueueSnackbar(
+ `Bestandsführung ${trackStock ? 'aktiviert' : 'deaktiviert'} und Bestand angepasst.`,
+ { variant: 'success' }
+ );
+ } else if (trackStockChanged) {
+ enqueueSnackbar(
+ `Bestandsführung für „${article.name || article.sku}“ ${trackStock ? 'aktiviert' : 'deaktiviert'}.`,
+ { variant: 'success' }
+ );
+ } else if (hasAdjustment) {
+ enqueueSnackbar(
+ `Bestand für „${article.name || article.sku}“ erfolgreich angepasst (${amount > 0 ? `+${amount}` : amount}).`,
+ { variant: 'success' }
+ );
+ }
+
+ // Reload article in automat cache
void artikelAutomat.actions.reloadArticle(article.sku).catch(() => {});
- if (onAdjustSuccess) {
- onAdjustSuccess(result);
+ if (updatedArticle) {
+ onArticleUpdated?.(updatedArticle);
+ }
+ if (adjustResult && onAdjustSuccess) {
+ onAdjustSuccess(adjustResult);
}
if (onClose) {
onClose();
@@ -229,10 +283,16 @@ export default class ArticleStockAdjustDialog extends PureComponent {
submitting,
error,
warehouses,
+ trackStock,
+ initialTrackStock,
} = this.state;
+ const trackStockChanged = trackStock !== initialTrackStock;
const currentStock = this.getCurrentStock(warehouseId);
const { valid, amount, newStock, isZeroChange } = this.calculateAdjustment();
+ const hasAdjustment = trackStock && valid && amount !== 0;
+ const canSubmit =
+ !submitting && (trackStockChanged || (hasAdjustment && Boolean(warehouseId)));
const selectedWarehouse = warehouses.find((w) => Number(w.id) === Number(warehouseId));
const unit =
@@ -247,6 +307,13 @@ export default class ArticleStockAdjustDialog extends PureComponent {
maxWidth="sm"
fullWidth
aria-labelledby="stock-adjust-dialog-title"
+ slotProps={{
+ paper: {
+ sx: {
+ minHeight: 560,
+ },
+ },
+ }}
>
-
-
+
+
{/* Article overview */}
+ {/* Track Stock Toggle Card */}
+
+
+
+ Bestand verfolgen
+
+
+ {trackStock
+ ? 'Lagerbestand wird für diesen Artikel geführt und bei Buchungen aktualisiert.'
+ : 'Keine Bestandsführung. Artikel hat unbegrenzte Verfügbarkeit.'}
+
+
+
+
+
{warehouses.length === 0 ? (
Es sind keine Lager vorhanden. Bitte legen Sie zuerst unter „Artikel → Lager“ ein Lager an.
) : (
- <>
+
{/* Warehouse selection & Current stock display */}
}
@@ -358,7 +465,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
onChange={this.handleModeChange}
size="small"
fullWidth
- disabled={submitting}
+ disabled={submitting || !trackStock}
>
@@ -380,7 +487,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
type="number"
value={diffValue}
onChange={this.handleDiffChange}
- disabled={submitting}
+ disabled={submitting || !trackStock}
placeholder="z.B. +5 oder -2"
slotProps={{
input: {
@@ -409,7 +516,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
type="number"
value={targetValue}
onChange={this.handleTargetChange}
- disabled={submitting}
+ disabled={submitting || !trackStock}
placeholder="z.B. 10"
helperText={
isZeroChange
@@ -459,7 +566,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
label="Grund / Buchungstext"
value={reason}
onChange={this.handleReasonChange}
- disabled={submitting}
+ disabled={submitting || !trackStock}
placeholder="z.B. Inventur, Bruch, Schwund"
helperText="Wird im Journal / Ledger als Transaktionstext gespeichert"
/>
@@ -470,14 +577,14 @@ export default class ArticleStockAdjustDialog extends PureComponent {
label={preset}
size="small"
clickable
- disabled={submitting}
+ disabled={submitting || !trackStock}
onClick={() => this.setState({ reason: preset })}
sx={{ fontSize: '0.75rem' }}
/>
))}
- >
+
)}
{error && (
@@ -497,7 +604,7 @@ export default class ArticleStockAdjustDialog extends PureComponent {
variant="contained"
color="primary"
onClick={this.handleSubmit}
- disabled={submitting || !valid || amount === 0 || !warehouseId}
+ disabled={!canSubmit}
startIcon={
submitting ? (
@@ -507,7 +614,11 @@ export default class ArticleStockAdjustDialog extends PureComponent {
}
sx={{ minWidth: 150, fontWeight: 600 }}
>
- {submitting ? 'Wird gebucht...' : 'Bestand anpassen'}
+ {submitting
+ ? 'Wird gespeichert...'
+ : hasAdjustment
+ ? 'Bestand anpassen'
+ : 'Speichern'}
diff --git a/src/components/article/ArticleTileTab.jsx b/src/components/article/ArticleTileTab.jsx
index 56078c3..076bc8d 100644
--- a/src/components/article/ArticleTileTab.jsx
+++ b/src/components/article/ArticleTileTab.jsx
@@ -159,7 +159,7 @@ class ArticleTileTab extends PureComponent {
case ARTICLE_TAB.seo:
return ;
case ARTICLE_TAB.label:
- return ;
+ return ;
case ARTICLE_TAB.attributes:
return ;
case ARTICLE_TAB.compound:
diff --git a/src/components/article/boxes/ArticleViewStock.jsx b/src/components/article/boxes/ArticleViewStock.jsx
index 53e6e70..39d0ba4 100644
--- a/src/components/article/boxes/ArticleViewStock.jsx
+++ b/src/components/article/boxes/ArticleViewStock.jsx
@@ -3,6 +3,7 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import WarehouseIcon from '@mui/icons-material/Warehouse';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
+import Tooltip from '@mui/material/Tooltip';
import { PanelTile } from 'dashgui/panels';
import { formatStock } from '../../../pages/artikel/searchFormat';
import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog';
@@ -30,6 +31,9 @@ export default class ArticleViewStock extends PureComponent {
render() {
const { article: articleData } = this.props;
const { adjustOpen } = this.state;
+ const isTrackStock =
+ articleData?.track_stock !== false && articleData?.track_stock !== 0;
+
const rawWarehouses = Array.isArray(articleData?.warehouses)
? articleData.warehouses
: [];
@@ -63,149 +67,196 @@ export default class ArticleViewStock extends PureComponent {
onClick: this.handleOpenAdjust,
}}
>
-
- {/* Top section: Headline and Total Stock */}
-
-
- Bestand
-
-
-
+
+ {/* Top section: Headline and Total Stock */}
+
0 ? 'text.primary' : 'text.secondary',
+ textTransform: 'uppercase',
+ letterSpacing: 0.6,
+ fontWeight: 600,
+ display: 'block',
}}
>
- {formatStock(totalStock)}
+ Bestand
- {unit ? (
-
- {unit}
-
- ) : null}
-
-
- {/* Bottom section: Per-warehouse breakdown */}
- {hasWarehouses ? (
-
-
- {warehouses.map((wh) => (
+ {isTrackStock ? (
+
+ 0 ? 'text.primary' : 'text.secondary',
+ }}
+ >
+ {formatStock(totalStock)}
+
+ {unit ? (
+
+ {unit}
+
+ ) : null}
+
+
+ ) : (
+
+
+ Keine Erfassung
+
+
+ Bestand wird nicht überwacht
+
+
+ )}
+
+
+ {/* Bottom section: Per-warehouse breakdown */}
+ {isTrackStock && hasWarehouses ? (
+
+
+ {warehouses.map((wh) => (
-
-
- {wh.name}
+
+
+ {wh.name}
+
+
+
+ 0
+ ? 'text.primary'
+ : 'text.secondary',
+ }}
+ >
+ {formatStock(wh.stock)}
-
- 0
- ? 'text.primary'
- : 'text.secondary',
- }}
- >
- {formatStock(wh.stock)}
-
-
- ))}
+ ))}
+
-
- ) : null}
-
-
+ ) : null}
+
+
-
- >
- );
-}
+
+ >
+ );
+ }
}
diff --git a/src/components/article/tabs/ArticleLabelTab.jsx b/src/components/article/tabs/ArticleLabelTab.jsx
index d1da224..5a3e242 100644
--- a/src/components/article/tabs/ArticleLabelTab.jsx
+++ b/src/components/article/tabs/ArticleLabelTab.jsx
@@ -1,12 +1,256 @@
-import { Component } from 'react';
+import { PureComponent } from 'react';
+import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
+import CircularProgress from '@mui/material/CircularProgress';
+import Button from '@mui/material/Button';
+import TextField from '@mui/material/TextField';
+import MenuItem from '@mui/material/MenuItem';
+import Grid from '@mui/material/Grid';
+import Paper from '@mui/material/Paper';
+import PrintIcon from '@mui/icons-material/Print';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import { enqueueSnackbar } from 'notistack';
+
+import { labeltemplate, printer, article } from '../../../api';
+import { notifyError } from '../../../utils/notify';
+import BackendError from '../../BackendError';
+
+export default class ArticleLabelTab extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ templates: null,
+ printers: null,
+ selectedTemplateId: '',
+ selectedPrinterId: '',
+ quantity: 1,
+ loading: true,
+ error: null,
+ };
+ }
+
+ componentDidMount() {
+ this.loadData();
+ }
+
+ async loadData() {
+ this.setState({ loading: true, error: null });
+ try {
+ const [resTemplates, resPrinters] = await Promise.all([
+ labeltemplate.list(),
+ printer.list(),
+ ]);
+
+ const templates = resTemplates.labeltemplates || [];
+ const zplPrinters = (resPrinters.printers || []).filter((p) => p.type === 'zpl');
+
+ this.setState({
+ templates,
+ printers: zplPrinters,
+ selectedTemplateId: templates.length > 0 ? templates[0].id : '',
+ selectedPrinterId: zplPrinters.length > 0 ? zplPrinters[0].id : '',
+ loading: false,
+ });
+ } catch (error) {
+ this.setState({ error, loading: false });
+ }
+ }
+
+ handlePrint = async () => {
+ const { selectedTemplateId, selectedPrinterId, quantity } = this.state;
+ const { article: articleData } = this.props;
+
+ if (!selectedTemplateId || !selectedPrinterId || quantity < 1) {
+ enqueueSnackbar('Bitte Vorlage, Drucker und Menge auswählen', { variant: 'warning' });
+ return;
+ }
+
+ try {
+ await article.printLabel(articleData.sku, {
+ templateId: selectedTemplateId,
+ printerId: selectedPrinterId,
+ quantity,
+ });
+ enqueueSnackbar('Druckauftrag erfolgreich gesendet', { variant: 'success' });
+ } catch (err) {
+ notifyError(err);
+ }
+ };
-export default class ArticleLabelTab extends Component {
render() {
+ const {
+ templates,
+ printers,
+ selectedTemplateId,
+ selectedPrinterId,
+ quantity,
+ loading,
+ error,
+ } = this.state;
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ this.loadData()} />
+
+ );
+ }
+
+ if (templates.length === 0) {
+ return (
+
+
+ Es sind keine ZPL-Etikettenvorlagen vorhanden.
+
+
+ );
+ }
+
+ if (printers.length === 0) {
+ return (
+
+
+ Es sind keine ZPL-Drucker konfiguriert.
+
+
+ );
+ }
+
return (
-
- Label
-
+
+
+
+ {templates.map((t) => {
+ const isSelected = t.id === selectedTemplateId;
+ return (
+
+ this.setState({ selectedTemplateId: t.id })}
+ sx={{
+ p: 2,
+ cursor: 'pointer',
+ border: '2px solid',
+ borderColor: isSelected ? 'primary.main' : 'divider',
+ bgcolor: isSelected ? 'action.selected' : 'background.paper',
+ boxShadow: isSelected ? 3 : 0,
+ transition: 'all 0.2s',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ position: 'relative',
+ gap: 2,
+ '&:hover': {
+ borderColor: 'primary.main',
+ boxShadow: isSelected ? 3 : 1,
+ },
+ }}
+ >
+ {isSelected && (
+
+ )}
+
+ {t.thumb ? (
+
+ ) : (
+
+ Keine Vorschau
+
+ )}
+
+
+
+ {t.name}
+
+
+ {t.width}x{t.height} ({t.dpi} dpi)
+
+
+
+
+ );
+ })}
+
+
+
+
+
+ this.setState({ selectedPrinterId: e.target.value })}
+ sx={{ minWidth: 200 }}
+ size="small"
+ >
+ {printers.map((p) => (
+
+ ))}
+
+
+ {
+ const val = parseInt(e.target.value, 10);
+ this.setState({ quantity: isNaN(val) ? 1 : Math.max(1, val) });
+ }}
+ inputProps={{ min: 1, max: 9999 }}
+ sx={{ width: 100 }}
+ size="small"
+ />
+
+ }
+ onClick={this.handlePrint}
+ disabled={!selectedTemplateId || !selectedPrinterId || quantity < 1}
+ sx={{ height: 40 }}
+ >
+ Etiketten drucken
+
+
+
+
);
}
}
diff --git a/src/nav.js b/src/nav.js
index af5063c..3664908 100644
--- a/src/nav.js
+++ b/src/nav.js
@@ -15,6 +15,7 @@ import AddBoxIcon from '@mui/icons-material/AddBox';
import StorefrontIcon from '@mui/icons-material/Storefront';
import RequestQuoteIcon from '@mui/icons-material/RequestQuote';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
+import LabelIcon from '@mui/icons-material/Label';
import { isKategorienPath } from './pages/artikel/categoryRoute';
import { deliveryEditorAutomat } from './automats/deliveryEditorAutomat';
@@ -105,6 +106,7 @@ export const SUB_NAV = {
{ segment: 'kategorien', label: 'Kategorieen', title: 'Kategorien', icon: CategoryIcon },
{ segment: 'lager', label: 'Lager', icon: WarehouseIcon },
{ segment: 'marken', label: 'Marken', icon: CopyrightIcon },
+ { segment: 'vorlagen', label: 'Vorlagen', icon: LabelIcon },
],
'/lieferung': [
{ segment: '', label: 'Liste', title: 'Lieferungen', icon: ListAltIcon },
diff --git a/src/pages/artikel/lager.jsx b/src/pages/artikel/lager.jsx
index ce541ce..fae7fe5 100644
--- a/src/pages/artikel/lager.jsx
+++ b/src/pages/artikel/lager.jsx
@@ -1,4 +1,4 @@
-import { PureComponent } from 'react';
+import { PureComponent, createRef } from 'react';
import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
@@ -9,7 +9,9 @@ import ListItem from '@mui/material/ListItem';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
+import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
import WarehouseIcon from '@mui/icons-material/Warehouse';
+import Sortable from 'sortablejs';
import { enqueueSnackbar } from 'notistack';
import BackendError from '../../components/BackendError';
import SingleLineTextEdit from 'dashgui/SingleLineTextEdit';
@@ -20,12 +22,6 @@ import { notifyError } from '../../utils/notify';
import { setLastArticleSku } from '../../automats';
import warehouseAutomat from '../../automats/warehouseAutomat';
-function sortWarehouses(warehouses) {
- return [...warehouses].sort((a, b) =>
- String(a.name).localeCompare(String(b.name), 'de'),
- );
-}
-
function draftsFrom(warehouses) {
return Object.fromEntries(warehouses.map((row) => [row.id, row.name]));
}
@@ -50,7 +46,7 @@ class ArtikelLagerPage extends PureComponent {
constructor(props) {
super(props);
const { prefill } = getInitialParams(props);
- const initialWarehouses = sortWarehouses(warehouseAutomat.state.warehouses || []);
+ const initialWarehouses = warehouseAutomat.state.warehouses || [];
this.state = {
status: warehouseAutomat.state.status === 'ready' ? 'ready' : 'loading',
error: warehouseAutomat.state.error ? backendErrorFrom(warehouseAutomat.state.error) : null,
@@ -60,9 +56,14 @@ class ArtikelLagerPage extends PureComponent {
busyKey: null,
};
this._cancelled = false;
+ this.listRef = createRef();
+ this._sortable = null;
+
this.handleCreate = this.handleCreate.bind(this);
this.handleRetry = this.handleRetry.bind(this);
this.loadWarehouses = this.loadWarehouses.bind(this);
+ this._initSortable = this._initSortable.bind(this);
+ this._destroySortable = this._destroySortable.bind(this);
}
componentDidMount() {
@@ -85,27 +86,76 @@ class ArtikelLagerPage extends PureComponent {
void this.loadWarehouses();
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps, prevState) {
if (prevProps.location !== this.props.location) {
const { prefill } = getInitialParams(this.props);
if (prefill && prefill !== this.state.newName) {
this.setState({ newName: prefill });
}
}
+
+ // Re-initialise Sortable when warehouses change or list mounts
+ if (prevState.warehouses !== this.state.warehouses && this.listRef.current) {
+ this._initSortable();
+ }
}
componentWillUnmount() {
this._cancelled = true;
this.unsub?.();
+ this._destroySortable();
+ }
+
+ _initSortable() {
+ this._destroySortable();
+ const el = this.listRef.current;
+ if (!el) return;
+
+ this._sortable = Sortable.create(el, {
+ handle: '.drag-handle',
+ animation: 150,
+ ghostClass: 'sortable-ghost',
+ chosenClass: 'sortable-chosen',
+ onEnd: (evt) => {
+ const { oldIndex, newIndex } = evt;
+ if (oldIndex === newIndex) return;
+
+ this.setState((prev) => {
+ const next = [...prev.warehouses];
+ const [moved] = next.splice(oldIndex, 1);
+ next.splice(newIndex, 0, moved);
+ return { warehouses: next };
+ }, () => {
+ const ids = this.state.warehouses.map((w) => w.id);
+ void this._persistOrder(ids);
+ });
+ },
+ });
+ }
+
+ _destroySortable() {
+ this._sortable?.destroy();
+ this._sortable = null;
+ }
+
+ async _persistOrder(warehouseIds) {
+ try {
+ await warehouseAutomat.actions.reorder(warehouseIds);
+ } catch (err) {
+ if (this._cancelled) return;
+ notifyError(err);
+ // Roll back optimistic reorder
+ void this.refreshFromServer();
+ }
}
applyWarehouses(warehouses) {
- const sorted = sortWarehouses(warehouses);
+ // Preserve order returned by the server (already sorted by sort/name from backend)
this.setState((prev) => {
const currentDrafts = prev.drafts || {};
- const nextDrafts = { ...draftsFrom(sorted) };
+ const nextDrafts = { ...draftsFrom(warehouses) };
// Preserve unsaved in-progress edits for still-existing items if not busy
- for (const wh of sorted) {
+ for (const wh of warehouses) {
if (prev.busyKey !== wh.id && currentDrafts[wh.id] !== undefined) {
nextDrafts[wh.id] = currentDrafts[wh.id];
}
@@ -113,7 +163,7 @@ class ArtikelLagerPage extends PureComponent {
return {
status: 'ready',
error: null,
- warehouses: sorted,
+ warehouses,
drafts: nextDrafts,
};
});
@@ -155,7 +205,7 @@ class ArtikelLagerPage extends PureComponent {
await this.refreshFromServer();
if (this._cancelled) return;
this.setState({ newName: '', busyKey: null });
- enqueueSnackbar(`Lager „${newWarehouse.name || name}“ angelegt.`, { variant: 'success' });
+ enqueueSnackbar(`Lager „${newWarehouse.name || name}" angelegt.`, { variant: 'success' });
if (returnTo && this.props.navigate) {
this.props.navigate(returnTo);
@@ -196,7 +246,7 @@ class ArtikelLagerPage extends PureComponent {
async handleDelete(wh) {
if (this.state.busyKey != null) return;
- if (!window.confirm(`Lager „${wh.name}“ wirklich löschen?`)) {
+ if (!window.confirm(`Lager „${wh.name}" wirklich löschen?`)) {
return;
}
@@ -233,113 +283,137 @@ class ArtikelLagerPage extends PureComponent {
}
return (
-
-
-
- {returnTo ? (
- this.props.navigate?.(returnTo)}
- >
- Zurück
-
- }
- >
- {newName
- ? `Lagername „${newName}“ übernommen.`
- : 'Neues Lager anlegen.'}
-
- ) : null}
+ <>
+ {/* SortableJS ghost / chosen styling */}
+
-
- Lager der ausgewählten Firma.
-
-
-
- {warehouses.length === 0 ? (
-
- Noch keine Lager angelegt.
-
- ) : (
- warehouses.map((wh) => (
-
-
-
+
+
+ {returnTo ? (
+
- this.setState((prev) => ({
- drafts: { ...prev.drafts, [wh.id]: next },
- }))
- }
- onBlur={() => void this.handleRename(wh)}
- onKeyDown={(event) => {
- if (event.key === 'Enter') {
- event.preventDefault();
- event.target.blur();
- }
- if (event.key === 'Escape') {
- event.preventDefault();
- this.setState((prev) => ({
- drafts: { ...prev.drafts, [wh.id]: wh.name },
- }));
- event.target.blur();
- }
- }}
- sx={{ flex: 1 }}
- />
- void this.handleDelete(wh)}
+ onClick={() => this.props.navigate?.(returnTo)}
>
-
-
-
- ))
- )}
-
-
-
- this.setState({ newName: next })}
- onKeyDown={(event) => {
- if (event.key === 'Enter') {
- event.preventDefault();
- void this.handleCreate();
+ Zurück
+
}
- }}
- sx={{ flex: 1 }}
- />
-
-
-
-
-
+ >
+ {newName
+ ? `Lagername „${newName}" übernommen.`
+ : 'Neues Lager anlegen.'}
+
+ ) : null}
+
+
+ Reihenfolge per Drag & Drop anpassen.
+
+
+
+ {warehouses.length === 0 ? (
+
+ Noch keine Lager angelegt.
+
+ ) : (
+ warehouses.map((wh) => (
+
+
+
+
+
+
+ this.setState((prev) => ({
+ drafts: { ...prev.drafts, [wh.id]: next },
+ }))
+ }
+ onBlur={() => void this.handleRename(wh)}
+ onKeyDown={(event) => {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ event.target.blur();
+ }
+ if (event.key === 'Escape') {
+ event.preventDefault();
+ this.setState((prev) => ({
+ drafts: { ...prev.drafts, [wh.id]: wh.name },
+ }));
+ event.target.blur();
+ }
+ }}
+ sx={{ flex: 1 }}
+ />
+ void this.handleDelete(wh)}
+ >
+
+
+
+ ))
+ )}
+
+
+
+ this.setState({ newName: next })}
+ onKeyDown={(event) => {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ void this.handleCreate();
+ }
+ }}
+ sx={{ flex: 1 }}
+ />
+
+
+
+
+
+ >
);
}
}
diff --git a/src/pages/artikel/marken.jsx b/src/pages/artikel/marken.jsx
index 68fc3d4..8c0645e 100644
--- a/src/pages/artikel/marken.jsx
+++ b/src/pages/artikel/marken.jsx
@@ -181,10 +181,6 @@ class ArtikelMarkenPage extends PureComponent {
return (
-
- Marken der ausgewählten Firma.
-
-
{brands.length === 0 ? (
diff --git a/src/pages/artikel/vorlagen.jsx b/src/pages/artikel/vorlagen.jsx
new file mode 100644
index 0000000..355370c
--- /dev/null
+++ b/src/pages/artikel/vorlagen.jsx
@@ -0,0 +1,594 @@
+import { PureComponent } from 'react';
+import Box from '@mui/material/Box';
+import Button from '@mui/material/Button';
+import CircularProgress from '@mui/material/CircularProgress';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogContent';
+import DialogTitle from '@mui/material/DialogTitle';
+import Divider from '@mui/material/Divider';
+import IconButton from '@mui/material/IconButton';
+import InputAdornment from '@mui/material/InputAdornment';
+import TextField from '@mui/material/TextField';
+import ToggleButton from '@mui/material/ToggleButton';
+import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
+import Tooltip from '@mui/material/Tooltip';
+import Typography from '@mui/material/Typography';
+import AddIcon from '@mui/icons-material/Add';
+import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
+import EditIcon from '@mui/icons-material/Edit';
+import LabelIcon from '@mui/icons-material/Label';
+import { CanvasEditor } from 'react-canvas-label-editor';
+import 'react-canvas-label-editor/style.css';
+import BackendError from '../../components/BackendError';
+import { PanelTile, PanelTileGrid } from 'dashgui/panels';
+import { backendErrorFrom } from '../../utils/backendError';
+import { notifyError } from '../../utils/notify';
+import { setLastArticleSku } from '../../automats';
+import { labeltemplate } from '../../api';
+import { enqueueSnackbar } from 'notistack';
+
+const MIN_HEIGHT_MM = 10;
+const DEFAULT_HEIGHT_MM = 25;
+const DEFAULT_DPI = 203;
+
+function getCanvasWidth(widthClass, dpi) {
+ if (widthClass === '4') {
+ return dpi === 300 ? 1248 : 832;
+ }
+ return dpi === 300 ? 640 : 448;
+}
+
+function getMinHeightPx(dpi) {
+ return Math.max(80, Math.round((MIN_HEIGHT_MM * dpi) / 25.4));
+}
+
+function mmToPx(mm, dpi) {
+ return Math.round((Number(mm) * dpi) / 25.4);
+}
+
+function pxToMm(px, dpi) {
+ return Number(((px / dpi) * 25.4).toFixed(1));
+}
+
+class ArtikelVorlagenPage extends PureComponent {
+ constructor(props) {
+ super(props);
+ const initialDpi = DEFAULT_DPI;
+ const initialWidthClass = '2';
+ const initialHeightMm = DEFAULT_HEIGHT_MM;
+
+ this.state = {
+ status: 'loading',
+ error: null,
+ templates: [],
+ // Editor dialog state
+ editorOpen: false,
+ editorLoading: false,
+ editorTemplate: null, // null = new, object = edit
+ editorName: '',
+ editorObjects: [],
+ editorDpi: initialDpi,
+ editorWidthClass: initialWidthClass,
+ editorWidth: getCanvasWidth(initialWidthClass, initialDpi),
+ editorHeightMm: initialHeightMm,
+ editorHeight: mmToPx(initialHeightMm, initialDpi),
+ editorClipboard: null,
+ saving: false,
+ // Delete busy
+ deletingId: null,
+ };
+ this._cancelled = false;
+ this._currentEditId = null;
+ this.handleRetry = this.handleRetry.bind(this);
+ this.handleOpenNew = this.handleOpenNew.bind(this);
+ this.handleOpenEdit = this.handleOpenEdit.bind(this);
+ this.handleEditorClose = this.handleEditorClose.bind(this);
+ this.handleEditorSave = this.handleEditorSave.bind(this);
+ this.handleWidthClassChange = this.handleWidthClassChange.bind(this);
+ this.handleDpiChange = this.handleDpiChange.bind(this);
+ this.handleHeightMmChange = this.handleHeightMmChange.bind(this);
+ this.handleHeightMmBlur = this.handleHeightMmBlur.bind(this);
+ }
+
+ componentDidMount() {
+ setLastArticleSku(null);
+ this._cancelled = false;
+ void this.loadTemplates();
+ }
+
+ componentWillUnmount() {
+ this._cancelled = true;
+ }
+
+ async loadTemplates() {
+ this.setState({ status: 'loading', error: null });
+ try {
+ const { labeltemplates } = await labeltemplate.list();
+ if (this._cancelled) return;
+ this.setState({ status: 'ready', templates: labeltemplates || [] });
+ } catch (err) {
+ if (this._cancelled) return;
+ this.setState({ status: 'failed', error: backendErrorFrom(err) });
+ }
+ }
+
+ handleRetry() {
+ void this.loadTemplates();
+ }
+
+ handleOpenNew() {
+ this._currentEditId = null;
+ const dpi = DEFAULT_DPI;
+ const widthClass = '2';
+ const width = getCanvasWidth(widthClass, dpi);
+ const heightMm = DEFAULT_HEIGHT_MM;
+ const height = mmToPx(heightMm, dpi);
+
+ this.setState({
+ editorOpen: true,
+ editorLoading: false,
+ editorTemplate: null,
+ editorName: 'Neue Vorlage',
+ editorObjects: [],
+ editorDpi: dpi,
+ editorWidthClass: widthClass,
+ editorWidth: width,
+ editorHeightMm: heightMm,
+ editorHeight: height,
+ });
+ }
+
+ async handleOpenEdit(tmpl) {
+ const fetchId = tmpl.id;
+ this._currentEditId = fetchId;
+ const initialDpi = tmpl.dpi === 300 ? 300 : 203;
+ const initialWidthClass = (tmpl.width || 0) >= 800 ? '4' : '2';
+ const initialWidth = tmpl.width || getCanvasWidth(initialWidthClass, initialDpi);
+ const initialHeight = tmpl.height || mmToPx(DEFAULT_HEIGHT_MM, initialDpi);
+ const initialHeightMm = pxToMm(initialHeight, initialDpi);
+
+ this.setState({
+ editorOpen: true,
+ editorLoading: true,
+ editorTemplate: tmpl,
+ editorName: tmpl.name,
+ editorObjects: [],
+ editorDpi: initialDpi,
+ editorWidthClass: initialWidthClass,
+ editorWidth: initialWidth,
+ editorHeightMm: initialHeightMm,
+ editorHeight: initialHeight,
+ });
+
+ try {
+ const { labeltemplate: full } = await labeltemplate.get(fetchId);
+ if (this._cancelled || this._currentEditId !== fetchId || !this.state.editorOpen) return;
+ const content = full?.content || {};
+ const dpi = full?.dpi === 300 ? 300 : 203;
+ const widthClass = (full?.width || 0) >= 800 ? '4' : '2';
+ const width = full?.width || getCanvasWidth(widthClass, dpi);
+ const height = full?.height || mmToPx(DEFAULT_HEIGHT_MM, dpi);
+ const heightMm = pxToMm(height, dpi);
+
+ this.setState({
+ editorLoading: false,
+ editorTemplate: full,
+ editorName: full.name ?? tmpl.name,
+ editorObjects: content.objects || [],
+ editorDpi: dpi,
+ editorWidthClass: widthClass,
+ editorWidth: width,
+ editorHeightMm: heightMm,
+ editorHeight: height,
+ });
+ } catch (err) {
+ if (this._cancelled || this._currentEditId !== fetchId) return;
+ notifyError(err);
+ this.setState({ editorOpen: false, editorLoading: false, editorTemplate: null });
+ }
+ }
+
+ handleWidthClassChange(event, nextValue) {
+ if (!nextValue) return;
+ const width = getCanvasWidth(nextValue, this.state.editorDpi);
+ this.setState({
+ editorWidthClass: nextValue,
+ editorWidth: width,
+ });
+ }
+
+ handleDpiChange(event, nextValue) {
+ if (!nextValue) return;
+ const dpi = Number(nextValue);
+ const width = getCanvasWidth(this.state.editorWidthClass, dpi);
+ const mm = parseFloat(this.state.editorHeightMm) || DEFAULT_HEIGHT_MM;
+ const minHeightPx = getMinHeightPx(dpi);
+ const height = Math.max(minHeightPx, mmToPx(mm, dpi));
+ this.setState({
+ editorDpi: dpi,
+ editorWidth: width,
+ editorHeight: height,
+ });
+ }
+
+ handleHeightMmChange(event) {
+ const val = event.target.value;
+ const dpi = this.state.editorDpi;
+ const num = parseFloat(val);
+ const minHeightPx = getMinHeightPx(dpi);
+ const height = !isNaN(num) && num > 0
+ ? Math.max(minHeightPx, mmToPx(num, dpi))
+ : this.state.editorHeight;
+ this.setState({
+ editorHeightMm: val,
+ editorHeight: height,
+ });
+ }
+
+ handleHeightMmBlur() {
+ const dpi = this.state.editorDpi;
+ const num = parseFloat(this.state.editorHeightMm);
+ const safeMm = !isNaN(num) && num >= MIN_HEIGHT_MM ? num : MIN_HEIGHT_MM;
+ const minHeightPx = getMinHeightPx(dpi);
+ this.setState({
+ editorHeightMm: safeMm,
+ editorHeight: Math.max(minHeightPx, mmToPx(safeMm, dpi)),
+ });
+ }
+
+ handleEditorClose() {
+ if (this.state.saving) return;
+ this._currentEditId = null;
+ this.setState({ editorOpen: false, editorLoading: false, editorTemplate: null });
+ }
+
+ async handleEditorSave() {
+ const {
+ editorTemplate, editorName, editorObjects,
+ editorHeight, editorWidth, editorDpi,
+ } = this.state;
+ const name = editorName.trim();
+ if (!name) return;
+
+ this.setState({ saving: true });
+ const body = {
+ name,
+ width: editorWidth,
+ height: editorHeight,
+ dpi: editorDpi,
+ type: 'zpl',
+ content: { objects: editorObjects },
+ };
+
+ try {
+ if (editorTemplate) {
+ const { labeltemplate: updated } = await labeltemplate.update(editorTemplate.id, body);
+ if (this._cancelled) return;
+ this.setState((prev) => ({
+ saving: false,
+ editorOpen: false,
+ templates: prev.templates.map((t) => (t.id === updated.id ? updated : t)),
+ }));
+ enqueueSnackbar(`Vorlage „${updated.name}" gespeichert.`, { variant: 'success' });
+ } else {
+ const { labeltemplate: created } = await labeltemplate.create(body);
+ if (this._cancelled) return;
+ this.setState((prev) => ({
+ saving: false,
+ editorOpen: false,
+ templates: [...prev.templates, created],
+ }));
+ enqueueSnackbar(`Vorlage „${created.name}" angelegt.`, { variant: 'success' });
+ }
+ } catch (err) {
+ if (this._cancelled) return;
+ notifyError(err);
+ this.setState({ saving: false });
+ }
+ }
+
+ async handleDelete(tmpl) {
+ if (this.state.deletingId != null) return;
+ if (!window.confirm(`Vorlage „${tmpl.name}" wirklich löschen?`)) return;
+
+ this.setState({ deletingId: tmpl.id });
+ try {
+ await labeltemplate.delete(tmpl.id);
+ if (this._cancelled) return;
+ this.setState((prev) => ({
+ deletingId: null,
+ templates: prev.templates.filter((t) => t.id !== tmpl.id),
+ }));
+ enqueueSnackbar('Vorlage gelöscht.', { variant: 'success' });
+ } catch (err) {
+ if (this._cancelled) return;
+ notifyError(err);
+ this.setState({ deletingId: null });
+ }
+ }
+
+ renderEditor() {
+ const {
+ editorOpen, editorLoading, editorTemplate, editorName, editorObjects,
+ editorHeight, editorWidth, editorDpi, editorWidthClass, editorHeightMm,
+ editorClipboard, saving,
+ } = this.state;
+
+ const minHeightPx = getMinHeightPx(editorDpi);
+
+ return (
+
+ );
+ }
+
+ render() {
+ const { status, error, templates, deletingId } = this.state;
+
+ if (status === 'loading') {
+ return (
+
+
+
+ );
+ }
+
+ if (status === 'failed') {
+ return ;
+ }
+
+ return (
+ <>
+
+
+
+ }
+ onClick={this.handleOpenNew}
+ >
+ Neue Vorlage
+
+
+
+ {templates.length === 0 ? (
+
+
+ Noch keine Vorlagen angelegt.
+
+ ) : (
+
+ {templates.map((tmpl) => (
+
+ {/* Thumbnail */}
+ this.handleOpenEdit(tmpl)}
+ sx={{
+ height: 100,
+ bgcolor: '#f8f8f8',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderBottom: '1px solid',
+ borderColor: 'divider',
+ overflow: 'hidden',
+ cursor: 'pointer',
+ }}
+ >
+ {tmpl.thumb ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Footer */}
+
+
+ {tmpl.name}
+
+
+
+ this.handleOpenEdit(tmpl)}
+ disabled={deletingId != null}
+ >
+
+
+
+
+
+
+ void this.handleDelete(tmpl)}
+ disabled={deletingId === tmpl.id}
+ >
+ {deletingId === tmpl.id
+ ?
+ : }
+
+
+
+
+
+ {/* Dimensions chip */}
+
+
+ {Number(((tmpl.width / (tmpl.dpi || 203)) * 25.4).toFixed(0))} × {Number(((tmpl.height / (tmpl.dpi || 203)) * 25.4).toFixed(0))} mm ({tmpl.width} × {tmpl.height} px) · {tmpl.dpi || 203} DPI
+
+
+ ))}
+
+ )}
+
+
+
+ {this.renderEditor()}
+ >
+ );
+ }
+}
+
+export default ArtikelVorlagenPage;
diff --git a/src/pages/lieferung/lieferanten.jsx b/src/pages/lieferung/lieferanten.jsx
index ccd73e6..ff08a54 100644
--- a/src/pages/lieferung/lieferanten.jsx
+++ b/src/pages/lieferung/lieferanten.jsx
@@ -246,10 +246,6 @@ class LieferungLieferantenPage extends PureComponent {
) : null}
-
- Lieferanten der ausgewählten Firma.
-
-
{suppliers.length === 0 ? (