From 96ae3bbbba9c0e3bb89355b18403a997f7904760 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Thu, 12 Feb 2026 12:01:39 +0100 Subject: [PATCH] customze device brand #2784 --- CHANGELOG_LATEST.md | 1 + interface/.typesafe-i18n.json | 2 +- interface/package.json | 16 +- interface/pnpm-lock.yaml | 348 +++++++++++----------- interface/src/app/main/Customizations.tsx | 48 ++- src/core/emsdevice.cpp | 46 ++- src/core/emsdevice.h | 24 +- src/core/emsesp.cpp | 4 +- src/emsesp_version.h | 2 +- src/web/WebCustomizationService.cpp | 50 ++-- src/web/WebCustomizationService.h | 9 +- 11 files changed, 306 insertions(+), 244 deletions(-) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 94ea9c546..232b748fb 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -7,6 +7,7 @@ For more details go to [emsesp.org](https://emsesp.org/). ## Added - comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935) +- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784) ## Fixed diff --git a/interface/.typesafe-i18n.json b/interface/.typesafe-i18n.json index ab39dacfa..f6eb40742 100644 --- a/interface/.typesafe-i18n.json +++ b/interface/.typesafe-i18n.json @@ -1,5 +1,5 @@ { "adapter": "react", "baseLocale": "pl", - "$schema": "https://unpkg.com/typesafe-i18n@5.26.2/schema/typesafe-i18n.json" + "$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json" } \ No newline at end of file diff --git a/interface/package.json b/interface/package.json index 20ed71327..e497a9859 100644 --- a/interface/package.json +++ b/interface/package.json @@ -26,8 +26,8 @@ "@alova/adapter-xhr": "2.3.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@mui/icons-material": "^7.3.7", - "@mui/material": "^7.3.7", + "@mui/icons-material": "^7.3.8", + "@mui/material": "^7.3.8", "@preact/compat": "^18.3.1", "@table-library/react-table-library": "4.1.15", "alova": "3.5.0", @@ -43,7 +43,7 @@ "react-icons": "^5.5.0", "react-router": "^7.13.0", "react-toastify": "^11.0.5", - "typesafe-i18n": "^5.26.2", + "typesafe-i18n": "^5.27.1", "typescript": "^5.9.3" }, "devDependencies": { @@ -52,8 +52,8 @@ "@preact/compat": "^18.3.1", "@preact/preset-vite": "^2.10.3", "@trivago/prettier-plugin-sort-imports": "^6.0.2", - "@types/node": "^25.2.2", - "@types/react": "^19.2.13", + "@types/node": "^25.2.3", + "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "axe-core": "^4.11.1", "concurrently": "^9.2.1", @@ -62,10 +62,10 @@ "prettier": "^3.8.1", "rollup-plugin-visualizer": "^6.0.5", "terser": "^5.46.0", - "typescript-eslint": "^8.54.0", + "typescript-eslint": "^8.55.0", "vite": "^7.3.1", "vite-plugin-imagemin": "^0.6.1", - "vite-tsconfig-paths": "^6.1.0" + "vite-tsconfig-paths": "^6.1.1" }, - "packageManager": "pnpm@10.29.2" + "packageManager": "pnpm@10.29.3" } diff --git a/interface/pnpm-lock.yaml b/interface/pnpm-lock.yaml index 993277ad1..cefa009f5 100644 --- a/interface/pnpm-lock.yaml +++ b/interface/pnpm-lock.yaml @@ -13,22 +13,22 @@ importers: version: 2.3.1(alova@3.5.0) '@emotion/react': specifier: ^11.14.0 - version: 11.14.0(@types/react@19.2.13)(react@19.2.4) + version: 11.14.0(@types/react@19.2.14)(react@19.2.4) '@emotion/styled': specifier: ^11.14.1 - version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) + version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@mui/icons-material': - specifier: ^7.3.7 - version: 7.3.7(@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) + specifier: ^7.3.8 + version: 7.3.8(@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@mui/material': - specifier: ^7.3.7 - version: 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^7.3.8 + version: 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@preact/compat': specifier: ^18.3.1 version: 18.3.1(preact@10.28.3) '@table-library/react-table-library': specifier: 4.1.15 - version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) alova: specifier: 3.5.0 version: 3.5.0 @@ -69,8 +69,8 @@ importers: specifier: ^11.0.5 version: 11.0.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) typesafe-i18n: - specifier: ^5.26.2 - version: 5.26.2(typescript@5.9.3) + specifier: ^5.27.1 + version: 5.27.1(typescript@5.9.3) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -83,19 +83,19 @@ importers: version: 10.0.1(eslint@10.0.0) '@preact/preset-vite': specifier: ^2.10.3 - version: 2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)) + version: 2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)) '@trivago/prettier-plugin-sort-imports': specifier: ^6.0.2 version: 6.0.2(prettier@3.8.1) '@types/node': - specifier: ^25.2.2 - version: 25.2.2 + specifier: ^25.2.3 + version: 25.2.3 '@types/react': - specifier: ^19.2.13 - version: 19.2.13 + specifier: ^19.2.14 + version: 19.2.14 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.13) + version: 19.2.3(@types/react@19.2.14) axe-core: specifier: ^4.11.1 version: 4.11.1 @@ -118,17 +118,17 @@ importers: specifier: ^5.46.0 version: 5.46.0 typescript-eslint: - specifier: ^8.54.0 - version: 8.54.0(eslint@10.0.0)(typescript@5.9.3) + specifier: ^8.55.0 + version: 8.55.0(eslint@10.0.0)(typescript@5.9.3) vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.2.2)(terser@5.46.0) + version: 7.3.1(@types/node@25.2.3)(terser@5.46.0) vite-plugin-imagemin: specifier: ^0.6.1 - version: 0.6.1(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)) + version: 0.6.1(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)) vite-tsconfig-paths: - specifier: ^6.1.0 - version: 6.1.0(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)) + specifier: ^6.1.1 + version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)) packages: @@ -535,27 +535,27 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@mui/core-downloads-tracker@7.3.7': - resolution: {integrity: sha512-8jWwS6FweMkpyRkrJooamUGe1CQfO1yJ+lM43IyUJbrhHW/ObES+6ry4vfGi8EKaldHL3t3BG1bcLcERuJPcjg==} + '@mui/core-downloads-tracker@7.3.8': + resolution: {integrity: sha512-s9UHZo7QJVly7gNArEZkbbsimHqJZhElgBpXIJdehZ4OWXt+CCr0SBDgUCDJnQrqpd1dWK2dLq5rmO4mCBmI3w==} - '@mui/icons-material@7.3.7': - resolution: {integrity: sha512-3Q+ulAqG+A1+R4ebgoIs7AccaJhIGy+Xi/9OnvX376jQ6wcy+rz4geDGrxQxCGzdjOQr4Z3NgyFSZCz4T999lA==} + '@mui/icons-material@7.3.8': + resolution: {integrity: sha512-88sWg/UJc1X82OMO+ISR4E3P58I3BjFVg0qkmDu7OWlN8VijneZD3ylFA+ImxuPjMHW3SHosfSJYy1fztoz0fw==} engines: {node: '>=14.0.0'} peerDependencies: - '@mui/material': ^7.3.7 + '@mui/material': ^7.3.8 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - '@mui/material@7.3.7': - resolution: {integrity: sha512-6bdIxqzeOtBAj2wAsfhWCYyMKPLkRO9u/2o5yexcL0C3APqyy91iGSWgT3H7hg+zR2XgE61+WAu12wXPON8b6A==} + '@mui/material@7.3.8': + resolution: {integrity: sha512-QKd1RhDXE1hf2sQDNayA9ic9jGkEgvZOf0tTkJxlBPG8ns8aS4rS8WwYURw2x5y3739p0HauUXX9WbH7UufFLw==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 - '@mui/material-pigment-css': ^7.3.7 + '@mui/material-pigment-css': ^7.3.8 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -569,8 +569,8 @@ packages: '@types/react': optional: true - '@mui/private-theming@7.3.7': - resolution: {integrity: sha512-w7r1+CYhG0syCAQUWAuV5zSaU2/67WA9JXUderdb7DzCIJdp/5RmJv6L85wRjgKCMsxFF0Kfn0kPgPbPgw/jdw==} + '@mui/private-theming@7.3.8': + resolution: {integrity: sha512-du5dlPZ9XL3xW2apHoGDXBI+QLtyVJGrXNCfcNYfP/ojkz1RQ0rRV6VG9Rkm1DqEFRG8mjjTL7zmE1Bvn1eR4A==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -579,8 +579,8 @@ packages: '@types/react': optional: true - '@mui/styled-engine@7.3.7': - resolution: {integrity: sha512-y/QkNXv6cF6dZ5APztd/dFWfQ6LHKPx3skyYO38YhQD4+Cxd6sFAL3Z38WMSSC8LQz145Mpp3CcLrSCLKPwYAg==} + '@mui/styled-engine@7.3.8': + resolution: {integrity: sha512-JHAeXQzS0tJ+Fq3C6J4TVDsW+yKhO4uuxuiLaopNStJeQYBIUCXpKYyUCcgXym4AmhbznQnv9RlHywSH6b0FOg==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.4.1 @@ -592,8 +592,8 @@ packages: '@emotion/styled': optional: true - '@mui/system@7.3.7': - resolution: {integrity: sha512-DovL3k+FBRKnhmatzUMyO5bKkhMLlQ9L7Qw5qHrre3m8zCZmE+31NDVBFfqrbrA7sq681qaEIHdkWD5nmiAjyQ==} + '@mui/system@7.3.8': + resolution: {integrity: sha512-hoFRj4Zw2Km8DPWZp/nKG+ao5Jw5LSk2m/e4EGc6M3RRwXKEkMSG4TgtfVJg7dS2homRwtdXSMW+iRO0ZJ4+IA==} engines: {node: '>=14.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -608,16 +608,16 @@ packages: '@types/react': optional: true - '@mui/types@7.4.10': - resolution: {integrity: sha512-0+4mSjknSu218GW3isRqoxKRTOrTLd/vHi/7UC4+wZcUrOAqD9kRk7UQRL1mcrzqRoe7s3UT6rsRpbLkW5mHpQ==} + '@mui/types@7.4.11': + resolution: {integrity: sha512-fZ2xO9D08IKOxO2oUBi1nnVKH6oJUD+64cnv4YAaFoC0E5+i1+S5AHbNqqvZlYYsbPEQ6qEVwuBqY3jl5W4G+Q==} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - '@mui/utils@7.3.7': - resolution: {integrity: sha512-+YjnjMRnyeTkWnspzoxRdiSOgkrcpTikhNPoxOZW0APXx+urHtUoXJ9lbtCZRCA5a4dg5gSbd19alL1DvRs5fg==} + '@mui/utils@7.3.8': + resolution: {integrity: sha512-kZRcE2620CBGr+XI8YMmwPj6WIPwSF7uMJjvSfqd8zXVvlz0MCJbzRRUGNf8NgflCLthdji2DdS643TeyJ3+nA==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -901,8 +901,8 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. - '@types/node@25.2.2': - resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==} + '@types/node@25.2.3': + resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -920,8 +920,8 @@ packages: peerDependencies: '@types/react': '*' - '@types/react@19.2.13': - resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} @@ -929,63 +929,63 @@ packages: '@types/svgo@2.6.4': resolution: {integrity: sha512-l4cmyPEckf8moNYHdJ+4wkHvFxjyW6ulm9l4YGaOxeyBWPhBOT0gvni1InpFPdzx1dKf/2s62qGITwxNWnPQng==} - '@typescript-eslint/eslint-plugin@8.54.0': - resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==} + '@typescript-eslint/eslint-plugin@8.55.0': + resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.54.0 + '@typescript-eslint/parser': ^8.55.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.54.0': - resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==} + '@typescript-eslint/parser@8.55.0': + resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.54.0': - resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==} + '@typescript-eslint/project-service@8.55.0': + resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.54.0': - resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==} + '@typescript-eslint/scope-manager@8.55.0': + resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.54.0': - resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==} + '@typescript-eslint/tsconfig-utils@8.55.0': + resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.54.0': - resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==} + '@typescript-eslint/type-utils@8.55.0': + resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.54.0': - resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==} + '@typescript-eslint/types@8.55.0': + resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.54.0': - resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==} + '@typescript-eslint/typescript-estree@8.55.0': + resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.54.0': - resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==} + '@typescript-eslint/utils@8.55.0': + resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.54.0': - resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==} + '@typescript-eslint/visitor-keys@8.55.0': + resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: @@ -2945,14 +2945,14 @@ packages: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - typesafe-i18n@5.26.2: - resolution: {integrity: sha512-2QAriFmiY5JwUAJtG7yufoE/XZ1aFBY++wj7YFS2yo89a3jLBfKoWSdq5JfQYk1V2BS7V2c/u+KEcaCQoE65hw==} + typesafe-i18n@5.27.1: + resolution: {integrity: sha512-749uWo2ZXETT//kWjVYPm8QPYR8xLh8G0wLfoAyCAtAmysX67uCaAyLjAjAWojL6fuJpE5B6yIjwvO9orXzUPg==} hasBin: true peerDependencies: typescript: '>=3.5.1' - typescript-eslint@8.54.0: - resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==} + typescript-eslint@8.55.0: + resolution: {integrity: sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -3015,8 +3015,8 @@ packages: peerDependencies: vite: 5.x || 6.x || 7.x - vite-tsconfig-paths@6.1.0: - resolution: {integrity: sha512-kpd3sY9glHIDaq4V/Tlc1Y8WaKtutoc3B525GHxEVKWX42FKfQsXvjFOemu1I8VIN8pNbrMLWVTbW79JaRUxKg==} + vite-tsconfig-paths@6.1.1: + resolution: {integrity: sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==} peerDependencies: vite: '*' @@ -3289,7 +3289,7 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4)': + '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 @@ -3301,7 +3301,7 @@ snapshots: hoist-non-react-statics: 3.3.2 react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 transitivePeerDependencies: - supports-color @@ -3315,18 +3315,18 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) '@emotion/serialize': 1.3.3 '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4) '@emotion/utils': 1.4.2 react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 transitivePeerDependencies: - supports-color @@ -3496,25 +3496,25 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@mui/core-downloads-tracker@7.3.7': {} + '@mui/core-downloads-tracker@7.3.8': {} - '@mui/icons-material@7.3.7(@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)': + '@mui/icons-material@7.3.8(@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 - '@mui/material': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mui/material': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@mui/material@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 - '@mui/core-downloads-tracker': 7.3.7 - '@mui/system': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) - '@mui/types': 7.4.10(@types/react@19.2.13) - '@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4) + '@mui/core-downloads-tracker': 7.3.8 + '@mui/system': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@mui/types': 7.4.11(@types/react@19.2.14) + '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) '@popperjs/core': 2.11.8 - '@types/react-transition-group': 4.4.12(@types/react@19.2.13) + '@types/react-transition-group': 4.4.12(@types/react@19.2.14) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 @@ -3523,20 +3523,20 @@ snapshots: react-is: 19.2.4 react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) - '@types/react': 19.2.13 + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@types/react': 19.2.14 - '@mui/private-theming@7.3.7(@types/react@19.2.13)(react@19.2.4)': + '@mui/private-theming@7.3.8(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 - '@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4) + '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) prop-types: 15.8.1 react: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@mui/styled-engine@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(react@19.2.4)': + '@mui/styled-engine@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@emotion/cache': 11.14.0 @@ -3546,42 +3546,42 @@ snapshots: prop-types: 15.8.1 react: 19.2.4 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) - '@mui/system@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4)': + '@mui/system@7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 - '@mui/private-theming': 7.3.7(@types/react@19.2.13)(react@19.2.4) - '@mui/styled-engine': 7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(react@19.2.4) - '@mui/types': 7.4.10(@types/react@19.2.13) - '@mui/utils': 7.3.7(@types/react@19.2.13)(react@19.2.4) + '@mui/private-theming': 7.3.8(@types/react@19.2.14)(react@19.2.4) + '@mui/styled-engine': 7.3.8(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + '@mui/types': 7.4.11(@types/react@19.2.14) + '@mui/utils': 7.3.8(@types/react@19.2.14)(react@19.2.4) clsx: 2.1.1 csstype: 3.2.3 prop-types: 15.8.1 react: 19.2.4 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4) - '@types/react': 19.2.13 + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) + '@types/react': 19.2.14 - '@mui/types@7.4.10(@types/react@19.2.13)': + '@mui/types@7.4.11(@types/react@19.2.14)': dependencies: '@babel/runtime': 7.28.6 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@mui/utils@7.3.7(@types/react@19.2.13)(react@19.2.4)': + '@mui/utils@7.3.8(@types/react@19.2.14)(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 - '@mui/types': 7.4.10(@types/react@19.2.13) + '@mui/types': 7.4.11(@types/react@19.2.14) '@types/prop-types': 15.7.15 clsx: 2.1.1 prop-types: 15.8.1 react: 19.2.4 react-is: 19.2.4 optionalDependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 '@noble/hashes@1.8.0': {} @@ -3607,18 +3607,18 @@ snapshots: dependencies: preact: 10.28.3 - '@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))': + '@preact/preset-vite@2.10.3(@babel/core@7.29.0)(preact@10.28.3)(rollup@4.57.1)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) - '@prefresh/vite': 2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)) + '@prefresh/vite': 2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)) '@rollup/pluginutils': 5.3.0(rollup@4.57.1) babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.29.0) debug: 4.4.3 picocolors: 1.1.1 - vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0) - vite-prerender-plugin: 0.5.12(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)) + vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0) + vite-prerender-plugin: 0.5.12(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)) transitivePeerDependencies: - preact - rollup @@ -3632,7 +3632,7 @@ snapshots: '@prefresh/utils@1.2.1': {} - '@prefresh/vite@2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0))': + '@prefresh/vite@2.4.11(preact@10.28.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0))': dependencies: '@babel/core': 7.29.0 '@prefresh/babel-plugin': 0.5.2 @@ -3640,7 +3640,7 @@ snapshots: '@prefresh/utils': 1.2.1 '@rollup/pluginutils': 4.2.1 preact: 10.28.3 - vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0) + vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0) transitivePeerDependencies: - supports-color @@ -3734,9 +3734,9 @@ snapshots: '@sindresorhus/is@0.7.0': {} - '@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@table-library/react-table-library@4.1.15(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.2.13)(react@19.2.4) + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) clsx: 1.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) @@ -3766,7 +3766,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 6.0.0 - '@types/node': 25.2.2 + '@types/node': 25.2.3 '@types/imagemin-gifsicle@7.0.4': dependencies: @@ -3795,19 +3795,19 @@ snapshots: '@types/imagemin@7.0.1': dependencies: - '@types/node': 25.2.2 + '@types/node': 25.2.3 '@types/json-schema@7.0.15': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 25.2.2 + '@types/node': 25.2.3 '@types/minimatch@6.0.0': dependencies: minimatch: 10.1.2 - '@types/node@25.2.2': + '@types/node@25.2.3': dependencies: undici-types: 7.16.0 @@ -3815,34 +3815,34 @@ snapshots: '@types/prop-types@15.7.15': {} - '@types/react-dom@19.2.3(@types/react@19.2.13)': + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@types/react-transition-group@4.4.12(@types/react@19.2.13)': + '@types/react-transition-group@4.4.12(@types/react@19.2.14)': dependencies: - '@types/react': 19.2.13 + '@types/react': 19.2.14 - '@types/react@19.2.13': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 '@types/responselike@1.0.3': dependencies: - '@types/node': 25.2.2 + '@types/node': 25.2.3 '@types/svgo@2.6.4': dependencies: - '@types/node': 25.2.2 + '@types/node': 25.2.3 - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.54.0(eslint@10.0.0)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/type-utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/parser': 8.55.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.55.0 eslint: 10.0.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3851,41 +3851,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3)': + '@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 eslint: 10.0.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.54.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.55.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) - '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.54.0': + '@typescript-eslint/scope-manager@8.55.0': dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/visitor-keys': 8.55.0 - '@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.54.0(eslint@10.0.0)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.55.0(eslint@10.0.0)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3) debug: 4.4.3 eslint: 10.0.0 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -3893,14 +3893,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.54.0': {} + '@typescript-eslint/types@8.55.0': {} - '@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.55.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.54.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/project-service': 8.55.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.4 @@ -3910,20 +3910,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.54.0(eslint@10.0.0)(typescript@5.9.3)': + '@typescript-eslint/utils@8.55.0(eslint@10.0.0)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.0) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) eslint: 10.0.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.54.0': + '@typescript-eslint/visitor-keys@8.55.0': dependencies: - '@typescript-eslint/types': 8.54.0 + '@typescript-eslint/types': 8.55.0 eslint-visitor-keys: 4.2.1 acorn-jsx@5.3.2(acorn@8.15.0): @@ -5931,16 +5931,16 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.15 - typesafe-i18n@5.26.2(typescript@5.9.3): + typesafe-i18n@5.27.1(typescript@5.9.3): dependencies: typescript: 5.9.3 - typescript-eslint@8.54.0(eslint@10.0.0)(typescript@5.9.3): + typescript-eslint@8.55.0(eslint@10.0.0)(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3) - '@typescript-eslint/parser': 8.54.0(eslint@10.0.0)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.55.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@10.0.0)(typescript@5.9.3) eslint: 10.0.0 typescript: 5.9.3 transitivePeerDependencies: @@ -5986,7 +5986,7 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-plugin-imagemin@0.6.1(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)): + vite-plugin-imagemin@0.6.1(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)): dependencies: '@types/imagemin': 7.0.1 '@types/imagemin-gifsicle': 7.0.4 @@ -6011,11 +6011,11 @@ snapshots: imagemin-webp: 6.1.0 jpegtran-bin: 6.0.1 pathe: 0.2.0 - vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0) + vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0) transitivePeerDependencies: - supports-color - vite-prerender-plugin@0.5.12(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)): + vite-prerender-plugin@0.5.12(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)): dependencies: kolorist: 1.8.0 magic-string: 0.30.21 @@ -6023,19 +6023,19 @@ snapshots: simple-code-frame: 1.3.0 source-map: 0.7.6 stack-trace: 1.0.0-pre2 - vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0) + vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0) - vite-tsconfig-paths@6.1.0(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.2)(terser@5.46.0)): + vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(terser@5.46.0)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) - vite: 7.3.1(@types/node@25.2.2)(terser@5.46.0) + vite: 7.3.1(@types/node@25.2.3)(terser@5.46.0) transitivePeerDependencies: - supports-color - typescript - vite@7.3.1(@types/node@25.2.2)(terser@5.46.0): + vite@7.3.1(@types/node@25.2.3)(terser@5.46.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -6044,7 +6044,7 @@ snapshots: rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.2.2 + '@types/node': 25.2.3 fsevents: 2.3.3 terser: 5.46.0 diff --git a/interface/src/app/main/Customizations.tsx b/interface/src/app/main/Customizations.tsx index 21711380e..53fe71cfb 100644 --- a/interface/src/app/main/Customizations.tsx +++ b/interface/src/app/main/Customizations.tsx @@ -111,13 +111,14 @@ const Customizations = () => { const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] = useState(''); // needed for API URL const [selectedDeviceName, setSelectedDeviceName] = useState(''); + const [selectedDeviceBrand, setSelectedDeviceBrand] = useState(''); const { send: sendResetCustomizations } = useRequest(resetCustomizations(), { immediate: false }); const { send: sendDeviceName } = useRequest( - (data: { id: number; name: string }) => writeDeviceName(data), + (data: { id: number; name: string; brand: string }) => writeDeviceName(data), { immediate: false } @@ -267,6 +268,7 @@ const Customizations = () => { if (device) { setSelectedDeviceTypeNameURL(device.url || ''); setSelectedDeviceName(device.n); + setSelectedDeviceBrand(device.b); } setNumChanges(0); setRestartNeeded(false); @@ -442,7 +444,11 @@ const Customizations = () => { }, [devices, deviceEntities, selectedDevice, sendCustomizationEntities, LL]); const renameDevice = useCallback(async () => { - await sendDeviceName({ id: selectedDevice, name: selectedDeviceName }) + await sendDeviceName({ + id: selectedDevice, + name: selectedDeviceName, + brand: selectedDeviceBrand + }) .then(() => { toast.success(LL.UPDATED_OF(LL.NAME(1))); }) @@ -453,7 +459,14 @@ const Customizations = () => { setRename(false); await fetchCoreData(); }); - }, [selectedDevice, selectedDeviceName, sendDeviceName, LL, fetchCoreData]); + }, [ + selectedDevice, + selectedDeviceName, + selectedDeviceBrand, + sendDeviceName, + LL, + fetchCoreData + ]); const renderDeviceList = () => ( <> @@ -462,15 +475,26 @@ const Customizations = () => { {rename ? ( - setSelectedDeviceName(e.target.value)} - margin="normal" - /> + <> + setSelectedDeviceName(e.target.value)} + margin="normal" + /> + setSelectedDeviceBrand(e.target.value)} + margin="normal" + /> + ) : ( DeviceValue::NUM_TAGS ? 0 : tag]); } +uint8_t EMSdevice::tag_to_flag(const uint8_t tag) { + if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) { + return CommandFlag::CMD_FLAG_HC; + } else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) { + return CommandFlag::CMD_FLAG_DHW; + } else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) { + return CommandFlag::CMD_FLAG_HS; + } else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) { + return CommandFlag::CMD_FLAG_AHS; + } else if (tag >= DeviceValueTAG::TAG_SRC1 && tag <= DeviceValueTAG::TAG_SRC16) { + return CommandFlag::CMD_FLAG_SRC; + } + return 0; +} + // convert UOM to a char string - translating only for hours/minutes/seconds const char * EMSdevice::uom_to_string(uint8_t uom) { switch (uom) { @@ -90,6 +105,9 @@ const char * EMSdevice::uom_to_string(uint8_t uom) { } const char * EMSdevice::brand_to_char() { + if (!custom_brand().empty()) { + return custom_brand().c_str(); + } switch (brand_) { case EMSdevice::Brand::BOSCH: return F_(bosch); @@ -316,7 +334,7 @@ std::string EMSdevice::to_string() { return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ")"; } - if (brand_ == Brand::NO_BRAND) { + if (brand_ == Brand::NO_BRAND && custom_brand().empty()) { return std::string(name()) + " (DeviceID:" + Helpers::hextoa(device_id_) + ", ProductID:" + Helpers::itoa(product_id_) + ", Version:" + version_ + ")"; } @@ -332,7 +350,7 @@ std::string EMSdevice::to_string_version() { // returns out brand + device name // translated std::string EMSdevice::to_string_short() { - if (brand_ == Brand::NO_BRAND) { + if (brand_ == Brand::NO_BRAND && custom_brand().empty()) { return std::string(device_type_2_device_name_translated()) + ": " + name(); } @@ -650,25 +668,21 @@ void EMSdevice::add_device_value(int8_t tag, // to b // add a new command if it has a function attached if (has_cmd) { - uint8_t flags = CommandFlag::ADMIN_ONLY; // executing commands require admin privileges - - if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) { - flags |= CommandFlag::CMD_FLAG_HC; - } else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) { - flags |= CommandFlag::CMD_FLAG_DHW; - } else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) { - flags |= CommandFlag::CMD_FLAG_HS; - } else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) { - flags |= CommandFlag::CMD_FLAG_AHS; - } else if (tag >= DeviceValueTAG::TAG_SRC1 && tag <= DeviceValueTAG::TAG_SRC16) { - flags |= CommandFlag::CMD_FLAG_SRC; - } - + uint8_t flags = CommandFlag::ADMIN_ONLY | tag_to_flag(tag); // executing commands require admin privileges // add the command to our library Command::add(device_type_, device_id_, short_name, f, fullname, flags); } } +void EMSdevice::erase_device_values() { + for (auto & dv : devicevalues_) { + if (dv.has_cmd) { + Command::erase_command(device_type_, dv.short_name, tag_to_flag(dv.tag)); + } + } + devicevalues_.clear(); +} + // single list of options void EMSdevice::register_device_value(int8_t tag, void * value_p, diff --git a/src/core/emsdevice.h b/src/core/emsdevice.h index 93675ade7..555f9d738 100644 --- a/src/core/emsdevice.h +++ b/src/core/emsdevice.h @@ -55,6 +55,7 @@ class EMSdevice { static const char * tag_to_mqtt(int8_t tag); static uint8_t decode_brand(uint8_t value); static bool export_values(uint8_t device_type, JsonObject output, const int8_t id, const uint8_t output_target); + static uint8_t tag_to_flag(const uint8_t tag); // non static functions @@ -124,6 +125,14 @@ class EMSdevice { return custom_name_; } + // set custom brand + void custom_brand(std::string const & custom_brand) { + custom_brand_ = custom_brand; + } + + std::string custom_brand() const { + return custom_brand_; + } // set device model void model(std::string const & model) { model_ = model; @@ -282,6 +291,8 @@ class EMSdevice { int16_t min, uint32_t max); + void erase_device_values(); + void register_device_value(int8_t tag, void * value_p, uint8_t type, const char * const ** options, const char * const * name, uint8_t uom, const cmd_function_p f); @@ -524,12 +535,13 @@ class EMSdevice { uint8_t device_id_ = 0; uint8_t product_id_ = 0; char version_[6]; - const char * default_name_; // the fixed name the EMS model taken from the device library - std::string custom_name_ = ""; // custom name - std::string model_ = ""; // model, taken from the 0x01 telegram. see process_deviceName() - uint8_t flags_ = 0; - uint8_t brand_ = Brand::NO_BRAND; - bool active_ = true; + const char * default_name_; // the fixed name the EMS model taken from the device library + std::string custom_name_ = ""; // custom name + std::string custom_brand_ = ""; // custom brand + std::string model_ = ""; // model, taken from the 0x01 telegram. see process_deviceName() + uint8_t flags_ = 0; + uint8_t brand_ = Brand::NO_BRAND; + bool active_ = true; bool ha_config_done_ = false; bool has_update_ = false; diff --git a/src/core/emsesp.cpp b/src/core/emsesp.cpp index a85dedad2..4b9dae4a4 100644 --- a/src/core/emsesp.cpp +++ b/src/core/emsesp.cpp @@ -1310,6 +1310,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const if (product_id == 0 || (*it)->product_id() != 0) { // update only with valid product_id return true; } + (*it)->erase_device_values(); emsdevices.erase(it); // erase the old device without product_id and re detect break; } @@ -1450,6 +1451,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const if ((e.device_id == device_id) && (e.product_id == product_id)) { LOG_DEBUG("Have customizations for %s with deviceID 0x%02X productID %d", e.custom_name.c_str(), device_id, product_id); emsdevices.back()->custom_name(e.custom_name); + emsdevices.back()->custom_brand(e.custom_brand); break; } } @@ -1760,7 +1762,7 @@ void EMSESP::start() { nvs_.begin("ems-esp", false, "nvs"); // fallback to small nvs } - LOG_DEBUG("NVS device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str()); + LOG_DEBUG("Fuse device information: %s", system_.getBBQKeesGatewayDetails().isEmpty() ? "not set" : system_.getBBQKeesGatewayDetails().c_str()); webSettingsService.begin(); // load EMS-ESP Application settings diff --git a/src/emsesp_version.h b/src/emsesp_version.h index b5cec000c..2cbbb958a 100644 --- a/src/emsesp_version.h +++ b/src/emsesp_version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.8.2-dev.3" +#define EMSESP_APP_VERSION "3.8.2-dev.4" diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index d974c979d..fdb249740 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -76,10 +76,11 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root) // Masked entities customization and custom device name (optional) JsonArray masked_entitiesJson = root["masked_entities"].to(); for (const EntityCustomization & entityCustomization : customizations.entityCustomizations) { - JsonObject entityJson = masked_entitiesJson.add(); - entityJson["product_id"] = entityCustomization.product_id; - entityJson["device_id"] = entityCustomization.device_id; - entityJson["custom_name"] = entityCustomization.custom_name; + JsonObject entityJson = masked_entitiesJson.add(); + entityJson["product_id"] = entityCustomization.product_id; + entityJson["device_id"] = entityCustomization.device_id; + entityJson["custom_name"] = entityCustomization.custom_name; + entityJson["custom_brand"] = entityCustomization.custom_brand; // entries are in the form [optional customname] e.g "08heatingactive|heating is on" JsonArray masked_entityJson = entityJson["entity_ids"].to(); @@ -134,7 +135,7 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c analog.type = analogJson["type"]; analog.is_system = analogJson["is_system"] | false; if (_start && analog.type == EMSESP::analogsensor_.AnalogType::DIGITAL_OUT && analog.uom > DeviceValue::DeviceValueUOM::NONE) { - analog.offset = analog.uom - 1; + analog.offset = analog.uom > 1 ? 1 : 0; } customizations.analogCustomizations.push_back(analog); // add to list } @@ -146,10 +147,11 @@ StateUpdateResult WebCustomization::update(JsonObject root, WebCustomization & c if (root["masked_entities"].is()) { auto masked_entities = root["masked_entities"].as(); for (const JsonObject masked_entity : masked_entities) { - auto emsEntity = EntityCustomization(); - emsEntity.product_id = masked_entity["product_id"]; - emsEntity.device_id = masked_entity["device_id"]; - emsEntity.custom_name = masked_entity["custom_name"] | ""; + auto emsEntity = EntityCustomization(); + emsEntity.product_id = masked_entity["product_id"]; + emsEntity.device_id = masked_entity["device_id"]; + emsEntity.custom_name = masked_entity["custom_name"] | ""; + emsEntity.custom_brand = masked_entity["custom_brand"] | ""; auto masked_entity_ids = masked_entity["entity_ids"].as(); for (const JsonVariant masked_entity_id : masked_entity_ids) { @@ -242,17 +244,19 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J uint8_t unique_device_id = json["id"]; // find product id and device id using the unique id if (emsdevice->unique_id() == unique_device_id) { - uint8_t product_id = emsdevice->product_id(); - uint8_t device_id = emsdevice->device_id(); - auto custom_name = json["name"].as(); + uint8_t product_id = emsdevice->product_id(); + uint8_t device_id = emsdevice->device_id(); + std::string custom_name = json["name"] | ""; + std::string custom_brand = json["brand"] | ""; // updates current record or creates a new one bool entry_exists = false; update([&](WebCustomization & settings) { for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) { if ((*it).product_id == product_id && (*it).device_id == device_id) { - (*it).custom_name = custom_name; - entry_exists = true; + (*it).custom_name = custom_name; + (*it).custom_brand = custom_brand; + entry_exists = true; break; } else { ++it; @@ -262,9 +266,10 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J // if we don't have any customization for this device, create a new entry if (!entry_exists) { EntityCustomization new_entry; - new_entry.product_id = product_id; - new_entry.device_id = device_id; - new_entry.custom_name = custom_name; + new_entry.product_id = product_id; + new_entry.device_id = device_id; + new_entry.custom_name = custom_name; + new_entry.custom_brand = custom_brand; settings.entityCustomizations.push_back(new_entry); } @@ -273,6 +278,7 @@ void WebCustomizationService::writeDeviceName(AsyncWebServerRequest * request, J // update the EMS Device record real-time emsdevice->custom_name(custom_name); + emsdevice->custom_brand(custom_brand); } } } @@ -459,10 +465,11 @@ void WebCustomizationService::load_test_data() { // EMS entities, mark some as favorites webCustomization.entityCustomizations.clear(); - auto emsEntity = EntityCustomization(); - emsEntity.product_id = 123; - emsEntity.device_id = 8; - emsEntity.custom_name = "My Custom Boiler"; + auto emsEntity = EntityCustomization(); + emsEntity.product_id = 123; + emsEntity.device_id = 8; + emsEntity.custom_name = "My Custom Boiler"; + emsEntity.custom_brand = "My Brand"; emsEntity.entity_ids.push_back("08heatingactive|is my heating on?"); emsEntity.entity_ids.push_back("08tapwateractive"); emsEntity.entity_ids.push_back("08selflowtemp|<90"); @@ -472,6 +479,7 @@ void WebCustomizationService::load_test_data() { for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice->is_device_id(emsEntity.device_id)) { emsdevice->custom_name(emsEntity.custom_name); + emsdevice->custom_brand(emsEntity.custom_brand); break; } } diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index a8369d091..e8aab9c0f 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -63,10 +63,11 @@ class AnalogCustomization { // we use product_id and device_id to make the device unique class EntityCustomization { public: - uint8_t product_id; // device's product id - uint8_t device_id; // device's device id - std::string custom_name; // custom device name - std::vector entity_ids; // array of entity ids with masks and optional custom fullname + uint8_t product_id; // device's product id + uint8_t device_id; // device's device id + std::string custom_name; // custom device name + std::string custom_brand; // custom brand name + std::vector entity_ids; // array of entity ids with masks and optional custom fullname }; class WebCustomization {