From 2f0bf200338005af2a1d83ecf85b60913768fbc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Thu, 17 Sep 2026 09:45:14 +0200 Subject: [PATCH] v0.14.23-fixed_js --- FILE_MANIFEST.sha256 | 12 ++++++------ SOURCE_MANIFEST.sha256 | 10 +++++----- src/api/history.rs | 4 ++-- web/js-dynamic/core.js | 8 ++++++-- web/js-dynamic/forms.js | 7 ++++++- web/js/custom-chart.js | 11 ++++++++--- web/js/sw.js | 2 +- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/FILE_MANIFEST.sha256 b/FILE_MANIFEST.sha256 index 0bfca48..0831f70 100644 --- a/FILE_MANIFEST.sha256 +++ b/FILE_MANIFEST.sha256 @@ -4,7 +4,7 @@ a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore f22febd60f53442e200fd1cb2d077d55319918a034812645f96f07d70abace89 ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE 120d48f01abeee74e84d4257bffc1fe7da9e8b3a07a048284b2c18ea273b07a6 ./README.md -4207577ded7d1bbe99ce37664c0748a57eb8019eebc261e40c6256be4b9d29b2 ./SOURCE_MANIFEST.sha256 +83dbdd1c6acd9ffbab24d367b70ce20c59bf03d6a545b6bac8348145c777cdc2 ./SOURCE_MANIFEST.sha256 29e9821e5ed216ea3565dd6d8bc0b174ed3cf9fa72c4ccebbfa99e98db3ad8f9 ./build.rs 27203e279ab83dd2ff638db02d23d4b00f8864c92f09e8ed3194574b989c43ae ./docs/API.md 8b548d02dbdf0563f2be617a1d677459bd1959bed93a1799a01bf61bb5aed405 ./docs/FLOW.md @@ -110,7 +110,7 @@ ca21f6d5a407e2e3532899d53ba4e8682c2fe961a46d8cd870ddc459721513ef ./src/api/devi d59b080b392b574ec94276c7b485b455d0d1abacc7de2ef29dcbfcf7d86dbdb0 ./src/api/flows.rs a17ab0b6d683d285441be15f2af33172d7caa9a57ec8b32e59107379631a377e ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -eb88001591ef26601391198b8b87f08cf445fbdd855faa152e33c5554e23f6b7 ./src/api/history.rs +3cc64b9c992805f3fbf01c0785cf29ce3121750bf30bd6420ed6e5cf2f8df422 ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs 8495967c3df72110f591c744975984c78cafc8181b2d430e7fd5b9baf57eba95 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs @@ -207,12 +207,12 @@ e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon. 9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js-dynamic/README.md 27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js-dynamic/bootstrap.js 5d57253a013fd1cb79e4b8701d4be6e394e3f2acbce73dfcd726a86e5878f1a1 ./web/js-dynamic/charts.js -1c7a779d6b793413e6f92e6bea910d035ffa22356aae965923a14ed84ab6bd8d ./web/js-dynamic/core.js +7d81a798fb9a91125642d3bb8c938d4b1dcaef3aa580203bc48bf73308229bd7 ./web/js-dynamic/core.js 752b3c3b59558b42d867d4a15329238f0213f354b76f7011c10e31b4e6dbb311 ./web/js-dynamic/dashboard.js 0f975542ae1d9bd7216123dd3718be6e9a25dbe643eb899c67024d293940fae5 ./web/js-dynamic/entities.js 7a4d02bb1ebfa3a5962c7a0b567338d460b99f30ec582fda3a7fec9f6fe54840 ./web/js-dynamic/events.js 1865ef1ed93f04fe323338ac44ef06c9b19ad6ec222d47085ce51cb4c03fe13d ./web/js-dynamic/flows.js -a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js-dynamic/forms.js +3ae714de6b71c068ba665c81a7689f994b1716284e8d937db669ad500f12cf63 ./web/js-dynamic/forms.js 92d013bb5d64f64aa8c55380704540a5f72732bde7ccd16554965e401daf50ea ./web/js-dynamic/history.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js-dynamic/main.js 86031d4f7f7d1b46412c8fbb09ff1ad1b2b4cd84eb949bc749b27663f1dc27fa ./web/js-dynamic/navigation.js @@ -221,8 +221,8 @@ a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js-dynam c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js-dynamic/select-ui.js f7245f0e6cb5011196704f201675ebc6c19d902b8253ffcdbf9ead46cb1c6f86 ./web/js-dynamic/settings-ui.js 672e404470bc6331aa6d658523b221659ec64222af9cc9c17ced978f725790da ./web/js-dynamic/settings.js -43a6afc9d48e55eb7169a8b3a2ac7d8be8e337be0b1028a2f7fbf6f18c8247f6 ./web/js/custom-chart.js +930777048669688985b494a10dad8e591c82666071bde1018eef8f725a660895 ./web/js/custom-chart.js 6ae536b18db756bf5eda9adb1b8a550d5a02bfc80f0b7da27fa146039f22e884 ./web/js/lang-init.js -7403cd7f4b2e09b2564be094bd4bd8e81dbed0f329de4cde91fdc48d752bbf70 ./web/js/sw.js +e3fc113d4c349f33f3faa32e7a46c96a85c71643f43f2e488065dc9715e27333 ./web/js/sw.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/js/theme-init.js 6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest diff --git a/SOURCE_MANIFEST.sha256 b/SOURCE_MANIFEST.sha256 index d6d6b93..ff4b6d6 100644 --- a/SOURCE_MANIFEST.sha256 +++ b/SOURCE_MANIFEST.sha256 @@ -109,7 +109,7 @@ ca21f6d5a407e2e3532899d53ba4e8682c2fe961a46d8cd870ddc459721513ef ./src/api/devi d59b080b392b574ec94276c7b485b455d0d1abacc7de2ef29dcbfcf7d86dbdb0 ./src/api/flows.rs a17ab0b6d683d285441be15f2af33172d7caa9a57ec8b32e59107379631a377e ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -eb88001591ef26601391198b8b87f08cf445fbdd855faa152e33c5554e23f6b7 ./src/api/history.rs +3cc64b9c992805f3fbf01c0785cf29ce3121750bf30bd6420ed6e5cf2f8df422 ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs 8495967c3df72110f591c744975984c78cafc8181b2d430e7fd5b9baf57eba95 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs @@ -206,12 +206,12 @@ e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon. 9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js-dynamic/README.md 27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js-dynamic/bootstrap.js 5d57253a013fd1cb79e4b8701d4be6e394e3f2acbce73dfcd726a86e5878f1a1 ./web/js-dynamic/charts.js -1c7a779d6b793413e6f92e6bea910d035ffa22356aae965923a14ed84ab6bd8d ./web/js-dynamic/core.js +7d81a798fb9a91125642d3bb8c938d4b1dcaef3aa580203bc48bf73308229bd7 ./web/js-dynamic/core.js 752b3c3b59558b42d867d4a15329238f0213f354b76f7011c10e31b4e6dbb311 ./web/js-dynamic/dashboard.js 0f975542ae1d9bd7216123dd3718be6e9a25dbe643eb899c67024d293940fae5 ./web/js-dynamic/entities.js 7a4d02bb1ebfa3a5962c7a0b567338d460b99f30ec582fda3a7fec9f6fe54840 ./web/js-dynamic/events.js 1865ef1ed93f04fe323338ac44ef06c9b19ad6ec222d47085ce51cb4c03fe13d ./web/js-dynamic/flows.js -a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js-dynamic/forms.js +3ae714de6b71c068ba665c81a7689f994b1716284e8d937db669ad500f12cf63 ./web/js-dynamic/forms.js 92d013bb5d64f64aa8c55380704540a5f72732bde7ccd16554965e401daf50ea ./web/js-dynamic/history.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js-dynamic/main.js 86031d4f7f7d1b46412c8fbb09ff1ad1b2b4cd84eb949bc749b27663f1dc27fa ./web/js-dynamic/navigation.js @@ -220,8 +220,8 @@ a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js-dynam c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js-dynamic/select-ui.js f7245f0e6cb5011196704f201675ebc6c19d902b8253ffcdbf9ead46cb1c6f86 ./web/js-dynamic/settings-ui.js 672e404470bc6331aa6d658523b221659ec64222af9cc9c17ced978f725790da ./web/js-dynamic/settings.js -43a6afc9d48e55eb7169a8b3a2ac7d8be8e337be0b1028a2f7fbf6f18c8247f6 ./web/js/custom-chart.js +930777048669688985b494a10dad8e591c82666071bde1018eef8f725a660895 ./web/js/custom-chart.js 6ae536b18db756bf5eda9adb1b8a550d5a02bfc80f0b7da27fa146039f22e884 ./web/js/lang-init.js -7403cd7f4b2e09b2564be094bd4bd8e81dbed0f329de4cde91fdc48d752bbf70 ./web/js/sw.js +e3fc113d4c349f33f3faa32e7a46c96a85c71643f43f2e488065dc9715e27333 ./web/js/sw.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/js/theme-init.js 6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest diff --git a/src/api/history.rs b/src/api/history.rs index e7ee0e4..536bc33 100644 --- a/src/api/history.rs +++ b/src/api/history.rs @@ -654,12 +654,12 @@ async fn public_custom_chart( Query(query): Query, ) -> Result, AppError> { if token.len() < 32 || token.len() > 128 || !token.starts_with("chart_") { - return Err(AppError::NotFound("custom chart".into())); + return Err(AppError::NotFound("chart id not found".into())); } let payload = state .db .get_public_chart_share(&hash_token(&token))? - .ok_or_else(|| AppError::NotFound("custom chart".into()))?; + .ok_or_else(|| AppError::NotFound("chart id not found".into()))?; let share: PublicCustomChartShare = serde_json::from_value(payload)?; validate_public_chart_spec(&share.series)?; diff --git a/web/js-dynamic/core.js b/web/js-dynamic/core.js index 444ff58..67f9462 100644 --- a/web/js-dynamic/core.js +++ b/web/js-dynamic/core.js @@ -413,8 +413,12 @@ async function api(path, options = {}) { } const response = await fetch(withBase(path), { ...options, headers, body }); if (response.status === 401) { - showTokenDialog(); - throw new Error(tr('auth.invalid')); + const invalidToken = Boolean(app.token); + const message = invalidToken ? tr('auth.invalid') : tr('auth.required'); + showTokenDialog(invalidToken ? message : ''); + const error = new Error(message); + error.status = response.status; + throw error; } if (!response.ok) { let message = tr('error.http', { status: response.status }); diff --git a/web/js-dynamic/forms.js b/web/js-dynamic/forms.js index 4b7eaef..c38627a 100644 --- a/web/js-dynamic/forms.js +++ b/web/js-dynamic/forms.js @@ -315,8 +315,13 @@ document.addEventListener('cancel', event => { if (confirmDiscardForm(form)) dialog.close(); }, true); -function showTokenDialog() { +function showTokenDialog(errorMessage = '') { const dialog = $('#tokenDialog'); + const form = $('#tokenForm'); + if (form) { + clearFormErrors(form); + if (errorMessage) showFieldError(form.elements.token, errorMessage); + } if (!dialog.open) dialog.showModal(); } diff --git a/web/js/custom-chart.js b/web/js/custom-chart.js index 23141a8..266a543 100644 --- a/web/js/custom-chart.js +++ b/web/js/custom-chart.js @@ -19,6 +19,7 @@ const withBase = path => `${PUBLIC_BASE}${path.startsWith('/') ? path : `/${path const PUBLIC_DEFAULT_LANGUAGE = String(document.documentElement.lang || '').trim(); const PUBLIC_RANGE_KEYS = ['history.6h', 'history.24h', 'history.7d', 'history.30d', 'history.90d', 'history.1y']; let publicLanguageManifest = null; +const publicLanguagePacks = new Map(); let publicChartLanguage = PUBLIC_DEFAULT_LANGUAGE; let publicChartTranslations = {}; let publicChartLocale = PUBLIC_DEFAULT_LANGUAGE; @@ -49,9 +50,13 @@ async function setPublicChartLanguage(language) { || languages.find(entry => entry.code === fallbackCode) || languages[0]; if (!item) throw new Error('language pack unavailable'); - const response = await fetch(withBase(item.path || `/lang/${encodeURIComponent(item.code)}.json`), { headers: { Accept: 'application/json' } }); - if (!response.ok) throw new Error(`language ${item.code} HTTP ${response.status}`); - const pack = await response.json(); + let pack = publicLanguagePacks.get(item.code); + if (!pack) { + const response = await fetch(withBase(item.path || `/lang/${encodeURIComponent(item.code)}.json`), { headers: { Accept: 'application/json' } }); + if (!response.ok) throw new Error(`language ${item.code} HTTP ${response.status}`); + pack = await response.json(); + publicLanguagePacks.set(item.code, pack); + } publicChartLanguage = item.code; publicChartTranslations = pack.translations || {}; publicChartLocale = pack.meta?.locale || item.locale || item.code; diff --git a/web/js/sw.js b/web/js/sw.js index 886080d..da85b22 100644 --- a/web/js/sw.js +++ b/web/js/sw.js @@ -1,7 +1,7 @@ const CACHE = 'gree-controller-__GREE_ASSET_CACHE__'; const SCOPE = new URL(self.registration.scope).pathname.replace(/\/$/, ''); const path = value => `${SCOPE}${value.startsWith('/') ? value : `/${value}`}` || '/'; -const ASSETS = [path('__GREE_STYLES_ASSET__'), path('__GREE_APP_ASSET__'), path('__GREE_THEME_INIT_ASSET__'), path('__GREE_LANG_INIT_ASSET__'), path('/favicon.svg'), path('/manifest.webmanifest')]; +const ASSETS = [path('__GREE_STYLES_ASSET__'), path('__GREE_APP_ASSET__'), path('__GREE_THEME_INIT_ASSET__'), path('__GREE_LANG_INIT_ASSET__'), path('/manifest.webmanifest')]; self.addEventListener('install', event => event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(ASSETS)).then(() => self.skipWaiting()))); self.addEventListener('activate', event => event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(key => key !== CACHE).map(key => caches.delete(key)))).then(() => self.clients.claim()))); self.addEventListener('fetch', event => {