feat(DeviceDetailOverlay): conditionally render UI elements based on device type and improve cache handling

This commit is contained in:
Jaime Idolpx 2026-06-11 22:20:14 -04:00
parent fefb7699fa
commit e4a5eac676

View File

@ -311,24 +311,26 @@ export default function DeviceDetailOverlay({
<div className="p-4 space-y-6">
<div className="space-y-4">
<div className="flex items-center justify-between">
<label className="text-sm text-neutral-500">Enabled</label>
<button
onClick={() => {
const path = getDevicePath();
updateDeviceSetting([...path, 'enabled'], deviceData.enabled ? 0 : 1);
}}
className={`relative w-12 h-6 rounded-full transition-colors ${
deviceData.enabled ? 'bg-blue-600' : 'bg-neutral-300'
}`}
>
<div
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
deviceData.enabled ? 'translate-x-6' : 'translate-x-0.5'
{!device.physical && (
<div className="flex items-center justify-between">
<label className="text-sm text-neutral-500">Enabled</label>
<button
onClick={() => {
const path = getDevicePath();
updateDeviceSetting([...path, 'enabled'], deviceData.enabled ? 0 : 1);
}}
className={`relative w-12 h-6 rounded-full transition-colors ${
deviceData.enabled ? 'bg-blue-600' : 'bg-neutral-300'
}`}
/>
</button>
</div>
>
<div
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
deviceData.enabled ? 'translate-x-6' : 'translate-x-0.5'
}`}
/>
</button>
</div>
)}
<div>
<label className="text-sm text-neutral-500 block mb-2">Type</label>
@ -350,104 +352,21 @@ export default function DeviceDetailOverlay({
/>
</div>
<div>
<label className="text-sm text-neutral-500 block mb-2">Base URL</label>
<div className="flex gap-2">
<input
type="text"
value={deviceData.base_url ?? ''}
onChange={(e) => {
const path = getDevicePath();
updateDeviceSetting([...path, 'base_url'], e.target.value);
}}
className="flex-1 px-3 py-2 border border-neutral-300 rounded-lg"
/>
<button
onClick={() => setBrowsingField('base_url')}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-neutral-100"
title="Browse"
>
<FolderOpen className="w-5 h-5" />
</button>
<button
onClick={() => {
const path = getDevicePath();
updateDeviceSetting([...path, 'base_url'], '');
}}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-red-50 hover:border-red-300 hover:text-red-500"
title="Clear Base URL"
>
<X className="w-5 h-5" />
</button>
</div>
</div>
<div>
<label className="text-sm text-neutral-500 block mb-2">URL</label>
<div className="flex gap-2">
<input
type="text"
value={deviceData.url ?? ''}
onChange={(e) => {
const newUrl = e.target.value;
const devicePath = getDevicePath();
const newConfig = JSON.parse(JSON.stringify(config));
let dev = newConfig;
for (const k of devicePath) dev = dev[k];
if (isOutsideBase(newUrl, dev.base_url || '')) clearBaseAndCache(dev);
dev.url = newUrl;
setConfig(newConfig);
}}
className="flex-1 px-3 py-2 border border-neutral-300 rounded-lg"
/>
<button
onClick={() => setBrowsingField('url')}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-neutral-100"
title="Browse"
>
<FolderOpen className="w-5 h-5" />
</button>
<button
onClick={() => {
const devicePath = getDevicePath();
const newConfig = JSON.parse(JSON.stringify(config));
let dev = newConfig;
for (const k of devicePath) dev = dev[k];
delete dev.url;
delete dev.media_set;
setConfig(newConfig);
}}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-red-50 hover:border-red-300 hover:text-red-500"
title="Clear URL and media set"
>
<X className="w-5 h-5" />
</button>
</div>
{mediaSetFiles && (
<div className="mt-3">
<MediaSet files={mediaSetFiles} activeUrl={deviceData.url ?? ''} onSwitch={switchMedia} />
</div>
)}
</div>
{(deviceData.cache !== undefined ||
(deviceData.base_url ?? '').includes('://') ||
(deviceData.url ?? '').includes('://')) && (
{!device.physical && <>
<div>
<label className="text-sm text-neutral-500 block mb-2">Cache</label>
<label className="text-sm text-neutral-500 block mb-2">Base URL</label>
<div className="flex gap-2">
<input
type="text"
value={deviceData.cache ?? ''}
value={deviceData.base_url ?? ''}
onChange={(e) => {
const path = getDevicePath();
updateDeviceSetting([...path, 'cache'], e.target.value);
updateDeviceSetting([...path, 'base_url'], e.target.value);
}}
className="flex-1 px-3 py-2 border border-neutral-300 rounded-lg"
/>
<button
onClick={() => setBrowsingField('cache')}
onClick={() => setBrowsingField('base_url')}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-neutral-100"
title="Browse"
>
@ -456,35 +375,125 @@ export default function DeviceDetailOverlay({
<button
onClick={() => {
const path = getDevicePath();
updateDeviceSetting([...path, 'cache'], '');
updateDeviceSetting([...path, 'base_url'], '');
}}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-red-50 hover:border-red-300 hover:text-red-500"
title="Clear Cache"
title="Clear Base URL"
>
<X className="w-5 h-5" />
</button>
</div>
</div>
)}
<div>
<label className="text-sm text-neutral-500 block mb-2">URL</label>
<div className="flex gap-2">
<input
type="text"
value={deviceData.url ?? ''}
onChange={(e) => {
const newUrl = e.target.value;
const devicePath = getDevicePath();
const newConfig = JSON.parse(JSON.stringify(config));
let dev = newConfig;
for (const k of devicePath) dev = dev[k];
if (isOutsideBase(newUrl, dev.base_url || '')) clearBaseAndCache(dev);
dev.url = newUrl;
setConfig(newConfig);
}}
className="flex-1 px-3 py-2 border border-neutral-300 rounded-lg"
/>
<button
onClick={() => setBrowsingField('url')}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-neutral-100"
title="Browse"
>
<FolderOpen className="w-5 h-5" />
</button>
<button
onClick={() => {
const devicePath = getDevicePath();
const newConfig = JSON.parse(JSON.stringify(config));
let dev = newConfig;
for (const k of devicePath) dev = dev[k];
delete dev.url;
delete dev.media_set;
setConfig(newConfig);
}}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-red-50 hover:border-red-300 hover:text-red-500"
title="Clear URL and media set"
>
<X className="w-5 h-5" />
</button>
</div>
{mediaSetFiles && (
<div className="mt-3">
<MediaSet files={mediaSetFiles} activeUrl={deviceData.url ?? ''} onSwitch={switchMedia} />
</div>
)}
</div>
{(deviceData.cache !== undefined ||
(deviceData.base_url ?? '').includes('://') ||
(deviceData.url ?? '').includes('://')) && (
<div>
<label className="text-sm text-neutral-500 block mb-2">Cache</label>
<div className="flex gap-2">
<input
type="text"
value={deviceData.cache ?? ''}
onChange={(e) => {
const path = getDevicePath();
updateDeviceSetting([...path, 'cache'], e.target.value);
}}
className="flex-1 px-3 py-2 border border-neutral-300 rounded-lg"
/>
<button
onClick={() => setBrowsingField('cache')}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-neutral-100"
title="Browse"
>
<FolderOpen className="w-5 h-5" />
</button>
<button
onClick={() => {
const path = getDevicePath();
updateDeviceSetting([...path, 'cache'], '');
}}
className="px-3 py-2 border border-neutral-300 rounded-lg bg-neutral-50 hover:bg-red-50 hover:border-red-300 hover:text-red-500"
title="Clear Cache"
>
<X className="w-5 h-5" />
</button>
</div>
</div>
)}
</>}
{deviceData.mode !== undefined && (
<div className="flex items-center justify-between">
<label className="text-sm text-neutral-500">Mode</label>
<div className="flex rounded-lg border border-neutral-300 overflow-hidden text-sm">
{([0, 1] as const).map((val, i) => (
<button
key={val}
onClick={() => updateDeviceSetting([...getDevicePath(), 'mode'], val)}
className={`px-4 py-2 ${i > 0 ? 'border-l border-neutral-300' : ''} ${
(deviceData.mode ?? 0) === val
? 'bg-blue-600 text-white'
: 'bg-white text-neutral-700 hover:bg-neutral-50'
}`}
>
{val === 0 ? 'Read Only' : 'Write Enabled'}
</button>
))}
</div>
{device.physical
? <span className="text-sm text-neutral-700 px-3 py-2">
{(deviceData.mode ?? 0) === 0 ? 'Read Only' : 'Write Enabled'}
</span>
: <div className="flex rounded-lg border border-neutral-300 overflow-hidden text-sm">
{([0, 1] as const).map((val, i) => (
<button
key={val}
onClick={() => updateDeviceSetting([...getDevicePath(), 'mode'], val)}
className={`px-4 py-2 ${i > 0 ? 'border-l border-neutral-300' : ''} ${
(deviceData.mode ?? 0) === val
? 'bg-blue-600 text-white'
: 'bg-white text-neutral-700 hover:bg-neutral-50'
}`}
>
{val === 0 ? 'Read Only' : 'Write Enabled'}
</button>
))}
</div>
}
</div>
)}