@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteDevice as apiDeleteDevice, syncParentPluginConfigFromDisk, fetchDevices } from './api.js'
|
|
1
|
+
import { deleteDevice as apiDeleteDevice, deleteAllDevices as apiDeleteAllDevices, syncParentPluginConfigFromDisk, fetchDevices } from './api.js'
|
|
2
2
|
import { uiLog } from './logger.js'
|
|
3
3
|
import { hideBusyUi, showBusyUi } from './modal.js'
|
|
4
4
|
import { renderDeviceList } from './render.js'
|
|
@@ -111,3 +111,126 @@ export async function deleteDeviceFromConfig(deviceId: string, deviceName: strin
|
|
|
111
111
|
hideBusyUi()
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
+
|
|
115
|
+
async function confirmDeleteAllDialog(deviceCount: number): Promise<boolean> {
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
const overlay = document.createElement('div')
|
|
118
|
+
overlay.style.position = 'fixed'
|
|
119
|
+
overlay.style.top = '0'
|
|
120
|
+
overlay.style.left = '0'
|
|
121
|
+
overlay.style.width = '100%'
|
|
122
|
+
overlay.style.height = '100%'
|
|
123
|
+
overlay.style.background = 'rgba(0,0,0,0.7)'
|
|
124
|
+
overlay.style.display = 'flex'
|
|
125
|
+
overlay.style.alignItems = 'center'
|
|
126
|
+
overlay.style.justifyContent = 'center'
|
|
127
|
+
overlay.style.zIndex = '10000'
|
|
128
|
+
|
|
129
|
+
const modal = document.createElement('div')
|
|
130
|
+
modal.style.background = getComputedStyle(document.body).backgroundColor
|
|
131
|
+
modal.style.color = getComputedStyle(document.body).color
|
|
132
|
+
modal.style.padding = '20px'
|
|
133
|
+
modal.style.borderRadius = '10px'
|
|
134
|
+
modal.style.minWidth = '380px'
|
|
135
|
+
modal.style.maxWidth = '90vw'
|
|
136
|
+
modal.style.boxShadow = '0 12px 40px rgba(0,0,0,0.35)'
|
|
137
|
+
modal.style.borderTop = '3px solid #ef4444'
|
|
138
|
+
|
|
139
|
+
const title = document.createElement('h3')
|
|
140
|
+
title.textContent = '⚠️ Remove All Devices'
|
|
141
|
+
title.style.margin = '0 0 12px 0'
|
|
142
|
+
title.style.color = '#ef4444'
|
|
143
|
+
|
|
144
|
+
const message = document.createElement('p')
|
|
145
|
+
message.innerHTML = `Are you sure you want to remove <strong>all ${deviceCount} device(s)</strong> from your configuration?<br><br>This action cannot be undone.`
|
|
146
|
+
message.style.margin = '0 0 18px 0'
|
|
147
|
+
message.style.lineHeight = '1.5'
|
|
148
|
+
|
|
149
|
+
const actions = document.createElement('div')
|
|
150
|
+
actions.style.display = 'flex'
|
|
151
|
+
actions.style.justifyContent = 'flex-end'
|
|
152
|
+
actions.style.gap = '10px'
|
|
153
|
+
|
|
154
|
+
const cancelBtn = document.createElement('button')
|
|
155
|
+
cancelBtn.textContent = 'Cancel'
|
|
156
|
+
cancelBtn.style.background = '#6b7280'
|
|
157
|
+
cancelBtn.style.padding = '8px 16px'
|
|
158
|
+
cancelBtn.style.fontSize = '13px'
|
|
159
|
+
cancelBtn.className = 'secondary'
|
|
160
|
+
|
|
161
|
+
const deleteBtn = document.createElement('button')
|
|
162
|
+
deleteBtn.textContent = 'Remove All'
|
|
163
|
+
deleteBtn.style.background = '#ef4444'
|
|
164
|
+
deleteBtn.style.padding = '8px 20px'
|
|
165
|
+
deleteBtn.style.fontSize = '13px'
|
|
166
|
+
|
|
167
|
+
const cleanup = (result: boolean) => {
|
|
168
|
+
overlay.remove()
|
|
169
|
+
resolve(result)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
cancelBtn.onclick = () => cleanup(false)
|
|
173
|
+
deleteBtn.onclick = () => cleanup(true)
|
|
174
|
+
overlay.addEventListener('click', (event) => {
|
|
175
|
+
if (event.target === overlay) {
|
|
176
|
+
cleanup(false)
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
actions.appendChild(cancelBtn)
|
|
181
|
+
actions.appendChild(deleteBtn)
|
|
182
|
+
modal.appendChild(title)
|
|
183
|
+
modal.appendChild(message)
|
|
184
|
+
modal.appendChild(actions)
|
|
185
|
+
overlay.appendChild(modal)
|
|
186
|
+
document.body.appendChild(overlay)
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export async function deleteAllDevicesFromConfig(): Promise<void> {
|
|
191
|
+
uiLog.info('Remove All Devices button clicked')
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
// Get current device count
|
|
195
|
+
const list = await fetchDevices()
|
|
196
|
+
if (!list || list.length === 0) {
|
|
197
|
+
toastWarning('No devices to remove')
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const confirmed = await confirmDeleteAllDialog(list.length)
|
|
202
|
+
if (!confirmed) {
|
|
203
|
+
uiLog.info('Remove all cancelled by user')
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
showBusyUi()
|
|
208
|
+
uiLog.info('Sending delete all devices request')
|
|
209
|
+
const resp = await apiDeleteAllDevices()
|
|
210
|
+
uiLog.info('Delete all response:', resp)
|
|
211
|
+
|
|
212
|
+
if (!resp || resp.success === false) {
|
|
213
|
+
throw new Error(resp?.data?.message || 'Failed to delete all devices')
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
uiLog.info('Syncing parent config from disk...')
|
|
217
|
+
const synced = await syncParentPluginConfigFromDisk(true)
|
|
218
|
+
if (!synced) {
|
|
219
|
+
toastWarning('Devices deleted, but configuration sync failed')
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
uiLog.info('Refreshing device list...')
|
|
223
|
+
const updatedList = await fetchDevices()
|
|
224
|
+
uiLog.info('Rendering devices:', updatedList.length)
|
|
225
|
+
renderDeviceList(updatedList)
|
|
226
|
+
|
|
227
|
+
const deletedCount = resp?.deletedCount || list.length
|
|
228
|
+
uiLog.info(`✓ Removed ${deletedCount} device(s) successfully`)
|
|
229
|
+
toastSuccess(`Removed ${deletedCount} device(s) successfully`)
|
|
230
|
+
} catch (e) {
|
|
231
|
+
uiLog.error('Delete all error:', e)
|
|
232
|
+
toastError(e instanceof Error ? e.message : 'Failed to delete all devices')
|
|
233
|
+
} finally {
|
|
234
|
+
hideBusyUi()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -4,5 +4,6 @@ export declare function addDeviceToConfig(device: any, options?: {
|
|
|
4
4
|
}): Promise<{
|
|
5
5
|
added: boolean;
|
|
6
6
|
}>;
|
|
7
|
+
export declare function initRemoveAllButton(): Promise<void>;
|
|
7
8
|
export declare function loadConfiguredDevices(): Promise<void>;
|
|
8
9
|
//# sourceMappingURL=devices.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/devices.ts"],"names":[],"mappings":"AAMA,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAkE3I;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D"}
|
|
1
|
+
{"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/devices.ts"],"names":[],"mappings":"AAMA,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CAkE3I;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQzD;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3D"}
|
|
@@ -64,6 +64,16 @@ export async function addDeviceToConfig(device, options = {}) {
|
|
|
64
64
|
hideBusyUi();
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
+
export async function initRemoveAllButton() {
|
|
68
|
+
const removeAllBtn = document.getElementById('removeAllBtn');
|
|
69
|
+
if (!removeAllBtn) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
removeAllBtn.addEventListener('click', async () => {
|
|
73
|
+
const { deleteAllDevicesFromConfig } = await import('./devices-delete.js');
|
|
74
|
+
await deleteAllDevicesFromConfig();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
67
77
|
export async function loadConfiguredDevices() {
|
|
68
78
|
const list = await fetchDevices();
|
|
69
79
|
renderDeviceList(list);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/devices.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"devices.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/devices.ts"],"names":[],"mappings":"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"}
|
|
@@ -72,6 +72,16 @@ export async function addDeviceToConfig(device: any, options: { refresh?: boolea
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export async function initRemoveAllButton(): Promise<void> {
|
|
76
|
+
const removeAllBtn = document.getElementById('removeAllBtn')
|
|
77
|
+
if (!removeAllBtn) { return }
|
|
78
|
+
|
|
79
|
+
removeAllBtn.addEventListener('click', async () => {
|
|
80
|
+
const { deleteAllDevicesFromConfig } = await import('./devices-delete.js')
|
|
81
|
+
await deleteAllDevicesFromConfig()
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
export async function loadConfiguredDevices(): Promise<void> {
|
|
76
86
|
const list = await fetchDevices()
|
|
77
87
|
renderDeviceList(list)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/discovery.ts"],"names":[],"mappings":"AAYA,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/discovery.ts"],"names":[],"mappings":"AAYA,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAoOrD;AAiCD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE"}
|
|
@@ -2,7 +2,7 @@ import { addDevicesInBulk, discoverDevices as apiDiscoverDevices, syncParentPlug
|
|
|
2
2
|
import { loadConfiguredDevices } from './devices.js';
|
|
3
3
|
import { uiLog } from './logger.js';
|
|
4
4
|
import { hideBusyUi, showBusyUi } from './modal.js';
|
|
5
|
-
import { renderDiscoveredDevices } from './render.js';
|
|
5
|
+
import { renderDiscoveredDevices, filterDevices, sortDevices, getDiscoveryPreferences, setDiscoveryPreferences } from './render.js';
|
|
6
6
|
import { toastError, toastInfo, toastSuccess, toastWarning } from './toast.js';
|
|
7
7
|
export async function discoverDevices() {
|
|
8
8
|
const btn = document.getElementById('discoverBtn');
|
|
@@ -36,6 +36,9 @@ export async function discoverDevices() {
|
|
|
36
36
|
deviceId: d.id,
|
|
37
37
|
name: d.name,
|
|
38
38
|
type: d.type,
|
|
39
|
+
rssi: d.rssi,
|
|
40
|
+
address: d.address,
|
|
41
|
+
model: d.model,
|
|
39
42
|
})));
|
|
40
43
|
uiLog.info('Bulk add response:', bulkResult);
|
|
41
44
|
if (!bulkResult || bulkResult.success === false) {
|
|
@@ -82,10 +85,112 @@ export async function discoverDevices() {
|
|
|
82
85
|
return;
|
|
83
86
|
}
|
|
84
87
|
status.textContent = `Found ${devices.length} device(s)`;
|
|
85
|
-
|
|
86
|
-
document.
|
|
87
|
-
|
|
88
|
+
// Create filter/sort controls
|
|
89
|
+
const controlsDiv = document.createElement('div');
|
|
90
|
+
controlsDiv.style.cssText = 'margin-bottom: 12px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center;';
|
|
91
|
+
// Load saved preferences
|
|
92
|
+
const preferences = getDiscoveryPreferences();
|
|
93
|
+
// Filter buttons
|
|
94
|
+
const filterLabel = document.createElement('label');
|
|
95
|
+
filterLabel.style.fontSize = '12px';
|
|
96
|
+
filterLabel.style.fontWeight = '500';
|
|
97
|
+
filterLabel.textContent = 'Filter:';
|
|
98
|
+
const filterGroup = document.createElement('div');
|
|
99
|
+
filterGroup.style.display = 'flex';
|
|
100
|
+
filterGroup.style.gap = '4px';
|
|
101
|
+
const filterOptions = [
|
|
102
|
+
{ label: 'All', value: 'all' },
|
|
103
|
+
{ label: 'BLE', value: 'ble' },
|
|
104
|
+
{ label: 'API', value: 'api' },
|
|
105
|
+
{ label: 'Both', value: 'both' },
|
|
106
|
+
{ label: 'IR', value: 'ir' },
|
|
107
|
+
];
|
|
108
|
+
for (const option of filterOptions) {
|
|
109
|
+
const btn = document.createElement('button');
|
|
110
|
+
btn.textContent = option.label;
|
|
111
|
+
btn.style.padding = '4px 8px';
|
|
112
|
+
btn.style.fontSize = '11px';
|
|
113
|
+
btn.style.borderRadius = '3px';
|
|
114
|
+
btn.style.cursor = 'pointer';
|
|
115
|
+
btn.style.border = preferences.connectionType === option.value ? '2px solid #007AFF' : '1px solid #ccc';
|
|
116
|
+
btn.style.backgroundColor = preferences.connectionType === option.value ? '#f0f7ff' : '#fff';
|
|
117
|
+
btn.onclick = () => {
|
|
118
|
+
preferences.connectionType = option.value;
|
|
119
|
+
setDiscoveryPreferences(preferences);
|
|
120
|
+
updateDiscoveryView(devices, preferences);
|
|
121
|
+
// Update button styles
|
|
122
|
+
for (const b of Array.from(filterGroup.querySelectorAll('button'))) {
|
|
123
|
+
;
|
|
124
|
+
b.style.border = '1px solid #ccc';
|
|
125
|
+
b.style.backgroundColor = '#fff';
|
|
126
|
+
}
|
|
127
|
+
btn.style.border = '2px solid #007AFF';
|
|
128
|
+
btn.style.backgroundColor = '#f0f7ff';
|
|
129
|
+
};
|
|
130
|
+
filterGroup.appendChild(btn);
|
|
131
|
+
}
|
|
132
|
+
// Sort dropdown
|
|
133
|
+
const sortLabel = document.createElement('label');
|
|
134
|
+
sortLabel.style.fontSize = '12px';
|
|
135
|
+
sortLabel.style.fontWeight = '500';
|
|
136
|
+
sortLabel.style.marginLeft = '8px';
|
|
137
|
+
sortLabel.textContent = 'Sort:';
|
|
138
|
+
const sortSelect = document.createElement('select');
|
|
139
|
+
sortSelect.style.fontSize = '11px';
|
|
140
|
+
sortSelect.style.padding = '4px 8px';
|
|
141
|
+
sortSelect.style.borderRadius = '3px';
|
|
142
|
+
sortSelect.value = preferences.sortBy;
|
|
143
|
+
const sortOptions = [
|
|
144
|
+
{ label: 'Name', value: 'name' },
|
|
145
|
+
{ label: 'Signal Strength', value: 'signal' },
|
|
146
|
+
{ label: 'Type', value: 'type' },
|
|
147
|
+
{ label: 'Connection', value: 'connection' },
|
|
148
|
+
];
|
|
149
|
+
for (const opt of sortOptions) {
|
|
150
|
+
const option = document.createElement('option');
|
|
151
|
+
option.value = opt.value;
|
|
152
|
+
option.textContent = opt.label;
|
|
153
|
+
sortSelect.appendChild(option);
|
|
154
|
+
}
|
|
155
|
+
sortSelect.onchange = () => {
|
|
156
|
+
preferences.sortBy = sortSelect.value;
|
|
157
|
+
setDiscoveryPreferences(preferences);
|
|
158
|
+
updateDiscoveryView(devices, preferences);
|
|
159
|
+
};
|
|
160
|
+
// Search box
|
|
161
|
+
const searchInput = document.createElement('input');
|
|
162
|
+
searchInput.type = 'text';
|
|
163
|
+
searchInput.placeholder = 'Search by name, ID, or type...';
|
|
164
|
+
searchInput.style.fontSize = '11px';
|
|
165
|
+
searchInput.style.padding = '4px 8px';
|
|
166
|
+
searchInput.style.borderRadius = '3px';
|
|
167
|
+
searchInput.style.border = '1px solid #ccc';
|
|
168
|
+
searchInput.style.flex = '1';
|
|
169
|
+
searchInput.style.minWidth = '200px';
|
|
170
|
+
searchInput.style.maxWidth = '300px';
|
|
171
|
+
searchInput.value = preferences.searchQuery;
|
|
172
|
+
let searchTimeout;
|
|
173
|
+
searchInput.oninput = () => {
|
|
174
|
+
clearTimeout(searchTimeout);
|
|
175
|
+
searchTimeout = setTimeout(() => {
|
|
176
|
+
preferences.searchQuery = searchInput.value;
|
|
177
|
+
setDiscoveryPreferences(preferences);
|
|
178
|
+
updateDiscoveryView(devices, preferences);
|
|
179
|
+
}, 300); // Debounce search
|
|
180
|
+
};
|
|
181
|
+
// Assemble controls
|
|
182
|
+
controlsDiv.appendChild(filterLabel);
|
|
183
|
+
controlsDiv.appendChild(filterGroup);
|
|
184
|
+
controlsDiv.appendChild(sortLabel);
|
|
185
|
+
controlsDiv.appendChild(sortSelect);
|
|
186
|
+
controlsDiv.appendChild(searchInput);
|
|
187
|
+
// Clear list and add controls
|
|
188
|
+
list.innerHTML = '';
|
|
189
|
+
list.appendChild(controlsDiv);
|
|
190
|
+
// Display discovery list
|
|
88
191
|
list.style.display = 'block';
|
|
192
|
+
// Initial render with saved preferences
|
|
193
|
+
await updateDiscoveryView(devices, preferences);
|
|
89
194
|
}
|
|
90
195
|
catch (e) {
|
|
91
196
|
uiLog.error('Discovery error:', e);
|
|
@@ -100,6 +205,27 @@ export async function discoverDevices() {
|
|
|
100
205
|
btn.textContent = '🔍 Discover Devices';
|
|
101
206
|
}
|
|
102
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Update discovery list with filtered and sorted devices
|
|
210
|
+
*/
|
|
211
|
+
async function updateDiscoveryView(allDevices, preferences) {
|
|
212
|
+
// Apply filters and sort
|
|
213
|
+
const filtered = filterDevices(allDevices, preferences.connectionType, preferences.searchQuery);
|
|
214
|
+
const sorted = sortDevices(filtered, preferences.sortBy);
|
|
215
|
+
// Render updated list
|
|
216
|
+
const ul = await renderDiscoveredDevices(sorted);
|
|
217
|
+
document.getElementById('discoveredDevices')?.replaceWith(ul);
|
|
218
|
+
ul.id = 'discoveredDevices';
|
|
219
|
+
// Update status with count
|
|
220
|
+
const status = document.getElementById('discoverStatus');
|
|
221
|
+
if (status) {
|
|
222
|
+
const totalCount = allDevices.length;
|
|
223
|
+
const filteredCount = sorted.length;
|
|
224
|
+
status.textContent = filteredCount === totalCount
|
|
225
|
+
? `Found ${totalCount} device(s)`
|
|
226
|
+
: `Showing ${filteredCount} of ${totalCount} device(s)`;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
103
229
|
export async function addDeviceToConfig(device) {
|
|
104
230
|
const { addDeviceToConfig: addDevice } = await import('./devices.js');
|
|
105
231
|
await addDevice(device);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,eAAe,IAAI,kBAAkB,EAErC,8BAA8B,GAC/B,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -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)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modals.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/modals.ts"],"names":[],"mappings":"AAGA,wBAAsB,UAAU,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"modals.d.ts","sourceRoot":"","sources":["../../../../src/homebridge-ui/public/js/modals.ts"],"names":[],"mappings":"AAGA,wBAAsB,UAAU,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAoM3D"}
|