Files
netfelix-audio-fix/src/routes/__root.tsx
Felix Förtsch cdcb1ff706 drop multi-node ssh execution, unify job runner to local + fix job completion atomicity
- remove nodes table, ssh service, nodes api, NodesPage route
- execute.ts: local-only spawn, atomic CAS job claim via UPDATE status
- wrap job done + subtitle_files insert + review_plans status in db transaction
- stream ffmpeg output per line with 500ms throttled flush
- bump version to 2026.04.13
2026-04-13 07:25:19 +02:00

70 lines
2.5 KiB
TypeScript

import { createRootRoute, Link, Outlet } from '@tanstack/react-router';
import { useEffect, useState } from 'react';
import { cn } from '~/shared/lib/utils';
import { api } from '~/shared/lib/api';
declare const __APP_VERSION__: string;
export const Route = createRootRoute({
component: RootLayout,
});
function NavLink({ to, children }: { to: string; children: React.ReactNode }) {
return (
<Link
to={to}
className={cn('px-2.5 py-1 rounded text-[0.85rem] no-underline transition-colors text-gray-500 hover:bg-gray-100 hover:text-gray-900')}
activeProps={{ className: 'bg-gray-100 text-gray-900 font-medium' }}
activeOptions={{ exact: true }}
>
{children}
</Link>
);
}
function VersionBadge() {
const [serverVersion, setServerVersion] = useState<string | null>(null);
useEffect(() => { api.get<{ version: string }>('/api/version').then((d) => setServerVersion(d.version)).catch(() => {}); }, []);
const buildVersion = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : null;
const mismatch = buildVersion && serverVersion && buildVersion !== serverVersion;
return (
<span className="text-[0.65rem] text-gray-400 font-mono ml-1" title={mismatch ? `Frontend: ${buildVersion}, Server: ${serverVersion}` : undefined}>
v{serverVersion ?? buildVersion ?? '?'}
{mismatch && <span className="text-amber-500 ml-1" title="Frontend and server versions differ — rebuild or refresh"></span>}
</span>
);
}
function RootLayout() {
const isDev = import.meta.env.DEV;
return (
<div className="min-h-screen bg-white text-gray-900 text-sm">
{isDev && (
<div className="bg-amber-100 border-b border-amber-300 text-amber-800 text-xs font-semibold text-center py-1 px-4">
DEV MODE fresh test database, 50 movies + 10 series per scan
</div>
)}
<nav className="flex flex-wrap items-center gap-0.5 px-3 sm:px-5 py-2 sm:py-0 sm:h-12 bg-white border-b border-gray-200 sticky top-0 z-50">
<Link to="/" className="font-bold text-[0.95rem] mr-3 sm:mr-5 no-underline text-gray-900">
🎬 netfelix
</Link>
<VersionBadge />
<div className="flex flex-wrap items-center gap-0.5">
<NavLink to="/scan">Scan</NavLink>
<NavLink to="/pipeline">Pipeline</NavLink>
<NavLink to="/review/subtitles">Subtitles</NavLink>
</div>
<div className="flex-1" />
<div className="flex items-center gap-0.5">
<NavLink to="/settings">Settings</NavLink>
</div>
</nav>
<main className="max-w-[1600px] mx-auto px-3 sm:px-5 pt-4 pb-12">
<Outlet />
</main>
</div>
);
}
import type React from 'react';