feat(DeviceDetailOverlay): conditionally render UI elements based on device type and improve cache handling
This commit is contained in:
parent
fefb7699fa
commit
e4a5eac676
|
|
@ -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>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user