feat(DeviceDetailOverlay, DevicesPage): enhance device handling with physical device support and improve navigation logic
This commit is contained in:
parent
9a7d93b9a7
commit
fefb7699fa
|
|
@ -14,6 +14,8 @@ interface Device {
|
||||||
enabled: boolean | number;
|
enabled: boolean | number;
|
||||||
url?: string;
|
url?: string;
|
||||||
mode?: number;
|
mode?: number;
|
||||||
|
physical?: boolean;
|
||||||
|
physicalModel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeviceDetailOverlayProps {
|
interface DeviceDetailOverlayProps {
|
||||||
|
|
@ -249,9 +251,16 @@ export default function DeviceDetailOverlay({
|
||||||
<button onClick={onClose} className="p-2 -m-2">
|
<button onClick={onClose} className="p-2 -m-2">
|
||||||
<X className="w-6 h-6" />
|
<X className="w-6 h-6" />
|
||||||
</button>
|
</button>
|
||||||
<div className={`flex flex-col items-center gap-0.5 ${deviceData.enabled ? 'text-blue-600' : 'text-neutral-400'}`}>
|
<div className={`flex flex-col items-center gap-0.5 ${
|
||||||
|
device.physical ? 'text-green-600' : deviceData.enabled ? 'text-blue-600' : 'text-neutral-400'
|
||||||
|
}`}>
|
||||||
<span className="text-sm font-semibold leading-none">{device.number}</span>
|
<span className="text-sm font-semibold leading-none">{device.number}</span>
|
||||||
{getDeviceIcon(device.type)}
|
{getDeviceIcon(device.type)}
|
||||||
|
{device.physical && (
|
||||||
|
<span className="text-xs text-green-700 px-1 py-0.5 bg-green-50 border border-green-200 rounded leading-none">
|
||||||
|
Physical
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowCommandMenu(!showCommandMenu)}
|
onClick={() => setShowCommandMenu(!showCommandMenu)}
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
// Auto-open the overlay when the parent passes a device ID
|
// Auto-open the overlay when the parent passes a device ID
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!openDeviceId) return;
|
if (!openDeviceId) return;
|
||||||
const idx = devices.findIndex(d => d.id === openDeviceId);
|
const idx = displayDevices.findIndex(d => d.id === openDeviceId);
|
||||||
if (idx >= 0) setSelectedDeviceIndex(idx);
|
if (idx >= 0) setSelectedDeviceIndex(idx);
|
||||||
onClearOpenDevice?.();
|
onClearOpenDevice?.();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
|
@ -195,8 +195,7 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeviceClick = (dd: DisplayDevice) => {
|
const handleDeviceClick = (dd: DisplayDevice) => {
|
||||||
if (dd.physical) return;
|
const idx = displayDevices.findIndex(d => d.id === dd.id);
|
||||||
const idx = devices.findIndex(d => d.number === dd.number);
|
|
||||||
if (idx >= 0) setSelectedDeviceIndex(idx);
|
if (idx >= 0) setSelectedDeviceIndex(idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -206,7 +205,7 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
if (selectedDeviceIndex === null) return;
|
if (selectedDeviceIndex === null) return;
|
||||||
if (direction === 'prev' && selectedDeviceIndex > 0)
|
if (direction === 'prev' && selectedDeviceIndex > 0)
|
||||||
setSelectedDeviceIndex(selectedDeviceIndex - 1);
|
setSelectedDeviceIndex(selectedDeviceIndex - 1);
|
||||||
else if (direction === 'next' && selectedDeviceIndex < devices.length - 1)
|
else if (direction === 'next' && selectedDeviceIndex < displayDevices.length - 1)
|
||||||
setSelectedDeviceIndex(selectedDeviceIndex + 1);
|
setSelectedDeviceIndex(selectedDeviceIndex + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -235,6 +234,19 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
found.sort((a, b) => parseInt(a.number) - parseInt(b.number));
|
found.sort((a, b) => parseInt(a.number) - parseInt(b.number));
|
||||||
|
|
||||||
setPhysicalDevices(found);
|
setPhysicalDevices(found);
|
||||||
|
|
||||||
|
// Disable any virtual device that now has a physical device at the same address.
|
||||||
|
const newConfig = JSON.parse(JSON.stringify(config));
|
||||||
|
let disabledCount = 0;
|
||||||
|
for (const p of found) {
|
||||||
|
const virt = newConfig.devices?.iec?.[p.number];
|
||||||
|
if (virt && virt.enabled) {
|
||||||
|
virt.enabled = 0;
|
||||||
|
disabledCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (disabledCount > 0) setConfig(newConfig);
|
||||||
|
|
||||||
setIsScanning(false);
|
setIsScanning(false);
|
||||||
toast.dismiss(toastId);
|
toast.dismiss(toastId);
|
||||||
toast.success(`Found ${found.length} physical device${found.length !== 1 ? 's' : ''} on the bus`);
|
toast.success(`Found ${found.length} physical device${found.length !== 1 ? 's' : ''} on the bus`);
|
||||||
|
|
@ -348,8 +360,7 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
{/* Info — clickable for virtual devices */}
|
{/* Info — clickable for virtual devices */}
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDeviceClick(device)}
|
onClick={() => handleDeviceClick(device)}
|
||||||
disabled={device.physical}
|
className="flex-1 min-w-0 text-left"
|
||||||
className="flex-1 min-w-0 text-left disabled:cursor-default"
|
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<span className={!device.physical && !device.enabled ? 'text-neutral-400' : 'text-neutral-900'}>
|
<span className={!device.physical && !device.enabled ? 'text-neutral-400' : 'text-neutral-900'}>
|
||||||
|
|
@ -401,16 +412,15 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* DeviceDetailOverlay — virtual devices only */}
|
|
||||||
{selectedDeviceIndex !== null && (
|
{selectedDeviceIndex !== null && (
|
||||||
<DeviceDetailOverlay
|
<DeviceDetailOverlay
|
||||||
device={devices[selectedDeviceIndex]}
|
device={displayDevices[selectedDeviceIndex]}
|
||||||
config={config}
|
config={config}
|
||||||
setConfig={setConfig}
|
setConfig={setConfig}
|
||||||
onClose={handleCloseOverlay}
|
onClose={handleCloseOverlay}
|
||||||
onNavigate={handleNavigate}
|
onNavigate={handleNavigate}
|
||||||
hasPrev={selectedDeviceIndex > 0}
|
hasPrev={selectedDeviceIndex > 0}
|
||||||
hasNext={selectedDeviceIndex < devices.length - 1}
|
hasNext={selectedDeviceIndex < displayDevices.length - 1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user