feat(StatusPage): remove directory and disk map overlays to simplify UI
This commit is contained in:
parent
30b9bb2d49
commit
5ae3a6e584
|
|
@ -1,12 +1,10 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { HardDrive, Activity, Wifi, Radio, Signal, Clock, RefreshCw, FolderOpen, Map, Loader2 } from 'lucide-react';
|
import { HardDrive, Activity, Wifi, Radio, Clock, RefreshCw, Loader2 } from 'lucide-react';
|
||||||
import { useWs } from '../ws';
|
import { useWs } from '../ws';
|
||||||
import DeviceDetailOverlay from './DeviceDetailOverlay';
|
import DeviceDetailOverlay from './DeviceDetailOverlay';
|
||||||
import MediaSet from './MediaSet';
|
import MediaSet from './MediaSet';
|
||||||
import { ImageWithFallback } from './figma/ImageWithFallback';
|
import { ImageWithFallback } from './figma/ImageWithFallback';
|
||||||
import { Dialog, DialogContent, DialogTitle, DialogDescription } from './ui/dialog';
|
import { Dialog, DialogContent, DialogTitle, DialogDescription } from './ui/dialog';
|
||||||
import DirectoryListing from './DirectoryListing';
|
|
||||||
import { listDirectory, normalizePath, splitPath, type EntryInfo } from '../webdav';
|
|
||||||
|
|
||||||
interface StatusPageProps {
|
interface StatusPageProps {
|
||||||
config: any;
|
config: any;
|
||||||
|
|
@ -82,51 +80,6 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) {
|
||||||
const [showResetModal, setShowResetModal] = useState<null | 'meatloaf' | 'host'>(null);
|
const [showResetModal, setShowResetModal] = useState<null | 'meatloaf' | 'host'>(null);
|
||||||
const [resetStatus, setResetStatus] = useState('idle'); // 'idle' | 'in-progress' | 'done'
|
const [resetStatus, setResetStatus] = useState('idle'); // 'idle' | 'in-progress' | 'done'
|
||||||
|
|
||||||
// Overlay state for directory/disk map
|
|
||||||
const [showDirectory, setShowDirectory] = useState(false);
|
|
||||||
const [showDiskMap, setShowDiskMap] = useState(false);
|
|
||||||
|
|
||||||
// Real directory contents for the active device's mounted file.
|
|
||||||
// Pulled from the WebDAV server (parent folder of the mounted image).
|
|
||||||
const [dirEntries, setDirEntries] = useState<EntryInfo[]>([]);
|
|
||||||
const [dirLoading, setDirLoading] = useState(false);
|
|
||||||
const [dirError, setDirError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const directoryPath: string | null = (() => {
|
|
||||||
const url = activeDevice?.url;
|
|
||||||
if (!url) return null;
|
|
||||||
return splitPath(normalizePath(url)).parent;
|
|
||||||
})();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!showDirectory) return;
|
|
||||||
if (!directoryPath) {
|
|
||||||
setDirEntries([]);
|
|
||||||
setDirError(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let cancelled = false;
|
|
||||||
setDirLoading(true);
|
|
||||||
setDirError(null);
|
|
||||||
listDirectory(directoryPath)
|
|
||||||
.then((items) => {
|
|
||||||
if (cancelled) return;
|
|
||||||
setDirEntries(items);
|
|
||||||
})
|
|
||||||
.catch((e: any) => {
|
|
||||||
if (cancelled) return;
|
|
||||||
setDirError((e && e.message) || 'Failed to load directory');
|
|
||||||
setDirEntries([]);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
if (cancelled) return;
|
|
||||||
setDirLoading(false);
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}, [showDirectory, directoryPath]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4 space-y-4">
|
<div className="p-4 space-y-4">
|
||||||
|
|
||||||
|
|
@ -163,8 +116,6 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Directory and Disk Map buttons at bottom */}
|
|
||||||
|
|
||||||
{/* New device info cards */}
|
{/* New device info cards */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="bg-neutral-50 rounded-lg p-3 flex flex-col items-start justify-center w-full mb-2">
|
<div className="bg-neutral-50 rounded-lg p-3 flex flex-col items-start justify-center w-full mb-2">
|
||||||
|
|
@ -200,20 +151,6 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col gap-2 mt-6">
|
|
||||||
<button
|
|
||||||
className="flex items-center justify-center gap-2 px-3 py-3 rounded bg-neutral-200 text-neutral-700 hover:bg-blue-600 hover:text-white transition text-base font-medium w-full"
|
|
||||||
onClick={() => setShowDirectory(true)}
|
|
||||||
>
|
|
||||||
<FolderOpen className="w-5 h-5" /> Show Directory
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="flex items-center justify-center gap-2 px-3 py-3 rounded bg-neutral-200 text-neutral-700 hover:bg-blue-600 hover:text-white transition text-base font-medium w-full"
|
|
||||||
onClick={() => setShowDiskMap(true)}
|
|
||||||
>
|
|
||||||
<Map className="w-5 h-5" /> Show Disk Map
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showDeviceOverlay && (
|
{showDeviceOverlay && (
|
||||||
|
|
@ -236,71 +173,6 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Directory Overlay */}
|
|
||||||
{showDirectory && (
|
|
||||||
<>
|
|
||||||
<div className="fixed inset-0 z-40 bg-black/40 backdrop-blur-md" onClick={() => setShowDirectory(false)} />
|
|
||||||
<div className="fixed inset-0 z-50 bg-white shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
|
||||||
<div className="flex items-center justify-between p-4 border-b">
|
|
||||||
<div className="min-w-0">
|
|
||||||
<h2 className="text-xl font-medium">Directory</h2>
|
|
||||||
<div className="text-xs text-neutral-500 truncate mt-0.5">
|
|
||||||
Device #{activeDevice.number} • {activeDevice.url ? activeDevice.url.split('/').pop() : 'No file mounted'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button onClick={() => setShowDirectory(false)} className="p-2 -m-2 hover:bg-neutral-100 rounded-lg"><svg xmlns='http://www.w3.org/2000/svg' className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor'><path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M6 18L18 6M6 6l12 12' /></svg></button>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 min-h-0 flex flex-col">
|
|
||||||
{!activeDevice?.url && (
|
|
||||||
<div className="p-8 text-center text-neutral-500 text-sm">
|
|
||||||
No file mounted on this device.
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeDevice?.url && dirLoading && (
|
|
||||||
<div className="p-8 text-center text-neutral-500 text-sm flex flex-col items-center gap-2">
|
|
||||||
<Loader2 className="w-6 h-6 animate-spin" />
|
|
||||||
Loading directory from WebDAV…
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeDevice?.url && !dirLoading && dirError && (
|
|
||||||
<div className="p-4 text-sm">
|
|
||||||
<div className="text-red-600 mb-2">Failed to load directory</div>
|
|
||||||
<div className="text-neutral-500 text-xs break-all">{dirError}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{activeDevice?.url && !dirLoading && !dirError && (
|
|
||||||
<DirectoryListing
|
|
||||||
entries={dirEntries.map((e) => ({
|
|
||||||
name: e.name,
|
|
||||||
type: e.type === 'folder' ? 'DIR' : (e.name.split('.').pop() || 'FILE').toUpperCase(),
|
|
||||||
blocks: e.type === 'file' ? Math.max(1, Math.ceil(e.size / 254)) : 0,
|
|
||||||
}))}
|
|
||||||
footerNote={`${dirEntries.length} ENTRIES · ${directoryPath ?? ''}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Disk Map Overlay */}
|
|
||||||
{showDiskMap && (
|
|
||||||
<>
|
|
||||||
<div className="fixed inset-0 z-40 bg-black/40 backdrop-blur-md" onClick={() => setShowDiskMap(false)} />
|
|
||||||
<div className="fixed inset-0 z-50 bg-white shadow-2xl flex flex-col" onClick={(e) => e.stopPropagation()}>
|
|
||||||
<div className="flex items-center justify-between p-4 border-b">
|
|
||||||
<h2 className="text-xl font-medium">Disk Map</h2>
|
|
||||||
<button onClick={() => setShowDiskMap(false)} className="p-2 -m-2 hover:bg-neutral-100 rounded-lg"><svg xmlns='http://www.w3.org/2000/svg' className='w-6 h-6' fill='none' viewBox='0 0 24 24' stroke='currentColor'><path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M6 18L18 6M6 6l12 12' /></svg></button>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 min-h-0 overflow-auto flex items-center justify-center text-neutral-500 p-4">
|
|
||||||
<span>Disk map visualization goes here.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{/* Reset Activity Modal */}
|
{/* Reset Activity Modal */}
|
||||||
<Dialog open={!!showResetModal} onOpenChange={open => !open && setShowResetModal(null)}>
|
<Dialog open={!!showResetModal} onOpenChange={open => !open && setShowResetModal(null)}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user