Zigbee2mqtt: add IEEE address and link to open Z2M#2488
Zigbee2mqtt: add IEEE address and link to open Z2M#2488William-De71 wants to merge 5 commits intoGladysAssistant:masterfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds IEEE address exposure to Zigbee2MQTT devices (UI + merged discovered data), optional “Open in Zigbee2MQTT” links, a Z2M_FRONTEND_URL config (backend + setup UI), i18n entries, styles, and corresponding test/fixture updates. Changes
Sequence DiagramsequenceDiagram
participant User
participant Frontend
participant Server
participant Variables
participant Z2M
User->>Frontend: Open device or discover page
Frontend->>Frontend: componentWillMount / init
Frontend->>Server: GET /api/v1/service/zigbee2mqtt/setup (getZ2mUrl)
Server->>Variables: gladys.variable.getValue('Z2M_FRONTEND_URL') / other vars
Variables-->>Server: returns z2mFrontendUrl or null
Server-->>Frontend: respond with setup (z2mUrl)
Frontend->>Frontend: set z2mUrl, fetch devices & discovered devices
Frontend->>Frontend: merge discovered.ieee_address into devices
Frontend->>User: render device entries (show ieee_address if present)
alt ieee_address present and z2mUrl available
User->>Frontend: Click "Open in Z2M"
Frontend->>Z2M: Open constructed Z2M device URL in new tab
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js (1)
45-53:⚠️ Potential issue | 🟠 MajorDerive
z2mUrlfromz2mFrontendUrlas well, and refresh it after save.Right now
z2mUrlis only computed forMQTT_MODE.LOCAL. The new remote frontend URL is loaded intoconfiguration, but never propagated into the derivedz2mUrlstate, so any UI still consumingz2mUrlstays blank/stale for remote setups.Suggested fix
class Zigbee2mqttSetupPage extends Component { + getZ2mUrl = configuration => { + if (configuration.mqttMode === MQTT_MODE.LOCAL && this.props.session.gatewayClient === undefined) { + const url = new URL(config.localApiUrl); + return `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort || '8080'}`; + } + + if (configuration.mqttMode === MQTT_MODE.REMOTE) { + return configuration.z2mFrontendUrl || null; + } + + return null; + }; + handleZ2MStatus = zigbee2mqttStatus => { this.setState({ zigbee2mqttStatus }); }; @@ const configuration = {}; Object.keys(VARIABLE_MAP).forEach(key => (configuration[VARIABLE_MAP[key]] = savedConfig[key])); this.setState({ configuration, + z2mUrl: this.getZ2mUrl(configuration), loadZigbee2mqttConfig: RequestStatus.Success }); - if (this.props.session.gatewayClient === undefined && configuration.mqttMode === MQTT_MODE.LOCAL) { - const url = new URL(config.localApiUrl); - const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort || '8080'}`; - this.setState({ z2mUrl }); - } @@ const configuration = {}; Object.keys(VARIABLE_MAP).forEach(key => (configuration[VARIABLE_MAP[key]] = savedConfig[key])); this.setState({ configuration, + z2mUrl: this.getZ2mUrl(configuration), setupZigee2mqttStatus: RequestStatus.Success });Also applies to: 68-73
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js` around lines 45 - 53, The z2mUrl state is only set for MQTT_MODE.LOCAL and never derived from configuration.z2mFrontendUrl, so remote setups leave z2mUrl stale; update the logic that sets z2mUrl (the block that currently checks this.props.session.gatewayClient and MQTT_MODE.LOCAL) to also derive z2mUrl from configuration.z2mFrontendUrl when present, and ensure the same derivation is applied after save/update actions (the code paths around saving the configuration) so z2mUrl is refreshed whenever configuration is loaded or saved; reference the state key z2mUrl, the configuration object, and MQTT_MODE.LOCAL and z2mFrontendUrl when making the change.
🧹 Nitpick comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js (1)
10-25: ExtractgetZ2mUrlinto a shared Zigbee2MQTT helper.This block is now effectively duplicated with
front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js, Lines 13-28. Any future fix to URL normalization or store clearing has to be applied twice.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js` around lines 10 - 25, Duplicate logic in getZ2mUrl should be extracted into a shared Zigbee2MQTT helper: create a new helper function (e.g., resolveZ2mUrl or getZ2mUrlFromConfig) that accepts the same inputs used here (state.httpClient, state.session, config.localApiUrl, and store.setState or return value) and encapsulates the URL normalization and store-setting logic currently in getZ2mUrl; export that helper and replace the inline getZ2mUrl implementations in both front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js and device-page/actions.js to call the shared function (or await its result and then set store state consistently), ensuring you preserve the existing behavior for local vs external modes and the case where z2mUrl remains undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@front/src/config/i18n/de.json`:
- Around line 981-983: The translation key "connectionUrl" currently opens a
user-provided URL in a new tab using target="_blank" and must include
rel="noopener noreferrer" to prevent the opened page from accessing
window.opener; update the "connectionUrl" value (the string containing the
anchor tag) to add rel="noopener noreferrer" to the <a> element while preserving
the existing href and target attributes so the link remains functional and safe.
In `@front/src/config/i18n/en.json`:
- Line 876: The translation string "connectionUrl" contains an external anchor
with target="_blank" but lacks rel="noopener noreferrer"; update the value for
the "connectionUrl" key so the anchor tag becomes <a href="{{url}}"
target="_blank" rel="noopener noreferrer"> (i.e., add rel="noopener noreferrer"
to the anchor) to match other external links and avoid introducing an opener
relationship.
In `@front/src/config/i18n/fr.json`:
- Line 1111: The translation string "connectionUrl" currently opens an external
link with target="_blank" but omits rel attributes; update the value for the
"connectionUrl" key to include rel="noopener noreferrer" in the anchor tag so
the external page cannot access window.opener (i.e., modify the string for the
"connectionUrl" key to add rel="noopener noreferrer" to the <a> tag).
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js`:
- Around line 46-49: The action currently fails entirely if the discovered
devices call errors; wrap the second Promise
(state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })) in a try/catch or resolve it separately so that
zigbee2mqttsReceived still returns; set discoveredDevices to an empty array on
error and only attach ieeeAddress when discoveredDevices contains a match (use
the existing discoveredDevices variable and the zigbee2mqttsReceived result),
thereby preserving loaded devices even when discovery/IEEE enrichment is
unavailable.
- Around line 13-27: Clear any stale z2mUrl before attempting to load setup and
DRY the logic into a shared helper: in getZ2mUrl (and the duplicate in
discover-page/actions.js) immediately call store.setState({ z2mUrl: undefined })
or use a shared async helper (e.g., fetchZ2mUrlFromSetup) that performs
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'), returns the resolved
z2mUrl or undefined, and then call store.setState({ z2mUrl }) with that result;
replace the duplicated URL-construction branches in getZ2mUrl and the
discover-page action with a single call to the helper so both pages consistently
clear stale values and set the new z2mUrl only on success.
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx`:
- Around line 169-174: The IEEE address input in Zigbee2mqttBox.jsx is using the
disabled attribute which prevents focus and copying; change the input rendering
that references props.device.ieeeAddress to use the readOnly attribute instead
of disabled (i.e., replace disabled with readOnly on the input element) so the
value remains non-editable but selectable/focusable for support/debug flows.
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Around line 134-152: The device URL built for opening Zigbee2MQTT is missing
the required tab segment; update the href construction that uses z2mUrl and
ieeeAddress (in the DiscoveredBox component where
href={`${z2mUrl}/#/device/0/${ieeeAddress}`} is built) to append a default tab
(e.g. `/info`) so it becomes `${z2mUrl}/#/device/0/${ieeeAddress}/info`; apply
the same fix to the analogous href in Zigbee2mqttBox.jsx to ensure both links
include the tab segment.
In `@server/services/zigbee2mqtt/utils/convertDevice.js`:
- Line 12: The server is destructuring device.ieee_address but consumers expect
device.ieeeAddress; update the destructuring to capture ieee_address as
ieeeAddress (e.g., const { friendly_name: name, definition = {}, ieee_address:
ieeeAddress } = device) and ensure the returned object from convertDevice
includes the ieeeAddress property (also fix the object construction around the
block that currently maps properties at lines referenced as 25-27) so the
emitted device has ieeeAddress available for the UI.
---
Outside diff comments:
In `@front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js`:
- Around line 45-53: The z2mUrl state is only set for MQTT_MODE.LOCAL and never
derived from configuration.z2mFrontendUrl, so remote setups leave z2mUrl stale;
update the logic that sets z2mUrl (the block that currently checks
this.props.session.gatewayClient and MQTT_MODE.LOCAL) to also derive z2mUrl from
configuration.z2mFrontendUrl when present, and ensure the same derivation is
applied after save/update actions (the code paths around saving the
configuration) so z2mUrl is refreshed whenever configuration is loaded or saved;
reference the state key z2mUrl, the configuration object, and MQTT_MODE.LOCAL
and z2mFrontendUrl when making the change.
---
Nitpick comments:
In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js`:
- Around line 10-25: Duplicate logic in getZ2mUrl should be extracted into a
shared Zigbee2MQTT helper: create a new helper function (e.g., resolveZ2mUrl or
getZ2mUrlFromConfig) that accepts the same inputs used here (state.httpClient,
state.session, config.localApiUrl, and store.setState or return value) and
encapsulates the URL normalization and store-setting logic currently in
getZ2mUrl; export that helper and replace the inline getZ2mUrl implementations
in both front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
and device-page/actions.js to call the shared function (or await its result and
then set store state consistently), ensuring you preserve the existing behavior
for local vs external modes and the case where z2mUrl remains undefined.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5f96260f-13d9-4cbe-8e1e-abde79daab75
⛔ Files ignored due to path filters (1)
front/src/assets/integrations/logos/logo_zigbee2mqtt.pngis excluded by!**/*.png
📒 Files selected for processing (25)
front/src/config/i18n/de.jsonfront/src/config/i18n/en.jsonfront/src/config/i18n/fr.jsonfront/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsxfront/src/routes/integration/all/zigbee2mqtt/device-page/actions.jsfront/src/routes/integration/all/zigbee2mqtt/device-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/device-page/style.cssfront/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsxfront/src/routes/integration/all/zigbee2mqtt/discover-page/actions.jsfront/src/routes/integration/all/zigbee2mqtt/discover-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/discover-page/style.cssfront/src/routes/integration/all/zigbee2mqtt/setup-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/setup-page/remote/SetupRemoteOptions.jsxserver/services/zigbee2mqtt/lib/constants.jsserver/services/zigbee2mqtt/lib/getConfiguration.jsserver/services/zigbee2mqtt/lib/saveConfiguration.jsserver/services/zigbee2mqtt/utils/convertDevice.jsserver/test/services/zigbee2mqtt/lib/getConfiguration.test.jsserver/test/services/zigbee2mqtt/lib/getSetup.test.jsserver/test/services/zigbee2mqtt/lib/payloads/discovered_devices.jsonserver/test/services/zigbee2mqtt/lib/payloads/event_device_result.jsonserver/test/services/zigbee2mqtt/lib/saveConfiguration.test.jsserver/test/services/zigbee2mqtt/utils/convertDevice.test.jsserver/test/services/zigbee2mqtt/utils/payloads/CCT5015.jsonserver/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json
front/src/config/i18n/de.json
Outdated
| "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", | ||
| "z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle", | ||
| "z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080" |
There was a problem hiding this comment.
Add rel="noopener noreferrer" to the new external link.
This string opens a user-configured URL in a new tab but still grants the opened page access to window.opener. That is avoidable here and should be closed off.
Suggested fix
- "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+ "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", | |
| "z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle", | |
| "z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080" | |
| "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>", | |
| "z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle", | |
| "z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/config/i18n/de.json` around lines 981 - 983, The translation key
"connectionUrl" currently opens a user-provided URL in a new tab using
target="_blank" and must include rel="noopener noreferrer" to prevent the opened
page from accessing window.opener; update the "connectionUrl" value (the string
containing the anchor tag) to add rel="noopener noreferrer" to the <a> element
while preserving the existing href and target attributes so the link remains
functional and safe.
| "mqtt": "MQTT", | ||
| "status": "Status", | ||
| "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>" | ||
| "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", |
There was a problem hiding this comment.
Add rel="noopener noreferrer" to this external link.
This new target="_blank" link reintroduces an opener relationship. Please keep it aligned with the rest of the file’s external links.
Suggested fix
- "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+ "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", | |
| "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/config/i18n/en.json` at line 876, The translation string
"connectionUrl" contains an external anchor with target="_blank" but lacks
rel="noopener noreferrer"; update the value for the "connectionUrl" key so the
anchor tag becomes <a href="{{url}}" target="_blank" rel="noopener noreferrer">
(i.e., add rel="noopener noreferrer" to the anchor) to match other external
links and avoid introducing an opener relationship.
| "mqtt": "MQTT", | ||
| "status": "Statut", | ||
| "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>" | ||
| "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", |
There was a problem hiding this comment.
Add rel="noopener noreferrer" to the new external link.
Line 1111 opens a configured URL in a new tab with target="_blank" but no rel, so the Zigbee2MQTT frontend keeps access to window.opener.
Suggested fix
- "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+ "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>", | |
| "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/config/i18n/fr.json` at line 1111, The translation string
"connectionUrl" currently opens an external link with target="_blank" but omits
rel attributes; update the value for the "connectionUrl" key to include
rel="noopener noreferrer" in the anchor tag so the external page cannot access
window.opener (i.e., modify the string for the "connectionUrl" key to add
rel="noopener noreferrer" to the <a> tag).
| async getZ2mUrl(state) { | ||
| try { | ||
| const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'); | ||
| if (configuration.Z2M_MQTT_MODE === 'local') { | ||
| if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) { | ||
| const url = new URL(config.localApiUrl); | ||
| const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`; | ||
| store.setState({ z2mUrl }); | ||
| } | ||
| } else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) { | ||
| store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL }); | ||
| } | ||
| } catch (e) { | ||
| // z2mUrl stays undefined, link won't be shown | ||
| } |
There was a problem hiding this comment.
Clear stale z2mUrl values before loading setup.
Lines 13-27 only write z2mUrl in success branches. In the SPA store, a value from a previous visit survives when setup no longer exposes a frontend URL or this request fails, so the “Open in Zigbee2mqtt” link can keep pointing to an invalid target. The same logic is duplicated in front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js, Lines 10-25, so a shared helper would keep both pages consistent.
Suggested fix
async getZ2mUrl(state) {
+ store.setState({ z2mUrl: undefined });
try {
const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
if (configuration.Z2M_MQTT_MODE === 'local') {
if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
const url = new URL(config.localApiUrl);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async getZ2mUrl(state) { | |
| try { | |
| const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'); | |
| if (configuration.Z2M_MQTT_MODE === 'local') { | |
| if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) { | |
| const url = new URL(config.localApiUrl); | |
| const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`; | |
| store.setState({ z2mUrl }); | |
| } | |
| } else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) { | |
| store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL }); | |
| } | |
| } catch (e) { | |
| // z2mUrl stays undefined, link won't be shown | |
| } | |
| async getZ2mUrl(state) { | |
| store.setState({ z2mUrl: undefined }); | |
| try { | |
| const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'); | |
| if (configuration.Z2M_MQTT_MODE === 'local') { | |
| if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) { | |
| const url = new URL(config.localApiUrl); | |
| const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`; | |
| store.setState({ z2mUrl }); | |
| } | |
| } else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) { | |
| store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL }); | |
| } | |
| } catch (e) { | |
| // z2mUrl stays undefined, link won't be shown | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 13 - 27, Clear any stale z2mUrl before attempting to load setup and DRY
the logic into a shared helper: in getZ2mUrl (and the duplicate in
discover-page/actions.js) immediately call store.setState({ z2mUrl: undefined })
or use a shared async helper (e.g., fetchZ2mUrlFromSetup) that performs
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'), returns the resolved
z2mUrl or undefined, and then call store.setState({ z2mUrl }) with that result;
replace the duplicated URL-construction branches in getZ2mUrl and the
discover-page action with a single call to the helper so both pages consistently
clear stale values and set the new z2mUrl only on success.
| const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([ | ||
| state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options), | ||
| state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false }) | ||
| ]); |
There was a problem hiding this comment.
Don’t make IEEE enrichment a hard dependency for loading devices.
Lines 46-49 reject the whole action if /discovered is unavailable, even though that response is only used to attach ieeeAddress. A transient MQTT/discovery failure would now blank the saved-device list as well.
Suggested fix
- const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
- state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
- state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
- ]);
+ const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
+ state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
+ state.httpClient
+ .get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
+ .catch(() => [])
+ ]);Based on learnings: degraded-mode return is preferred over throwing errors because preserving available data is more useful than failing fast; discovery should remain resilient.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([ | |
| state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options), | |
| state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false }) | |
| ]); | |
| const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([ | |
| state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options), | |
| state.httpClient | |
| .get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false }) | |
| .catch(() => []) | |
| ]); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 46 - 49, The action currently fails entirely if the discovered devices
call errors; wrap the second Promise
(state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })) in a try/catch or resolve it separately so that
zigbee2mqttsReceived still returns; set discoveredDevices to an empty array on
error and only attach ieeeAddress when discoveredDevices contains a match (use
the existing discoveredDevices variable and the zigbee2mqttsReceived result),
thereby preserving loaded devices even when discovery/IEEE enrichment is
unavailable.
| <div class="form-group"> | ||
| <label class="form-label"> | ||
| <Text id="integration.zigbee2mqtt.ieeeAddressLabel" /> | ||
| </label> | ||
| <input type="text" class="form-control" value={props.device.ieeeAddress} disabled /> | ||
| {props.z2mUrl && ( |
There was a problem hiding this comment.
Use readOnly instead of disabled for the IEEE address field.
A disabled input can't be focused or copied normally, which makes the new identifier harder to reuse for support/debug flows. readOnly keeps it non-editable without blocking selection.
Suggested fix
- <div class="form-group">
- <label class="form-label">
+ <div class="form-group">
+ <label class="form-label" for={`ieee_${props.deviceIndex}`}>
<Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
</label>
- <input type="text" class="form-control" value={props.device.ieeeAddress} disabled />
+ <input
+ id={`ieee_${props.deviceIndex}`}
+ type="text"
+ class="form-control"
+ value={props.device.ieeeAddress}
+ readOnly
+ />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div class="form-group"> | |
| <label class="form-label"> | |
| <Text id="integration.zigbee2mqtt.ieeeAddressLabel" /> | |
| </label> | |
| <input type="text" class="form-control" value={props.device.ieeeAddress} disabled /> | |
| {props.z2mUrl && ( | |
| <div class="form-group"> | |
| <label class="form-label" for={`ieee_${props.deviceIndex}`}> | |
| <Text id="integration.zigbee2mqtt.ieeeAddressLabel" /> | |
| </label> | |
| <input | |
| id={`ieee_${props.deviceIndex}`} | |
| type="text" | |
| class="form-control" | |
| value={props.device.ieeeAddress} | |
| readOnly | |
| /> | |
| {props.z2mUrl && ( |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx`
around lines 169 - 174, The IEEE address input in Zigbee2mqttBox.jsx is using
the disabled attribute which prevents focus and copying; change the input
rendering that references props.device.ieeeAddress to use the readOnly attribute
instead of disabled (i.e., replace disabled with readOnly on the input element)
so the value remains non-editable but selectable/focusable for support/debug
flows.
| {ieeeAddress && ( | ||
| <div class="form-group"> | ||
| <label class="form-label"> | ||
| <Text id="integration.zigbee2mqtt.ieeeAddressLabel" /> | ||
| </label> | ||
| <input type="text" class="form-control" value={ieeeAddress} disabled /> | ||
| {z2mUrl && ( | ||
| <a | ||
| href={`${z2mUrl}/#/device/0/${ieeeAddress}`} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class={`${style.z2mDeviceLink} mt-2 text-muted`} | ||
| > | ||
| <img src={logoZigbee2mqtt} alt="Zigbee2mqtt" class={style.z2mDeviceLinkLogo} /> | ||
| <Text id="integration.zigbee2mqtt.openInZ2mButton" /> | ||
| </a> | ||
| )} | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Zigbee2MQTT frontend device page URL format
💡 Result:
In the current Zigbee2MQTT WindFront UI (the default frontend), device pages are hash-routed and use the device’s IEEE address plus a source index:
-
Device page (default “info” tab):
http(s)://<host>:<port>/#/device/<sourceIdx>/<ieee_address>/info(raw.githubusercontent.com) -
General format (any tab):
http(s)://<host>:<port>/#/device/<sourceIdx>/<ieee_address>/<tab>
where<tab>is one of:info | exposes | bind | reporting | settings | settings-specific | state | clusters | groups | scene | dev-console. (raw.githubusercontent.com)
If you use frontend.base_url (reverse proxy subpath), it becomes:
http(s)://<host>:<port><base_url>/#/device/<sourceIdx>/<ieee_address>/<tab>. (zigbee2mqtt.io)
Citations:
- 1: https://raw.githubusercontent.com/Nerivec/zigbee2mqtt-windfront/main/src/pages/DevicePage.tsx
- 2: https://raw.githubusercontent.com/Nerivec/zigbee2mqtt-windfront/main/src/pages/DevicePage.tsx
- 3: https://www.zigbee2mqtt.io/guide/configuration/frontend.html?utm_source=openai
🏁 Script executed:
# Quick verification: check if there are other instances of this Z2M URL pattern in the codebase
rg 'device/0/' front/Repository: GladysAssistant/Gladys
Length of output: 379
The Zigbee2MQTT URL is missing the required tab segment.
According to Zigbee2MQTT frontend routing, the correct format is /#/device/<sourceIdx>/<ieee_address>/<tab> where <tab> is one of: info, exposes, bind, reporting, settings, settings-specific, state, clusters, groups, scene, or dev-console.
The current URL ${z2mUrl}/#/device/0/${ieeeAddress} is incomplete. Add a default tab (typically /info):
href={`${z2mUrl}/#/device/0/${ieeeAddress}/info`}
Note: The same issue exists in front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`
around lines 134 - 152, The device URL built for opening Zigbee2MQTT is missing
the required tab segment; update the href construction that uses z2mUrl and
ieeeAddress (in the DiscoveredBox component where
href={`${z2mUrl}/#/device/0/${ieeeAddress}`} is built) to append a default tab
(e.g. `/info`) so it becomes `${z2mUrl}/#/device/0/${ieeeAddress}/info`; apply
the same fix to the analogous href in Zigbee2mqttBox.jsx to ensure both links
include the tab segment.
There was a problem hiding this comment.
♻️ Duplicate comments (3)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)
142-142:⚠️ Potential issue | 🟡 MinorThe Zigbee2MQTT URL is missing the required
/infotab segment.According to Z2M frontend routing, the correct format is
/#/device/<sourceIdx>/<ieee_address>/<tab>. Append/infoto the URL:- href={`${z2mUrl}/#/device/0/${ieee_address}`} + href={`${z2mUrl}/#/device/0/${ieee_address}/info`},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx` at line 142, The generated Zigbee2MQTT device link is missing the required tab segment; update the href template in DiscoveredBox.jsx (the expression using z2mUrl and ieee_address) so it builds `${z2mUrl}/#/device/0/${ieee_address}/info` (i.e., append `/info` to the existing path) to match the Z2M frontend route format.front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js (2)
13-27:⚠️ Potential issue | 🟡 MinorClear stale
z2mUrlbefore loading setup.If this request fails, or setup no longer yields a usable URL, the old value remains in the store and the link can point to the wrong Zigbee2MQTT instance. Reset it before Line 15, then populate it only on success.
Suggested fix
async getZ2mUrl(state) { + store.setState({ z2mUrl: undefined }); try { const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'); if (configuration.Z2M_MQTT_MODE === 'local') { if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) { const url = new URL(config.localApiUrl); const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`; store.setState({ z2mUrl }); } } else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) { store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL }); } } catch (e) { // z2mUrl stays undefined, link won't be shown } },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around lines 13 - 27, The getZ2mUrl function currently leaves a stale z2mUrl in the store if the HTTP request fails or returns no usable URL; before calling state.httpClient.get('/api/v1/service/zigbee2mqtt/setup') clear the stored value (e.g., call store.setState({ z2mUrl: undefined })) so the link is removed, then only call store.setState to populate z2mUrl inside the existing success branches (where configuration.Z2M_MQTT_MODE === 'local' and the external branch) and do not set it in the catch block.
43-46:⚠️ Potential issue | 🟠 MajorDon’t make IEEE enrichment a hard dependency for loading devices.
Line 45 makes
/discoveredrequired for the whole page load, even though it is only used to attachieee_address. A transient discovery error now rejects the entirePromise.alland prevents the saved-device list from loading. Fall back to[]for enrichment data instead.Suggested fix
const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([ state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options), - state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false }) + state.httpClient + .get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false }) + .catch(() => []) ]);Based on learnings: degraded-mode return is preferred over throwing errors because preserving available data is more useful than failing fast. Discovery should remain resilient.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around lines 43 - 46, The code currently treats the discovered devices fetch as a hard dependency by using Promise.all([state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options), state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })]) which causes the whole load to fail if the discovered route errors; change this to allow enrichment to degrade gracefully by either using Promise.allSettled or catching the discoveredDevices promise and falling back to an empty array ([]) so zigbee2mqttsReceived still loads and you can attach ieee_address only when discoveredDevices is available (reference symbols: zigbee2mqttsReceived, discoveredDevices, Promise.all, state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered')).
🧹 Nitpick comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)
136-139: Consider addingid/forattributes for accessibility consistency.Other form inputs in this file (e.g.,
name_${deviceIndex},room_${deviceIndex},topic_${deviceIndex}) useidattributes with correspondingforattributes on labels. The IEEE address input lacks this pattern.♿ Proposed fix for accessibility consistency
<div class="form-group"> - <label class="form-label"> + <label class="form-label" for={`ieee_address_${deviceIndex}`}> <Text id="integration.zigbee2mqtt.ieeeAddressLabel" /> </label> - <input type="text" class="form-control" value={ieee_address} disabled /> + <input id={`ieee_address_${deviceIndex}`} type="text" class="form-control" value={ieee_address} disabled />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx` around lines 136 - 139, The IEEE address input lacks an id/for pairing for accessibility; update the label and input in the DiscoveredBox component to follow the same pattern used by other fields (e.g., name_${deviceIndex}, room_${deviceIndex}). Add a unique id for the input (such as `ieee_${deviceIndex}` or similar based on `deviceIndex`) and set the label's htmlFor/for attribute to that id so the label is correctly associated with the `ieee_address` input. Ensure the id value is unique per device instance and use the same `deviceIndex` variable used elsewhere in this component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js`:
- Around line 13-27: The getZ2mUrl function currently leaves a stale z2mUrl in
the store if the HTTP request fails or returns no usable URL; before calling
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup') clear the stored value
(e.g., call store.setState({ z2mUrl: undefined })) so the link is removed, then
only call store.setState to populate z2mUrl inside the existing success branches
(where configuration.Z2M_MQTT_MODE === 'local' and the external branch) and do
not set it in the catch block.
- Around line 43-46: The code currently treats the discovered devices fetch as a
hard dependency by using
Promise.all([state.httpClient.get('/api/v1/service/zigbee2mqtt/device',
options), state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })]) which causes the whole load to fail if the
discovered route errors; change this to allow enrichment to degrade gracefully
by either using Promise.allSettled or catching the discoveredDevices promise and
falling back to an empty array ([]) so zigbee2mqttsReceived still loads and you
can attach ieee_address only when discoveredDevices is available (reference
symbols: zigbee2mqttsReceived, discoveredDevices, Promise.all,
state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered')).
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Line 142: The generated Zigbee2MQTT device link is missing the required tab
segment; update the href template in DiscoveredBox.jsx (the expression using
z2mUrl and ieee_address) so it builds
`${z2mUrl}/#/device/0/${ieee_address}/info` (i.e., append `/info` to the
existing path) to match the Z2M frontend route format.
---
Nitpick comments:
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Around line 136-139: The IEEE address input lacks an id/for pairing for
accessibility; update the label and input in the DiscoveredBox component to
follow the same pattern used by other fields (e.g., name_${deviceIndex},
room_${deviceIndex}). Add a unique id for the input (such as
`ieee_${deviceIndex}` or similar based on `deviceIndex`) and set the label's
htmlFor/for attribute to that id so the label is correctly associated with the
`ieee_address` input. Ensure the id value is unique per device instance and use
the same `deviceIndex` variable used elsewhere in this component.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d564f7ee-eb42-4c1d-a402-9bcc03ff95ba
📒 Files selected for processing (3)
front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsxfront/src/routes/integration/all/zigbee2mqtt/device-page/actions.jsfront/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
- front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
e827419 to
6a5094d
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)
142-142:⚠️ Potential issue | 🟡 MinorAdd a default tab segment to the Zigbee2MQTT device URL.
At Line 142, the route is built as
/#/device/0/${ieee_address}. This has already been flagged and still risks breaking deep-linking on Windfront versions expecting.../${tab}(commonly/info).Suggested patch
- href={`${z2mUrl}/#/device/0/${ieee_address}`} + href={`${z2mUrl}/#/device/0/${encodeURIComponent(ieee_address)}/info`}In the current Zigbee2MQTT Windfront frontend, what is the expected device hash route format: /#/device/<sourceIdx>/<ieee_address> or /#/device/<sourceIdx>/<ieee_address>/<tab> (e.g., /info)?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx` at line 142, The device link built in DiscoveredBox.jsx currently uses href={`${z2mUrl}/#/device/0/${ieee_address}`} which omits the expected tab segment; update the href to include a default tab (e.g., `/info`) so deep-links become `${z2mUrl}/#/device/0/${ieee_address}/info`; locate the JSX anchor using z2mUrl and ieee_address and append the `/info` segment (or use a DEFAULT_Z2M_TAB constant and reference that) to ensure compatibility with Windfront routes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Line 142: The device link built in DiscoveredBox.jsx currently uses
href={`${z2mUrl}/#/device/0/${ieee_address}`} which omits the expected tab
segment; update the href to include a default tab (e.g., `/info`) so deep-links
become `${z2mUrl}/#/device/0/${ieee_address}/info`; locate the JSX anchor using
z2mUrl and ieee_address and append the `/info` segment (or use a DEFAULT_Z2M_TAB
constant and reference that) to ensure compatibility with Windfront routes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4f83f0dd-52db-4f57-8f17-c33faa253778
⛔ Files ignored due to path filters (1)
front/src/assets/integrations/logos/logo_zigbee2mqtt.pngis excluded by!**/*.png
📒 Files selected for processing (25)
front/src/config/i18n/de.jsonfront/src/config/i18n/en.jsonfront/src/config/i18n/fr.jsonfront/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsxfront/src/routes/integration/all/zigbee2mqtt/device-page/actions.jsfront/src/routes/integration/all/zigbee2mqtt/device-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/device-page/style.cssfront/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsxfront/src/routes/integration/all/zigbee2mqtt/discover-page/actions.jsfront/src/routes/integration/all/zigbee2mqtt/discover-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/discover-page/style.cssfront/src/routes/integration/all/zigbee2mqtt/setup-page/index.jsfront/src/routes/integration/all/zigbee2mqtt/setup-page/remote/SetupRemoteOptions.jsxserver/services/zigbee2mqtt/lib/constants.jsserver/services/zigbee2mqtt/lib/getConfiguration.jsserver/services/zigbee2mqtt/lib/saveConfiguration.jsserver/services/zigbee2mqtt/utils/convertDevice.jsserver/test/services/zigbee2mqtt/lib/getConfiguration.test.jsserver/test/services/zigbee2mqtt/lib/getSetup.test.jsserver/test/services/zigbee2mqtt/lib/payloads/discovered_devices.jsonserver/test/services/zigbee2mqtt/lib/payloads/event_device_result.jsonserver/test/services/zigbee2mqtt/lib/saveConfiguration.test.jsserver/test/services/zigbee2mqtt/utils/convertDevice.test.jsserver/test/services/zigbee2mqtt/utils/payloads/CCT5015.jsonserver/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json
✅ Files skipped from review due to trivial changes (12)
- server/services/zigbee2mqtt/utils/convertDevice.js
- server/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json
- server/services/zigbee2mqtt/lib/constants.js
- server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
- server/test/services/zigbee2mqtt/lib/getConfiguration.test.js
- server/test/services/zigbee2mqtt/utils/payloads/CCT5015.json
- front/src/routes/integration/all/zigbee2mqtt/device-page/style.css
- front/src/routes/integration/all/zigbee2mqtt/discover-page/style.css
- front/src/config/i18n/en.json
- server/test/services/zigbee2mqtt/lib/payloads/discovered_devices.json
- front/src/config/i18n/de.json
- server/test/services/zigbee2mqtt/utils/convertDevice.test.js
🚧 Files skipped from review as they are similar to previous changes (10)
- server/services/zigbee2mqtt/lib/saveConfiguration.js
- server/test/services/zigbee2mqtt/lib/getSetup.test.js
- server/services/zigbee2mqtt/lib/getConfiguration.js
- front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
- front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js
- front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js
- front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
- front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
- front/src/config/i18n/fr.json
- front/src/routes/integration/all/zigbee2mqtt/device-page/index.js
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2488 +/- ##
=======================================
Coverage 98.81% 98.81%
=======================================
Files 1009 1009
Lines 17662 17665 +3
=======================================
+ Hits 17452 17455 +3
Misses 210 210 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
#4119 Bundle Size — 11.6MiB (+1.41%).da09c12(current) vs 198578d master#4106(baseline) Warning Bundle contains 2 duplicate packages – View duplicate packages Bundle metrics
Bundle size by type
Bundle analysis report Branch William-De71:features/zigbee2mqt... Project dashboard Generated by RelativeCI Documentation Report issue |
Pull Request check-list
To ensure your Pull Request can be accepted as fast as possible, make sure to review and check all of these items:
npm teston both front/server)npm run eslinton both front/server)npm run prettieron both front/server)npm run compare-translationson front)front/src/config/demo.js) so that the demo website is working without a backend? (if needed) See https://demo.gladysassistant.com.NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.
Description of change
add IEEE address and link to open Z2M on device & discover page
https://community.gladysassistant.com/t/ajout-de-lid-zigbee2mqtt-dans-la-configuration-des-appareils/9616
Summary by CodeRabbit
New Features
Translations