@switchbot/homebridge-switchbot 5.1.0-beta.8 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +0 -63
- package/.github/scripts/normalize-changelog-header.cjs +1 -1
- package/.github/scripts/npm-version-script-esm-auto.js +1 -1
- package/.github/scripts/resolve-version-bump-esm.js +1 -1
- package/CHANGELOG.md +10 -9
- package/MIGRATION.md +0 -5
- package/README.md +0 -25
- package/config.schema.json +0 -11
- package/dist/{Platform.HAP.d.ts → SwitchBotHAPPlatform.d.ts} +16 -2
- package/dist/SwitchBotHAPPlatform.d.ts.map +1 -0
- package/dist/{Platform.HAP.js → SwitchBotHAPPlatform.js} +111 -40
- package/dist/SwitchBotHAPPlatform.js.map +1 -0
- package/dist/{Platform.Matter.d.ts → SwitchBotMatterPlatform.d.ts} +2 -4
- package/dist/SwitchBotMatterPlatform.d.ts.map +1 -0
- package/dist/{Platform.Matter.js → SwitchBotMatterPlatform.js} +6 -62
- package/dist/SwitchBotMatterPlatform.js.map +1 -0
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +5 -15
- package/dist/deviceFactory.js.map +1 -1
- package/dist/devices/genericDevice.d.ts +63 -5
- package/dist/devices/genericDevice.d.ts.map +1 -1
- package/dist/devices/genericDevice.js +251 -11
- package/dist/devices/genericDevice.js.map +1 -1
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/config.js +2 -9
- package/dist/homebridge-ui/endpoints/config.js.map +1 -1
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +2 -9
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -1
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +0 -8
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -1
- package/dist/homebridge-ui/public/css/styles.css +1 -61
- package/dist/homebridge-ui/public/index.html +2 -61
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/advanced-settings.js +3 -4
- package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -1
- package/dist/homebridge-ui/public/js/advanced-settings.ts +3 -4
- package/dist/homebridge-ui/public/js/api.d.ts +0 -16
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +0 -48
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +1 -61
- package/dist/homebridge-ui/public/js/app.js +115 -267
- package/dist/homebridge-ui/public/js/app.js.map +4 -4
- package/dist/homebridge-ui/public/js/app.ts +4 -47
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.js +5 -11
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -1
- package/dist/homebridge-ui/public/js/credentials.ts +5 -11
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +0 -6
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +0 -6
- package/dist/homebridge-ui/public/js/modals.d.ts +0 -1
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/modals.js +0 -53
- package/dist/homebridge-ui/public/js/modals.js.map +1 -1
- package/dist/homebridge-ui/public/js/modals.ts +0 -58
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +1 -2
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +1 -2
- package/dist/homebridge-ui/settings.js.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.d.ts +0 -8
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.js +0 -8
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +0 -11
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/dist/utils.d.ts +0 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +0 -27
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +15 -15
- package/docs/index.html +5 -22
- package/docs/variables/default.html +1 -1
- package/package.json +15 -9
- package/scripts/build-ui.js +0 -30
- package/src/{Platform.HAP.ts → SwitchBotHAPPlatform.ts} +112 -39
- package/src/{Platform.Matter.ts → SwitchBotMatterPlatform.ts} +8 -63
- package/src/deviceFactory.ts +5 -14
- package/src/devices/genericDevice.ts +271 -12
- package/src/homebridge-ui/endpoints/config.ts +2 -10
- package/src/homebridge-ui/public/css/styles.css +1 -61
- package/src/homebridge-ui/public/index.html +0 -59
- package/src/homebridge-ui/public/js/advanced-settings.ts +3 -4
- package/src/homebridge-ui/public/js/api.ts +1 -61
- package/src/homebridge-ui/public/js/app.ts +4 -47
- package/src/homebridge-ui/public/js/credentials.ts +5 -11
- package/src/homebridge-ui/public/js/devices.ts +0 -6
- package/src/homebridge-ui/public/js/modals.ts +0 -58
- package/src/homebridge-ui/public/js/render.ts +1 -2
- package/src/homebridge-ui/utils/config-parser.ts +0 -9
- package/src/index.ts +2 -2
- package/src/settings.ts +0 -12
- package/src/utils.ts +0 -31
- package/test/device/deviceFactory.spec.ts +9 -0
- package/test/device/getstate-cache.spec.ts +62 -0
- package/test/device/getstate-returns-status.spec.ts +89 -0
- package/test/device/water-detector-battery.spec.ts +81 -0
- package/test/device/water-detector-leak.spec.ts +43 -0
- package/test/hap-push-updates.spec.ts +150 -0
- package/test/platform/accessory-restore.spec.ts +2 -2
- package/test/platform/matter-childbridge.spec.ts +1 -1
- package/test/platform/matter-integration.spec.ts +1 -51
- package/test/platform/platform-edge.spec.ts +2 -2
- package/test/platform/platform.integration.spec.ts +1 -1
- package/test/utils/utils.spec.ts +0 -15
- package/.github/npm-version-script-esm.js +0 -97
- package/dist/Platform.HAP.d.ts.map +0 -1
- package/dist/Platform.HAP.js.map +0 -1
- package/dist/Platform.Matter.d.ts.map +0 -1
- package/dist/Platform.Matter.js.map +0 -1
- package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js +0 -23
- package/dist/homebridge-ui/homebridge-ui/utils/v4-detection.js.map +0 -1
- package/dist/homebridge-ui/public/js/legacy-view.d.ts +0 -3
- package/dist/homebridge-ui/public/js/legacy-view.d.ts.map +0 -1
- package/dist/homebridge-ui/public/js/legacy-view.js +0 -43
- package/dist/homebridge-ui/public/js/legacy-view.js.map +0 -1
- package/dist/homebridge-ui/public/js/legacy-view.ts +0 -99
- package/dist/homebridge-ui/utils/v4-detection.d.ts +0 -12
- package/dist/homebridge-ui/utils/v4-detection.d.ts.map +0 -1
- package/dist/homebridge-ui/utils/v4-detection.js +0 -23
- package/dist/homebridge-ui/utils/v4-detection.js.map +0 -1
- package/src/homebridge-ui/public/js/legacy-view.js +0 -43
- package/src/homebridge-ui/public/js/legacy-view.ts +0 -99
- package/src/homebridge-ui/utils/v4-detection.ts +0 -23
- package/test/homebridge-ui/config-parser.spec.ts +0 -61
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { disableLegacyView, enableLegacyView } from './legacy-view.js'
|
|
2
|
-
|
|
3
|
-
// Toggle button visibility and view containers
|
|
4
|
-
function updateViewButtons() {
|
|
5
|
-
const legacyBtn = document.getElementById('legacyViewBtn')
|
|
6
|
-
const dynamicBtn = document.getElementById('dynamicViewBtn')
|
|
7
|
-
const legacyContainer = document.getElementById('legacyViewContainer')
|
|
8
|
-
if (legacyContainer && legacyContainer.style.display === 'block') {
|
|
9
|
-
if (legacyBtn) {
|
|
10
|
-
legacyBtn.style.display = 'none'
|
|
11
|
-
}
|
|
12
|
-
if (dynamicBtn) {
|
|
13
|
-
dynamicBtn.style.display = 'inline-block'
|
|
14
|
-
}
|
|
15
|
-
} else {
|
|
16
|
-
if (legacyBtn) {
|
|
17
|
-
legacyBtn.style.display = 'inline-block'
|
|
18
|
-
}
|
|
19
|
-
if (dynamicBtn) {
|
|
20
|
-
dynamicBtn.style.display = 'none'
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
26
|
-
const legacyBtn = document.getElementById('legacyViewBtn')
|
|
27
|
-
const dynamicBtn = document.getElementById('dynamicViewBtn')
|
|
28
|
-
if (legacyBtn) {
|
|
29
|
-
legacyBtn.addEventListener('click', () => {
|
|
30
|
-
console.log('[SwitchBot UI] Legacy View button clicked')
|
|
31
|
-
enableLegacyView()
|
|
32
|
-
updateViewButtons()
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
if (dynamicBtn) {
|
|
36
|
-
dynamicBtn.addEventListener('click', () => {
|
|
37
|
-
console.log('[SwitchBot UI] Dynamic View button clicked')
|
|
38
|
-
disableLegacyView()
|
|
39
|
-
updateViewButtons()
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
updateViewButtons()
|
|
43
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"legacy-view.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/legacy-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// legacy-view.ts
|
|
2
|
-
// Renders the config UI from config.schema.json and toggles between legacy and dynamic UI
|
|
3
|
-
|
|
4
|
-
import schema from '../../../../config.schema.json'
|
|
5
|
-
|
|
6
|
-
function renderLegacyView() {
|
|
7
|
-
const container = document.getElementById('legacyConfigForm')
|
|
8
|
-
if (!container) {
|
|
9
|
-
const legacyContainer = document.getElementById('legacyViewContainer')
|
|
10
|
-
if (legacyContainer) {
|
|
11
|
-
legacyContainer.innerHTML = '<div style="color:red;font-weight:bold">[SwitchBot UI] Error: legacyConfigForm container not found</div>'
|
|
12
|
-
}
|
|
13
|
-
console.error('[SwitchBot UI] Error: legacyConfigForm container not found')
|
|
14
|
-
return
|
|
15
|
-
}
|
|
16
|
-
container.innerHTML = ''
|
|
17
|
-
const { properties } = schema.schema
|
|
18
|
-
const layout = schema.layout || []
|
|
19
|
-
const form = document.createElement('form')
|
|
20
|
-
for (const section of layout) {
|
|
21
|
-
const fieldset = document.createElement('fieldset')
|
|
22
|
-
if (section.title) {
|
|
23
|
-
const legend = document.createElement('legend')
|
|
24
|
-
legend.textContent = section.title
|
|
25
|
-
fieldset.appendChild(legend)
|
|
26
|
-
}
|
|
27
|
-
for (const key of section.items) {
|
|
28
|
-
const prop = properties[key]
|
|
29
|
-
if (!prop) {
|
|
30
|
-
continue
|
|
31
|
-
}
|
|
32
|
-
if (prop.type === 'array' && prop.items && prop.items.properties) {
|
|
33
|
-
// Render array of devices as a table
|
|
34
|
-
const table = document.createElement('table')
|
|
35
|
-
table.style.marginBottom = '12px'
|
|
36
|
-
const thead = document.createElement('thead')
|
|
37
|
-
const headerRow = document.createElement('tr')
|
|
38
|
-
for (const colKey of Object.keys(prop.items.properties)) {
|
|
39
|
-
const th = document.createElement('th')
|
|
40
|
-
th.textContent = prop.items.properties[colKey].title || colKey
|
|
41
|
-
headerRow.appendChild(th)
|
|
42
|
-
}
|
|
43
|
-
thead.appendChild(headerRow)
|
|
44
|
-
table.appendChild(thead)
|
|
45
|
-
// No data rows (read-only legacy view)
|
|
46
|
-
fieldset.appendChild(table)
|
|
47
|
-
continue
|
|
48
|
-
}
|
|
49
|
-
const label = document.createElement('label')
|
|
50
|
-
label.textContent = prop.title || key
|
|
51
|
-
label.style.display = 'block'
|
|
52
|
-
let input: HTMLElement
|
|
53
|
-
if (prop.enum) {
|
|
54
|
-
const select = document.createElement('select')
|
|
55
|
-
select.name = key
|
|
56
|
-
for (const opt of prop.enum) {
|
|
57
|
-
const option = document.createElement('option')
|
|
58
|
-
option.value = opt
|
|
59
|
-
option.textContent = opt
|
|
60
|
-
select.appendChild(option)
|
|
61
|
-
}
|
|
62
|
-
input = select
|
|
63
|
-
} else if (prop.type === 'boolean') {
|
|
64
|
-
const checkbox = document.createElement('input')
|
|
65
|
-
checkbox.type = 'checkbox'
|
|
66
|
-
checkbox.name = key
|
|
67
|
-
if (prop.default) {
|
|
68
|
-
checkbox.checked = true
|
|
69
|
-
}
|
|
70
|
-
input = checkbox
|
|
71
|
-
} else {
|
|
72
|
-
const text = document.createElement('input')
|
|
73
|
-
text.name = key
|
|
74
|
-
text.type = prop.format === 'password' ? 'password' : 'text'
|
|
75
|
-
if (prop.default) {
|
|
76
|
-
text.value = prop.default
|
|
77
|
-
}
|
|
78
|
-
input = text
|
|
79
|
-
}
|
|
80
|
-
label.appendChild(input)
|
|
81
|
-
fieldset.appendChild(label)
|
|
82
|
-
}
|
|
83
|
-
form.appendChild(fieldset)
|
|
84
|
-
}
|
|
85
|
-
container.appendChild(form)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function enableLegacyView() {
|
|
89
|
-
document.getElementById('dynamicUiContainer')!.style.display = 'none'
|
|
90
|
-
document.getElementById('legacyViewContainer')!.style.display = 'block'
|
|
91
|
-
renderLegacyView()
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function disableLegacyView() {
|
|
95
|
-
document.getElementById('dynamicUiContainer')!.style.display = 'block'
|
|
96
|
-
document.getElementById('legacyViewContainer')!.style.display = 'none'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// (window assignment removed; handled in .js entry point)
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detect whether a platform config block is in the legacy v4 format.
|
|
3
|
-
*
|
|
4
|
-
* v4 configs stored credentials under a `credentials` sub-object and devices
|
|
5
|
-
* under `options.devices`. v5+ flattened these to `openApiToken`,
|
|
6
|
-
* `openApiSecret`, and a root-level `devices` array.
|
|
7
|
-
*
|
|
8
|
-
* This helper has no Node.js-specific dependencies so it can be imported from
|
|
9
|
-
* both the Homebridge server-side code and the browser-side plugin UI bundle.
|
|
10
|
-
*/
|
|
11
|
-
export declare function isV4Config(platform: any): boolean;
|
|
12
|
-
//# sourceMappingURL=v4-detection.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"v4-detection.d.ts","sourceRoot":"","sources":["../../../src/homebridge-ui/utils/v4-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAYjD"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detect whether a platform config block is in the legacy v4 format.
|
|
3
|
-
*
|
|
4
|
-
* v4 configs stored credentials under a `credentials` sub-object and devices
|
|
5
|
-
* under `options.devices`. v5+ flattened these to `openApiToken`,
|
|
6
|
-
* `openApiSecret`, and a root-level `devices` array.
|
|
7
|
-
*
|
|
8
|
-
* This helper has no Node.js-specific dependencies so it can be imported from
|
|
9
|
-
* both the Homebridge server-side code and the browser-side plugin UI bundle.
|
|
10
|
-
*/
|
|
11
|
-
export function isV4Config(platform) {
|
|
12
|
-
if (!platform || typeof platform !== 'object') {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
// Presence of a `credentials` sub-object is the clearest v4 signal
|
|
16
|
-
const hasCredentials = platform.credentials !== undefined && typeof platform.credentials === 'object';
|
|
17
|
-
// Presence of `options.devices` is the other v4 signal
|
|
18
|
-
const hasOptionsDevices = platform.options !== undefined
|
|
19
|
-
&& typeof platform.options === 'object'
|
|
20
|
-
&& Array.isArray(platform.options.devices);
|
|
21
|
-
return hasCredentials || hasOptionsDevices;
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=v4-detection.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"v4-detection.js","sourceRoot":"","sources":["../../../src/homebridge-ui/utils/v4-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,QAAa;IACtC,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAA;IACd,CAAC;IACD,mEAAmE;IACnE,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,QAAQ,CAAA;IACrG,uDAAuD;IACvD,MAAM,iBAAiB,GACnB,QAAQ,CAAC,OAAO,KAAK,SAAS;WAC7B,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ;WACpC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5C,OAAO,cAAc,IAAI,iBAAiB,CAAA;AAC5C,CAAC"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { disableLegacyView, enableLegacyView } from './legacy-view.js'
|
|
2
|
-
|
|
3
|
-
// Toggle button visibility and view containers
|
|
4
|
-
function updateViewButtons() {
|
|
5
|
-
const legacyBtn = document.getElementById('legacyViewBtn')
|
|
6
|
-
const dynamicBtn = document.getElementById('dynamicViewBtn')
|
|
7
|
-
const legacyContainer = document.getElementById('legacyViewContainer')
|
|
8
|
-
if (legacyContainer && legacyContainer.style.display === 'block') {
|
|
9
|
-
if (legacyBtn) {
|
|
10
|
-
legacyBtn.style.display = 'none'
|
|
11
|
-
}
|
|
12
|
-
if (dynamicBtn) {
|
|
13
|
-
dynamicBtn.style.display = 'inline-block'
|
|
14
|
-
}
|
|
15
|
-
} else {
|
|
16
|
-
if (legacyBtn) {
|
|
17
|
-
legacyBtn.style.display = 'inline-block'
|
|
18
|
-
}
|
|
19
|
-
if (dynamicBtn) {
|
|
20
|
-
dynamicBtn.style.display = 'none'
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
26
|
-
const legacyBtn = document.getElementById('legacyViewBtn')
|
|
27
|
-
const dynamicBtn = document.getElementById('dynamicViewBtn')
|
|
28
|
-
if (legacyBtn) {
|
|
29
|
-
legacyBtn.addEventListener('click', () => {
|
|
30
|
-
console.log('[SwitchBot UI] Legacy View button clicked')
|
|
31
|
-
enableLegacyView()
|
|
32
|
-
updateViewButtons()
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
if (dynamicBtn) {
|
|
36
|
-
dynamicBtn.addEventListener('click', () => {
|
|
37
|
-
console.log('[SwitchBot UI] Dynamic View button clicked')
|
|
38
|
-
disableLegacyView()
|
|
39
|
-
updateViewButtons()
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
updateViewButtons()
|
|
43
|
-
})
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// legacy-view.ts
|
|
2
|
-
// Renders the config UI from config.schema.json and toggles between legacy and dynamic UI
|
|
3
|
-
|
|
4
|
-
import schema from '../../../../config.schema.json'
|
|
5
|
-
|
|
6
|
-
function renderLegacyView() {
|
|
7
|
-
const container = document.getElementById('legacyConfigForm')
|
|
8
|
-
if (!container) {
|
|
9
|
-
const legacyContainer = document.getElementById('legacyViewContainer')
|
|
10
|
-
if (legacyContainer) {
|
|
11
|
-
legacyContainer.innerHTML = '<div style="color:red;font-weight:bold">[SwitchBot UI] Error: legacyConfigForm container not found</div>'
|
|
12
|
-
}
|
|
13
|
-
console.error('[SwitchBot UI] Error: legacyConfigForm container not found')
|
|
14
|
-
return
|
|
15
|
-
}
|
|
16
|
-
container.innerHTML = ''
|
|
17
|
-
const { properties } = schema.schema
|
|
18
|
-
const layout = schema.layout || []
|
|
19
|
-
const form = document.createElement('form')
|
|
20
|
-
for (const section of layout) {
|
|
21
|
-
const fieldset = document.createElement('fieldset')
|
|
22
|
-
if (section.title) {
|
|
23
|
-
const legend = document.createElement('legend')
|
|
24
|
-
legend.textContent = section.title
|
|
25
|
-
fieldset.appendChild(legend)
|
|
26
|
-
}
|
|
27
|
-
for (const key of section.items) {
|
|
28
|
-
const prop = properties[key]
|
|
29
|
-
if (!prop) {
|
|
30
|
-
continue
|
|
31
|
-
}
|
|
32
|
-
if (prop.type === 'array' && prop.items && prop.items.properties) {
|
|
33
|
-
// Render array of devices as a table
|
|
34
|
-
const table = document.createElement('table')
|
|
35
|
-
table.style.marginBottom = '12px'
|
|
36
|
-
const thead = document.createElement('thead')
|
|
37
|
-
const headerRow = document.createElement('tr')
|
|
38
|
-
for (const colKey of Object.keys(prop.items.properties)) {
|
|
39
|
-
const th = document.createElement('th')
|
|
40
|
-
th.textContent = prop.items.properties[colKey].title || colKey
|
|
41
|
-
headerRow.appendChild(th)
|
|
42
|
-
}
|
|
43
|
-
thead.appendChild(headerRow)
|
|
44
|
-
table.appendChild(thead)
|
|
45
|
-
// No data rows (read-only legacy view)
|
|
46
|
-
fieldset.appendChild(table)
|
|
47
|
-
continue
|
|
48
|
-
}
|
|
49
|
-
const label = document.createElement('label')
|
|
50
|
-
label.textContent = prop.title || key
|
|
51
|
-
label.style.display = 'block'
|
|
52
|
-
let input: HTMLElement
|
|
53
|
-
if (prop.enum) {
|
|
54
|
-
const select = document.createElement('select')
|
|
55
|
-
select.name = key
|
|
56
|
-
for (const opt of prop.enum) {
|
|
57
|
-
const option = document.createElement('option')
|
|
58
|
-
option.value = opt
|
|
59
|
-
option.textContent = opt
|
|
60
|
-
select.appendChild(option)
|
|
61
|
-
}
|
|
62
|
-
input = select
|
|
63
|
-
} else if (prop.type === 'boolean') {
|
|
64
|
-
const checkbox = document.createElement('input')
|
|
65
|
-
checkbox.type = 'checkbox'
|
|
66
|
-
checkbox.name = key
|
|
67
|
-
if (prop.default) {
|
|
68
|
-
checkbox.checked = true
|
|
69
|
-
}
|
|
70
|
-
input = checkbox
|
|
71
|
-
} else {
|
|
72
|
-
const text = document.createElement('input')
|
|
73
|
-
text.name = key
|
|
74
|
-
text.type = prop.format === 'password' ? 'password' : 'text'
|
|
75
|
-
if (prop.default) {
|
|
76
|
-
text.value = prop.default
|
|
77
|
-
}
|
|
78
|
-
input = text
|
|
79
|
-
}
|
|
80
|
-
label.appendChild(input)
|
|
81
|
-
fieldset.appendChild(label)
|
|
82
|
-
}
|
|
83
|
-
form.appendChild(fieldset)
|
|
84
|
-
}
|
|
85
|
-
container.appendChild(form)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function enableLegacyView() {
|
|
89
|
-
document.getElementById('dynamicUiContainer')!.style.display = 'none'
|
|
90
|
-
document.getElementById('legacyViewContainer')!.style.display = 'block'
|
|
91
|
-
renderLegacyView()
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function disableLegacyView() {
|
|
95
|
-
document.getElementById('dynamicUiContainer')!.style.display = 'block'
|
|
96
|
-
document.getElementById('legacyViewContainer')!.style.display = 'none'
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// (window assignment removed; handled in .js entry point)
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detect whether a platform config block is in the legacy v4 format.
|
|
3
|
-
*
|
|
4
|
-
* v4 configs stored credentials under a `credentials` sub-object and devices
|
|
5
|
-
* under `options.devices`. v5+ flattened these to `openApiToken`,
|
|
6
|
-
* `openApiSecret`, and a root-level `devices` array.
|
|
7
|
-
*
|
|
8
|
-
* This helper has no Node.js-specific dependencies so it can be imported from
|
|
9
|
-
* both the Homebridge server-side code and the browser-side plugin UI bundle.
|
|
10
|
-
*/
|
|
11
|
-
export function isV4Config(platform: any): boolean {
|
|
12
|
-
if (!platform || typeof platform !== 'object') {
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
// Presence of a `credentials` sub-object is the clearest v4 signal
|
|
16
|
-
const hasCredentials = platform.credentials !== undefined && typeof platform.credentials === 'object'
|
|
17
|
-
// Presence of `options.devices` is the other v4 signal
|
|
18
|
-
const hasOptionsDevices
|
|
19
|
-
= platform.options !== undefined
|
|
20
|
-
&& typeof platform.options === 'object'
|
|
21
|
-
&& Array.isArray(platform.options.devices)
|
|
22
|
-
return hasCredentials || hasOptionsDevices
|
|
23
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { isV4Config } from '../../src/homebridge-ui/utils/v4-detection.js'
|
|
4
|
-
|
|
5
|
-
describe('isV4Config', () => {
|
|
6
|
-
it('returns false for null/undefined input', () => {
|
|
7
|
-
expect(isV4Config(null)).toBe(false)
|
|
8
|
-
expect(isV4Config(undefined)).toBe(false)
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
it('returns false for an empty v5 config block', () => {
|
|
12
|
-
expect(isV4Config({ platform: 'SwitchBot', devices: [] })).toBe(false)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('returns false for a v5 config with credentials omitted', () => {
|
|
16
|
-
expect(isV4Config({ platform: 'SwitchBot', openApiToken: 'tok', openApiSecret: 'sec', devices: [] })).toBe(false)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('returns true when a credentials sub-object is present (v4 token location)', () => {
|
|
20
|
-
const v4 = {
|
|
21
|
-
platform: 'SwitchBot',
|
|
22
|
-
credentials: { token: 'tok', secret: 'sec', notice: 'Keep your token a secret!' },
|
|
23
|
-
options: { devices: [] },
|
|
24
|
-
}
|
|
25
|
-
expect(isV4Config(v4)).toBe(true)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('returns true when options.devices array is present without credentials (partial v4)', () => {
|
|
29
|
-
const partialV4 = {
|
|
30
|
-
platform: 'SwitchBot',
|
|
31
|
-
options: {
|
|
32
|
-
devices: [{ deviceId: 'aabbcc', configDeviceName: 'Curtain', configDeviceType: 'Curtain', connectionType: 'BLE' }],
|
|
33
|
-
},
|
|
34
|
-
}
|
|
35
|
-
expect(isV4Config(partialV4)).toBe(true)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('returns true for the exact config from the bug report', () => {
|
|
39
|
-
const bugReportConfig = {
|
|
40
|
-
name: 'SwitchBot',
|
|
41
|
-
credentials: { notice: 'Keep your token a secret!' },
|
|
42
|
-
options: {
|
|
43
|
-
devices: [
|
|
44
|
-
{
|
|
45
|
-
deviceId: 'xxxxxxxx',
|
|
46
|
-
configDeviceName: 'Curtain',
|
|
47
|
-
configDeviceType: 'Curtain',
|
|
48
|
-
connectionType: 'BLE',
|
|
49
|
-
hide_lightsensor: false,
|
|
50
|
-
set_min: 96,
|
|
51
|
-
set_max: 12,
|
|
52
|
-
maxRetry: 0,
|
|
53
|
-
logging: 'standard',
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
},
|
|
57
|
-
platform: 'SwitchBot',
|
|
58
|
-
}
|
|
59
|
-
expect(isV4Config(bugReportConfig)).toBe(true)
|
|
60
|
-
})
|
|
61
|
-
})
|