diff --git a/VERSION.json b/VERSION.json index 9be816ca..d400e03c 100644 --- a/VERSION.json +++ b/VERSION.json @@ -1,8 +1,9 @@ { - "version": "1.2.3", - "last_build": "2026-04-11-1131", - "commit": "a5e2f", + "version": "1.2.4", + "last_build": "2026-04-11-1146", + "commit": "b6e3f", "changelog": [ + "v1.2.4: Offline LDAP auth support and UI affordance improvements (Dropdown chevrons, soft password dots)", "v1.2.3: System-wide UI consistency (standardized font sizes, removed uppercase)", "v1.2.2: UI Readability refactor (Removed uppercase/tracking, increased font sizes)", "v1.2.1: Git path persistence, master/dev/vX branching, and UI case-sensitivity fix", diff --git a/backend/routers/users.py b/backend/routers/users.py index 78096b4b..11deeb28 100644 --- a/backend/routers/users.py +++ b/backend/routers/users.py @@ -152,18 +152,26 @@ def login(form_data: schemas.UserLogin, db: Session = Depends(get_db)): ldap_role = authenticate_ldap(form_data.username, form_data.password) if ldap_role: authenticated = True + # Cache hash for offline support + new_hash = get_password_hash(form_data.password) + # If user doesn't exist locally, create a stub for role management if not user: - user = models.User(username=form_data.username, role=ldap_role, origin="ldap") + user = models.User( + username=form_data.username, + role=ldap_role, + origin="ldap", + hashed_password=new_hash + ) db.add(user) db.commit() db.refresh(user) else: - # Update role if it changed in LDAP - if user.role != ldap_role: - user.role = ldap_role - db.commit() - db.refresh(user) + # Update role if it changed in LDAP and refresh cached hash + user.role = ldap_role + user.hashed_password = new_hash + db.commit() + db.refresh(user) else: raise HTTPException(status_code=400, detail="Invalid username or password, or insufficient permissions") diff --git a/dev_docs/ARCHIVE_LOGS.md b/dev_docs/ARCHIVE_LOGS.md index aaa1dc37..7c4ef1f0 100644 --- a/dev_docs/ARCHIVE_LOGS.md +++ b/dev_docs/ARCHIVE_LOGS.md @@ -1,12 +1,15 @@ -### [2026-04-11 11:30] v1.2.3: System-Wide UI Homogenization -**Purpose:** Completed UI refactoring for all secondary pages (`Inventory`, `Logs`, `Scanner`, `IdentityCheckOverlay`). Standardized font sizes to `xs`/`sm`, removed legacy `uppercase` styling, and fixed Title Case for buttons. Handed over a fully consistent high-density UI. +### [2026-04-11 11:45] v1.2.4: Offline Auth & UX Polish +**Purpose:** Implemented local password hash caching for LDAP users to allow login in no-network environments (basements/subsoils). Refined UI by softening password field dots and adding visual indicators (chevrons) to all dropdowns for better affordance. **Modified Files:** -- `frontend/app/inventory/page.tsx` -- `frontend/app/logs/page.tsx` -- `frontend/components/Scanner.tsx` -- `frontend/components/IdentityCheckOverlay.tsx` +- `backend/routers/users.py` (LDAP offline cache) +- `frontend/app/admin/page.tsx` (Password/Dropdown UI) +- `frontend/app/login/page.tsx` (Password UI) +- `frontend/app/inventory/page.tsx` (Dropdown UI) +- `frontend/app/page.tsx` (Dropdown UI) +- `frontend/components/IdentityCheckOverlay.tsx` (Password UI) - `VERSION.json` -- `dev_docs/ARCHIVE_LOGS.md` + +### [2026-04-11 11:30] v1.2.3: System-Wide UI Homogenization ### [2026-04-11 11:21] v1.2.2: UI Readability & Density Optimization diff --git a/frontend/app/admin/page.tsx b/frontend/app/admin/page.tsx index e9179ded..893d61f0 100644 --- a/frontend/app/admin/page.tsx +++ b/frontend/app/admin/page.tsx @@ -193,7 +193,7 @@ export default function AdminPage() {
-

Local Users (Manual)

+

Local Users

@@ -250,7 +250,7 @@ export default function AdminPage() {
-

Enterprise (LDAP) Users

+

Enterprise Users (LDAP)

@@ -603,20 +603,23 @@ export default function AdminPage() { placeholder="••••••••" value={editUserForm.password} onChange={(e) => setEditUserForm({ ...editUserForm, password: e.target.value })} - className="w-full bg-slate-950 border border-slate-800 focus:border-primary rounded-2xl py-4 px-5 text-white outline-none transition-all" + className="w-full bg-slate-950 border border-slate-800 focus:border-primary rounded-2xl py-4 px-5 text-white/50 focus:text-white outline-none transition-all placeholder:text-slate-800" />
- +
+ + +
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index a5b624ff..49d4e384 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -568,16 +568,19 @@ export default function Home() {
- +
+ + +
diff --git a/frontend/components/IdentityCheckOverlay.tsx b/frontend/components/IdentityCheckOverlay.tsx index c0ab7ee7..74191510 100644 --- a/frontend/components/IdentityCheckOverlay.tsx +++ b/frontend/components/IdentityCheckOverlay.tsx @@ -137,7 +137,7 @@ const IdentityCheckOverlay = memo(({ show, users, onAuthenticated }: IdentityChe ref={enterprisePassRef} type="password" onKeyDown={(e) => e.key === 'Enter' && handleLogin()} - className="w-full bg-slate-800/50 border border-slate-800 focus:border-primary rounded-2xl py-4 pl-12 pr-4 text-white focus:outline-none transition-all placeholder:text-slate-700 font-mono" + className="w-full bg-slate-800/50 border border-slate-800 focus:border-primary rounded-2xl py-4 pl-12 pr-4 text-white/50 focus:text-white focus:outline-none transition-all placeholder:text-slate-700 font-mono" placeholder="Enter password" />
@@ -174,7 +174,7 @@ const IdentityCheckOverlay = memo(({ show, users, onAuthenticated }: IdentityChe type="password" autoFocus onKeyDown={(e) => e.key === 'Enter' && handleLogin()} - className="w-full bg-slate-800/50 border border-slate-800 focus:border-primary rounded-2xl py-4 pl-12 pr-4 text-white focus:outline-none transition-all placeholder:text-slate-700 font-mono" + className="w-full bg-slate-800/50 border border-slate-800 focus:border-primary rounded-2xl py-4 pl-12 pr-4 text-white/50 focus:text-white focus:outline-none transition-all placeholder:text-slate-700 font-mono" placeholder="Enter password" />