feat(App, FileManager): add Print Manager functionality and enhance file manager path handling

This commit is contained in:
Jaime Idolpx 2026-06-08 04:28:50 -04:00
parent 63d2ff9f69
commit 4ce0b46b07
2 changed files with 21 additions and 8 deletions

View File

@ -1,5 +1,5 @@
import { useState } from 'react';
import { Cpu, Settings, Wifi, Network, HardDrive, Activity, MoreHorizontal, Search, Wrench, User, LogOut, Bell, FileText, AppWindow, Folder, Edit, Eye, Database, Upload, Download, Code2, LayoutList, Image, ChevronLeft, Loader2, Check, AlertCircle, RefreshCw, Terminal, Link } from 'lucide-react';
import { Cpu, Settings, Wifi, Network, HardDrive, Activity, MoreHorizontal, Search, Wrench, User, LogOut, Bell, FileText, AppWindow, Folder, Edit, Eye, Database, Upload, Download, Code2, LayoutList, Image, ChevronLeft, Loader2, Check, AlertCircle, RefreshCw, Terminal, Link, Printer } from 'lucide-react';
import { Toaster } from 'sonner';
import StatusPage from './components/StatusPage';
import DevicesPage from './components/DevicesPage';
@ -17,6 +17,7 @@ type Page = 'status' | 'devices' | 'iec' | 'network' | 'other' | 'general' | 'to
type AppId =
| 'file-manager'
| 'print-manager'
| 'serial-console'
| 'directory-editor'
| 'sector-editor'
@ -60,6 +61,7 @@ export default function App() {
<h2 className="text-lg font-semibold mb-4 text-blue-700">Management</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
<AppCard icon={<Folder className="w-7 h-7" />} label="File Manager" onClick={() => setCurrentPage('file-manager')} />
<AppCard icon={<Printer className="w-7 h-7" />} label="Print Manager" onClick={() => setCurrentPage('print-manager')} />
<AppCard icon={<Terminal className="w-7 h-7" />} label="Serial Console" onClick={() => setCurrentPage('serial-console')} />
<AppCard icon={<Link className="w-7 h-7" />} label="Short Codes" onClick={() => setCurrentPage('serial-console')} />
</div>
@ -115,6 +117,13 @@ export default function App() {
setConfig={setConfig}
onNavigateToDevice={(id) => { setCurrentPage('devices'); setDevicesOpenId(id); }}
/>,
'print-manager': <FileManager
title="Print Manager"
rootPath="/sd/.print"
onBack={() => setCurrentPage('apps')}
config={config}
setConfig={setConfig}
/>,
'serial-console': <AppPage title="Serial Console" onBack={() => setCurrentPage('apps')} />,
'directory-editor': <AppPage title="Directory Editor" onBack={() => setCurrentPage('apps')} />,
'sector-editor': <AppPage title="Sector Editor" onBack={() => setCurrentPage('apps')} />,

View File

@ -247,6 +247,8 @@ function EntryIcon({ entry }: { entry: EntryInfo }) {
interface FileManagerProps {
initialPath?: string;
rootPath?: string;
title?: string;
config?: any;
setConfig?: (c: any) => void;
onBack?: () => void;
@ -303,8 +305,9 @@ async function _getEntryBytes(entry: EntryInfo): Promise<Uint8Array> {
const FM_PATH_KEY = 'fileManager.path';
export default function FileManager({ initialPath = '/', config, setConfig, onBack, onNavigateToDevice }: FileManagerProps) {
const [path, setPath] = useState(() => normalizePath(localStorage.getItem(FM_PATH_KEY) || initialPath));
export default function FileManager({ initialPath = '/', rootPath, title, config, setConfig, onBack, onNavigateToDevice }: FileManagerProps) {
const pathKey = rootPath ? `fileManager.path:${rootPath}` : FM_PATH_KEY;
const [path, setPath] = useState(() => normalizePath(localStorage.getItem(pathKey) || rootPath || initialPath));
const [entries, setEntries] = useState<EntryInfo[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@ -357,12 +360,13 @@ export default function FileManager({ initialPath = '/', config, setConfig, onBa
useEffect(() => { localStorage.setItem('fileManager.sortAsc', String(sortAsc)); }, [sortAsc]);
const navigateTo = (p: string) => {
const norm = normalizePath(p);
localStorage.setItem(FM_PATH_KEY, norm);
let norm = normalizePath(p);
if (rootPath && !norm.startsWith(rootPath)) norm = rootPath;
localStorage.setItem(pathKey, norm);
setPath(norm);
setFilter('');
};
const navigateUp = () => { if (path !== '/') navigateTo(splitPath(path).parent); };
const navigateUp = () => { if (path !== (rootPath ?? '/')) navigateTo(splitPath(path).parent); };
// ── Sort + filter ────────────────────────────────────────────────────────
@ -674,7 +678,7 @@ export default function FileManager({ initialPath = '/', config, setConfig, onBa
<ChevronLeft className="w-5 h-5" />
</button>
)}
<h2 className="font-semibold flex-1 text-sm">File Manager</h2>
<h2 className="font-semibold flex-1 text-sm">{title ?? 'File Manager'}</h2>
<button onClick={() => void load(path)} className="p-1.5 rounded hover:bg-neutral-100" title="Refresh">
<RefreshCw className="w-4 h-4" />
</button>
@ -689,7 +693,7 @@ export default function FileManager({ initialPath = '/', config, setConfig, onBa
{/* Breadcrumb */}
<div className="flex items-center gap-1 text-sm text-neutral-600 overflow-x-auto">
<button onClick={() => navigateTo('/')} className="p-1 rounded hover:bg-neutral-100 flex-shrink-0" title="Root">
<button onClick={() => navigateTo(rootPath ?? '/')} className="p-1 rounded hover:bg-neutral-100 flex-shrink-0" title="Root">
<Home className="w-4 h-4" />
</button>
{pathParts.map((part, i) => (