Skip to content

Commit c7d8222

Browse files
authored
fix: clear UC cluster warnings when Studio reports components installed (#1713)
* fix: clear UC cluster warnings when Studio reports components installed
1 parent e733173 commit c7d8222

3 files changed

Lines changed: 148 additions & 16 deletions

File tree

src/util/common-mixin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ export default {
303303
)
304304

305305
return requiredComponentIdList.filter(
306-
(id) => !selectedUcComponentIds.includes(id)
306+
(id) => !selectedUcComponentIds.includes(Util.extractUcClusterCode(id))
307307
)
308308
},
309309

src/util/util.js

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -153,24 +153,50 @@ export function getUcComponents(ucComponentTreeResponse) {
153153
}
154154

155155
/**
156-
* Extract a list of cluster id from a list of Uc component id
156+
* Returns the short cluster code from a UC component id, regardless of which
157+
* prefix format the id uses. Strips everything up to the last '%' and then
158+
* everything up to the last '-', and lowercases the result. Use this when
159+
* you need to compare ids that came from different sources.
157160
*
158-
* return: a list of ids
159-
* id value example:
160-
* "zigbee_basic" from "studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic"
161-
"%extension-matter%matter_level_control" from "matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control"
162-
* @param {*} ucComponentIds - an array of ids
161+
* Examples:
162+
* "studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic"
163+
* -> "zigbee_basic"
164+
* "matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control"
165+
* -> "matter_level_control"
166+
* "%extension-zigbee%zigbee_basic"
167+
* -> "zigbee_basic"
168+
* "zigbee_basic"
169+
* -> "zigbee_basic"
170+
*
171+
* @param {*} id
172+
* @returns {string}
173+
*/
174+
export function extractUcClusterCode(id) {
175+
if (id == null) return ''
176+
let s = String(id).toLowerCase()
177+
const lastPct = s.lastIndexOf('%')
178+
if (lastPct >= 0 && lastPct < s.length - 1) s = s.substring(lastPct + 1)
179+
const lastDash = s.lastIndexOf('-')
180+
if (lastDash >= 0 && lastDash < s.length - 1) s = s.substring(lastDash + 1)
181+
return s
182+
}
183+
184+
/**
185+
* Returns the short cluster codes (see extractUcClusterCode) for a list of UC
186+
* component objects.
187+
*
188+
* Example:
189+
* input: [
190+
* { id: "studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic" },
191+
* { id: "matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control" }
192+
* ]
193+
* output: ["zigbee_basic", "matter_level_control"]
194+
*
195+
* @param {*} ucComponents - an array of UC component objects with `id`
196+
* @returns {string[]}
163197
*/
164198
export function getClusterIdsByUcComponents(ucComponents) {
165-
return ucComponents
166-
.map((component) => component.id)
167-
.map((id) => {
168-
if (id.includes('zigbee')) {
169-
return id.substr(id.lastIndexOf('-') + 1)
170-
} else if (id.includes('%extension-')) {
171-
return id.substr(id.lastIndexOf('%extension-'))
172-
}
173-
})
199+
return ucComponents.map((c) => extractUcClusterCode(c.id))
174200
}
175201

176202
/**

test/util.test.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,109 @@ test(
6161
},
6262
timeout.short()
6363
)
64+
65+
// extractUcClusterCode and getClusterIdsByUcComponents together back the
66+
// "Required SLC Component not installed" warning. They reduce UC component
67+
// ids to a canonical short cluster code so selected ids (from Studio's tree)
68+
// and required ids (from the ZCL extension's component map) can be compared
69+
// regardless of which prefix format the source happens to use.
70+
test(
71+
'extractUcClusterCode: collapses all known id formats to the short code',
72+
() => {
73+
// Studio tree leaf, zigbee
74+
expect(
75+
util.extractUcClusterCode(
76+
'studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic'
77+
)
78+
).toEqual('zigbee_basic')
79+
80+
// Studio tree leaf, matter
81+
expect(
82+
util.extractUcClusterCode(
83+
'studiocomproot-Matter-Clusters-Common-matter_basic'
84+
)
85+
).toEqual('matter_basic')
86+
87+
// %extension form used by the ZCL extension required-component map
88+
expect(util.extractUcClusterCode('%extension-zigbee%zigbee_basic')).toEqual(
89+
'zigbee_basic'
90+
)
91+
expect(
92+
util.extractUcClusterCode('%extension-matter%matter_level_control')
93+
).toEqual('matter_level_control')
94+
95+
// Composite path with %extension inside (what Studio sends for matter)
96+
expect(
97+
util.extractUcClusterCode(
98+
'matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control'
99+
)
100+
).toEqual('matter_level_control')
101+
102+
// Bare short code passes through
103+
expect(util.extractUcClusterCode('zigbee_basic')).toEqual('zigbee_basic')
104+
105+
// Defensive cases
106+
expect(util.extractUcClusterCode(null)).toEqual('')
107+
expect(util.extractUcClusterCode(undefined)).toEqual('')
108+
expect(util.extractUcClusterCode('')).toEqual('')
109+
},
110+
timeout.short()
111+
)
112+
113+
test(
114+
'getClusterIdsByUcComponents: maps mixed zigbee+matter components to short codes',
115+
() => {
116+
const components = [
117+
{ id: 'studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic' },
118+
{ id: 'studiocomproot-Zigbee-Cluster_Library-HA-zigbee_on_off' },
119+
{
120+
id: 'matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control'
121+
},
122+
{ id: '%extension-matter%matter_basic' }
123+
]
124+
expect(util.getClusterIdsByUcComponents(components)).toEqual([
125+
'zigbee_basic',
126+
'zigbee_on_off',
127+
'matter_level_control',
128+
'matter_basic'
129+
])
130+
},
131+
timeout.short()
132+
)
133+
134+
test(
135+
'getClusterIdsByUcComponents + extractUcClusterCode: matter and zigbee required ids both match',
136+
() => {
137+
// Mirrors the comparison in common-mixin's missingUcComponentDependencies:
138+
// selectedIds = getClusterIdsByUcComponents(selected)
139+
// missing = required.filter(r => !selectedIds.includes(extractUcClusterCode(r)))
140+
const selected = [
141+
{ id: 'studiocomproot-Zigbee-Cluster_Library-Common-zigbee_basic' },
142+
{
143+
id: 'matter:1.0.0-Matter-Clusters-%extension-matter%matter_level_control'
144+
}
145+
]
146+
const selectedIds = util.getClusterIdsByUcComponents(selected)
147+
148+
// Required ids come from the ZCL extension in %extension-...%name form.
149+
const required = [
150+
'%extension-zigbee%zigbee_basic',
151+
'%extension-matter%matter_level_control'
152+
]
153+
const missing = required.filter(
154+
(id) => !selectedIds.includes(util.extractUcClusterCode(id))
155+
)
156+
expect(missing).toEqual([])
157+
158+
// Anything genuinely not in selected stays in the missing list.
159+
const requiredWithGap = [
160+
'%extension-zigbee%zigbee_basic',
161+
'%extension-zigbee%zigbee_on_off' // not selected
162+
]
163+
const missingWithGap = requiredWithGap.filter(
164+
(id) => !selectedIds.includes(util.extractUcClusterCode(id))
165+
)
166+
expect(missingWithGap).toEqual(['%extension-zigbee%zigbee_on_off'])
167+
},
168+
timeout.short()
169+
)

0 commit comments

Comments
 (0)