@switchbot/homebridge-switchbot 5.0.0-beta.109 → 5.0.0-beta.110
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/config.schema.json +4 -0
- package/dist/device-types.d.ts +18 -2
- package/dist/device-types.d.ts.map +1 -1
- package/dist/device-types.js +71 -0
- package/dist/device-types.js.map +1 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +1 -0
- package/dist/deviceFactory.js.map +1 -1
- package/dist/homebridge-ui/endpoints/config.d.ts +0 -3
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/config.js +40 -9
- package/dist/homebridge-ui/endpoints/config.js.map +1 -1
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/devices.js +59 -2
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -1
- package/dist/homebridge-ui/public/css/styles.css +254 -0
- package/dist/homebridge-ui/public/index.html +23 -168
- package/dist/homebridge-ui/public/js/api.d.ts +4 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +14 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +17 -1
- package/dist/homebridge-ui/public/js/app.js +556 -44
- package/dist/homebridge-ui/public/js/app.js.map +3 -3
- package/dist/homebridge-ui/public/js/app.ts +2 -1
- package/dist/homebridge-ui/public/js/devices-delete.d.ts +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.js +108 -1
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices-delete.ts +124 -1
- package/dist/homebridge-ui/public/js/devices.d.ts +1 -0
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +10 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +10 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +130 -4
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +158 -4
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/modals.js +71 -26
- package/dist/homebridge-ui/public/js/modals.js.map +1 -1
- package/dist/homebridge-ui/public/js/modals.ts +74 -27
- package/dist/homebridge-ui/public/js/render.d.ts +57 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +286 -13
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +331 -11
- package/dist/homebridge-ui/utils/device-migration.d.ts +35 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/platform.js +2 -2
- package/dist/platform.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/device-types.ts +85 -0
- package/src/deviceFactory.ts +1 -0
- package/src/homebridge-ui/endpoints/config.ts +54 -10
- package/src/homebridge-ui/endpoints/devices.ts +62 -3
- package/src/homebridge-ui/public/css/styles.css +254 -0
- package/src/homebridge-ui/public/index.html +23 -168
- package/src/homebridge-ui/public/js/api.ts +17 -1
- package/src/homebridge-ui/public/js/app.ts +2 -1
- package/src/homebridge-ui/public/js/devices-delete.ts +124 -1
- package/src/homebridge-ui/public/js/devices.ts +10 -0
- package/src/homebridge-ui/public/js/discovery.ts +158 -4
- package/src/homebridge-ui/public/js/modals.ts +74 -27
- package/src/homebridge-ui/public/js/render.ts +331 -11
- package/src/homebridge-ui/utils/device-migration.ts +144 -0
- package/src/platform.ts +2 -2
- package/todo/COMPLETED.md +189 -0
- package/todo/README.md +59 -0
- package/todo/TODO.md +205 -0
- package/todo/mockups/filtering-sorting.svg +112 -0
- package/todo/mockups/modal-switchbot-theme.svg +66 -0
- package/todo/mockups/signal-strength-visualization.svg +94 -0
- package/TODO.md +0 -564
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { loadConfiguredDevices } from './devices.js'
|
|
8
8
|
import { uiLog } from './logger.js'
|
|
9
9
|
import { hideBusyUi, showBusyUi } from './modal.js'
|
|
10
|
-
import { renderDiscoveredDevices } from './render.js'
|
|
10
|
+
import { renderDiscoveredDevices, filterDevices, sortDevices, getDiscoveryPreferences, setDiscoveryPreferences } from './render.js'
|
|
11
11
|
import { toastError, toastInfo, toastSuccess, toastWarning } from './toast.js'
|
|
12
12
|
|
|
13
13
|
export async function discoverDevices(): Promise<void> {
|
|
@@ -48,6 +48,9 @@ export async function discoverDevices(): Promise<void> {
|
|
|
48
48
|
deviceId: d.id,
|
|
49
49
|
name: d.name,
|
|
50
50
|
type: d.type,
|
|
51
|
+
rssi: d.rssi,
|
|
52
|
+
address: d.address,
|
|
53
|
+
model: d.model,
|
|
51
54
|
})),
|
|
52
55
|
)
|
|
53
56
|
uiLog.info('Bulk add response:', bulkResult)
|
|
@@ -100,10 +103,130 @@ export async function discoverDevices(): Promise<void> {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
status.textContent = `Found ${devices.length} device(s)`
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
|
|
107
|
+
// Create filter/sort controls
|
|
108
|
+
const controlsDiv = document.createElement('div')
|
|
109
|
+
controlsDiv.style.cssText = 'margin-bottom: 12px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center;'
|
|
110
|
+
|
|
111
|
+
// Load saved preferences
|
|
112
|
+
const preferences = getDiscoveryPreferences()
|
|
113
|
+
|
|
114
|
+
// Filter buttons
|
|
115
|
+
const filterLabel = document.createElement('label')
|
|
116
|
+
filterLabel.style.fontSize = '12px'
|
|
117
|
+
filterLabel.style.fontWeight = '500'
|
|
118
|
+
filterLabel.textContent = 'Filter:'
|
|
119
|
+
|
|
120
|
+
const filterGroup = document.createElement('div')
|
|
121
|
+
filterGroup.style.display = 'flex'
|
|
122
|
+
filterGroup.style.gap = '4px'
|
|
123
|
+
|
|
124
|
+
const filterOptions: Array<{ label: string, value: 'all' | 'ble' | 'api' | 'both' | 'ir' }> = [
|
|
125
|
+
{ label: 'All', value: 'all' },
|
|
126
|
+
{ label: 'BLE', value: 'ble' },
|
|
127
|
+
{ label: 'API', value: 'api' },
|
|
128
|
+
{ label: 'Both', value: 'both' },
|
|
129
|
+
{ label: 'IR', value: 'ir' },
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
for (const option of filterOptions) {
|
|
133
|
+
const btn = document.createElement('button')
|
|
134
|
+
btn.textContent = option.label
|
|
135
|
+
btn.style.padding = '4px 8px'
|
|
136
|
+
btn.style.fontSize = '11px'
|
|
137
|
+
btn.style.borderRadius = '3px'
|
|
138
|
+
btn.style.cursor = 'pointer'
|
|
139
|
+
btn.style.border = preferences.connectionType === option.value ? '2px solid #007AFF' : '1px solid #ccc'
|
|
140
|
+
btn.style.backgroundColor = preferences.connectionType === option.value ? '#f0f7ff' : '#fff'
|
|
141
|
+
|
|
142
|
+
btn.onclick = () => {
|
|
143
|
+
preferences.connectionType = option.value
|
|
144
|
+
setDiscoveryPreferences(preferences)
|
|
145
|
+
updateDiscoveryView(devices, preferences)
|
|
146
|
+
// Update button styles
|
|
147
|
+
for (const b of Array.from(filterGroup.querySelectorAll('button'))) {
|
|
148
|
+
;(b as HTMLButtonElement).style.border = '1px solid #ccc'
|
|
149
|
+
;(b as HTMLButtonElement).style.backgroundColor = '#fff'
|
|
150
|
+
}
|
|
151
|
+
btn.style.border = '2px solid #007AFF'
|
|
152
|
+
btn.style.backgroundColor = '#f0f7ff'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
filterGroup.appendChild(btn)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Sort dropdown
|
|
159
|
+
const sortLabel = document.createElement('label')
|
|
160
|
+
sortLabel.style.fontSize = '12px'
|
|
161
|
+
sortLabel.style.fontWeight = '500'
|
|
162
|
+
sortLabel.style.marginLeft = '8px'
|
|
163
|
+
sortLabel.textContent = 'Sort:'
|
|
164
|
+
|
|
165
|
+
const sortSelect = document.createElement('select')
|
|
166
|
+
sortSelect.style.fontSize = '11px'
|
|
167
|
+
sortSelect.style.padding = '4px 8px'
|
|
168
|
+
sortSelect.style.borderRadius = '3px'
|
|
169
|
+
sortSelect.value = preferences.sortBy
|
|
170
|
+
|
|
171
|
+
const sortOptions = [
|
|
172
|
+
{ label: 'Name', value: 'name' },
|
|
173
|
+
{ label: 'Signal Strength', value: 'signal' },
|
|
174
|
+
{ label: 'Type', value: 'type' },
|
|
175
|
+
{ label: 'Connection', value: 'connection' },
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
for (const opt of sortOptions) {
|
|
179
|
+
const option = document.createElement('option')
|
|
180
|
+
option.value = opt.value
|
|
181
|
+
option.textContent = opt.label
|
|
182
|
+
sortSelect.appendChild(option)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
sortSelect.onchange = () => {
|
|
186
|
+
preferences.sortBy = sortSelect.value as any
|
|
187
|
+
setDiscoveryPreferences(preferences)
|
|
188
|
+
updateDiscoveryView(devices, preferences)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Search box
|
|
192
|
+
const searchInput = document.createElement('input')
|
|
193
|
+
searchInput.type = 'text'
|
|
194
|
+
searchInput.placeholder = 'Search by name, ID, or type...'
|
|
195
|
+
searchInput.style.fontSize = '11px'
|
|
196
|
+
searchInput.style.padding = '4px 8px'
|
|
197
|
+
searchInput.style.borderRadius = '3px'
|
|
198
|
+
searchInput.style.border = '1px solid #ccc'
|
|
199
|
+
searchInput.style.flex = '1'
|
|
200
|
+
searchInput.style.minWidth = '200px'
|
|
201
|
+
searchInput.style.maxWidth = '300px'
|
|
202
|
+
searchInput.value = preferences.searchQuery
|
|
203
|
+
|
|
204
|
+
let searchTimeout: NodeJS.Timeout
|
|
205
|
+
searchInput.oninput = () => {
|
|
206
|
+
clearTimeout(searchTimeout)
|
|
207
|
+
searchTimeout = setTimeout(() => {
|
|
208
|
+
preferences.searchQuery = searchInput.value
|
|
209
|
+
setDiscoveryPreferences(preferences)
|
|
210
|
+
updateDiscoveryView(devices, preferences)
|
|
211
|
+
}, 300) // Debounce search
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Assemble controls
|
|
215
|
+
controlsDiv.appendChild(filterLabel)
|
|
216
|
+
controlsDiv.appendChild(filterGroup)
|
|
217
|
+
controlsDiv.appendChild(sortLabel)
|
|
218
|
+
controlsDiv.appendChild(sortSelect)
|
|
219
|
+
controlsDiv.appendChild(searchInput)
|
|
220
|
+
|
|
221
|
+
// Clear list and add controls
|
|
222
|
+
list.innerHTML = ''
|
|
223
|
+
list.appendChild(controlsDiv)
|
|
224
|
+
|
|
225
|
+
// Display discovery list
|
|
106
226
|
list.style.display = 'block'
|
|
227
|
+
|
|
228
|
+
// Initial render with saved preferences
|
|
229
|
+
await updateDiscoveryView(devices, preferences)
|
|
107
230
|
} catch (e) {
|
|
108
231
|
uiLog.error('Discovery error:', e)
|
|
109
232
|
status.textContent = `Error: ${e instanceof Error ? e.message : 'Discovery failed'}`
|
|
@@ -117,6 +240,37 @@ export async function discoverDevices(): Promise<void> {
|
|
|
117
240
|
}
|
|
118
241
|
}
|
|
119
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Update discovery list with filtered and sorted devices
|
|
245
|
+
*/
|
|
246
|
+
async function updateDiscoveryView(
|
|
247
|
+
allDevices: any[],
|
|
248
|
+
preferences: {
|
|
249
|
+
connectionType: 'all' | 'ble' | 'api' | 'both' | 'ir'
|
|
250
|
+
sortBy: 'name' | 'signal' | 'type' | 'connection'
|
|
251
|
+
searchQuery: string
|
|
252
|
+
},
|
|
253
|
+
): Promise<void> {
|
|
254
|
+
// Apply filters and sort
|
|
255
|
+
const filtered = filterDevices(allDevices, preferences.connectionType, preferences.searchQuery)
|
|
256
|
+
const sorted = sortDevices(filtered, preferences.sortBy)
|
|
257
|
+
|
|
258
|
+
// Render updated list
|
|
259
|
+
const ul = await renderDiscoveredDevices(sorted)
|
|
260
|
+
document.getElementById('discoveredDevices')?.replaceWith(ul)
|
|
261
|
+
ul.id = 'discoveredDevices'
|
|
262
|
+
|
|
263
|
+
// Update status with count
|
|
264
|
+
const status = document.getElementById('discoverStatus')
|
|
265
|
+
if (status) {
|
|
266
|
+
const totalCount = allDevices.length
|
|
267
|
+
const filteredCount = sorted.length
|
|
268
|
+
status.textContent = filteredCount === totalCount
|
|
269
|
+
? `Found ${totalCount} device(s)`
|
|
270
|
+
: `Showing ${filteredCount} of ${totalCount} device(s)`
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
120
274
|
export async function addDeviceToConfig(device: any): Promise<void> {
|
|
121
275
|
const { addDeviceToConfig: addDevice } = await import('./devices.js')
|
|
122
276
|
await addDevice(device)
|
|
@@ -18,58 +18,90 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
18
18
|
const modal = document.createElement('div')
|
|
19
19
|
modal.style.background = getComputedStyle(document.body).backgroundColor
|
|
20
20
|
modal.style.color = getComputedStyle(document.body).color
|
|
21
|
-
modal.style.padding = '
|
|
22
|
-
modal.style.borderRadius = '
|
|
23
|
-
modal.style.minWidth = '
|
|
24
|
-
modal.style.
|
|
21
|
+
modal.style.padding = '0'
|
|
22
|
+
modal.style.borderRadius = '10px'
|
|
23
|
+
modal.style.minWidth = '440px'
|
|
24
|
+
modal.style.maxWidth = '90vw'
|
|
25
|
+
modal.style.boxShadow = '0 8px 32px rgba(0,0,0,0.35)'
|
|
26
|
+
modal.style.overflow = 'hidden'
|
|
27
|
+
modal.style.borderTop = '3px solid var(--switchbot-red, #ef4444)'
|
|
25
28
|
|
|
26
29
|
const title = document.createElement('h3')
|
|
27
30
|
title.textContent = 'Edit Device'
|
|
28
31
|
title.style.marginTop = '0'
|
|
32
|
+
title.style.marginBottom = '16px'
|
|
33
|
+
title.style.padding = '20px 20px 0'
|
|
34
|
+
title.style.fontSize = '18px'
|
|
35
|
+
title.style.fontWeight = '600'
|
|
36
|
+
title.style.color = 'var(--switchbot-red, #ef4444)'
|
|
37
|
+
title.style.letterSpacing = '-0.02em'
|
|
38
|
+
|
|
39
|
+
const contentDiv = document.createElement('div')
|
|
40
|
+
contentDiv.style.padding = '0 20px 20px'
|
|
29
41
|
|
|
30
42
|
const nameLabel = document.createElement('label')
|
|
31
43
|
nameLabel.textContent = 'Device Name'
|
|
32
44
|
nameLabel.style.display = 'block'
|
|
33
|
-
nameLabel.style.marginBottom = '
|
|
45
|
+
nameLabel.style.marginBottom = '6px'
|
|
34
46
|
nameLabel.style.fontWeight = '500'
|
|
47
|
+
nameLabel.style.fontSize = '12px'
|
|
48
|
+
nameLabel.style.color = '#6b7280'
|
|
35
49
|
|
|
36
50
|
const nameInput = document.createElement('input')
|
|
37
51
|
nameInput.type = 'text'
|
|
38
52
|
nameInput.value = device.name || device.id
|
|
39
53
|
nameInput.style.width = '100%'
|
|
40
|
-
nameInput.style.marginBottom = '
|
|
54
|
+
nameInput.style.marginBottom = '12px'
|
|
55
|
+
nameInput.style.padding = '8px 10px'
|
|
56
|
+
nameInput.style.borderRadius = '6px'
|
|
57
|
+
nameInput.style.fontSize = '14px'
|
|
58
|
+
nameInput.style.boxSizing = 'border-box'
|
|
59
|
+
nameInput.style.transition = 'border-color 0.2s ease'
|
|
41
60
|
|
|
42
61
|
// Read-only API device type field
|
|
43
62
|
const apiTypeLabel = document.createElement('label')
|
|
44
63
|
apiTypeLabel.textContent = 'Device Type (API - Read Only)'
|
|
45
64
|
apiTypeLabel.style.display = 'block'
|
|
46
|
-
apiTypeLabel.style.marginBottom = '
|
|
65
|
+
apiTypeLabel.style.marginBottom = '6px'
|
|
47
66
|
apiTypeLabel.style.fontWeight = '500'
|
|
67
|
+
apiTypeLabel.style.fontSize = '12px'
|
|
68
|
+
apiTypeLabel.style.color = '#6b7280'
|
|
48
69
|
|
|
49
70
|
const apiTypeInput = document.createElement('input')
|
|
50
71
|
apiTypeInput.type = 'text'
|
|
51
72
|
apiTypeInput.value = device.deviceType || device.type || 'Unknown'
|
|
52
73
|
apiTypeInput.readOnly = true
|
|
53
74
|
apiTypeInput.style.width = '100%'
|
|
54
|
-
apiTypeInput.style.marginBottom = '
|
|
75
|
+
apiTypeInput.style.marginBottom = '12px'
|
|
76
|
+
apiTypeInput.style.padding = '8px 10px'
|
|
77
|
+
apiTypeInput.style.borderRadius = '6px'
|
|
78
|
+
apiTypeInput.style.fontSize = '13px'
|
|
55
79
|
apiTypeInput.style.opacity = '0.6'
|
|
56
80
|
apiTypeInput.style.cursor = 'not-allowed'
|
|
81
|
+
apiTypeInput.style.boxSizing = 'border-box'
|
|
82
|
+
apiTypeInput.style.backgroundColor = '#f9fafb'
|
|
57
83
|
|
|
58
84
|
// Editable config device type dropdown
|
|
59
85
|
const typeLabel = document.createElement('label')
|
|
60
86
|
typeLabel.textContent = 'Config Device Type (Override)'
|
|
61
87
|
typeLabel.style.display = 'block'
|
|
62
|
-
typeLabel.style.marginBottom = '
|
|
88
|
+
typeLabel.style.marginBottom = '6px'
|
|
63
89
|
typeLabel.style.fontWeight = '500'
|
|
90
|
+
typeLabel.style.fontSize = '12px'
|
|
91
|
+
typeLabel.style.color = '#6b7280'
|
|
64
92
|
|
|
65
93
|
const typeSelect = document.createElement('select')
|
|
66
94
|
typeSelect.style.width = '100%'
|
|
67
|
-
typeSelect.style.padding = '8px'
|
|
68
|
-
typeSelect.style.marginBottom = '
|
|
69
|
-
typeSelect.style.borderRadius = '
|
|
95
|
+
typeSelect.style.padding = '8px 10px'
|
|
96
|
+
typeSelect.style.marginBottom = '12px'
|
|
97
|
+
typeSelect.style.borderRadius = '6px'
|
|
98
|
+
typeSelect.style.fontSize = '14px'
|
|
70
99
|
typeSelect.style.background = getComputedStyle(nameInput).background
|
|
71
100
|
typeSelect.style.color = getComputedStyle(nameInput).color
|
|
72
101
|
typeSelect.style.border = getComputedStyle(nameInput).border
|
|
102
|
+
typeSelect.style.boxSizing = 'border-box'
|
|
103
|
+
typeSelect.style.cursor = 'pointer'
|
|
104
|
+
typeSelect.style.transition = 'border-color 0.2s ease'
|
|
73
105
|
|
|
74
106
|
// Add option groups with all API device types
|
|
75
107
|
Object.keys(DEVICE_TYPES).forEach((categoryName) => {
|
|
@@ -90,24 +122,37 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
90
122
|
typeSelect.appendChild(optgroup)
|
|
91
123
|
})
|
|
92
124
|
|
|
93
|
-
const buttons = document.createElement('div')
|
|
94
|
-
buttons.style.display = 'flex'
|
|
95
|
-
buttons.style.gap = '8px'
|
|
96
|
-
buttons.style.justifyContent = 'flex-end'
|
|
97
|
-
|
|
98
125
|
const errorMessage = document.createElement('div')
|
|
99
|
-
errorMessage.style.color = '#ef4444'
|
|
126
|
+
errorMessage.style.color = 'var(--switchbot-red, #ef4444)'
|
|
100
127
|
errorMessage.style.marginBottom = '12px'
|
|
101
128
|
errorMessage.style.fontSize = '12px'
|
|
102
129
|
errorMessage.style.display = 'none'
|
|
130
|
+
errorMessage.style.padding = '8px 10px'
|
|
131
|
+
errorMessage.style.background = 'var(--switchbot-red-light, #fee2e2)'
|
|
132
|
+
errorMessage.style.borderRadius = '6px'
|
|
133
|
+
errorMessage.style.fontWeight = '500'
|
|
134
|
+
|
|
135
|
+
const buttons = document.createElement('div')
|
|
136
|
+
buttons.style.display = 'flex'
|
|
137
|
+
buttons.style.gap = '10px'
|
|
138
|
+
buttons.style.justifyContent = 'flex-end'
|
|
139
|
+
buttons.style.marginTop = '18px'
|
|
140
|
+
buttons.style.paddingTop = '18px'
|
|
141
|
+
buttons.style.borderTop = '1px solid rgba(0, 0, 0, 0.08)'
|
|
103
142
|
|
|
104
143
|
const cancelBtn = document.createElement('button')
|
|
105
144
|
cancelBtn.textContent = 'Cancel'
|
|
106
|
-
cancelBtn.
|
|
145
|
+
cancelBtn.className = 'secondary'
|
|
146
|
+
cancelBtn.style.background = '#6b7280'
|
|
147
|
+
cancelBtn.style.padding = '8px 16px'
|
|
148
|
+
cancelBtn.style.fontSize = '13px'
|
|
107
149
|
cancelBtn.onclick = () => div.remove()
|
|
108
150
|
|
|
109
151
|
const saveBtn = document.createElement('button')
|
|
110
152
|
saveBtn.textContent = 'Save'
|
|
153
|
+
saveBtn.style.background = 'var(--switchbot-red, #ef4444)'
|
|
154
|
+
saveBtn.style.padding = '8px 20px'
|
|
155
|
+
saveBtn.style.fontSize = '13px'
|
|
111
156
|
saveBtn.onclick = async () => {
|
|
112
157
|
try {
|
|
113
158
|
const { updateDevice, syncParentPluginConfigFromDisk, fetchDevices } = await import('./api.js')
|
|
@@ -137,15 +182,17 @@ export async function editDevice(device: any): Promise<void> {
|
|
|
137
182
|
buttons.appendChild(cancelBtn)
|
|
138
183
|
buttons.appendChild(saveBtn)
|
|
139
184
|
|
|
185
|
+
contentDiv.appendChild(nameLabel)
|
|
186
|
+
contentDiv.appendChild(nameInput)
|
|
187
|
+
contentDiv.appendChild(apiTypeLabel)
|
|
188
|
+
contentDiv.appendChild(apiTypeInput)
|
|
189
|
+
contentDiv.appendChild(typeLabel)
|
|
190
|
+
contentDiv.appendChild(typeSelect)
|
|
191
|
+
contentDiv.appendChild(errorMessage)
|
|
192
|
+
contentDiv.appendChild(buttons)
|
|
193
|
+
|
|
140
194
|
modal.appendChild(title)
|
|
141
|
-
modal.appendChild(
|
|
142
|
-
modal.appendChild(nameInput)
|
|
143
|
-
modal.appendChild(apiTypeLabel)
|
|
144
|
-
modal.appendChild(apiTypeInput)
|
|
145
|
-
modal.appendChild(typeLabel)
|
|
146
|
-
modal.appendChild(typeSelect)
|
|
147
|
-
modal.appendChild(errorMessage)
|
|
148
|
-
modal.appendChild(buttons)
|
|
195
|
+
modal.appendChild(contentDiv)
|
|
149
196
|
|
|
150
197
|
div.appendChild(modal)
|
|
151
198
|
document.body.appendChild(div)
|