Build [v1.4.1] - Security hardening, PWA and UI refinements

This commit is contained in:
Daniel Bedeleanu
2026-04-12 10:45:57 +03:00
parent f3d861b1a2
commit 50ae3671c9
16 changed files with 492 additions and 176 deletions

View File

@@ -42,7 +42,6 @@ export default function AdminPage() {
server_uri: 'ldap://192.168.84.107:3890',
base_dn: 'dc=example,dc=com',
user_template: 'cn={username},ou=people,dc=example,dc=com',
required_group: 'inventory',
groups_dn: 'ou=groups',
use_tls: false,
role_mappings: []
@@ -263,7 +262,7 @@ export default function AdminPage() {
</header>
{/* User Management Section */}
<section className="bg-slate-900/40 border border-slate-800/40 p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] shadow-2xl space-y-8">
<section className="glass-card p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] space-y-8">
<div className="flex items-center justify-between px-2">
<div className="flex items-center gap-4">
<div className="p-3 bg-primary/10 rounded-2xl text-primary border border-primary/20">
@@ -370,7 +369,7 @@ export default function AdminPage() {
</section>
{/* Enterprise Integration (LDAP) Section */}
<section className="bg-slate-900/40 border border-slate-800/40 p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] shadow-2xl space-y-8">
<section className="glass-card p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] space-y-8">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-6 px-2">
<div className="flex items-center gap-4">
<div className="p-3 bg-indigo-500/10 rounded-2xl text-indigo-500 border border-indigo-500/20">
@@ -438,24 +437,47 @@ export default function AdminPage() {
/>
</div>
<div className="space-y-1.5">
<label className="text-[10px] font-black text-slate-500 px-1">Groups DN (Search base for groups)</label>
<input
type="text"
placeholder="ou=groups,dc=example,dc=com"
value={ldapConfig.groups_dn}
onChange={(e) => setLdapConfig({ ...ldapConfig, groups_dn: e.target.value })}
className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono"
/>
</div>
<div className="grid sm:grid-cols-2 gap-4">
<div className="space-y-1.5">
<label className="text-[10px] font-black text-slate-500 px-1">Groups DN</label>
<label className="text-[10px] font-black text-slate-500 px-1">Admin Security Group</label>
<input
type="text"
placeholder="ou=groups"
value={ldapConfig.groups_dn}
onChange={(e) => setLdapConfig({ ...ldapConfig, groups_dn: e.target.value })}
placeholder="inventory_admins"
value={ldapConfig.role_mappings?.find((m: any) => m.role === 'admin')?.group || ''}
onChange={(e) => {
const newMappings = [...(ldapConfig.role_mappings || [])];
const idx = newMappings.findIndex((m: any) => m.role === 'admin');
if (idx >= 0) newMappings[idx] = { ...newMappings[idx], group: e.target.value };
else newMappings.push({ role: 'admin', group: e.target.value });
setLdapConfig({ ...ldapConfig, role_mappings: newMappings });
}}
className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono"
/>
</div>
<div className="space-y-1.5">
<label className="text-[10px] font-black text-slate-500 px-1">Required Security Group</label>
<label className="text-[10px] font-black text-slate-500 px-1">User Security Group</label>
<input
type="text"
placeholder="inventory_admins"
value={ldapConfig.required_group}
onChange={(e) => setLdapConfig({ ...ldapConfig, required_group: e.target.value })}
placeholder="inventory_users"
value={ldapConfig.role_mappings?.find((m: any) => m.role === 'user')?.group || ''}
onChange={(e) => {
const newMappings = [...(ldapConfig.role_mappings || [])];
const idx = newMappings.findIndex((m: any) => m.role === 'user');
if (idx >= 0) newMappings[idx] = { ...newMappings[idx], group: e.target.value };
else newMappings.push({ role: 'user', group: e.target.value });
setLdapConfig({ ...ldapConfig, role_mappings: newMappings });
}}
className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono"
/>
</div>
@@ -472,16 +494,22 @@ export default function AdminPage() {
Enabling LDAP will allow users from your network domain to log in using their enterprise credentials.
Local account passwords will still function as a fail-safe backup.
</p>
<div className="flex items-center gap-4 text-[10px] font-black">
<div className="flex items-center gap-1.5">
<div className={cn("w-1.5 h-1.5 rounded-full", ldapConfig.use_tls ? "bg-green-500" : "bg-slate-800")} />
<span className="text-slate-400">LDAPS / TLS</span>
<div className="flex items-center justify-between gap-4 pt-2">
<div className="flex items-center gap-2">
<Shield size={14} className={cn("transition-colors", ldapConfig.use_tls ? "text-green-400" : "text-slate-600")} />
<span className="text-[10px] font-black text-slate-400">LDAPS / TLS Encryption</span>
</div>
<button
onClick={() => setLdapConfig({ ...ldapConfig, use_tls: !ldapConfig.use_tls })}
className="text-indigo-500 hover:text-indigo-400 underline decoration-indigo-500/30 font-bold"
className={cn(
"relative inline-flex h-6 w-10 items-center rounded-full transition-all duration-300 outline-none",
ldapConfig.use_tls ? "bg-green-600" : "bg-slate-800"
)}
>
Toggle Security Layer
<span className={cn(
"inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-300",
ldapConfig.use_tls ? "translate-x-5" : "translate-x-1"
)} />
</button>
</div>
</div>
@@ -507,7 +535,7 @@ export default function AdminPage() {
</section>
{/* Category Management Section */}
<section className="bg-slate-900/40 border border-slate-800/40 p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] shadow-2xl space-y-8">
<section className="glass-card p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] space-y-8">
<div className="flex items-center justify-between px-2">
<div className="flex items-center gap-4">
<div className="p-3 bg-primary/10 rounded-2xl text-primary border border-primary/20">
@@ -604,7 +632,7 @@ export default function AdminPage() {
</section>
{/* Database & Continuity Card */}
<section className="bg-slate-900/40 border border-slate-800/40 p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] shadow-2xl space-y-8">
<section className="glass-card p-6 md:p-8 rounded-[2.5rem] md:rounded-[3rem] space-y-8">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-6 px-2">
<div className="flex items-center gap-4">
<div className="p-3 bg-amber-500/10 rounded-2xl text-amber-500 border border-amber-500/20">

View File

@@ -36,8 +36,27 @@ body {
background: #334155; /* slate-700 */
}
/* Support for Firefox (limited) */
* {
scrollbar-width: thin;
scrollbar-color: #1e293b #020617;
/* Modern Utility for Premium Glassmorphism */
@layer utilities {
.glass-card {
@apply bg-slate-900/40 backdrop-blur-xl border border-slate-800/50 shadow-2xl;
background-image: linear-gradient(135deg, rgba(255,255,255,0.02) 0%, rgba(255,255,255,0) 100%);
}
.text-fluid-lg {
font-size: clamp(1.125rem, 3cqi, 1.5rem);
}
.text-fluid-xl {
font-size: clamp(1.5rem, 5cqi, 2.25rem);
}
}
/* Safe Area Insets for Modern Mobile Devices (iOS Notch/Home Bar) */
.pb-safe {
padding-bottom: env(safe-area-inset-bottom);
}
.pt-safe {
padding-top: env(safe-area-inset-top);
}

View File

@@ -23,7 +23,12 @@ export default function RootLayout({
<html lang="en" suppressHydrationWarning>
<head>
<link rel="manifest" href="/manifest.json" />
<link rel="apple-touch-icon" href="/icon-192x192.png" />
<link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="aInventory" />
<meta name="format-detection" content="telephone=no" />
<meta name="mobile-web-app-capable" content="yes" />
</head>
<body className="antialiased bg-slate-950 text-slate-100">
{children}

View File

@@ -470,7 +470,7 @@ export default function Home() {
</div>
{/* Scanner Section */}
<section className="bg-slate-900/50 border border-slate-800 rounded-3xl p-6 backdrop-blur-sm shadow-xl">
<section className="glass-card rounded-3xl p-6">
{showScanner ? (
<div className="space-y-4">
<div className="flex justify-between items-center">

View File

@@ -25,7 +25,7 @@ export default function BottomNav({
const isAdmin = pathname === '/admin';
return (
<footer className="fixed bottom-0 left-0 right-0 p-4 bg-slate-950/80 backdrop-blur-md border-t border-slate-900 z-40">
<footer className="fixed bottom-0 left-0 right-0 p-4 pb-safe bg-slate-950/80 backdrop-blur-md border-t border-slate-900 z-40">
<div className="max-w-4xl mx-auto flex justify-around items-center text-slate-400">
<button

View File

@@ -1,21 +1,38 @@
{
"name": "Inventory PWA",
"short_name": "Inventory",
"name": "TFM aInventory",
"short_name": "aInventory",
"description": "Unified inventory management with offline scanning",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#0a0a0a",
"theme_color": "#3b82f6",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/maskable-icon.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
"type": "image/png",
"purpose": "any"
}
],
"categories": ["business", "productivity"],
"shortcuts": [
{
"name": "Scanner",
"url": "/",
"icons": [{ "src": "/icons/icon-192x192.png", "sizes": "192x192" }]
}
]
}