boneIO 1.5.0.dev33__py3-none-any.whl → 1.5.0.dev35__py3-none-any.whl
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.
- boneio/boards/1.0/output_24_16.yaml +2 -0
- boneio/boards/1.0/output_32_10.yaml +2 -0
- boneio/boards/1.0/output_48_4.yaml +3 -0
- boneio/boards/1.0/output_cover.yaml +2 -0
- boneio/boards/1.0/output_cover_mix.yaml +2 -0
- boneio/core/manager/outputs.py +5 -3
- boneio/hardware/gpio/expanders/mcp23017.py +75 -13
- boneio/schema/schema.yaml +5 -0
- boneio/version.py +1 -1
- boneio/webui/frontend-dist/assets/BindingMatrix-BUi252df.js +1 -0
- boneio/webui/frontend-dist/assets/{ConfigEditor-Db9Hv4K7.js → ConfigEditor-BpkOsEkf.js} +1 -1
- boneio/webui/frontend-dist/assets/{EditItemDialog-BBgUejNu.js → EditItemDialog-BdrR2Xio.js} +1 -1
- boneio/webui/frontend-dist/assets/{EntityCard-V_dIvm7h.js → EntityCard-B5hsu-oX.js} +1 -1
- boneio/webui/frontend-dist/assets/{FormInputToggle-jYwQBCms.js → FormInputToggle-Ejf0vOFN.js} +1 -1
- boneio/webui/frontend-dist/assets/{InputsView--0TitNzt.js → InputsView-CooBY18i.js} +1 -1
- boneio/webui/frontend-dist/assets/{LogViewer-0bOsZFY4.js → LogViewer-CbBFb3Ub.js} +1 -1
- boneio/webui/frontend-dist/assets/{ModbusView-B65zWo-u.js → ModbusView-BnzMs_o-.js} +1 -1
- boneio/webui/frontend-dist/assets/{OutputsView-feRbZLV7.js → OutputsView-CZEYJaW6.js} +1 -1
- boneio/webui/frontend-dist/assets/{SensorView-BI9r6Khx.js → SensorView-B4KTE8L8.js} +1 -1
- boneio/webui/frontend-dist/assets/{SudoPasswordDialog-CdKObBJL.js → SudoPasswordDialog-DgYui8J1.js} +1 -1
- boneio/webui/frontend-dist/assets/{SystemState-Xwy9Q9yE.js → SystemState-Domna8FY.js} +1 -1
- boneio/webui/frontend-dist/assets/{TemplatesView-BZPOKY7l.js → TemplatesView-CYVg2x4r.js} +1 -1
- boneio/webui/frontend-dist/assets/{Tools--HWg7Etd.js → Tools-DmMBqc60.js} +1 -1
- boneio/webui/frontend-dist/assets/{UISettings-DrOjn7rw.js → UISettings-B22iRxos.js} +3 -3
- boneio/webui/frontend-dist/assets/{index-Co9Pvhx4.css → index-B17A-zgw.css} +1 -1
- boneio/webui/frontend-dist/assets/{index-DIN8b655.js → index-CqeQX4ri.js} +2 -2
- boneio/webui/frontend-dist/assets/useTranslation-B3o3o7lE.js +13 -0
- boneio/webui/frontend-dist/index.html +3 -3
- boneio/webui/frontend-dist/schema/config.schema.json +21 -0
- boneio/webui/frontend-dist/schema/mcp23017.schema.json +21 -0
- boneio/webui/frontend-dist/sw.js +1 -1
- boneio/webui/schema/config.schema.json +21 -0
- boneio/webui/schema/mcp23017.schema.json +21 -0
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/METADATA +1 -1
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/RECORD +39 -39
- boneio/webui/frontend-dist/assets/BindingMatrix-LxACKGJk.js +0 -1
- boneio/webui/frontend-dist/assets/useTranslation-Dy6J9cmj.js +0 -13
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/WHEEL +0 -0
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/entry_points.txt +0 -0
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/licenses/LICENSE +0 -0
- {boneio-1.5.0.dev33.dist-info → boneio-1.5.0.dev35.dist-info}/top_level.txt +0 -0
boneio/core/manager/outputs.py
CHANGED
|
@@ -185,9 +185,11 @@ class OutputManager:
|
|
|
185
185
|
id = expander[ID] or expander[ADDRESS]
|
|
186
186
|
address = expander[ADDRESS]
|
|
187
187
|
try:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
kwargs = {"i2c": self._manager._i2cbusio, "address": address, "reset": False}
|
|
189
|
+
if exp_type == MCP:
|
|
190
|
+
kwargs["inverted"] = expander.get("inverted", None)
|
|
191
|
+
kwargs["state_manager"] = getattr(self._manager, "_state_manager", None)
|
|
192
|
+
expander_dict[id] = _EXPANDER_CLASS[exp_type](**kwargs)
|
|
191
193
|
sleep_time = expander.get(INIT_SLEEP, TimePeriod(seconds=0))
|
|
192
194
|
if sleep_time.total_seconds > 0:
|
|
193
195
|
_LOGGER.debug(
|
|
@@ -12,6 +12,7 @@ import time
|
|
|
12
12
|
from typing import TYPE_CHECKING
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
+
from boneio.core.state.manager import StateManager
|
|
15
16
|
from boneio.hardware.i2c.bus import SMBus2I2C
|
|
16
17
|
|
|
17
18
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -49,13 +50,22 @@ class MCP23017:
|
|
|
49
50
|
pin0.switch_to_output(value=True)
|
|
50
51
|
"""
|
|
51
52
|
|
|
52
|
-
def __init__(
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
i2c: SMBus2I2C,
|
|
56
|
+
address: int = 0x20,
|
|
57
|
+
reset: bool = False,
|
|
58
|
+
inverted: bool | None = None,
|
|
59
|
+
state_manager: StateManager | None = None,
|
|
60
|
+
):
|
|
53
61
|
"""Initialize MCP23017.
|
|
54
62
|
|
|
55
63
|
Args:
|
|
56
64
|
i2c: I2C bus instance (SMBus2I2C)
|
|
57
65
|
address: I2C address of the device (default 0x20)
|
|
58
66
|
reset: Reset flag (unused, for API compatibility with Adafruit library)
|
|
67
|
+
inverted: Active-LOW relay board flag (True=active-LOW, False=active-HIGH, None=auto-detect)
|
|
68
|
+
state_manager: Optional StateManager instance to persist/read auto-detected logic
|
|
59
69
|
|
|
60
70
|
Raises:
|
|
61
71
|
ValueError: If address is not in valid range (0x20-0x27)
|
|
@@ -67,6 +77,7 @@ class MCP23017:
|
|
|
67
77
|
|
|
68
78
|
self._i2c = i2c
|
|
69
79
|
self._address = address
|
|
80
|
+
self._state_manager = state_manager
|
|
70
81
|
|
|
71
82
|
# Lock for thread-safe pin operations
|
|
72
83
|
# This prevents race conditions when multiple outputs are switched simultaneously
|
|
@@ -89,13 +100,55 @@ class MCP23017:
|
|
|
89
100
|
# Write to both registers for robustness in case of dirty startup
|
|
90
101
|
self._write_register_unlocked(0x0A, 0x20) # SEQOP=1 (disabled), BANK=0
|
|
91
102
|
self._write_register_unlocked(0x0B, 0x20) # Mirror register
|
|
103
|
+
|
|
104
|
+
# Read IODIR to check if this is cold boot (all inputs = 0xFF)
|
|
105
|
+
iodir_a = self._read_register_unlocked(IODIRA)
|
|
106
|
+
iodir_b = self._read_register_unlocked(IODIRB)
|
|
107
|
+
is_cold_boot = (iodir_a == 0xFF and iodir_b == 0xFF)
|
|
108
|
+
|
|
109
|
+
# Determine inverted state:
|
|
110
|
+
# 1. Config override
|
|
111
|
+
# 2. State manager persisted value
|
|
112
|
+
# 3. Auto-detection on cold boot (GPIO read)
|
|
113
|
+
# 4. Fallback (False)
|
|
114
|
+
state_key = f"mcp_0x{address:02x}_inverted"
|
|
115
|
+
if inverted is not None:
|
|
116
|
+
self._inverted = bool(inverted)
|
|
117
|
+
_LOGGER.info("MCP23017@0x%02X inverted set from config: %s", address, self._inverted)
|
|
118
|
+
elif state_manager and state_manager.get("hardware", state_key) is not None:
|
|
119
|
+
self._inverted = bool(state_manager.get("hardware", state_key))
|
|
120
|
+
_LOGGER.info("MCP23017@0x%02X inverted loaded from state: %s", address, self._inverted)
|
|
121
|
+
elif is_cold_boot:
|
|
122
|
+
gpio_a = self._read_register_unlocked(GPIOA)
|
|
123
|
+
gpio_b = self._read_register_unlocked(GPIOB)
|
|
124
|
+
self._inverted = (gpio_a == 0xFF and gpio_b == 0xFF)
|
|
125
|
+
_LOGGER.info(
|
|
126
|
+
"MCP23017@0x%02X auto-detected relay board logic: %s (GPIOA=0x%02X, GPIOB=0x%02X)",
|
|
127
|
+
address,
|
|
128
|
+
"active-LOW (inverted)" if self._inverted else "active-HIGH",
|
|
129
|
+
gpio_a,
|
|
130
|
+
gpio_b,
|
|
131
|
+
)
|
|
132
|
+
if state_manager:
|
|
133
|
+
state_manager.save_attribute("hardware", state_key, self._inverted)
|
|
134
|
+
else:
|
|
135
|
+
self._inverted = False
|
|
136
|
+
_LOGGER.info("MCP23017@0x%02X inverted fallback: False", address)
|
|
92
137
|
|
|
93
138
|
# Read current output latch states from hardware to preserve relay states
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
139
|
+
if is_cold_boot and self._inverted:
|
|
140
|
+
# Cold boot with active-LOW relays: set all pins to HIGH (0xFF) before setting IODIR=0x00
|
|
141
|
+
# so relays stay OFF during initial output configuration
|
|
142
|
+
self._port_a_state = 0xFF
|
|
143
|
+
self._port_b_state = 0xFF
|
|
144
|
+
self._write_register_unlocked(OLATA, 0xFF)
|
|
145
|
+
self._write_register_unlocked(OLATB, 0xFF)
|
|
146
|
+
else:
|
|
147
|
+
self._port_a_state = self._read_register_unlocked(OLATA)
|
|
148
|
+
self._port_b_state = self._read_register_unlocked(OLATB)
|
|
149
|
+
|
|
97
150
|
_LOGGER.debug(
|
|
98
|
-
f"MCP23017@0x{address:02X} preserved states: "
|
|
151
|
+
f"MCP23017@0x{address:02X} preserved states (inverted={self._inverted}): "
|
|
99
152
|
f"A=0b{self._port_a_state:08b}, B=0b{self._port_b_state:08b}"
|
|
100
153
|
)
|
|
101
154
|
|
|
@@ -104,7 +157,7 @@ class MCP23017:
|
|
|
104
157
|
self._write_register_unlocked(IODIRA, 0x00)
|
|
105
158
|
self._write_register_unlocked(IODIRB, 0x00)
|
|
106
159
|
|
|
107
|
-
_LOGGER.info(f"Initialized MCP23017 at address 0x{address:02X}")
|
|
160
|
+
_LOGGER.info(f"Initialized MCP23017 at address 0x{address:02X} (inverted={self._inverted})")
|
|
108
161
|
finally:
|
|
109
162
|
self._i2c.unlock()
|
|
110
163
|
|
|
@@ -191,6 +244,11 @@ class MCP23017:
|
|
|
191
244
|
iodir &= ~(1 << pin_bit) # Clear bit = output
|
|
192
245
|
self._write_register_unlocked(IODIRB, iodir)
|
|
193
246
|
|
|
247
|
+
@property
|
|
248
|
+
def inverted(self) -> bool:
|
|
249
|
+
"""Check whether expander operates in inverted (active-LOW) mode."""
|
|
250
|
+
return self._inverted
|
|
251
|
+
|
|
194
252
|
def _write_pin(self, pin_number: int, value: bool) -> None:
|
|
195
253
|
"""Write value to a pin using ATOMIC hardware Read-Modify-Write.
|
|
196
254
|
|
|
@@ -199,7 +257,7 @@ class MCP23017:
|
|
|
199
257
|
|
|
200
258
|
Args:
|
|
201
259
|
pin_number: Pin number (0-15)
|
|
202
|
-
value: Output state (True=HIGH, False=LOW)
|
|
260
|
+
value: Output state (True=ON/HIGH logical, False=OFF/LOW logical)
|
|
203
261
|
"""
|
|
204
262
|
with self._lock:
|
|
205
263
|
# Rate limiting: ensure minimum delay between I2C operations
|
|
@@ -223,8 +281,11 @@ class MCP23017:
|
|
|
223
281
|
# Read current state from hardware
|
|
224
282
|
current_state = self._read_register_unlocked(reg)
|
|
225
283
|
|
|
284
|
+
# Account for active-LOW inverted logic
|
|
285
|
+
effective_value = not value if self._inverted else value
|
|
286
|
+
|
|
226
287
|
# Calculate new state
|
|
227
|
-
if
|
|
288
|
+
if effective_value:
|
|
228
289
|
new_state = current_state | (1 << bit)
|
|
229
290
|
else:
|
|
230
291
|
new_state = current_state & ~(1 << bit)
|
|
@@ -232,7 +293,7 @@ class MCP23017:
|
|
|
232
293
|
# Only write if state changed
|
|
233
294
|
if new_state != current_state:
|
|
234
295
|
_LOGGER.debug(
|
|
235
|
-
f"MCP23017@0x{self._address:02X} pin {pin_number} -> {value}: "
|
|
296
|
+
f"MCP23017@0x{self._address:02X} pin {pin_number} -> {value} (phys={effective_value}): "
|
|
236
297
|
f"{'OLATA' if pin_number < 8 else 'OLATB'} "
|
|
237
298
|
f"0b{current_state:08b} -> 0b{new_state:08b}"
|
|
238
299
|
)
|
|
@@ -277,23 +338,24 @@ class MCP23017:
|
|
|
277
338
|
self._write_pin(pin_number, value)
|
|
278
339
|
|
|
279
340
|
def get_pin_value(self, pin_number: int) -> bool:
|
|
280
|
-
"""Get current pin value.
|
|
341
|
+
"""Get current logical pin value.
|
|
281
342
|
|
|
282
343
|
Args:
|
|
283
344
|
pin_number: Pin number (0-15)
|
|
284
345
|
|
|
285
346
|
Returns:
|
|
286
|
-
Current pin state
|
|
347
|
+
Current logical pin state (accounting for active-LOW inverted logic)
|
|
287
348
|
"""
|
|
288
349
|
if not 0 <= pin_number <= 15:
|
|
289
350
|
raise ValueError(f"Pin number must be 0-15, got {pin_number}")
|
|
290
351
|
|
|
291
352
|
with self._lock:
|
|
292
353
|
if pin_number < 8:
|
|
293
|
-
|
|
354
|
+
raw_state = bool(self._port_a_state & (1 << pin_number))
|
|
294
355
|
else:
|
|
295
356
|
pin_bit = pin_number - 8
|
|
296
|
-
|
|
357
|
+
raw_state = bool(self._port_b_state & (1 << pin_bit))
|
|
358
|
+
return not raw_state if self._inverted else raw_state
|
|
297
359
|
|
|
298
360
|
def verify_port_state(self) -> tuple[int, int]:
|
|
299
361
|
"""Read actual port states from hardware and compare with cached state.
|
boneio/schema/schema.yaml
CHANGED
boneio/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# flake8: noqa
|
|
2
|
-
__version__ = "1.5.0.
|
|
2
|
+
__version__ = "1.5.0.dev35"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{c as t}from"./monaco-61yH0vfd.js";import{b as n}from"./vendor-IzweXARb.js";import{F as r,I as i,M as a,O as o,Q as s,Vt as c,Xt as l,Yt as u,_ as d,m as f,p,ut as m,z as h,zt as g}from"./fa-C9nnJsGR.js";import{t as _}from"./useTranslation-B3o3o7lE.js";import{r as v}from"./utils-C8nShLO6.js";import{t as y}from"./EditItemDialog-BdrR2Xio.js";var b=e(t(),1);function x(e){return l({tag:`svg`,attr:{viewBox:`0 0 512 512`},child:[{tag:`path`,attr:{d:`M224 0c17.7 0 32 14.3 32 32l0 12 96-12c17.7 0 32 14.3 32 32s-14.3 32-32 32L256 84l-31-3.9-1-.1-1 .1L192 84 96 96C78.3 96 64 81.7 64 64s14.3-32 32-32l96 12 0-12c0-17.7 14.3-32 32-32zM0 224c0-17.7 14.3-32 32-32l96 0 22.6-22.6c6-6 14.1-9.4 22.6-9.4l18.7 0 0-43.8 32-4 32 4 0 43.8 18.7 0c8.5 0 16.6 3.4 22.6 9.4L320 192l32 0c88.4 0 160 71.6 160 160c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32s-14.3-32-32-32l-36.1 0c-20.2 29-53.9 48-91.9 48s-71.7-19-91.9-48L32 320c-17.7 0-32-14.3-32-32l0-64zM436.8 423.4c1.9-4.5 6.3-7.4 11.2-7.4s9.2 2.9 11.2 7.4l18.2 42.4c1.8 4.1 2.7 8.6 2.7 13.1l0 1.2c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-1.2c0-4.5 .9-8.9 2.7-13.1l18.2-42.4z`},child:[]}]})(e)}var S=n();function C({outputType:e,className:t}){switch(e){case`light`:return(0,S.jsx)(s,{className:v(`text-warning`,t)});case`switch`:return(0,S.jsx)(c,{className:v(`text-info`,t)});case`valve`:return(0,S.jsx)(x,{className:v(`text-accent`,t)});case`cover`:return(0,S.jsx)(o,{className:v(`text-secondary`,t)});case`shutter`:case`blind`:case`curtain`:return(0,S.jsx)(u,{className:v(`text-secondary`,t)});default:return null}}var w={single:`1×`,double:`2×`,triple:`3×`,long:`L`,pressed:`P`,released:`R`,double_then_long:`2×L`,single_then_long:`1×L`,double_then_single:`2×1`},T={TOGGLE:`short_toggle`,ON:`short_on`,OFF:`short_off`,OPEN:`short_open`,CLOSE:`short_close`,STOP:`short_stop`},E=[{key:`single`,labelKey:`binding_matrix.legend_single`,icon:`1×`},{key:`double`,labelKey:`binding_matrix.legend_double`,icon:`2×`},{key:`triple`,labelKey:`binding_matrix.legend_triple`,icon:`3×`},{key:`long`,labelKey:`binding_matrix.legend_long`,icon:`L`},{key:`pressed`,labelKey:`binding_matrix.legend_pressed`,icon:`P`},{key:`released`,labelKey:`binding_matrix.legend_released`,icon:`R`}],D=[{labelKey:`actions.toggle`,shortKey:`actions.short_toggle`},{labelKey:`actions.on`,shortKey:`actions.short_on`},{labelKey:`actions.off`,shortKey:`actions.short_off`},{labelKey:`actions.open`,shortKey:`actions.short_open`},{labelKey:`actions.close`,shortKey:`actions.short_close`},{labelKey:`actions.stop`,shortKey:`actions.short_stop`}],O={single:`single`,double:`double`,triple:`triple`,long:`long`,pressed:`pressed`,released:`released`,double_then_long:`sequences`,single_then_long:`sequences`,double_then_single:`sequences`};function k(e,t){let n=w[e.clickType]||e.clickType,r=T[e.actionValue];return`${n} ${r?t(`actions.${r}`):e.actionValue}`}function A(e,t){let n=`actions.${e.actionValue.toLowerCase()}`,r=t(n),i=r===n?e.actionValue:r;return`${e.clickType} → ${i}`}function j(e){let t=e.action||`output`,n=``,r=``,i;switch(t){case`output`:n=e.boneio_output||``,r=e.action_output||`TOGGLE`;break;case`cover`:n=e.boneio_cover||``,r=e.action_cover||`TOGGLE`;break;case`remote_output`:i=e.boneio_id||``,n=i?`${i}/${e.output_id||``}`:e.output_id||``,r=e.action_output||`TOGGLE`;break;case`remote_cover`:i=e.boneio_id||``,n=i?`${i}/${e.cover_id||``}`:e.cover_id||``,r=e.action_cover||`TOGGLE`;break;default:n=``,r=e.action_output||e.action_cover||``;break}return{targetId:n,actionType:t,actionValue:r,remoteDevice:i}}function M(e){let t=[],n=[`single`,`double`,`triple`,`long`,`pressed`,`released`,`double_then_long`,`single_then_long`,`double_then_single`],r=e.local_inputs||[];for(let e=0;e<r.length;e++){let i=r[e],a=i.id||i.boneio_input||i.pin||`local_${e}`,o=[];for(let e of n){let t=i.actions?.[e]||[];for(let n of t){let{targetId:t,actionType:r,actionValue:i,remoteDevice:a}=j(n);t&&o.push({clickType:e,actionType:r,targetId:t,actionValue:i,remoteDevice:a})}}t.push({id:a,name:i.name||i.id||i.boneio_input||i.pin||a,area:i.area||void 0,type:`local`,inputKind:i._type===`binary_sensor`?`binary_sensor`:`event`,bindings:o})}let i=e.remote_inputs||[];for(let e=0;e<i.length;e++){let r=i[e],a=r.boneio_id||r.remote_device||``,o=r.id||r.entity_id||``,s=a?`${a}/${o}`:o||`remote_${e}`,c=[];for(let e of n){let t=r.actions?.[e]||[];for(let n of t){let{targetId:t,actionType:r,actionValue:i,remoteDevice:a}=j(n);t&&c.push({clickType:e,actionType:r,targetId:t,actionValue:i,remoteDevice:a})}}t.push({id:s,name:r.name||r.id||o,area:r.area||void 0,type:`remote`,inputKind:r._type===`binary_sensor`?`binary_sensor`:`event`,remoteDevice:a,bindings:c})}return t}function N(e){let t=[],n=e.output||[];for(let e=0;e<n.length;e++){let r=n[e];if(r.output_type===`cover`||r.output_type===`none`)continue;let i=r.id||`output_${e}`;t.push({id:i,name:r.name||r.id||i,area:r.area||void 0,type:`output`,outputType:r.output_type})}let r=e.cover||[];for(let e=0;e<r.length;e++){let n=r[e],i=n.id||`cover_${e}`;t.push({id:i,name:n.name||n.id||i,area:n.area||void 0,type:`cover`,outputType:n.device_class||`cover`})}let i=e.remote_outputs||[];for(let e=0;e<i.length;e++){let n=i[e],r=n.boneio_id||n.remote_device||``,a=n.id||n.output_id||``,o=r?`${r}/${a}`:a||`remote_out_${e}`;t.push({id:o,name:n.name||n.id||a,area:n.area||void 0,type:`remote_output`,remoteDevice:r,outputType:n.output_type})}return t}function P({inputs:e,outputs:t,t:n}){let r=e.filter(e=>e.type===`local`),i=e.filter(e=>e.type===`remote`),a=t.filter(e=>e.type===`output`),o=t.filter(e=>e.type===`cover`),s=t.filter(e=>e.type===`remote_output`||e.type===`remote_cover`),c=r.filter(e=>e.bindings.length>0),l=i.filter(e=>e.bindings.length>0),u=new Set(e.flatMap(e=>e.bindings.map(e=>e.targetId))),d=a.filter(e=>u.has(e.id)),f=o.filter(e=>u.has(e.id)),p=s.filter(e=>u.has(e.id)),m=e.reduce((e,t)=>e+t.bindings.length,0);return(0,S.jsxs)(`div`,{className:`gap-3 grid grid-cols-1 md:grid-cols-4 mb-4`,children:[(0,S.jsxs)(`div`,{className:`space-y-1 bg-base-200/50 p-3 border border-base-300 rounded-xl`,children:[(0,S.jsx)(`h4`,{className:`font-bold text-xs text-base-content/50 uppercase tracking-wider`,children:n(`binding_matrix.local`)}),(0,S.jsxs)(`p`,{className:`text-xs text-base-content/70`,children:[`📥 `,n(`binding_matrix.inputs`),`: `,r.length,(0,S.jsxs)(`span`,{className:`ml-1 text-success`,children:[`(`,c.length,` ✓)`]}),(0,S.jsxs)(`span`,{className:`ml-1 text-warning`,children:[`(`,r.length-c.length,` ○)`]})]}),(0,S.jsxs)(`p`,{className:`text-xs text-base-content/70`,children:[`💡 `,n(`binding_matrix.outputs`),`: `,a.length,(0,S.jsxs)(`span`,{className:`ml-1 text-success`,children:[`(`,d.length,` ✓)`]}),(0,S.jsxs)(`span`,{className:`ml-1 text-warning`,children:[`(`,a.length-d.length,` ○)`]})]}),(0,S.jsxs)(`p`,{className:`text-xs text-base-content/70`,children:[`🚪 `,n(`binding_matrix.covers`),`: `,o.length,(0,S.jsxs)(`span`,{className:`ml-1 text-success`,children:[`(`,f.length,` ✓)`]}),(0,S.jsxs)(`span`,{className:`ml-1 text-warning`,children:[`(`,o.length-f.length,` ○)`]})]})]}),(i.length>0||s.length>0)&&(0,S.jsxs)(`div`,{className:`space-y-1 bg-info/5 p-3 border border-info/20 rounded-xl`,children:[(0,S.jsx)(`h4`,{className:`font-bold text-info/70 text-xs uppercase tracking-wider`,children:n(`binding_matrix.remote`)}),(0,S.jsxs)(`p`,{className:`text-xs text-base-content/70`,children:[`📥 `,n(`binding_matrix.inputs`),`: `,i.length,(0,S.jsxs)(`span`,{className:`ml-1 text-success`,children:[`(`,l.length,` ✓)`]}),(0,S.jsxs)(`span`,{className:`ml-1 text-warning`,children:[`(`,i.length-l.length,` ○)`]})]}),(0,S.jsxs)(`p`,{className:`text-xs text-base-content/70`,children:[`📡 `,n(`binding_matrix.outputs`),`: `,s.length,(0,S.jsxs)(`span`,{className:`ml-1 text-success`,children:[`(`,p.length,` ✓)`]}),(0,S.jsxs)(`span`,{className:`ml-1 text-warning`,children:[`(`,s.length-p.length,` ○)`]})]})]}),(0,S.jsxs)(`div`,{className:`flex flex-col justify-center bg-primary/5 p-3 border border-primary/20 rounded-xl`,children:[(0,S.jsx)(`p`,{className:`font-extrabold text-primary text-2xl`,children:m}),(0,S.jsx)(`p`,{className:`font-medium text-primary/70 text-xs`,children:n(`binding_matrix.total_bindings`)})]}),(0,S.jsxs)(`div`,{className:`bg-base-200/50 p-3 border border-base-300 rounded-xl`,children:[(0,S.jsx)(`h4`,{className:`mb-1.5 font-bold text-xs text-base-content/50 uppercase tracking-wider`,children:n(`binding_matrix.legend`)}),(0,S.jsx)(`div`,{className:`gap-x-3 gap-y-0.5 grid grid-cols-2`,children:E.map(e=>(0,S.jsxs)(`span`,{className:`text-xxs text-base-content/60`,children:[(0,S.jsx)(`span`,{className:`font-mono font-bold text-base-content/80`,children:e.icon}),` `,n(e.labelKey)]},e.key))}),(0,S.jsx)(`div`,{className:`gap-x-2 gap-y-0.5 grid grid-cols-3 mt-1.5 pt-1.5 border-base-300 border-t`,children:D.map(e=>(0,S.jsxs)(`span`,{className:`text-xxs text-base-content/60`,children:[(0,S.jsx)(`span`,{className:`font-mono font-bold text-base-content/80`,children:n(e.shortKey)}),` `,n(e.labelKey)]},e.shortKey))})]})]})}function F({inputs:e,outputs:t,t:n}){let[r,i]=(0,b.useState)(!0),[o,s]=(0,b.useState)(!0),c=new Set(e.flatMap(e=>e.bindings.map(e=>e.targetId))),l=e.filter(e=>e.type===`local`&&e.bindings.length===0),u=t.filter(e=>e.type===`output`&&!c.has(e.id)),p=t.filter(e=>e.type===`cover`&&!c.has(e.id)),m=e.filter(e=>e.type===`remote`&&e.bindings.length===0),h=t.filter(e=>(e.type===`remote_output`||e.type===`remote_cover`)&&!c.has(e.id)),g=l.length>0||u.length>0||p.length>0,_=m.length>0||h.length>0;return!g&&!_?null:(0,S.jsxs)(`div`,{className:`space-y-3 mt-4`,children:[g&&(0,S.jsxs)(`div`,{className:`bg-warning/5 border border-warning/20 rounded-xl overflow-hidden`,children:[(0,S.jsxs)(`button`,{className:`flex justify-between items-center hover:bg-warning/10 p-3 w-full font-semibold text-warning text-sm transition-colors`,onClick:()=>i(!r),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(a,{className:`w-3.5 h-3.5`}),n(`binding_matrix.unconfigured_local`)]}),r?(0,S.jsx)(d,{className:`w-3 h-3`}):(0,S.jsx)(f,{className:`w-3 h-3`})]}),r&&(0,S.jsxs)(`div`,{className:`space-y-2 p-3 pt-0`,children:[l.length>0&&(0,S.jsx)(I,{title:`📥 ${n(`binding_matrix.free_inputs`)} (${l.length})`,items:l.map(e=>({id:e.id,name:e.name,area:e.area}))}),u.length>0&&(0,S.jsx)(I,{title:`💡 ${n(`binding_matrix.free_outputs`)} (${u.length})`,items:u.map(e=>({id:e.id,name:e.name,area:e.area}))}),p.length>0&&(0,S.jsx)(I,{title:`🚪 ${n(`binding_matrix.free_covers`)} (${p.length})`,items:p.map(e=>({id:e.id,name:e.name,area:e.area}))})]})]}),_&&(0,S.jsxs)(`div`,{className:`bg-info/5 border border-info/20 rounded-xl overflow-hidden`,children:[(0,S.jsxs)(`button`,{className:`flex justify-between items-center hover:bg-info/10 p-3 w-full font-semibold text-info text-sm transition-colors`,onClick:()=>s(!o),children:[(0,S.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,S.jsx)(a,{className:`w-3.5 h-3.5`}),n(`binding_matrix.unconfigured_remote`)]}),o?(0,S.jsx)(d,{className:`w-3 h-3`}):(0,S.jsx)(f,{className:`w-3 h-3`})]}),o&&(0,S.jsxs)(`div`,{className:`space-y-2 p-3 pt-0`,children:[m.length>0&&(0,S.jsx)(I,{title:`📥 ${n(`binding_matrix.free_remote_inputs`)} (${m.length})`,items:m.map(e=>({id:e.id,name:e.name,area:e.area,badge:e.remoteDevice}))}),h.length>0&&(0,S.jsx)(I,{title:`📡 ${n(`binding_matrix.free_remote_outputs`)} (${h.length})`,items:h.map(e=>({id:e.id,name:e.name,area:e.area,badge:e.remoteDevice}))})]})]})]})}function I({title:e,items:t}){return(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`p`,{className:`mb-1 font-semibold text-xs text-base-content/60`,children:e}),(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,S.jsxs)(`span`,{className:`gap-1 font-mono text-xxs badge badge-sm badge-ghost`,title:e.id,children:[e.name,e.area&&(0,S.jsxs)(`span`,{className:`text-base-content/40`,children:[`(`,e.area,`)`]}),e.badge&&(0,S.jsxs)(`span`,{className:`text-info/60`,children:[`[`,e.badge,`]`]})]},e.id))})]})}function ee({inputs:e,outputs:t,areaFilter:n,hideEmpty:r,t:i,onEditInput:a,onEditOutput:o}){let[s,c]=(0,b.useState)(null),[l,u]=(0,b.useState)(null),d=(0,b.useRef)(null),f=(0,b.useRef)(!1),p=(0,b.useRef)(!1),h=(0,b.useRef)(0),g=(0,b.useRef)(0),[_,y]=(0,b.useState)(null),x=(0,b.useRef)(null),w=(0,b.useCallback)((e,t,n)=>{n||(e.preventDefault(),y({x:e.clientX,y:e.clientY,row:t}))},[]),T=(0,b.useCallback)((e,t,n)=>{if(n)return;let r=`touches`in e?{x:e.touches[0].clientX,y:e.touches[0].clientY}:{x:e.clientX,y:e.clientY};x.current=setTimeout(()=>{y({...r,row:t}),x.current=null},500)},[]),D=(0,b.useCallback)(()=>{x.current&&=(clearTimeout(x.current),null)},[]);(0,b.useEffect)(()=>{if(!_)return;let e=null,t=requestAnimationFrame(()=>{let t=()=>y(null);window.addEventListener(`click`,t),window.addEventListener(`contextmenu`,t,{capture:!0}),window.addEventListener(`scroll`,t,!0),e=()=>{window.removeEventListener(`click`,t),window.removeEventListener(`contextmenu`,t,{capture:!0}),window.removeEventListener(`scroll`,t,!0)}});return()=>{cancelAnimationFrame(t),e?.()}},[_]);let O=(0,b.useMemo)(()=>{let e=new Map;for(let n of t)e.set(n.id,n.area);return e},[t]),j=(0,b.useMemo)(()=>{let t=e;return n.size>0&&(t=t.filter(e=>{let t=e.area||`__none__`;return n.has(t)?!0:e.bindings.some(e=>{let t=O.get(e.targetId)||`__none__`;return n.has(t)})})),r&&(t=t.filter(e=>e.bindings.length>0)),t},[e,n,r,O]),M=(0,b.useMemo)(()=>new Set(e.flatMap(e=>e.bindings.map(e=>e.targetId))),[e]),N=(0,b.useMemo)(()=>{let t=new Map;for(let n of e){let e=n.area||`__none__`;for(let r of n.bindings)t.has(r.targetId)||t.set(r.targetId,new Set),t.get(r.targetId).add(e)}return t},[e]),P=(0,b.useMemo)(()=>{let e=t;return n.size>0&&(e=e.filter(e=>{let t=e.area||`__none__`;if(n.has(t))return!0;let r=N.get(e.id);if(r){for(let e of r)if(n.has(e))return!0}return!1})),r&&(e=e.filter(e=>M.has(e.id))),e},[t,n,r,M,N]),F=(0,b.useMemo)(()=>{let e=new Map;for(let t of j){let n=new Map;for(let e of t.bindings){let t=n.get(e.targetId)||[];t.push(e),n.set(e.targetId,t)}e.set(t.id,n)}return e},[j]);return j.length===0||P.length===0?(0,S.jsx)(`div`,{className:`py-12 text-base-content/40 text-center`,children:(0,S.jsx)(`p`,{className:`text-sm`,children:i(`binding_matrix.no_data`)})}):(0,S.jsxs)(`div`,{ref:d,className:`border border-base-300 rounded-xl overflow-x-auto cursor-grab active:cursor-grabbing select-none`,onMouseDown:e=>{f.current=!0,p.current=!1,h.current=e.clientX,g.current=d.current?.scrollLeft||0},onMouseMove:e=>{if(!f.current||!d.current)return;let t=e.clientX-h.current;!p.current&&Math.abs(t)>5&&(p.current=!0),p.current&&(d.current.scrollLeft=g.current-t)},onMouseUp:()=>{f.current=!1,p.current=!1},onMouseLeave:()=>{f.current=!1,p.current=!1},onClickCapture:e=>{p.current&&(e.stopPropagation(),e.preventDefault())},children:[(0,S.jsxs)(`table`,{className:`table table-xs w-auto`,children:[(0,S.jsx)(`thead`,{children:(0,S.jsxs)(`tr`,{children:[(0,S.jsx)(`th`,{className:`left-0 z-20 sticky bg-base-200 border-base-300 border-r min-w-30`}),P.map(e=>(0,S.jsxs)(`th`,{className:v(`group/col bg-base-200 px-2 py-2 border-base-300 border-r min-w-20 font-bold text-xxs text-center whitespace-nowrap cursor-pointer`,l===e.id&&`bg-primary/10`),onMouseEnter:()=>u(e.id),onMouseLeave:()=>u(null),onClick:()=>o(e),title:i(`binding_matrix.click_to_edit`),children:[(0,S.jsxs)(`div`,{className:`flex justify-center items-center gap-1`,children:[(0,S.jsx)(C,{outputType:e.outputType,className:`w-3 h-3 shrink-0`}),(0,S.jsx)(`span`,{className:`whitespace-nowrap`,children:e.name}),(0,S.jsx)(m,{className:`opacity-0 group-hover/col:opacity-40 w-2 h-2 transition-opacity shrink-0`})]}),e.area?(0,S.jsx)(`div`,{className:`font-normal text-xxs text-base-content/40 truncate`,children:e.area}):(0,S.jsx)(`div`,{className:`font-normal text-xxs text-base-content/20`,children:`—`}),e.remoteDevice&&(0,S.jsx)(`div`,{className:`font-normal text-info/50 text-xxs truncate`,children:e.remoteDevice})]},e.id))]})}),(0,S.jsx)(`tbody`,{children:j.map(e=>{let t=F.get(e.id);return(0,S.jsxs)(`tr`,{className:v(`hover:bg-base-200/50`,s===e.id&&`bg-base-200/40`),onMouseEnter:()=>c(e.id),onMouseLeave:()=>c(null),children:[(0,S.jsxs)(`td`,{className:v(`group/row left-0 z-10 sticky bg-base-100 border-base-300 border-r font-medium text-xs cursor-pointer`,s===e.id&&`bg-base-200/60`,e.bindings.length===0&&`text-base-content/30`),onClick:()=>a(e),title:i(`binding_matrix.click_to_edit`),children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-1 max-w-30 font-bold truncate`,title:e.id,children:[e.name,(0,S.jsx)(m,{className:`opacity-0 group-hover/row:opacity-40 w-2.5 h-2.5 transition-opacity shrink-0`})]}),e.area&&(0,S.jsx)(`div`,{className:`text-xxs text-base-content/40`,children:e.area}),e.remoteDevice&&(0,S.jsx)(`div`,{className:`text-info/50 text-xxs`,children:e.remoteDevice})]}),P.map(n=>{let r=t?.get(n.id)||[],o=s===e.id||l===n.id;return(0,S.jsx)(`td`,{className:v(`px-1 py-1 border-base-300 border-r text-xs text-center`,r.length>0?`bg-success/15 text-success font-medium`:`text-base-content/30`,o&&r.length>0&&`bg-success/25`,o&&r.length===0&&`bg-base-200/40`),onMouseEnter:()=>u(n.id),onMouseLeave:()=>{u(null),D()},onContextMenu:t=>w(t,e,r.length>0),onMouseDown:t=>{t.button===0&&T(t,e,r.length>0)},onMouseUp:D,onTouchStart:t=>T(t,e,r.length>0),onTouchEnd:D,onTouchMove:D,children:r.length>0&&(0,S.jsx)(`div`,{className:`flex flex-col gap-0.5`,children:r.map((t,n)=>(0,S.jsx)(`button`,{className:`hover:bg-success/30 px-0.5 rounded text-left whitespace-nowrap transition-colors cursor-pointer`,onClick:()=>a(e,t.clickType),title:`${A(t,i)}\n${i(`binding_matrix.click_to_edit`)}`,children:k(t,i)},n))})},n.id)})]},e.id)})})]}),_&&(0,S.jsxs)(`div`,{className:`z-50 fixed bg-base-100 shadow-xl py-1 border border-base-300 rounded-lg min-w-45 animate-in duration-100 fade-in zoom-in-95`,style:{left:_.x,top:_.y},onClick:e=>e.stopPropagation(),children:[(0,S.jsx)(`div`,{className:`px-3 py-1.5 font-semibold text-xxs text-base-content/40 uppercase tracking-wider`,children:i(`binding_matrix.add_action`)}),E.filter(e=>_.row.inputKind===`binary_sensor`?e.key===`pressed`||e.key===`released`:e.key!==`pressed`&&e.key!==`released`).map(e=>(0,S.jsxs)(`button`,{className:`flex items-center gap-2 hover:bg-primary/10 px-3 py-1.5 w-full text-sm text-left transition-colors`,onClick:()=>{a(_.row,e.key),y(null)},children:[(0,S.jsx)(`span`,{className:`font-mono text-base-content/70`,children:e.icon}),i(`binding_matrix.legend_${e.key}`)]},e.key))]})]})}function te({inputs:e,areaFilter:t,hideEmpty:n,t:r,onEditInput:i}){let[a,o]=(0,b.useState)(null),s=(0,b.useMemo)(()=>{let r=e;return t.size>0&&(r=r.filter(e=>{let n=e.area||`__none__`;return t.has(n)})),n&&(r=r.filter(e=>e.bindings.length>0)),r},[e,t,n]),c=(0,b.useCallback)(e=>{o(t=>t===e?null:e)},[]);return s.length===0?(0,S.jsx)(`div`,{className:`py-12 text-base-content/40 text-center`,children:(0,S.jsx)(`p`,{className:`text-sm`,children:r(`binding_matrix.no_data`)})}):(0,S.jsx)(`div`,{className:`space-y-1.5`,children:s.map(e=>{let t=a===e.id,n=e.bindings.length>0,o=new Map;for(let t of e.bindings){let e=o.get(t.targetId)||[];e.push(t),o.set(t.targetId,e)}return(0,S.jsxs)(`div`,{className:v(`border rounded-xl overflow-hidden transition-colors`,n?`border-success/20 bg-success/5`:`border-base-300 bg-base-200/30`),children:[(0,S.jsxs)(`button`,{className:`flex justify-between items-center hover:bg-base-200/30 p-3 w-full text-sm transition-colors`,onClick:()=>n&&c(e.id),disabled:!n,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[n?(0,S.jsx)(p,{className:`w-3.5 h-3.5 text-success shrink-0`}):(0,S.jsx)(g,{className:`w-3.5 h-3.5 text-base-content/20 shrink-0`}),(0,S.jsxs)(`div`,{className:`min-w-0 text-left`,children:[(0,S.jsx)(`span`,{className:v(`block font-semibold truncate`,!n&&`text-base-content/30`),children:e.name}),e.area&&(0,S.jsx)(`span`,{className:`text-xxs text-base-content/40`,children:e.area})]})]}),(0,S.jsxs)(`div`,{className:`flex items-center gap-2`,children:[n&&(0,S.jsx)(`span`,{className:`font-bold badge badge-sm badge-success`,children:e.bindings.length}),e.type===`remote`&&(0,S.jsx)(`span`,{className:`font-mono badge badge-xs badge-info`,children:e.remoteDevice}),n&&(t?(0,S.jsx)(d,{className:`w-3 h-3 text-base-content/30`}):(0,S.jsx)(f,{className:`w-3 h-3 text-base-content/30`}))]})]}),t&&n&&(0,S.jsxs)(`div`,{className:`space-y-2 bg-base-100/50 p-3 border-base-300 border-t`,children:[[...o.entries()].map(([e,t])=>(0,S.jsxs)(`div`,{className:`flex items-start gap-2 text-xs`,children:[(0,S.jsx)(`span`,{className:`mt-0.5 font-mono font-bold text-base-content/70 shrink-0`,children:`→`}),(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`span`,{className:`font-semibold`,children:e}),(0,S.jsx)(`div`,{className:`flex flex-wrap gap-1 mt-0.5`,children:t.map((e,t)=>(0,S.jsx)(`span`,{className:`gap-0.5 font-mono badge badge-xs badge-success`,children:k(e,r)},t))})]})]},e)),(0,S.jsxs)(`button`,{className:`gap-1 mt-1 btn-outline btn btn-xs btn-primary`,onClick:t=>{t.stopPropagation(),i(e)},children:[(0,S.jsx)(m,{className:`w-2.5 h-2.5`}),r(`binding_matrix.edit_input`)]})]})]},e.id)})})}var L=({formData:e,sections:t,onSaveSection:n,onUpdateFormData:a})=>{let{t:o}=_(),[s,c]=(0,b.useState)(new Set),[l,u]=(0,b.useState)(!1),[d,p]=(0,b.useState)(!1),[m,g]=(0,b.useState)(!1),[v,x]=(0,b.useState)(null),[C,w]=(0,b.useState)(``),[T,E]=(0,b.useState)(-1),[D,k]=(0,b.useState)(`basic`),[A,j]=(0,b.useState)(!1),[I,L]=(0,b.useState)(!1),R=(0,b.useRef)(null),[ne,z]=(0,b.useState)(!1),[B,V]=(0,b.useState)(null),[H,re]=(0,b.useState)(``),[U,ie]=(0,b.useState)(-1),[ae,W]=(0,b.useState)(!1),G=(0,b.useRef)(null),K=(0,b.useCallback)((t,n)=>{let r=t.type===`remote`?`remote_inputs`:`local_inputs`,i=e[r]||[],a=i.findIndex((e,n)=>{if(t.type===`remote`){let r=e.boneio_id||e.remote_device||``,i=e.id||e.entity_id||``;return(r?`${r}/${i}`:i||`remote_${n}`)===t.id}return(e.id||e.boneio_input||e.pin||`local_${n}`)===t.id});a<0||(w(r),E(a),x(JSON.parse(JSON.stringify(i[a]))),R.current=JSON.stringify(i[a]),k(n&&O[n]||`basic`),j(!1),g(!0))},[e]),oe=(0,b.useCallback)(async()=>{if(A||T<0||!v)return;let t=[...e[C]||[]];t[T]=v,L(!0);try{a(C,t),await n(C,t),g(!1),x(null)}catch(e){console.error(`Failed to save input:`,e)}finally{L(!1)}},[v,T,C,e,A,n,a]),se=(0,b.useCallback)(()=>{g(!1),x(null)},[]),q=(0,b.useMemo)(()=>M(e),[e]),J=(0,b.useMemo)(()=>N(e),[e]),ce=(0,b.useMemo)(()=>{let e=new Set;return q.forEach(t=>{t.area&&e.add(t.area)}),J.forEach(t=>{t.area&&e.add(t.area)}),[...e].sort()},[q,J]),le=(0,b.useMemo)(()=>q.some(e=>!e.area)||J.some(e=>!e.area),[q,J]),Y=(0,b.useMemo)(()=>e.output||[],[e.output]),X=(0,b.useMemo)(()=>e.cover||[],[e.cover]),Z=(0,b.useMemo)(()=>e.output_group||[],[e.output_group]),ue=(0,b.useMemo)(()=>e.remote_devices||[],[e.remote_devices]),de=(0,b.useMemo)(()=>e.remote_inputs||[],[e.remote_inputs]),Q=(0,b.useMemo)(()=>(e.local_inputs||[]).filter(e=>e._inputType===`binary_sensor`),[e.local_inputs]),fe=(0,b.useMemo)(()=>(e.local_inputs||[]).filter(e=>e._inputType!==`binary_sensor`),[e.local_inputs]),$=(0,b.useMemo)(()=>e.areas||[],[e.areas]),pe=(0,b.useMemo)(()=>{let e=t.find(e=>e.name===`local_inputs`);return e?.schema||e?.normalizedSchema||{}},[t]),me=(0,b.useMemo)(()=>{let e=t.find(e=>e.name===`output`);return e?.schema||e?.normalizedSchema||{}},[t]),he=(0,b.useMemo)(()=>t.find(e=>e.name===`output`)?.uiSchema||{},[t]),ge=(0,b.useMemo)(()=>{let e=t.find(e=>e.name===`cover`);return e?.schema||e?.normalizedSchema||{}},[t]),_e=(0,b.useCallback)(t=>{let n={output:`output`,cover:`cover`,remote_output:`remote_outputs`,remote_cover:`remote_covers`}[t.type]||`output`,r=e[n]||[],i=r.findIndex((e,n)=>{if(t.type===`remote_output`||t.type===`remote_cover`){let r=e.boneio_id||e.remote_device||``,i=e.id||e.output_id||``;return(r?`${r}/${i}`:i||`remote_out_${n}`)===t.id}return(e.id||``)===t.id});i<0||(re(n),ie(i),V(JSON.parse(JSON.stringify(r[i]))),G.current=JSON.stringify(r[i]),z(!0))},[e]),ve=(0,b.useCallback)(async()=>{if(U<0||!B)return;let t=[...e[H]||[]];t[U]=B,W(!0);try{a(H,t),await n(H,t),z(!1),V(null)}catch(e){console.error(`Failed to save output:`,e)}finally{W(!1)}},[B,U,H,e,n,a]),ye=(0,b.useCallback)(()=>{z(!1),V(null)},[]),be=v&&R.current&&JSON.stringify(v)!==R.current,xe=B&&G.current&&JSON.stringify(B)!==G.current;return(0,S.jsxs)(`div`,{className:`p-4 md:p-6 max-w-full`,children:[(0,S.jsxs)(`div`,{className:`mb-4`,children:[(0,S.jsx)(`h2`,{className:`font-extrabold text-xl tracking-tight`,children:o(`binding_matrix.title`)}),(0,S.jsx)(`p`,{className:`text-sm text-base-content/50`,children:o(`binding_matrix.subtitle`)})]}),(0,S.jsx)(P,{inputs:q,outputs:J,t:o}),(0,S.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 mb-4`,children:[(0,S.jsxs)(`div`,{className:`relative flex items-center gap-2`,children:[(0,S.jsx)(h,{className:`w-3 h-3 text-base-content/40`}),(0,S.jsxs)(`button`,{className:`justify-between gap-1 btn-outline min-w-40 btn btn-sm`,onClick:()=>u(e=>!e),children:[(0,S.jsx)(`span`,{className:`text-xs truncate`,children:s.size===0?o(`binding_matrix.all_areas`):s.size===1?s.has(`__none__`)?o(`binding_matrix.no_area`):[...s][0]:o(`binding_matrix.areas_selected`,{count:s.size})}),(0,S.jsx)(f,{className:`w-2.5 h-2.5 shrink-0`})]}),l&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(`div`,{className:`z-40 fixed inset-0`,onClick:()=>u(!1)}),(0,S.jsxs)(`div`,{className:`top-full left-0 z-50 absolute bg-base-100 shadow-xl mt-1 py-1 border border-base-300 rounded-lg min-w-50 max-h-75 overflow-y-auto`,children:[(0,S.jsxs)(`label`,{className:`flex items-center gap-2 hover:bg-base-200/60 px-3 py-1.5 transition-colors cursor-pointer`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-xs checkbox-primary`,checked:s.size===0,onChange:()=>c(new Set)}),(0,S.jsx)(`span`,{className:`font-semibold text-xs`,children:o(`binding_matrix.all_areas`)})]}),(0,S.jsx)(`div`,{className:`my-0.5 border-base-300 border-t`}),le&&(0,S.jsxs)(`label`,{className:`flex items-center gap-2 hover:bg-base-200/60 px-3 py-1.5 transition-colors cursor-pointer`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-xs checkbox-primary`,checked:s.has(`__none__`),onChange:()=>{let e=new Set(s);e.has(`__none__`)?e.delete(`__none__`):e.add(`__none__`),c(e)}}),(0,S.jsx)(`span`,{className:`text-xs text-base-content/50 italic`,children:o(`binding_matrix.no_area`)})]}),ce.map(e=>(0,S.jsxs)(`label`,{className:`flex items-center gap-2 hover:bg-base-200/60 px-3 py-1.5 transition-colors cursor-pointer`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-xs checkbox-primary`,checked:s.has(e),onChange:()=>{let t=new Set(s);t.has(e)?t.delete(e):t.add(e),c(t)}}),(0,S.jsx)(`span`,{className:`text-xs`,children:e})]},e))]})]})]}),(0,S.jsxs)(`label`,{className:`flex items-center gap-2 cursor-pointer`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-sm checkbox-primary`,checked:d,onChange:e=>p(e.target.checked)}),(0,S.jsxs)(`span`,{className:`flex items-center gap-1 font-medium text-xs text-base-content/60`,children:[d?(0,S.jsx)(i,{className:`w-3 h-3`}):(0,S.jsx)(r,{className:`w-3 h-3`}),o(`binding_matrix.hide_empty`)]})]})]}),(0,S.jsx)(`div`,{className:`hidden md:block`,children:(0,S.jsx)(ee,{inputs:q,outputs:J,areaFilter:s,hideEmpty:d,t:o,onEditInput:K,onEditOutput:_e})}),(0,S.jsx)(`div`,{className:`md:hidden`,children:(0,S.jsx)(te,{inputs:q,areaFilter:s,hideEmpty:d,t:o,onEditInput:K})}),(0,S.jsx)(F,{inputs:q,outputs:J,t:o}),(0,S.jsx)(y,{open:m,onOpenChange:g,editingItem:v,editingIndex:T,sectionType:C,schema:C===`remote_inputs`?t.find(e=>e.name===`remote_inputs`)?.schema||t.find(e=>e.name===`remote_inputs`)?.normalizedSchema||{}:pe,allBinarySensors:Q,allEvents:fe,allOutputs:Y,allOutputGroups:Z,allCovers:X,allAreas:$,allRemoteDevices:ue,allRemoteInputs:de,savedOutputs:Y,savedOutputGroups:Z,savedCovers:X,onChange:x,onSave:oe,onCancel:se,onValidationChange:j,saveDisabled:A||!be,isSaving:I,initialTab:D}),(0,S.jsx)(y,{open:ne,onOpenChange:z,editingItem:B,editingIndex:U,sectionType:H,schema:H===`cover`?ge:me,uiSchema:H===`cover`?void 0:he,allOutputs:Y,allCovers:X,allAreas:$,onChange:V,onSave:ve,onCancel:ye,saveDisabled:!xe,isSaving:ae})]})};export{L as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{a as t,c as n,i as r,n as i,o as a,r as o,t as s}from"./monaco-61yH0vfd.js";import{b as c}from"./vendor-IzweXARb.js";import{St as l,Xt as u,bt as d,g as f,m as p,xt as m}from"./fa-C9nnJsGR.js";import{r as h,t as g}from"./useTranslation-
|
|
1
|
+
import{r as e}from"./rolldown-runtime-QTnfLwEv.js";import{a as t,c as n,i as r,n as i,o as a,r as o,t as s}from"./monaco-61yH0vfd.js";import{b as c}from"./vendor-IzweXARb.js";import{St as l,Xt as u,bt as d,g as f,m as p,xt as m}from"./fa-C9nnJsGR.js";import{r as h,t as g}from"./useTranslation-B3o3o7lE.js";var _=e(n(),1);function v(){let[e,t]=(0,_.useState)(`dark`);return(0,_.useEffect)(()=>{t(localStorage.getItem(`theme`)||`dark`);let e=new MutationObserver(e=>{e.forEach(e=>{e.attributeName===`data-theme`&&t(document.documentElement.getAttribute(`data-theme`)||`dark`)})});return e.observe(document.documentElement,{attributes:!0,attributeFilter:[`data-theme`]}),()=>e.disconnect()},[]),e}function y(e){return u({tag:`svg`,attr:{viewBox:`0 0 24 24`},child:[{tag:`path`,attr:{d:`M11.28 9.53 8.81 12l2.47 2.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-3-3a.75.75 0 0 1 0-1.06l3-3a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734Z`},child:[]},{tag:`path`,attr:{d:`M3.75 2h16.5c.966 0 1.75.784 1.75 1.75v16.5A1.75 1.75 0 0 1 20.25 22H3.75A1.75 1.75 0 0 1 2 20.25V3.75C2 2.784 2.784 2 3.75 2ZM3.5 3.75v16.5c0 .138.112.25.25.25H15v-17H3.75a.25.25 0 0 0-.25.25Zm13 16.75h3.75a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25H16.5Z`},child:[]}]})(e)}var b=c();function x({isOpen:e,onClose:t}){let{t:n}=g(),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(null),s=async()=>{i(!0);try{let e=await h.get(`/api/check_configuration`);o({status:e.data.status,message:e.data.message})}catch{o({status:`error`,message:n(`config_check.failed`)})}finally{i(!1)}};return e?(0,b.jsx)(`div`,{className:`fixed inset-0 bg-base-300/80 flex items-center justify-center z-50`,children:(0,b.jsxs)(`div`,{className:`bg-base-200 p-8 rounded-lg shadow-lg max-w-2xl w-full mx-4`,children:[(0,b.jsx)(`h2`,{className:`text-2xl font-bold mb-6`,children:n(`config_check.title`)}),r?(0,b.jsxs)(`div`,{className:`flex flex-col items-center gap-4 py-8`,children:[(0,b.jsx)(`div`,{className:`loading loading-spinner loading-lg`}),(0,b.jsx)(`p`,{className:`text-lg`,children:n(`config_check.checking`)})]}):a?(0,b.jsxs)(`div`,{className:`space-y-4`,children:[(0,b.jsx)(`div`,{className:`text-lg font-semibold ${a.status===`success`?`text-success`:`text-error`}`,children:a.status===`success`?n(`config_check.valid`):n(`config_check.error`)}),a.message&&(0,b.jsx)(`pre`,{className:`bg-base-300 p-4 rounded-lg whitespace-pre-wrap`,children:a.message}),(0,b.jsxs)(`div`,{className:`flex justify-end gap-4 mt-6`,children:[(0,b.jsx)(`button`,{className:`btn btn-ghost`,onClick:()=>{o(null),t()},children:n(`common.close`)}),(0,b.jsx)(`button`,{className:`btn btn-primary`,onClick:()=>{o(null),s()},children:n(`config_check.check_again`)})]})]}):(0,b.jsxs)(`div`,{className:`space-y-6`,children:[(0,b.jsx)(`p`,{className:`text-base-content/70`,children:n(`config_check.description`)}),(0,b.jsxs)(`div`,{className:`flex justify-end gap-4`,children:[(0,b.jsx)(`button`,{className:`btn btn-ghost`,onClick:t,children:n(`common.cancel`)}),(0,b.jsx)(`button`,{className:`btn btn-primary`,onClick:s,children:n(`config_check.check_button`)})]})]})]})}):null}function S(e){return new Worker(`/assets/yaml.worker-BKRoXlmz.js`,{name:e?.name})}self.MonacoEnvironment={getWorker(e,t){return t===`yaml`?new S:t===`json`?new s:new i}},a.config({monaco:r});var C;function w(){let[e,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(null),[a,s]=(0,_.useState)(``),[c,u]=(0,_.useState)(!1),[g,S]=(0,_.useState)(`waiting`),[w,T]=(0,_.useState)(!0),[E,D]=(0,_.useState)(!1),O=v(),k=async()=>{try{n((await h.get(`/api/files`)).data.items)}catch(e){console.error(`Error loading directory:`,e)}},A=async e=>{try{let t=`/api/files/${encodeURIComponent(e)}`,n=await h.get(t);i(e),s(n.data.content),localStorage.setItem(`lastOpenedFile`,e)}catch(e){console.error(`Error loading file:`,e)}},j=async()=>{if(r)try{await h.put(`/api/files/${encodeURIComponent(r)}`,{content:a}),console.log(`File saved successfully`)}catch(e){console.error(`Error saving file:`,e)}},M=async e=>{if(!C){let t=(await h.get(`/schema/config.schema.json`)).data;C=await o(e,{enableSchemaRequest:!0,schemas:[{uri:window.location.origin+`/schema/config.schema.json`,fileMatch:[`config.yaml`,`config.yml`],schema:t},...Object.keys(t.properties).map(e=>({uri:window.location.origin+`/schema/${e}.schema.json`,fileMatch:[`${e}.yaml`,`${e}.yml`],schema:t.properties[e]}))],validate:!0})}},N=async(e,t)=>{e.addCommand(t.KeyMod.CtrlCmd|t.KeyCode.KeyS,()=>{j()})},P=e=>{n(t=>{let n=t=>t.map(t=>t.path===e?{...t,isOpen:!t.isOpen}:t.children?{...t,children:n(t.children)}:t);return n(t)})},F=(e,t=0)=>e.map(e=>{let n=t==0||e.isOpen;return(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`button`,{className:`flex items-center gap-2 w-full px-2 py-1 hover:bg-base-300 ${r===e.path?`bg-primary/10`:``}`,style:{paddingLeft:`${t*16+8}px`},onClick:()=>e.type===`file`?A(e.path):P(e.path),children:[e.type===`directory`&&(0,b.jsx)(`span`,{className:`text-xs`,children:n?(0,b.jsx)(p,{}):(0,b.jsx)(f,{})}),(0,b.jsx)(`span`,{className:`text-base-content/70`,children:e.type===`directory`?n?(0,b.jsx)(l,{}):(0,b.jsx)(m,{}):(0,b.jsx)(d,{})}),(0,b.jsx)(`span`,{className:`text-sm truncate`,children:e.name})]}),e.type===`directory`&&n&&e.children&&F(e.children,t+1)]},e.path)}),I=async()=>{try{return await h.get(`/api/files`),!0}catch{return!1}},L=async()=>{for(u(!0),S(`waiting`),await new Promise(e=>setTimeout(e,2e3)),S(`checking`);;){if(await I()){S(`ready`),await new Promise(e=>setTimeout(e,1e3)),u(!1),k();break}await new Promise(e=>setTimeout(e,1e3))}};return(0,_.useEffect)(()=>{(async()=>{await k();let e=localStorage.getItem(`lastOpenedFile`);e&&A(e)})()},[]),(0,b.jsxs)(`div`,{className:`flex h-full bg-base-300`,children:[c?(0,b.jsx)(`div`,{className:`fixed inset-0 bg-base-300/80 flex items-center justify-center z-50`,children:(0,b.jsxs)(`div`,{className:`bg-base-200 p-8 rounded-lg shadow-lg text-center`,children:[(0,b.jsx)(`div`,{className:`loading loading-spinner loading-lg mb-4`}),(0,b.jsxs)(`h2`,{className:`text-xl font-bold mb-4`,children:[g===`waiting`&&`Restarting Service...`,g===`checking`&&`Waiting for Service...`,g===`ready`&&`Service Restarted!`]}),(0,b.jsxs)(`p`,{className:`text-base-content/70`,children:[g===`waiting`&&`Initiating service restart`,g===`checking`&&`Checking if service is back online`,g===`ready`&&`Redirecting...`]})]})}):null,(0,b.jsxs)(`div`,{className:`${w?`w-64`:`w-0`} transition-all duration-300 bg-base-200 border-r border-base-content/10 overflow-hidden`,children:[(0,b.jsx)(`div`,{className:`p-2 text-sm font-semibold text-base-content/70 uppercase`,children:`Explorer`}),(0,b.jsx)(`div`,{className:`overflow-y-auto`,children:F(e)})]}),(0,b.jsxs)(`div`,{className:`flex-1 overflow-hidden flex flex-col h-full max-h-screen`,children:[(0,b.jsxs)(`div`,{className:`flex items-center p-2 border-b border-base-content/10`,children:[(0,b.jsx)(`button`,{onClick:()=>T(!w),className:`btn btn-ghost btn-sm p-1`,title:w?`Hide file tree`:`Show file tree`,children:(0,b.jsx)(y,{className:`h-5 w-5 opacity-70 transition-transform duration-200 ${w?``:`rotate-180`}`})}),r&&(0,b.jsx)(`span`,{className:`ml-2 text-sm opacity-70`,children:r})]}),(0,b.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,b.jsx)(t,{height:`100%`,width:`100%`,defaultLanguage:`yaml`,path:r||`config.yaml`,theme:O===`light`?`vs-light`:`vs-dark`,value:a,onChange:e=>s(e||``),onMount:N,beforeMount:M,options:{minimap:{enabled:!0},scrollBeyondLastLine:!1,fontSize:14,automaticLayout:!0,readOnly:!1,formatOnType:!0,formatOnPaste:!0,quickSuggestions:{other:!0,comments:!1,strings:!0}}})}),(0,b.jsxs)(`div`,{className:`h-12 bg-base-200 border-t border-base-content/10 flex items-center justify-end px-4 gap-4`,children:[(0,b.jsx)(`button`,{onClick:j,disabled:!r,className:`btn btn-primary btn-sm`,children:`Save`}),(0,b.jsx)(`button`,{onClick:()=>D(!0),className:`btn btn-primary btn-sm`,children:`Check Config`}),(0,b.jsx)(`button`,{onClick:async()=>{await j();try{if((await h.post(`/api/restart`)).data.status===`not available`){let e=document.getElementById(`toast`);e&&(e.classList.remove(`hidden`),setTimeout(()=>{e.classList.add(`hidden`)},5e3))}else console.log(`Service restarted successfully`),L()}catch(e){console.error(`Error restarting service:`,e)}},disabled:!r,className:`btn btn-secondary btn-sm`,children:`Save and Restart`})]})]}),(0,b.jsx)(`div`,{id:`toast`,className:`toast toast-end hidden`,children:(0,b.jsx)(`div`,{className:`alert alert-warning`,children:(0,b.jsx)(`span`,{children:`Restart not possible. Application is not running as systemd service. Restart manually.`})})}),(0,b.jsx)(x,{isOpen:E,onClose:()=>D(!1)})]})}export{w as default};
|