feat(App, DevicesPage, ToolsPage): remove OtherPage and enhance device settings management with hardware, modem, cassette, and BOIP configurations
This commit is contained in:
parent
48f0de753e
commit
7892ce699e
|
|
@ -6,7 +6,6 @@ import DevicesPage from './components/DevicesPage';
|
||||||
import GeneralPage from './components/GeneralPage';
|
import GeneralPage from './components/GeneralPage';
|
||||||
import NetworkPage from './components/NetworkPage';
|
import NetworkPage from './components/NetworkPage';
|
||||||
import IECPage from './components/IECPage';
|
import IECPage from './components/IECPage';
|
||||||
import OtherPage from './components/OtherPage';
|
|
||||||
import ToolsPage from './components/ToolsPage';
|
import ToolsPage from './components/ToolsPage';
|
||||||
import SearchOverlay from './components/SearchOverlay';
|
import SearchOverlay from './components/SearchOverlay';
|
||||||
import MediaManager from './components/MediaManager';
|
import MediaManager from './components/MediaManager';
|
||||||
|
|
@ -16,7 +15,7 @@ import logoSvg from '../imports/logo.svg';
|
||||||
import { useSettings } from './settings';
|
import { useSettings } from './settings';
|
||||||
import { WsProvider } from './ws';
|
import { WsProvider } from './ws';
|
||||||
|
|
||||||
type Page = 'status' | 'devices' | 'iec' | 'network' | 'other' | 'general' | 'tools' | 'apps' | AppId;
|
type Page = 'status' | 'devices' | 'iec' | 'network' | 'general' | 'tools' | 'apps' | AppId;
|
||||||
|
|
||||||
type AppId =
|
type AppId =
|
||||||
| 'file-manager'
|
| 'file-manager'
|
||||||
|
|
@ -73,7 +72,6 @@ export default function App() {
|
||||||
devices: <DevicesPage config={config} setConfig={setConfig} openDeviceId={devicesOpenId} onClearOpenDevice={() => setDevicesOpenId(null)} />,
|
devices: <DevicesPage config={config} setConfig={setConfig} openDeviceId={devicesOpenId} onClearOpenDevice={() => setDevicesOpenId(null)} />,
|
||||||
iec: <IECPage config={config} setConfig={setConfig} />,
|
iec: <IECPage config={config} setConfig={setConfig} />,
|
||||||
network: <NetworkPage config={config} setConfig={setConfig} />,
|
network: <NetworkPage config={config} setConfig={setConfig} />,
|
||||||
other: <OtherPage config={config} setConfig={setConfig} />,
|
|
||||||
general: <GeneralPage config={config} setConfig={setConfig} />,
|
general: <GeneralPage config={config} setConfig={setConfig} />,
|
||||||
tools: <ToolsPage config={config} setConfig={setConfig} />,
|
tools: <ToolsPage config={config} setConfig={setConfig} />,
|
||||||
apps: (
|
apps: (
|
||||||
|
|
@ -327,7 +325,7 @@ function AppPage({ title, onBack }: { title: string; onBack: () => void }) {
|
||||||
<span className="text-xs text-white">Network</span>
|
<span className="text-xs text-white">Network</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setCurrentPage('other')}
|
onClick={() => setCurrentPage('devices')}
|
||||||
className="flex-1 flex flex-col items-center gap-1 py-2"
|
className="flex-1 flex flex-col items-center gap-1 py-2"
|
||||||
>
|
>
|
||||||
<MoreHorizontal className="w-5 h-5 text-white" />
|
<MoreHorizontal className="w-5 h-5 text-white" />
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
const [selectedDeviceIndex, setSelectedDeviceIndex] = useState<number | null>(null);
|
const [selectedDeviceIndex, setSelectedDeviceIndex] = useState<number | null>(null);
|
||||||
const [isScanning, setIsScanning] = useState(false);
|
const [isScanning, setIsScanning] = useState(false);
|
||||||
|
|
||||||
|
const hardware = config.hardware || {};
|
||||||
|
const modem = config.modem || {};
|
||||||
|
const cassette = config.cassette || {};
|
||||||
|
const boip = config.boip || {};
|
||||||
|
|
||||||
const devices: Device[] = [];
|
const devices: Device[] = [];
|
||||||
|
|
||||||
// Printer devices
|
// Printer devices
|
||||||
|
|
@ -319,6 +324,112 @@ export default function DevicesPage({ config, setConfig, openDeviceId, onClearOp
|
||||||
hasNext={selectedDeviceIndex < devices.length - 1}
|
hasNext={selectedDeviceIndex < devices.length - 1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* ── Hardware ── */}
|
||||||
|
<h2 className="text-sm text-neutral-500 pt-4">Hardware</h2>
|
||||||
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">PS/2</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['hardware', 'ps2'], hardware.ps2 ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${hardware.ps2 ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${hardware.ps2 ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">User Port Enabled</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['hardware', 'userport', 'enabled'], hardware.userport?.enabled ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${hardware.userport?.enabled ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${hardware.userport?.enabled ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">User Port Mode</label>
|
||||||
|
<select
|
||||||
|
value={hardware.userport?.mode?.split('|')[0] || 'serial'}
|
||||||
|
onChange={(e) => updateSetting(['hardware', 'userport', 'mode'], e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
||||||
|
>
|
||||||
|
<option value="serial">Serial</option>
|
||||||
|
<option value="parallel">Parallel</option>
|
||||||
|
<option value="IEEE-488">IEEE-488</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Modem ── */}
|
||||||
|
<h2 className="text-sm text-neutral-500 pt-4">Modem</h2>
|
||||||
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">Modem Enabled</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['modem', 'modem_enabled'], modem.modem_enabled ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${modem.modem_enabled ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${modem.modem_enabled ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">Sniffer Enabled</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['modem', 'sniffer_enabled'], modem.sniffer_enabled ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${modem.sniffer_enabled ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${modem.sniffer_enabled ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Cassette ── */}
|
||||||
|
<h2 className="text-sm text-neutral-500 pt-4">Cassette</h2>
|
||||||
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">Enabled</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['cassette', 'enabled'], cassette.enabled ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${cassette.enabled ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${cassette.enabled ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">Play/Record</label>
|
||||||
|
<input type="text" value={cassette.play_record || ''} onChange={(e) => updateSetting(['cassette', 'play_record'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">Pulldown</label>
|
||||||
|
<input type="text" value={cassette.pulldown || ''} onChange={(e) => updateSetting(['cassette', 'pulldown'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">URL</label>
|
||||||
|
<input type="text" value={cassette.url || ''} onChange={(e) => updateSetting(['cassette', 'url'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── BOIP ── */}
|
||||||
|
<h2 className="text-sm text-neutral-500 pt-4">BOIP</h2>
|
||||||
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
<div className="p-4 flex items-center justify-between">
|
||||||
|
<label className="text-sm text-neutral-500">Enabled</label>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting(['boip', 'enabled'], boip.enabled ? 0 : 1)}
|
||||||
|
className={`relative w-12 h-6 rounded-full transition-colors ${boip.enabled ? 'bg-blue-600' : 'bg-neutral-300'}`}
|
||||||
|
>
|
||||||
|
<div className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${boip.enabled ? 'translate-x-6' : 'translate-x-0.5'}`} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">Host</label>
|
||||||
|
<input type="text" value={boip.host || ''} onChange={(e) => updateSetting(['boip', 'host'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
<div className="p-4">
|
||||||
|
<label className="text-sm text-neutral-500 block mb-2">Port</label>
|
||||||
|
<input type="text" value={boip.port || ''} onChange={(e) => updateSetting(['boip', 'port'], e.target.value)} className="w-full px-3 py-2 border border-neutral-300 rounded-lg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
interface OtherPageProps {
|
|
||||||
config: any;
|
|
||||||
setConfig: (config: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function OtherPage({ config, setConfig }: OtherPageProps) {
|
|
||||||
const updateSetting = (path: string[], value: any) => {
|
|
||||||
const newConfig = JSON.parse(JSON.stringify(config));
|
|
||||||
let current = newConfig;
|
|
||||||
|
|
||||||
for (let i = 0; i < path.length - 1; i++) {
|
|
||||||
current = current[path[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
current[path[path.length - 1]] = value;
|
|
||||||
setConfig(newConfig);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hardware = config.hardware || {};
|
|
||||||
const modem = config.modem || {};
|
|
||||||
const cassette = config.cassette || {};
|
|
||||||
const boip = config.boip || {};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-4 space-y-4">
|
|
||||||
<h2 className="text-sm text-neutral-500">Hardware</h2>
|
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">PS/2</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['hardware', 'ps2'], hardware.ps2 ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
hardware.ps2 ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
hardware.ps2 ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">User Port Enabled</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['hardware', 'userport', 'enabled'], hardware.userport?.enabled ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
hardware.userport?.enabled ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
hardware.userport?.enabled ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">User Port Mode</label>
|
|
||||||
<select
|
|
||||||
value={hardware.userport?.mode?.split('|')[0] || 'serial'}
|
|
||||||
onChange={(e) => updateSetting(['hardware', 'userport', 'mode'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
>
|
|
||||||
<option value="serial">Serial</option>
|
|
||||||
<option value="parallel">Parallel</option>
|
|
||||||
<option value="IEEE-488">IEEE-488</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className="text-sm text-neutral-500 pt-4">Modem</h2>
|
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">Modem Enabled</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['modem', 'modem_enabled'], modem.modem_enabled ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
modem.modem_enabled ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
modem.modem_enabled ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">Sniffer Enabled</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['modem', 'sniffer_enabled'], modem.sniffer_enabled ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
modem.sniffer_enabled ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
modem.sniffer_enabled ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className="text-sm text-neutral-500 pt-4">Cassette</h2>
|
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">Enabled</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['cassette', 'enabled'], cassette.enabled ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
cassette.enabled ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
cassette.enabled ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">Play/Record</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={cassette.play_record || ''}
|
|
||||||
onChange={(e) => updateSetting(['cassette', 'play_record'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">Pulldown</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={cassette.pulldown || ''}
|
|
||||||
onChange={(e) => updateSetting(['cassette', 'pulldown'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">URL</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={cassette.url || ''}
|
|
||||||
onChange={(e) => updateSetting(['cassette', 'url'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 className="text-sm text-neutral-500 pt-4">BOIP</h2>
|
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
|
||||||
<div className="p-4 flex items-center justify-between">
|
|
||||||
<label className="text-sm text-neutral-500">Enabled</label>
|
|
||||||
<button
|
|
||||||
onClick={() => updateSetting(['boip', 'enabled'], boip.enabled ? 0 : 1)}
|
|
||||||
className={`relative w-12 h-6 rounded-full transition-colors ${
|
|
||||||
boip.enabled ? 'bg-blue-600' : 'bg-neutral-300'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full transition-transform ${
|
|
||||||
boip.enabled ? 'translate-x-6' : 'translate-x-0.5'
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">Host</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={boip.host || ''}
|
|
||||||
onChange={(e) => updateSetting(['boip', 'host'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="p-4">
|
|
||||||
<label className="text-sm text-neutral-500 block mb-2">Port</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={boip.port || ''}
|
|
||||||
onChange={(e) => updateSetting(['boip', 'port'], e.target.value)}
|
|
||||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -200,6 +200,75 @@ export default function ToolsPage({ config }: ToolsPageProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4 space-y-4">
|
<div className="p-4 space-y-4">
|
||||||
|
|
||||||
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex items-center gap-3 mb-3">
|
||||||
|
<div className="w-10 h-10 bg-neutral-100 rounded-lg flex items-center justify-center">
|
||||||
|
<Wrench className="w-5 h-5 text-neutral-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium">System Information</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2 text-sm">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-neutral-500">Firmware Version</span>
|
||||||
|
<span className="text-neutral-900">v2.5.1</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-neutral-500">Hardware Revision</span>
|
||||||
|
<span className="text-neutral-900">Rev C</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-neutral-500">Serial Number</span>
|
||||||
|
<span className="text-neutral-900">ML-2024-0420</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleSystemUpdate}
|
||||||
|
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
||||||
|
>
|
||||||
|
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||||||
|
<Download className="w-5 h-5 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium">System Update</div>
|
||||||
|
<div className="text-sm text-neutral-500">Check for firmware updates</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setShowFirmware(true)}
|
||||||
|
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
||||||
|
>
|
||||||
|
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||||||
|
<Cpu className="w-5 h-5 text-purple-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium">Change Firmware</div>
|
||||||
|
<div className="text-sm text-neutral-500">Select a firmware version to install</div>
|
||||||
|
</div>
|
||||||
|
<ChevronRight className="w-4 h-4 text-neutral-400" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleExportLogs}
|
||||||
|
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
||||||
|
>
|
||||||
|
<div className="w-10 h-10 bg-neutral-100 rounded-lg flex items-center justify-center">
|
||||||
|
<FileText className="w-5 h-5 text-neutral-600" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium">Export System Logs</div>
|
||||||
|
<div className="text-sm text-neutral-500">Download diagnostic logs</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 className="text-sm text-neutral-500">System Tools</h2>
|
<h2 className="text-sm text-neutral-500">System Tools</h2>
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
||||||
|
|
@ -270,75 +339,6 @@ export default function ToolsPage({ config }: ToolsPageProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 className="text-sm text-neutral-500 pt-4">System</h2>
|
|
||||||
|
|
||||||
<div className="bg-white border border-neutral-200 rounded-lg divide-y divide-neutral-200">
|
|
||||||
<div className="p-4">
|
|
||||||
<div className="flex items-center gap-3 mb-3">
|
|
||||||
<div className="w-10 h-10 bg-neutral-100 rounded-lg flex items-center justify-center">
|
|
||||||
<Wrench className="w-5 h-5 text-neutral-600" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">System Information</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2 text-sm">
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-neutral-500">Firmware Version</span>
|
|
||||||
<span className="text-neutral-900">v2.5.1</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-neutral-500">Hardware Revision</span>
|
|
||||||
<span className="text-neutral-900">Rev C</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-neutral-500">Serial Number</span>
|
|
||||||
<span className="text-neutral-900">ML-2024-0420</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={handleSystemUpdate}
|
|
||||||
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
|
||||||
>
|
|
||||||
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
|
||||||
<Download className="w-5 h-5 text-purple-600" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">System Update</div>
|
|
||||||
<div className="text-sm text-neutral-500">Check for firmware updates</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => setShowFirmware(true)}
|
|
||||||
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
|
||||||
>
|
|
||||||
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
|
||||||
<Cpu className="w-5 h-5 text-purple-600" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">Change Firmware</div>
|
|
||||||
<div className="text-sm text-neutral-500">Select a firmware version to install</div>
|
|
||||||
</div>
|
|
||||||
<ChevronRight className="w-4 h-4 text-neutral-400" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={handleExportLogs}
|
|
||||||
className="w-full p-4 flex items-center gap-3 hover:bg-neutral-50 text-left"
|
|
||||||
>
|
|
||||||
<div className="w-10 h-10 bg-neutral-100 rounded-lg flex items-center justify-center">
|
|
||||||
<FileText className="w-5 h-5 text-neutral-600" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium">Export System Logs</div>
|
|
||||||
<div className="text-sm text-neutral-500">Download diagnostic logs</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showFirmware && <FirmwareOverlay onClose={() => setShowFirmware(false)} />}
|
{showFirmware && <FirmwareOverlay onClose={() => setShowFirmware(false)} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user