@switchbot/homebridge-switchbot 5.0.0-beta.153 → 5.0.0-beta.155
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/workflows/release.yml +63 -15
- package/.github/workflows/stale.yml +2 -4
- package/CHANGELOG.md +21 -29
- package/MIGRATION.md +6 -6
- package/README.md +5 -3
- package/dist/device-types.js +7 -7
- package/dist/device-types.js.map +1 -1
- package/dist/deviceFactory.d.ts +1 -1
- package/dist/deviceFactory.d.ts.map +1 -1
- package/dist/deviceFactory.js +20 -20
- package/dist/deviceFactory.js.map +1 -1
- package/dist/homebridge-ui/device-types.js +246 -0
- package/dist/homebridge-ui/device-types.js.map +1 -0
- package/dist/homebridge-ui/deviceCommandMapper.js +319 -0
- package/dist/homebridge-ui/deviceCommandMapper.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/devices.js +64 -1
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -1
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/endpoints/discovery.js +5 -1
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -1
- package/dist/homebridge-ui/errors.js +32 -0
- package/dist/homebridge-ui/errors.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js +90 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js +144 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js +219 -0
- package/dist/homebridge-ui/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/server.js +11 -0
- package/dist/homebridge-ui/homebridge-ui/server.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js +108 -0
- package/dist/homebridge-ui/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/api.js +24 -11
- package/dist/homebridge-ui/public/js/api.js.map +1 -1
- package/dist/homebridge-ui/public/js/api.ts +24 -12
- package/dist/homebridge-ui/public/js/app.js +117 -267
- package/dist/homebridge-ui/public/js/app.js.map +3 -3
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/devices.js +2 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -1
- package/dist/homebridge-ui/public/js/devices.ts +2 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +5 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.js +79 -245
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -1
- package/dist/homebridge-ui/public/js/discovery.ts +88 -247
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/render.js +2 -1
- package/dist/homebridge-ui/public/js/render.js.map +1 -1
- package/dist/homebridge-ui/public/js/render.ts +2 -1
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -1
- package/dist/homebridge-ui/public/js/toast.js +15 -6
- package/dist/homebridge-ui/public/js/toast.js.map +1 -1
- package/dist/homebridge-ui/public/js/toast.ts +14 -7
- package/dist/homebridge-ui/settings.js +8 -0
- package/dist/homebridge-ui/settings.js.map +1 -0
- package/dist/homebridge-ui/switchbotClient.js +247 -0
- package/dist/homebridge-ui/switchbotClient.js.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts +4 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.js +21 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -1
- package/dist/switchbotClient.d.ts +7 -1
- package/dist/switchbotClient.d.ts.map +1 -1
- package/dist/switchbotClient.js +82 -10
- package/dist/switchbotClient.js.map +1 -1
- package/docs/assets/main.js +1 -1
- package/docs/index.html +10 -4
- package/docs/variables/default.html +1 -1
- package/eslint.config.js +9 -10
- package/package.json +26 -24
- package/src/device-types.js +246 -0
- package/src/device-types.js.map +1 -0
- package/src/device-types.ts +7 -7
- package/src/deviceCommandMapper.js +319 -0
- package/src/deviceCommandMapper.js.map +1 -0
- package/src/deviceFactory.ts +22 -21
- package/src/errors.js +32 -0
- package/src/errors.js.map +1 -0
- package/src/homebridge-ui/endpoints/devices.ts +66 -1
- package/src/homebridge-ui/endpoints/discovery.ts +5 -1
- package/src/homebridge-ui/public/js/api.ts +24 -12
- package/src/homebridge-ui/public/js/devices.ts +2 -0
- package/src/homebridge-ui/public/js/discovery.ts +88 -247
- package/src/homebridge-ui/public/js/render.ts +2 -1
- package/src/homebridge-ui/public/js/toast.ts +14 -7
- package/src/homebridge-ui/utils/config-parser.ts +17 -0
- package/src/settings.js +8 -0
- package/src/settings.js.map +1 -0
- package/src/switchbotClient.js +247 -0
- package/src/switchbotClient.js.map +1 -0
- package/src/switchbotClient.ts +95 -10
- package/test/client/switchbotClient.spec.ts +42 -1
- package/test/e2e/run-e2e.spec.ts +1 -0
- package/tsconfig.ui.json +11 -0
- package/.github/workflows/beta-release.yml +0 -52
|
@@ -76,15 +76,21 @@ var init_modal = __esm({
|
|
|
76
76
|
// src/homebridge-ui/public/js/toast.ts
|
|
77
77
|
function showToast(method, message, title = "SwitchBot") {
|
|
78
78
|
try {
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
const hb = typeof window !== "undefined" ? window.homebridge : void 0;
|
|
80
|
+
const toast = hb && typeof hb.toast === "object" ? hb.toast : void 0;
|
|
81
|
+
const fn = toast && typeof toast[method] === "function" ? toast[method] : void 0;
|
|
82
|
+
if (fn) {
|
|
83
|
+
try {
|
|
84
|
+
fn(message, title);
|
|
85
|
+
return;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
uiLog.warn(`Toast ${method} threw:`, err);
|
|
88
|
+
}
|
|
84
89
|
}
|
|
85
90
|
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
86
91
|
} catch (e) {
|
|
87
|
-
uiLog.warn(`Toast ${method}
|
|
92
|
+
uiLog.warn(`Toast ${method} outer error:`, e);
|
|
93
|
+
uiLog.info(`[Toast:${method}] ${title} - ${message}`);
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
function toastSuccess(message, title) {
|
|
@@ -107,7 +113,7 @@ var init_toast = __esm({
|
|
|
107
113
|
}
|
|
108
114
|
});
|
|
109
115
|
|
|
110
|
-
// src/device-types.
|
|
116
|
+
// src/device-types.js
|
|
111
117
|
function getValidDeviceTypes() {
|
|
112
118
|
const validTypes = /* @__PURE__ */ new Set();
|
|
113
119
|
for (const category of Object.values(DEVICE_TYPES)) {
|
|
@@ -142,7 +148,7 @@ function isValidDeviceType(deviceType) {
|
|
|
142
148
|
}
|
|
143
149
|
var DEVICE_TYPES, DEVICE_TYPE_NORMALIZATION_MAP;
|
|
144
150
|
var init_device_types = __esm({
|
|
145
|
-
"src/device-types.
|
|
151
|
+
"src/device-types.js"() {
|
|
146
152
|
"use strict";
|
|
147
153
|
DEVICE_TYPES = {
|
|
148
154
|
"Window Coverings": ["Blind Tilt", "Curtain", "Curtain3", "Roller Shade"],
|
|
@@ -240,11 +246,10 @@ var init_device_types = __esm({
|
|
|
240
246
|
"Other Devices": ["AI Art Frame", "Bot", "Home Climate Panel", "Remote", "remote with screen"]
|
|
241
247
|
};
|
|
242
248
|
DEVICE_TYPE_NORMALIZATION_MAP = {
|
|
243
|
-
// --- node-switchbot
|
|
249
|
+
// --- node-switchbot v4 normalization additions ---
|
|
244
250
|
"hub mini": "Hub Mini",
|
|
245
251
|
"hub 3": "Hub 3",
|
|
246
252
|
"keypad": "Keypad",
|
|
247
|
-
// node-switchbot beta
|
|
248
253
|
"plug mini": "Plug Mini (US)",
|
|
249
254
|
// fallback to US if region not specified
|
|
250
255
|
"art frame": "AI Art Frame",
|
|
@@ -253,13 +258,11 @@ var init_device_types = __esm({
|
|
|
253
258
|
// alias for new lock vision
|
|
254
259
|
"lock pro": "Smart Lock Pro",
|
|
255
260
|
"lock lite": "Lock Lite",
|
|
256
|
-
// node-switchbot beta
|
|
257
261
|
"circulator fan": "Circulator Fan",
|
|
258
|
-
// node-switchbot beta
|
|
259
262
|
"smart thermostat radiator": "Smart Radiator Thermostat",
|
|
260
263
|
"climate panel": "Home Climate Panel",
|
|
261
264
|
"evaporative humidifier": "Humidifier",
|
|
262
|
-
// --- end node-switchbot
|
|
265
|
+
// --- end node-switchbot v4 additions ---
|
|
263
266
|
// Only keep the last occurrence for each key, all values canonical
|
|
264
267
|
"air purifier pm2.5": "Air Purifier PM2.5",
|
|
265
268
|
"pan/tilt cam plus 3k": "Pan/Tilt Cam Plus 3K",
|
|
@@ -298,7 +301,6 @@ var init_device_types = __esm({
|
|
|
298
301
|
"rgbicww strip light": "RGBICWW Strip Light",
|
|
299
302
|
"strip light": "Strip Light",
|
|
300
303
|
"strip light 3": "Strip Light 3",
|
|
301
|
-
// node-switchbot beta
|
|
302
304
|
// Vacuum conversions
|
|
303
305
|
"robot vacuum cleaner s1": "Robot Vacuum Cleaner S1",
|
|
304
306
|
"robot vacuum cleaner s1 plus": "Robot Vacuum Cleaner S1 Plus",
|
|
@@ -331,7 +333,7 @@ var init_device_types = __esm({
|
|
|
331
333
|
// Migration mappings for invalid/legacy device types
|
|
332
334
|
"lock vision pro": "Lock Vision Pro",
|
|
333
335
|
// Valid alias; map to canonical
|
|
334
|
-
// 'lock vision': 'Keypad Vision', // Invalid type (removed, now
|
|
336
|
+
// 'lock vision': 'Keypad Vision', // Invalid type (removed, now alias above)
|
|
335
337
|
"lock touch": "Keypad Touch",
|
|
336
338
|
// Invalid type
|
|
337
339
|
// Additional normalization for new/unknown types from logs
|
|
@@ -414,11 +416,6 @@ async function syncParentPluginConfigFromDisk(autoSave = false) {
|
|
|
414
416
|
uiLog.warn("Parent config sync API not available");
|
|
415
417
|
return false;
|
|
416
418
|
}
|
|
417
|
-
const diskResp = await homebridge.request("/platform-config", {});
|
|
418
|
-
if (!diskResp || diskResp.success === false || !diskResp.data) {
|
|
419
|
-
uiLog.warn("Failed to fetch fresh platform config from disk");
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
419
|
const pluginConfigBlocks = await homebridge.getPluginConfig();
|
|
423
420
|
if (!Array.isArray(pluginConfigBlocks) || !pluginConfigBlocks.length) {
|
|
424
421
|
uiLog.warn("No plugin config blocks returned from Homebridge");
|
|
@@ -429,12 +426,11 @@ async function syncParentPluginConfigFromDisk(autoSave = false) {
|
|
|
429
426
|
uiLog.warn("SwitchBot platform block not found in Homebridge plugin config");
|
|
430
427
|
return false;
|
|
431
428
|
}
|
|
432
|
-
const errors = validateAndFixDeviceTypes(
|
|
429
|
+
const errors = validateAndFixDeviceTypes(pluginConfigBlocks[index].devices || []);
|
|
433
430
|
if (errors.length > 0) {
|
|
434
431
|
toastError(`Invalid device types found: ${errors.map((e) => `${e.name} (${e.type})`).join(", ")}`);
|
|
435
432
|
return false;
|
|
436
433
|
}
|
|
437
|
-
pluginConfigBlocks[index] = diskResp.data;
|
|
438
434
|
await homebridge.updatePluginConfig(pluginConfigBlocks);
|
|
439
435
|
if (autoSave && typeof homebridge.savePluginConfig === "function") {
|
|
440
436
|
uiLog.info("Auto-saving config to disk...");
|
|
@@ -600,6 +596,7 @@ async function deleteDevice(deviceId) {
|
|
|
600
596
|
const normalizedDeviceId = String(deviceId).trim().toLowerCase();
|
|
601
597
|
const before = config.devices.length;
|
|
602
598
|
config.devices = config.devices.filter((d) => String(d.deviceId ?? d.id ?? "").trim().toLowerCase() !== normalizedDeviceId);
|
|
599
|
+
config.devices = config.devices.filter((d) => d && typeof d === "object" && d.deviceId && d.configDeviceType);
|
|
603
600
|
if (config.devices.length === before) {
|
|
604
601
|
throw new Error("Device not found in config");
|
|
605
602
|
}
|
|
@@ -614,16 +611,24 @@ async function deleteAllDevices() {
|
|
|
614
611
|
throw new TypeError("Homebridge UI API not available");
|
|
615
612
|
}
|
|
616
613
|
const configArr = await homebridge.getPluginConfig();
|
|
617
|
-
|
|
614
|
+
let idx = Array.isArray(configArr) ? configArr.findIndex(isSwitchBotPlatformConfig) : -1;
|
|
618
615
|
if (idx === -1) {
|
|
619
|
-
|
|
616
|
+
const newBlock = { platform: "SwitchBot", devices: [] };
|
|
617
|
+
configArr.push(newBlock);
|
|
618
|
+
idx = configArr.length - 1;
|
|
620
619
|
}
|
|
621
620
|
const config = configArr[idx];
|
|
622
621
|
if (!Array.isArray(config.devices)) {
|
|
623
|
-
|
|
622
|
+
config.devices = [];
|
|
624
623
|
}
|
|
625
624
|
const deletedCount = config.devices.length;
|
|
626
625
|
config.devices = [];
|
|
626
|
+
if (!config.platform) {
|
|
627
|
+
config.platform = "SwitchBot";
|
|
628
|
+
}
|
|
629
|
+
if (!config.name) {
|
|
630
|
+
config.name = "SwitchBot";
|
|
631
|
+
}
|
|
627
632
|
await homebridge.updatePluginConfig(configArr);
|
|
628
633
|
if (typeof homebridge.savePluginConfig === "function") {
|
|
629
634
|
await homebridge.savePluginConfig();
|
|
@@ -647,42 +652,6 @@ __export(discovery_exports, {
|
|
|
647
652
|
discoverDevices: () => discoverDevices2,
|
|
648
653
|
initializeDiscoverySettings: () => initializeDiscoverySettings
|
|
649
654
|
});
|
|
650
|
-
async function batchSetDeviceEnabled(selectedIds, enabled) {
|
|
651
|
-
const resp = await homebridge.request("/platform-config", {});
|
|
652
|
-
if (!resp || resp.success === false || !resp.data) {
|
|
653
|
-
throw new Error("Failed to load config");
|
|
654
|
-
}
|
|
655
|
-
const config = resp.data;
|
|
656
|
-
const configArr = Array.isArray(config) ? config : [config];
|
|
657
|
-
const platformIdx = configArr.findIndex((c) => (c.platform || c.name || "").toLowerCase().includes("switchbot"));
|
|
658
|
-
if (platformIdx === -1) {
|
|
659
|
-
throw new Error("SwitchBot platform config not found");
|
|
660
|
-
}
|
|
661
|
-
const platformConfig = configArr[platformIdx];
|
|
662
|
-
if (!Array.isArray(platformConfig.devices)) {
|
|
663
|
-
throw new TypeError("No devices array in config");
|
|
664
|
-
}
|
|
665
|
-
let changed = false;
|
|
666
|
-
for (const dev of platformConfig.devices) {
|
|
667
|
-
const id = String(dev.deviceId || dev.id || "").trim().toLowerCase();
|
|
668
|
-
if (selectedIds.has(id)) {
|
|
669
|
-
if (dev.enabled !== enabled) {
|
|
670
|
-
dev.enabled = enabled;
|
|
671
|
-
changed = true;
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
if (changed) {
|
|
676
|
-
if (typeof homebridge.updatePluginConfig === "function") {
|
|
677
|
-
await homebridge.updatePluginConfig(configArr);
|
|
678
|
-
} else {
|
|
679
|
-
throw new TypeError("homebridge.updatePluginConfig is not available");
|
|
680
|
-
}
|
|
681
|
-
if (typeof homebridge.savePluginConfig === "function") {
|
|
682
|
-
await homebridge.savePluginConfig();
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
655
|
function normalizeId(value) {
|
|
687
656
|
return String(value ?? "").trim().toLowerCase();
|
|
688
657
|
}
|
|
@@ -936,9 +905,9 @@ function getDiscoveryGroupByPreference() {
|
|
|
936
905
|
if (stored === "hub" || stored === "type") {
|
|
937
906
|
return stored;
|
|
938
907
|
}
|
|
939
|
-
return "
|
|
908
|
+
return "type";
|
|
940
909
|
} catch (_e) {
|
|
941
|
-
return "
|
|
910
|
+
return "type";
|
|
942
911
|
}
|
|
943
912
|
}
|
|
944
913
|
function setDiscoveryGroupByPreference(groupBy) {
|
|
@@ -1042,19 +1011,17 @@ async function discoverDevices2() {
|
|
|
1042
1011
|
const preferences = getDiscoveryPreferences();
|
|
1043
1012
|
let groupBy = getDiscoveryGroupByPreference();
|
|
1044
1013
|
let hideAdded = getDiscoveryHideAddedPreference();
|
|
1045
|
-
let controlsInitialized = false;
|
|
1046
1014
|
if (!window._discoverySelectedIds) {
|
|
1047
1015
|
window._discoverySelectedIds = /* @__PURE__ */ new Set();
|
|
1048
1016
|
}
|
|
1049
1017
|
const selectedIds = window._discoverySelectedIds;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
if (
|
|
1053
|
-
throw new
|
|
1054
|
-
}
|
|
1055
|
-
const
|
|
1056
|
-
const
|
|
1057
|
-
const platformIdx = configArr.findIndex((c) => (c.platform || c.name || "").toLowerCase().includes("switchbot"));
|
|
1018
|
+
let controlsInitialized = false;
|
|
1019
|
+
async function batchSetDeviceEnabled(selectedIds2, enabled) {
|
|
1020
|
+
if (typeof homebridge.getPluginConfig !== "function") {
|
|
1021
|
+
throw new TypeError("homebridge.getPluginConfig is not available");
|
|
1022
|
+
}
|
|
1023
|
+
const configArr = await homebridge.getPluginConfig();
|
|
1024
|
+
const platformIdx = Array.isArray(configArr) ? configArr.findIndex((c) => (c.platform || c.name || "").toLowerCase().includes("switchbot")) : -1;
|
|
1058
1025
|
if (platformIdx === -1) {
|
|
1059
1026
|
throw new Error("SwitchBot platform config not found");
|
|
1060
1027
|
}
|
|
@@ -1084,13 +1051,48 @@ async function discoverDevices2() {
|
|
|
1084
1051
|
}
|
|
1085
1052
|
}
|
|
1086
1053
|
const ensureDiscoveryControls = async () => {
|
|
1054
|
+
const selectAllBtn = document.createElement("button");
|
|
1055
|
+
selectAllBtn.textContent = "Select All";
|
|
1056
|
+
selectAllBtn.style.fontSize = "13px";
|
|
1057
|
+
selectAllBtn.style.padding = "6px 18px";
|
|
1058
|
+
selectAllBtn.style.borderRadius = "6px";
|
|
1059
|
+
selectAllBtn.style.background = "#f3f4f6";
|
|
1060
|
+
selectAllBtn.style.color = "#1d4ed8";
|
|
1061
|
+
selectAllBtn.style.border = "1px solid #d1d5db";
|
|
1062
|
+
selectAllBtn.style.cursor = "pointer";
|
|
1063
|
+
selectAllBtn.style.marginRight = "8px";
|
|
1064
|
+
selectAllBtn.onclick = () => {
|
|
1065
|
+
for (const d of discoveredDevices) {
|
|
1066
|
+
selectedIds.add(normalizeId(d.id));
|
|
1067
|
+
}
|
|
1068
|
+
window.dispatchEvent(new Event("discovery-selection-changed"));
|
|
1069
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1070
|
+
};
|
|
1071
|
+
const deselectAllBtn = document.createElement("button");
|
|
1072
|
+
deselectAllBtn.textContent = "Deselect All";
|
|
1073
|
+
deselectAllBtn.style.fontSize = "13px";
|
|
1074
|
+
deselectAllBtn.style.padding = "6px 18px";
|
|
1075
|
+
deselectAllBtn.style.borderRadius = "6px";
|
|
1076
|
+
deselectAllBtn.style.background = "#f3f4f6";
|
|
1077
|
+
deselectAllBtn.style.color = "#ef4444";
|
|
1078
|
+
deselectAllBtn.style.border = "1px solid #d1d5db";
|
|
1079
|
+
deselectAllBtn.style.cursor = "pointer";
|
|
1080
|
+
deselectAllBtn.onclick = () => {
|
|
1081
|
+
for (const d of discoveredDevices) {
|
|
1082
|
+
selectedIds.delete(normalizeId(d.id));
|
|
1083
|
+
}
|
|
1084
|
+
window.dispatchEvent(new Event("discovery-selection-changed"));
|
|
1085
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1086
|
+
};
|
|
1087
|
+
const selectControlsRow = document.createElement("div");
|
|
1088
|
+
selectControlsRow.style.display = "flex";
|
|
1089
|
+
selectControlsRow.style.gap = "10px";
|
|
1090
|
+
selectControlsRow.style.margin = "0 0 10px 0";
|
|
1091
|
+
selectControlsRow.appendChild(selectAllBtn);
|
|
1092
|
+
selectControlsRow.appendChild(deselectAllBtn);
|
|
1087
1093
|
if (controlsInitialized) {
|
|
1088
1094
|
return;
|
|
1089
1095
|
}
|
|
1090
|
-
if (!window._discoverySelectedIds) {
|
|
1091
|
-
window._discoverySelectedIds = /* @__PURE__ */ new Set();
|
|
1092
|
-
}
|
|
1093
|
-
const selectedIds2 = window._discoverySelectedIds;
|
|
1094
1096
|
const controlsDiv = document.createElement("div");
|
|
1095
1097
|
controlsDiv.style.cssText = "margin-bottom: 12px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center;";
|
|
1096
1098
|
const filterLabel = document.createElement("label");
|
|
@@ -1120,7 +1122,7 @@ async function discoverDevices2() {
|
|
|
1120
1122
|
filterBtn.onclick = () => {
|
|
1121
1123
|
preferences.connectionType = option.value;
|
|
1122
1124
|
setDiscoveryPreferences(preferences);
|
|
1123
|
-
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1125
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1124
1126
|
Array.prototype.forEach.call(filterGroup.querySelectorAll("button"), (b) => {
|
|
1125
1127
|
b.style.border = "1px solid #ccc";
|
|
1126
1128
|
b.style.backgroundColor = "#fff";
|
|
@@ -1157,18 +1159,27 @@ async function discoverDevices2() {
|
|
|
1157
1159
|
sortSelect.onchange = () => {
|
|
1158
1160
|
preferences.sortBy = sortSelect.value;
|
|
1159
1161
|
setDiscoveryPreferences(preferences);
|
|
1160
|
-
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1162
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1161
1163
|
};
|
|
1162
|
-
const groupLabel = document.createElement("label");
|
|
1163
|
-
groupLabel.style.fontSize = "12px";
|
|
1164
|
-
groupLabel.style.fontWeight = "500";
|
|
1165
|
-
groupLabel.style.marginLeft = "8px";
|
|
1166
|
-
groupLabel.textContent = "Group:";
|
|
1167
1164
|
const groupSelect = document.createElement("select");
|
|
1168
1165
|
groupSelect.style.fontSize = "11px";
|
|
1169
1166
|
groupSelect.style.padding = "4px 8px";
|
|
1170
1167
|
groupSelect.style.borderRadius = "3px";
|
|
1171
|
-
|
|
1168
|
+
if (!localStorage.getItem(DISCOVERY_GROUP_BY_KEY)) {
|
|
1169
|
+
groupSelect.value = "type";
|
|
1170
|
+
} else {
|
|
1171
|
+
groupSelect.value = groupBy;
|
|
1172
|
+
}
|
|
1173
|
+
const groupLabel = document.createElement("label");
|
|
1174
|
+
groupLabel.style.fontSize = "12px";
|
|
1175
|
+
groupLabel.style.fontWeight = "500";
|
|
1176
|
+
groupLabel.style.marginLeft = "8px";
|
|
1177
|
+
const groupLabelTextMap = {
|
|
1178
|
+
connection: "Connection",
|
|
1179
|
+
hub: "Hub",
|
|
1180
|
+
type: "Device Type"
|
|
1181
|
+
};
|
|
1182
|
+
groupLabel.textContent = `Group: ${groupLabelTextMap[groupSelect.value] || "Connection"}`;
|
|
1172
1183
|
const groupOptions = [
|
|
1173
1184
|
{ label: "Connection", value: "connection" },
|
|
1174
1185
|
{ label: "Hub", value: "hub" },
|
|
@@ -1183,7 +1194,8 @@ async function discoverDevices2() {
|
|
|
1183
1194
|
groupSelect.onchange = () => {
|
|
1184
1195
|
groupBy = groupSelect.value;
|
|
1185
1196
|
setDiscoveryGroupByPreference(groupBy);
|
|
1186
|
-
|
|
1197
|
+
groupLabel.textContent = `Group: ${groupLabelTextMap[groupSelect.value] || "Connection"}`;
|
|
1198
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1187
1199
|
};
|
|
1188
1200
|
const hideAddedLabel = document.createElement("label");
|
|
1189
1201
|
hideAddedLabel.style.display = "inline-flex";
|
|
@@ -1203,7 +1215,7 @@ async function discoverDevices2() {
|
|
|
1203
1215
|
hideAddedCheckbox.onchange = () => {
|
|
1204
1216
|
hideAdded = hideAddedCheckbox.checked;
|
|
1205
1217
|
setDiscoveryHideAddedPreference(hideAdded);
|
|
1206
|
-
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1218
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1207
1219
|
};
|
|
1208
1220
|
const searchInput = document.createElement("input");
|
|
1209
1221
|
searchInput.type = "text";
|
|
@@ -1223,7 +1235,7 @@ async function discoverDevices2() {
|
|
|
1223
1235
|
searchTimeout = setTimeout(() => {
|
|
1224
1236
|
preferences.searchQuery = searchInput.value;
|
|
1225
1237
|
setDiscoveryPreferences(preferences);
|
|
1226
|
-
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1238
|
+
void updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1227
1239
|
}, 300);
|
|
1228
1240
|
};
|
|
1229
1241
|
const actionBtnStyle = {
|
|
@@ -1248,14 +1260,14 @@ async function discoverDevices2() {
|
|
|
1248
1260
|
Object.assign(addSelectedBtn.style, actionBtnStyle);
|
|
1249
1261
|
addSelectedBtn.disabled = true;
|
|
1250
1262
|
addSelectedBtn.onclick = async () => {
|
|
1251
|
-
if (!
|
|
1263
|
+
if (!selectedIds.size) {
|
|
1252
1264
|
return;
|
|
1253
1265
|
}
|
|
1254
1266
|
addSelectedBtn.disabled = true;
|
|
1255
1267
|
addSelectedBtn.textContent = "Adding...";
|
|
1256
1268
|
try {
|
|
1257
1269
|
showBusyUi();
|
|
1258
|
-
const selectedDevices = discoveredDevices.filter((d) =>
|
|
1270
|
+
const selectedDevices = discoveredDevices.filter((d) => selectedIds.has(normalizeId(d.id)));
|
|
1259
1271
|
const bulkResult = await addDevicesInBulk(selectedDevices.map((d) => ({
|
|
1260
1272
|
deviceId: d.id,
|
|
1261
1273
|
name: d.name,
|
|
@@ -1272,10 +1284,10 @@ async function discoverDevices2() {
|
|
|
1272
1284
|
const skippedCount = bulkResult?.skippedCount ?? bulkResult?.data?.skippedCount ?? 0;
|
|
1273
1285
|
toastSuccess(`Added ${addedCount} device(s)${skippedCount > 0 ? ` (${skippedCount} skipped)` : ""}`);
|
|
1274
1286
|
await loadConfiguredDevices();
|
|
1275
|
-
|
|
1287
|
+
selectedIds.clear();
|
|
1276
1288
|
addSelectedBtn.disabled = true;
|
|
1277
1289
|
addSelectedBtn.textContent = "Add Selected";
|
|
1278
|
-
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1290
|
+
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1279
1291
|
} catch (e) {
|
|
1280
1292
|
uiLog.error("Batch add error:", e);
|
|
1281
1293
|
toastError(e instanceof Error ? e.message : "Failed to add devices");
|
|
@@ -1290,19 +1302,19 @@ async function discoverDevices2() {
|
|
|
1290
1302
|
Object.assign(enableSelectedBtn.style, actionBtnStyle);
|
|
1291
1303
|
enableSelectedBtn.disabled = true;
|
|
1292
1304
|
enableSelectedBtn.onclick = async () => {
|
|
1293
|
-
if (!
|
|
1305
|
+
if (!selectedIds.size) {
|
|
1294
1306
|
return;
|
|
1295
1307
|
}
|
|
1296
1308
|
enableSelectedBtn.disabled = true;
|
|
1297
1309
|
enableSelectedBtn.textContent = "Enabling...";
|
|
1298
1310
|
try {
|
|
1299
1311
|
showBusyUi();
|
|
1300
|
-
await
|
|
1312
|
+
await batchSetDeviceEnabled(selectedIds, true);
|
|
1301
1313
|
toastSuccess("Selected devices enabled");
|
|
1302
1314
|
await loadConfiguredDevices();
|
|
1303
1315
|
enableSelectedBtn.disabled = true;
|
|
1304
1316
|
enableSelectedBtn.textContent = "Enable Selected";
|
|
1305
|
-
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1317
|
+
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1306
1318
|
} catch (e) {
|
|
1307
1319
|
uiLog.error("Batch enable error:", e);
|
|
1308
1320
|
toastError(e instanceof Error ? e.message : "Failed to enable devices");
|
|
@@ -1317,19 +1329,19 @@ async function discoverDevices2() {
|
|
|
1317
1329
|
Object.assign(disableSelectedBtn.style, actionBtnStyle);
|
|
1318
1330
|
disableSelectedBtn.disabled = true;
|
|
1319
1331
|
disableSelectedBtn.onclick = async () => {
|
|
1320
|
-
if (!
|
|
1332
|
+
if (!selectedIds.size) {
|
|
1321
1333
|
return;
|
|
1322
1334
|
}
|
|
1323
1335
|
disableSelectedBtn.disabled = true;
|
|
1324
1336
|
disableSelectedBtn.textContent = "Disabling...";
|
|
1325
1337
|
try {
|
|
1326
1338
|
showBusyUi();
|
|
1327
|
-
await
|
|
1339
|
+
await batchSetDeviceEnabled(selectedIds, false);
|
|
1328
1340
|
toastSuccess("Selected devices disabled");
|
|
1329
1341
|
await loadConfiguredDevices();
|
|
1330
1342
|
disableSelectedBtn.disabled = true;
|
|
1331
1343
|
disableSelectedBtn.textContent = "Disable Selected";
|
|
1332
|
-
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded,
|
|
1344
|
+
await updateDiscoveryView(discoveredDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1333
1345
|
} catch (e) {
|
|
1334
1346
|
uiLog.error("Batch disable error:", e);
|
|
1335
1347
|
toastError(e instanceof Error ? e.message : "Failed to disable devices");
|
|
@@ -1356,6 +1368,7 @@ async function discoverDevices2() {
|
|
|
1356
1368
|
topActionRow.appendChild(enableSelectedBtn);
|
|
1357
1369
|
topActionRow.appendChild(disableSelectedBtn);
|
|
1358
1370
|
list.innerHTML = "";
|
|
1371
|
+
list.appendChild(selectControlsRow);
|
|
1359
1372
|
list.appendChild(topActionRow);
|
|
1360
1373
|
list.appendChild(controlsDiv);
|
|
1361
1374
|
let deviceListContainer = document.getElementById("discoveredDevices");
|
|
@@ -1372,7 +1385,7 @@ async function discoverDevices2() {
|
|
|
1372
1385
|
list.style.display = "block";
|
|
1373
1386
|
controlsInitialized = true;
|
|
1374
1387
|
const updateActionButtons = () => {
|
|
1375
|
-
const hasSelection =
|
|
1388
|
+
const hasSelection = selectedIds.size > 0;
|
|
1376
1389
|
addSelectedBtn.disabled = !hasSelection;
|
|
1377
1390
|
enableSelectedBtn.disabled = !hasSelection;
|
|
1378
1391
|
disableSelectedBtn.disabled = !hasSelection;
|
|
@@ -1690,21 +1703,10 @@ async function updateDiscoveryView(allDevices, preferences, groupBy, hideAdded,
|
|
|
1690
1703
|
toastError("Discovery UI error: device list container missing. Please reload the page.");
|
|
1691
1704
|
}
|
|
1692
1705
|
}
|
|
1693
|
-
const legacyAddSelectedBtns = [];
|
|
1694
|
-
const allBtns = document.querySelectorAll("button");
|
|
1695
|
-
for (let i = 0; i < allBtns.length; i++) {
|
|
1696
|
-
const btn = allBtns[i];
|
|
1697
|
-
if (btn.textContent && btn.textContent.trim() === "Add Selected") {
|
|
1698
|
-
legacyAddSelectedBtns.push(btn);
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
for (let i = 0; i < legacyAddSelectedBtns.length; i++) {
|
|
1702
|
-
legacyAddSelectedBtns[i].remove();
|
|
1703
|
-
}
|
|
1704
1706
|
function updateBatchButtonStates() {
|
|
1705
1707
|
const addSelectedBtn = document.getElementById("addSelectedBtn");
|
|
1706
|
-
const enableSelectedBtn = document.
|
|
1707
|
-
const disableSelectedBtn = document.
|
|
1708
|
+
const enableSelectedBtn = document.getElementById("enableSelectedBtn");
|
|
1709
|
+
const disableSelectedBtn = document.getElementById("disableSelectedBtn");
|
|
1708
1710
|
const hasSelection = selectedIds.size > 0;
|
|
1709
1711
|
if (addSelectedBtn) {
|
|
1710
1712
|
addSelectedBtn.disabled = !hasSelection;
|
|
@@ -1718,161 +1720,7 @@ async function updateDiscoveryView(allDevices, preferences, groupBy, hideAdded,
|
|
|
1718
1720
|
}
|
|
1719
1721
|
window.removeEventListener("discovery-selection-changed", updateBatchButtonStates);
|
|
1720
1722
|
window.addEventListener("discovery-selection-changed", updateBatchButtonStates);
|
|
1721
|
-
|
|
1722
|
-
if (!batchControls) {
|
|
1723
|
-
batchControls = document.createElement("div");
|
|
1724
|
-
batchControls.id = "batchImportControls";
|
|
1725
|
-
batchControls.style.display = "flex";
|
|
1726
|
-
batchControls.style.flexWrap = "wrap";
|
|
1727
|
-
batchControls.style.alignItems = "center";
|
|
1728
|
-
batchControls.style.gap = "18px";
|
|
1729
|
-
batchControls.style.margin = "8px 0 18px 0";
|
|
1730
|
-
batchControls.style.width = "100%";
|
|
1731
|
-
const buttonRow = document.createElement("div");
|
|
1732
|
-
buttonRow.style.display = "flex";
|
|
1733
|
-
buttonRow.style.flexWrap = "nowrap";
|
|
1734
|
-
buttonRow.style.alignItems = "center";
|
|
1735
|
-
buttonRow.style.justifyContent = "center";
|
|
1736
|
-
buttonRow.style.gap = "16px";
|
|
1737
|
-
buttonRow.style.width = "100%";
|
|
1738
|
-
const addSelectedBtn = document.createElement("button");
|
|
1739
|
-
addSelectedBtn.id = "addSelectedBtn";
|
|
1740
|
-
addSelectedBtn.textContent = "Add Selected to Config";
|
|
1741
|
-
addSelectedBtn.disabled = selectedIds.size === 0;
|
|
1742
|
-
addSelectedBtn.style.fontWeight = "600";
|
|
1743
|
-
const redButtonStyle = {
|
|
1744
|
-
width: "220px",
|
|
1745
|
-
padding: "12px 0",
|
|
1746
|
-
fontSize: "17px",
|
|
1747
|
-
marginBottom: "0",
|
|
1748
|
-
boxShadow: "0 2px 8px 0 rgba(220,38,38,0.10)",
|
|
1749
|
-
borderRadius: "8px"
|
|
1750
|
-
};
|
|
1751
|
-
Object.assign(addSelectedBtn.style, redButtonStyle);
|
|
1752
|
-
addSelectedBtn.style.background = "#ef4444";
|
|
1753
|
-
addSelectedBtn.style.color = "white";
|
|
1754
|
-
addSelectedBtn.style.transition = "background 0.2s, box-shadow 0.2s";
|
|
1755
|
-
addSelectedBtn.onmouseenter = function() {
|
|
1756
|
-
addSelectedBtn.style.background = "#dc2626";
|
|
1757
|
-
};
|
|
1758
|
-
addSelectedBtn.onmouseleave = function() {
|
|
1759
|
-
addSelectedBtn.style.background = "#ef4444";
|
|
1760
|
-
};
|
|
1761
|
-
addSelectedBtn.onclick = async () => {
|
|
1762
|
-
if (!selectedIds.size) {
|
|
1763
|
-
return;
|
|
1764
|
-
}
|
|
1765
|
-
addSelectedBtn.disabled = true;
|
|
1766
|
-
addSelectedBtn.textContent = "Adding...";
|
|
1767
|
-
try {
|
|
1768
|
-
const selectedDevices = visibleDevices.filter((d) => selectedIds.has(normalizeId(d.id)));
|
|
1769
|
-
const bulkResult = await addDevicesInBulk(selectedDevices.map((d) => ({
|
|
1770
|
-
deviceId: d.id,
|
|
1771
|
-
name: d.name,
|
|
1772
|
-
type: d.type,
|
|
1773
|
-
rssi: d.rssi,
|
|
1774
|
-
address: d.address,
|
|
1775
|
-
model: d.model
|
|
1776
|
-
})));
|
|
1777
|
-
uiLog.info("Batch add response:", bulkResult);
|
|
1778
|
-
if (!bulkResult || bulkResult.success === false) {
|
|
1779
|
-
throw new Error(bulkResult?.data?.message || "Batch add failed");
|
|
1780
|
-
}
|
|
1781
|
-
const addedCount = bulkResult?.addedCount ?? bulkResult?.data?.addedCount ?? 0;
|
|
1782
|
-
const skippedCount = bulkResult?.skippedCount ?? bulkResult?.data?.skippedCount ?? 0;
|
|
1783
|
-
toastSuccess(`Added ${addedCount} device(s)${skippedCount > 0 ? ` (${skippedCount} skipped)` : ""}`);
|
|
1784
|
-
await loadConfiguredDevices();
|
|
1785
|
-
selectedIds.clear();
|
|
1786
|
-
addSelectedBtn.disabled = true;
|
|
1787
|
-
addSelectedBtn.textContent = "Add Selected to Config";
|
|
1788
|
-
await updateDiscoveryView(allDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1789
|
-
} catch (e) {
|
|
1790
|
-
uiLog.error("Batch add error:", e);
|
|
1791
|
-
toastError(e instanceof Error ? e.message : "Failed to add devices");
|
|
1792
|
-
addSelectedBtn.disabled = false;
|
|
1793
|
-
addSelectedBtn.textContent = "Add Selected to Config";
|
|
1794
|
-
}
|
|
1795
|
-
};
|
|
1796
|
-
const enableSelectedBtn = document.createElement("button");
|
|
1797
|
-
enableSelectedBtn.textContent = "Enable Selected";
|
|
1798
|
-
enableSelectedBtn.style.fontWeight = "600";
|
|
1799
|
-
Object.assign(enableSelectedBtn.style, redButtonStyle);
|
|
1800
|
-
enableSelectedBtn.style.background = "#ef4444";
|
|
1801
|
-
enableSelectedBtn.style.color = "white";
|
|
1802
|
-
enableSelectedBtn.style.transition = "background 0.2s, box-shadow 0.2s";
|
|
1803
|
-
enableSelectedBtn.onmouseenter = function() {
|
|
1804
|
-
enableSelectedBtn.style.background = "#dc2626";
|
|
1805
|
-
};
|
|
1806
|
-
enableSelectedBtn.onmouseleave = function() {
|
|
1807
|
-
enableSelectedBtn.style.background = "#ef4444";
|
|
1808
|
-
};
|
|
1809
|
-
enableSelectedBtn.disabled = selectedIds.size === 0;
|
|
1810
|
-
enableSelectedBtn.onclick = async () => {
|
|
1811
|
-
if (!selectedIds.size) {
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
enableSelectedBtn.disabled = true;
|
|
1815
|
-
try {
|
|
1816
|
-
showBusyUi();
|
|
1817
|
-
await batchSetDeviceEnabled(selectedIds, true);
|
|
1818
|
-
toastSuccess("Selected devices enabled");
|
|
1819
|
-
await loadConfiguredDevices();
|
|
1820
|
-
await updateDiscoveryView(allDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1821
|
-
} catch (e) {
|
|
1822
|
-
uiLog.error("Batch enable error:", e);
|
|
1823
|
-
toastError(e instanceof Error ? e.message : "Failed to enable devices");
|
|
1824
|
-
} finally {
|
|
1825
|
-
hideBusyUi();
|
|
1826
|
-
enableSelectedBtn.disabled = false;
|
|
1827
|
-
}
|
|
1828
|
-
};
|
|
1829
|
-
const disableSelectedBtn = document.createElement("button");
|
|
1830
|
-
disableSelectedBtn.textContent = "Disable Selected";
|
|
1831
|
-
disableSelectedBtn.style.fontWeight = "600";
|
|
1832
|
-
Object.assign(disableSelectedBtn.style, redButtonStyle);
|
|
1833
|
-
disableSelectedBtn.style.background = "#ef4444";
|
|
1834
|
-
disableSelectedBtn.style.color = "white";
|
|
1835
|
-
disableSelectedBtn.style.transition = "background 0.2s, box-shadow 0.2s";
|
|
1836
|
-
disableSelectedBtn.onmouseenter = function() {
|
|
1837
|
-
disableSelectedBtn.style.background = "#dc2626";
|
|
1838
|
-
};
|
|
1839
|
-
disableSelectedBtn.onmouseleave = function() {
|
|
1840
|
-
disableSelectedBtn.style.background = "#ef4444";
|
|
1841
|
-
};
|
|
1842
|
-
disableSelectedBtn.disabled = selectedIds.size === 0;
|
|
1843
|
-
disableSelectedBtn.onclick = async () => {
|
|
1844
|
-
if (!selectedIds.size) {
|
|
1845
|
-
return;
|
|
1846
|
-
}
|
|
1847
|
-
disableSelectedBtn.disabled = true;
|
|
1848
|
-
try {
|
|
1849
|
-
showBusyUi();
|
|
1850
|
-
await batchSetDeviceEnabled(selectedIds, false);
|
|
1851
|
-
toastSuccess("Selected devices disabled");
|
|
1852
|
-
await loadConfiguredDevices();
|
|
1853
|
-
await updateDiscoveryView(allDevices, preferences, groupBy, hideAdded, selectedIds);
|
|
1854
|
-
} catch (e) {
|
|
1855
|
-
uiLog.error("Batch disable error:", e);
|
|
1856
|
-
toastError(e instanceof Error ? e.message : "Failed to disable devices");
|
|
1857
|
-
} finally {
|
|
1858
|
-
hideBusyUi();
|
|
1859
|
-
disableSelectedBtn.disabled = false;
|
|
1860
|
-
}
|
|
1861
|
-
};
|
|
1862
|
-
buttonRow.appendChild(addSelectedBtn);
|
|
1863
|
-
buttonRow.appendChild(enableSelectedBtn);
|
|
1864
|
-
buttonRow.appendChild(disableSelectedBtn);
|
|
1865
|
-
batchControls.appendChild(buttonRow);
|
|
1866
|
-
const listContainer = document.getElementById("discoveredList");
|
|
1867
|
-
if (listContainer) {
|
|
1868
|
-
listContainer.insertBefore(batchControls, listContainer.firstChild);
|
|
1869
|
-
}
|
|
1870
|
-
} else {
|
|
1871
|
-
const addSelectedBtn = document.getElementById("addSelectedBtn");
|
|
1872
|
-
if (addSelectedBtn) {
|
|
1873
|
-
addSelectedBtn.disabled = selectedIds.size === 0;
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1723
|
+
updateBatchButtonStates();
|
|
1876
1724
|
const status = document.getElementById("discoverStatus");
|
|
1877
1725
|
if (status) {
|
|
1878
1726
|
const totalCount = allDevices.length;
|
|
@@ -3020,6 +2868,7 @@ function renderDeviceDetailsPanel(device) {
|
|
|
3020
2868
|
}
|
|
3021
2869
|
}
|
|
3022
2870
|
const rows = [
|
|
2871
|
+
{ label: "Name", value: String(device?.name || device?.configDeviceName || "N/A") },
|
|
3023
2872
|
{ label: "Device ID", value: String(device?.id || device?.deviceId || "N/A"), copyable: !!(device?.id || device?.deviceId) },
|
|
3024
2873
|
{ label: "MAC Address", value: String(device?.address || "N/A"), copyable: !!device?.address },
|
|
3025
2874
|
{ label: "Device Type", value: String(device?.type || device?.configDeviceType || "N/A") },
|
|
@@ -3641,7 +3490,7 @@ function renderDeviceList(list) {
|
|
|
3641
3490
|
deleteBtn.style.background = "#ef4444";
|
|
3642
3491
|
deleteBtn.onclick = async () => {
|
|
3643
3492
|
const { deleteDeviceFromConfig: deleteDeviceFromConfig2 } = await Promise.resolve().then(() => (init_devices_delete(), devices_delete_exports));
|
|
3644
|
-
await deleteDeviceFromConfig2(d.id, d.name || d.id);
|
|
3493
|
+
await deleteDeviceFromConfig2(d.id || d.deviceId, d.name || d.id || d.deviceId);
|
|
3645
3494
|
};
|
|
3646
3495
|
buttons.appendChild(editBtn);
|
|
3647
3496
|
buttons.appendChild(copyBtn);
|
|
@@ -3717,6 +3566,7 @@ async function addDeviceToConfig2(device, options = {}) {
|
|
|
3717
3566
|
}
|
|
3718
3567
|
}
|
|
3719
3568
|
if (refresh) {
|
|
3569
|
+
await syncParentPluginConfigFromDisk(true);
|
|
3720
3570
|
await loadConfiguredDevices();
|
|
3721
3571
|
}
|
|
3722
3572
|
return { added: !alreadyExists };
|