Build [v1.14.30]

This commit is contained in:
2026-04-25 12:49:02 +03:00
parent 49d788cfe9
commit d0f166a370
6 changed files with 38 additions and 38 deletions

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"version": "1.14.29", "version": "1.14.30",
"last_build": "2026-04-25-1244", "last_build": "2026-04-25-1249",
"codename": "ConfigCore", "codename": "ConfigCore",
"commit": "18cb466b" "commit": "49d788cf"
} }

View File

@@ -26,18 +26,18 @@ export default function AdminPage() {
return ( return (
<PageShell> <PageShell>
<main data-testid="admin-page" className="p-3 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-6 mb-20 font-sans"> <main data-testid="admin-page" className="p-4 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-6 mb-20 font-sans">
<header className="flex items-center gap-4 mb-4 md:mb-6"> <header className="flex items-center gap-4 mb-6 md:mb-8">
<div className="p-3 md:p-4 bg-primary/10 rounded-none text-primary border border-primary/20 shadow-none"> <div className="p-4 bg-primary/10 text-primary border border-primary/20">
<Shield size={28} className="md:w-8 md:h-8" /> <Shield size={28} className="md:w-8 md:h-8" />
</div> </div>
<div> <div>
<h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Admin Control</h1> <h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Admin Control</h1>
<p className="text-[10px] md:text-xs text-[#888888] font-normal tracking-tight mt-0.5">System Configuration & Security</p> <p className="text-[10px] md:text-xs text-secondary font-normal tracking-tight mt-0.5">System Configuration & Security</p>
</div> </div>
<button <button
onClick={admin.handleLogout} onClick={admin.handleLogout}
className="ml-auto p-3 bg-[#1A1A1A] border border-[#222222] text-[#888888] hover:text-rose-500 rounded-none transition-all active:scale-95 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:ring-rose-500 focus-visible:outline-none" className="ml-auto p-3 bg-surface border border-slate-800 text-secondary hover:text-rose-500 transition-all active:scale-95 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:ring-rose-500 focus-visible:outline-none"
title="Secure Logout" title="Secure Logout"
aria-label="Logout from admin panel" aria-label="Logout from admin panel"
> >

View File

@@ -266,7 +266,7 @@ export default function InventoryPage() {
return ( return (
<PageShell> <PageShell>
<div className="p-3 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-4 font-sans"> <div className="p-4 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-4 font-sans">
<datalist id="existing-types"> <datalist id="existing-types">
{existingTypes.map(t => <option key={t} value={t} />)} {existingTypes.map(t => <option key={t} value={t} />)}
</datalist> </datalist>
@@ -274,24 +274,24 @@ export default function InventoryPage() {
{existingBoxes.map(b => <option key={b} value={b} />)} {existingBoxes.map(b => <option key={b} value={b} />)}
</datalist> </datalist>
<header className="flex items-center gap-4 mb-4 md:mb-6"> <header className="flex items-center gap-4 mb-6 md:mb-8">
<div className="p-3 md:p-4 bg-primary/10 text-primary border border-primary/20 rounded-none"> <div className="p-4 bg-primary/10 text-primary border border-primary/20">
<Package size={28} className="md:w-8 md:h-8" /> <Package size={28} className="md:w-8 md:h-8" />
</div> </div>
<div> <div>
<h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Inventory Catalog</h1> <h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Inventory Catalog</h1>
<p className="text-xs md:text-sm text-[#888888] font-normal mt-1 tracking-widest">Enterprise Stock Overview</p> <p className="text-xs md:text-sm text-secondary font-normal mt-1">Enterprise Stock Overview</p>
</div> </div>
<button <button
onClick={() => setShowSearchModal(true)} onClick={() => setShowSearchModal(true)}
className="ml-auto p-3 bg-[#1A1A1A] border border-[#222222] text-[#888888] hover:text-primary transition-all active:scale-95 rounded-none" className="ml-auto p-3 bg-surface border border-slate-800 text-secondary hover:text-primary transition-all active:scale-95"
title="Search Inventory" title="Search Inventory"
> >
<Search size={20} /> <Search size={20} />
</button> </button>
<button <button
onClick={() => setShowBoxManager(true)} onClick={() => setShowBoxManager(true)}
className="p-3 bg-[#1A1A1A] border border-[#222222] text-[#888888] hover:text-primary transition-all active:scale-95 rounded-none" className="p-3 bg-surface border border-slate-800 text-secondary hover:text-primary transition-all active:scale-95"
title="Manage Boxes" title="Manage Boxes"
> >
<Layout size={20} /> <Layout size={20} />

View File

@@ -87,15 +87,15 @@ export default function LogsPage() {
return ( return (
<PageShell> <PageShell>
<main className="p-3 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-6 mb-20"> <main className="p-4 md:p-8 max-w-7xl mx-auto space-y-3 md:space-y-6 mb-20">
<header className="flex flex-col sm:flex-row sm:items-end justify-between gap-3 md:gap-4"> <header className="flex flex-col sm:flex-row sm:items-end justify-between gap-3 md:gap-4 mb-6 md:mb-8">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="p-3 md:p-4 lg:p-5 xl:p-6 lg:p-8 xl:p-10 bg-primary/10 rounded-2xl text-primary border border-primary/20 shadow-xl shadow-primary/5"> <div className="p-4 bg-primary/10 text-primary border border-primary/20">
<History size={28} className="md:w-8 md:h-8" /> <History size={28} className="md:w-8 md:h-8" />
</div> </div>
<div> <div>
<h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Operations Audit</h1> <h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">Operations Audit</h1>
<p className="text-xs md:text-sm text-secondary font-normal tracking-widest mt-0.5">Real-time Intervention Tracking</p> <p className="text-xs md:text-sm text-secondary font-normal mt-0.5">Real-time Intervention Tracking</p>
</div> </div>
</div> </div>
@@ -103,7 +103,7 @@ export default function LogsPage() {
<button <button
onClick={loadData} onClick={loadData}
disabled={loading} disabled={loading}
className="flex items-center gap-2 px-5 py-2.5 bg-surface border border-slate-800 text-secondary hover:text-white rounded-2xl text-xs font-normal transition-all active:scale-95 disabled:opacity-50 shadow-xl" className="flex items-center gap-2 px-5 py-2.5 bg-surface border border-slate-800 text-secondary hover:text-white text-xs font-normal transition-all active:scale-95 disabled:opacity-50"
> >
<RefreshCw size={14} className={cn(loading && "animate-spin")} /> <RefreshCw size={14} className={cn(loading && "animate-spin")} />
Sync Logs Sync Logs
@@ -142,7 +142,7 @@ export default function LogsPage() {
placeholder="Filter by user, action or asset..." placeholder="Filter by user, action or asset..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-surface/50 border border-slate-800 rounded-2xl py-3 lg:py-4 xl:py-5.5 pr-4 pl-12 text-sm lg:text-base xl:text-lg lg:text-xl xl:text-2xl lg:text-3xl xl:text-4xl focus:border-primary outline-none transition-all placeholder:text-secondary shadow-2xl" className="w-full bg-surface/50 border border-slate-800 py-3 lg:py-4 xl:py-5.5 pr-4 pl-12 text-sm lg:text-base xl:text-lg lg:text-xl xl:text-2xl lg:text-3xl xl:text-4xl focus:border-primary outline-none transition-all placeholder:text-secondary"
/> />
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-secondary transition-colors group-focus-within:text-primary"> <div className="absolute left-4 top-1/2 -translate-y-1/2 text-secondary transition-colors group-focus-within:text-primary">
<Search size={18} /> <Search size={18} />
@@ -153,9 +153,9 @@ export default function LogsPage() {
<button <button
onClick={() => setFilterAction('ALL')} onClick={() => setFilterAction('ALL')}
className={cn( className={cn(
"px-5 py-2 rounded-full text-xs font-normal transition-all whitespace-nowrap border tracking-widest", "px-5 py-2 text-xs font-normal transition-all whitespace-nowrap border",
filterAction === 'ALL' filterAction === 'ALL'
? "bg-white text-slate-950 border-white shadow-xl shadow-white/10" ? "bg-white text-slate-950 border-white"
: "bg-surface/70 text-secondary border-slate-800 hover:border-slate-700" : "bg-surface/70 text-secondary border-slate-800 hover:border-slate-700"
)} )}
> >
@@ -166,9 +166,9 @@ export default function LogsPage() {
key={f} key={f}
onClick={() => setFilterAction(f)} onClick={() => setFilterAction(f)}
className={cn( className={cn(
"px-5 py-2 rounded-full text-xs font-normal transition-all whitespace-nowrap border tracking-widest", "px-5 py-2 text-xs font-normal transition-all whitespace-nowrap border",
filterAction === f filterAction === f
? "bg-primary text-white border-primary shadow-xl shadow-primary/10" ? "bg-primary text-white border-primary"
: "bg-surface/70 text-secondary border-slate-800 hover:border-slate-700" : "bg-surface/70 text-secondary border-slate-800 hover:border-slate-700"
)} )}
> >

View File

@@ -360,7 +360,7 @@ export default function Home() {
return ( return (
<PageShell> <PageShell>
<div className="p-3 md:p-8 overflow-x-hidden w-full max-w-7xl mx-auto"> <div className="p-4 md:p-8 overflow-x-hidden w-full max-w-7xl mx-auto">
{/* Search datalists for autocomplete */} {/* Search datalists for autocomplete */}
<datalist id="existing-types"> <datalist id="existing-types">
{existingTypes.map(t => <option key={t} value={t} />)} {existingTypes.map(t => <option key={t} value={t} />)}
@@ -370,33 +370,33 @@ export default function Home() {
</datalist> </datalist>
{/* Header */} {/* Header */}
<header className="flex flex-col sm:flex-row justify-between sm:items-center gap-3 md:gap-4 mb-3 md:mb-4 w-full px-1"> <header className="flex flex-col sm:flex-row justify-between sm:items-center gap-3 md:gap-4 mb-6 md:mb-8 w-full">
<div className="flex items-center gap-2 md:gap-3"> <div className="flex items-center gap-4">
<div className="p-1"> <div className="p-4 bg-primary/10 border border-primary/20">
<img <img
src="/logo.png" src="/logo.png"
alt="TFM aInventory" alt="TFM aInventory"
className="h-8 md:h-10 object-contain drop-shadow-xl rounded-lg" className="h-8 md:h-10 object-contain"
/> />
</div> </div>
<div> <div>
<h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">TFM aInventory</h1> <h1 className="text-2xl md:text-3xl font-normal tracking-tight text-white leading-tight">TFM aInventory</h1>
<p className="text-xs md:text-sm text-secondary font-normal tracking-tight mt-1 leading-relaxed">Check-in, Check-out & Trash Operations</p> <p className="text-xs md:text-sm text-secondary font-normal tracking-tight mt-1 leading-relaxed">Check-in, Check-out & Trash Operations</p>
</div> </div>
</div> </div>
<div className="flex flex-wrap items-center justify-between sm:justify-end gap-2 md:gap-3 bg-surface/50 sm:bg-transparent px-3 py-2 sm:p-0 rounded-2xl border border-slate-800/50 sm:border-none"> <div className="flex flex-wrap items-center justify-between sm:justify-end gap-2 md:gap-3 bg-surface/50 sm:bg-transparent px-3 py-2 sm:p-0 border border-slate-800/50 sm:border-none">
<div className="flex flex-wrap items-center gap-2 md:gap-3"> <div className="flex flex-wrap items-center gap-2 md:gap-3">
{isScannerReady && ( {isScannerReady && (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="w-1.5 h-1.5 rounded-full bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]" /> <div className="w-1.5 h-1.5 bg-green-500" />
<span className="text-xs font-normal text-green-500/90 whitespace-nowrap"> <span className="text-xs font-normal text-green-500/90 whitespace-nowrap">
Scanner: OK Scanner: OK
</span> </span>
</div> </div>
)} )}
<div className="flex items-center gap-2" data-testid={!isOnline ? "offline-indicator" : undefined}> <div className="flex items-center gap-2" data-testid={!isOnline ? "offline-indicator" : undefined}>
<div className={`w-1.5 h-1.5 rounded-full ${isOnline ? 'bg-green-500 animate-pulse shadow-[0_0_8px_rgba(34,197,94,0.6)]' : 'bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.6)]'}`} /> <div className={`w-1.5 h-1.5 ${isOnline ? 'bg-green-500 animate-pulse' : 'bg-rose-500'}`} />
<span className={`text-xs font-normal whitespace-nowrap ${isOnline ? 'text-green-500/90' : 'text-rose-500/90'}`} data-testid={!isOnline ? "offline-sync-indicator" : undefined}> <span className={`text-xs font-normal whitespace-nowrap ${isOnline ? 'text-green-500/90' : 'text-rose-500/90'}`} data-testid={!isOnline ? "offline-sync-indicator" : undefined}>
Sync: {isOnline ? 'Active' : 'Offline'} Sync: {isOnline ? 'Active' : 'Offline'}
</span> </span>
@@ -405,7 +405,7 @@ export default function Home() {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button <button
onClick={() => setShowSearch(true)} onClick={() => setShowSearch(true)}
className="p-2.5 bg-surface border border-slate-800 text-secondary rounded-xl hover:text-white transition-all active:scale-95" className="p-2.5 bg-surface border border-slate-800 text-secondary hover:text-white transition-all active:scale-95"
title="Search (Ctrl+K)" title="Search (Ctrl+K)"
> >
<Search size={18} /> <Search size={18} />
@@ -414,7 +414,7 @@ export default function Home() {
onClick={handleSync} onClick={handleSync}
disabled={syncing} disabled={syncing}
data-testid="manual-sync-button" data-testid="manual-sync-button"
className="p-2 lg:p-3 xl:p-4 lg:p-5 xl:p-6 lg:p-8 xl:p-10.5 bg-surface border border-slate-800 text-secondary rounded-xl hover:text-white transition-all active:scale-95 disabled:opacity-50" className="p-2.5 bg-surface border border-slate-800 text-secondary hover:text-white transition-all active:scale-95 disabled:opacity-50"
> >
<RefreshCw size={18} className={syncing ? "animate-spin text-primary" : ""} /> <RefreshCw size={18} className={syncing ? "animate-spin text-primary" : ""} />
</button> </button>
@@ -498,7 +498,7 @@ export default function Home() {
{/* Box Contents Selection Modal */} {/* Box Contents Selection Modal */}
{boxMatches.length > 0 && !selectedItem && ( {boxMatches.length > 0 && !selectedItem && (
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-background/80 animate-in fade-in duration-200"> <div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center p-4 bg-background/80 animate-in fade-in duration-200">
<div className="w-full max-w-lg bg-surface border border-slate-800 rounded-[2.5rem] shadow-2xl p-4 md:p-6 overflow-hidden animate-in slide-in-from-bottom-10 duration-300 flex flex-col max-h-[85vh]"> <div className="w-full max-w-lg bg-surface border border-slate-800 p-4 md:p-6 overflow-hidden animate-in slide-in-from-bottom-10 duration-300 flex flex-col max-h-[85vh]">
<div className="flex justify-between items-center mb-3 md:mb-4 shrink-0"> <div className="flex justify-between items-center mb-3 md:mb-4 shrink-0">
<div> <div>
<h3 className="text-xl font-normal tracking-tight flex items-center gap-2"> <h3 className="text-xl font-normal tracking-tight flex items-center gap-2">
@@ -507,7 +507,7 @@ export default function Home() {
</h3> </h3>
<p className="text-xs text-secondary font-normal mt-1">Select the item you want to {mode.replace('_', ' ').toLowerCase()}</p> <p className="text-xs text-secondary font-normal mt-1">Select the item you want to {mode.replace('_', ' ').toLowerCase()}</p>
</div> </div>
<button onClick={() => setBoxMatches([])} className="p-2 lg:p-3 xl:p-4 lg:p-5 xl:p-6 lg:p-8 xl:p-10 hover:bg-slate-800 rounded-full"> <button onClick={() => setBoxMatches([])} className="p-2 lg:p-3 xl:p-4 lg:p-5 xl:p-6 lg:p-8 xl:p-10 hover:bg-slate-800">
<X size={20} /> <X size={20} />
</button> </button>
</div> </div>
@@ -520,7 +520,7 @@ export default function Home() {
setBoxMatches([]); setBoxMatches([]);
setAdjustType(mode === 'CHECK_IN' ? 'ADD' : 'REMOVE'); setAdjustType(mode === 'CHECK_IN' ? 'ADD' : 'REMOVE');
}} }}
className="w-full text-left bg-background/50 hover:bg-slate-800 border border-slate-800/80 p-3 md:p-4 rounded-2xl flex items-center gap-2 md:gap-3 transition-all active:scale-[0.98] group" className="w-full text-left bg-background/50 hover:bg-slate-800 border border-slate-800/80 p-3 md:p-4 flex items-center gap-2 md:gap-3 transition-all active:scale-[0.98] group"
> >
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-normal text-white">{item.name}</p> <p className="text-sm font-normal text-white">{item.name}</p>