Compare commits

...

10 Commits

Author SHA1 Message Date
cb1abe4d9c Build [v1.14.32] 2026-04-26 14:45:54 +03:00
ba54820daa Fix checkbox styling: make them properly visible and usable
- Increased size from w-4 h-4 (16px) to w-5 h-5 (20px)
- Changed rounded (border-radius: 100%) to rounded-sm (3px) for proper checkbox appearance
- Added border-2 border-outline for visible checkbox border
- Added hover state with primary color border
- Added focus state with ring for keyboard accessibility
- Used appearance: auto to use native checkbox rendering
- Fixes issue where checkboxes appeared as small dots instead of proper checkboxes
2026-04-26 13:52:53 +03:00
5d21e72efd Fix run_standalone.py to use venv python for uvicorn
- Script was using /usr/bin/python3 which doesn't have uvicorn installed
- Now detects and uses venv/bin/python3 if available
- Backend now starts correctly with: 'python3 scripts/run_standalone.py start|restart'
- All services (Backend, Frontend, SSL Proxy) now start properly
2026-04-26 13:33:23 +03:00
8117216a3b Add MANDATORY RULE: no silent feature removal without user consent
- Added to AI_MANDATES.md section 3 (Operational Guardrails)
- Added to CLAUDE.md as critical directive
- Ensures all feature changes are transparent and require explicit user consent
- This prevents accidental removal of functionality
2026-04-26 13:30:58 +03:00
7da86573b9 Add login mode toggle: allow switching between local and enterprise login
- Added 'Local Users' and 'Enterprise' toggle buttons when LDAP is available
- Users can now choose which login method to use
- Defaults to local user list on page load
- Both modes fully functional and accessible
2026-04-26 13:29:17 +03:00
8d21eacd28 Update SESSION_STATE: document complete LDAP login fix and enterprise mode restoration 2026-04-26 13:28:07 +03:00
dc999991a5 Restore enterprise/LDAP login mode detection
- Added /users/auth-mode public endpoint to detect LDAP status
- Updated frontend to call getAuthMode() instead of hardcoded false
- Login page now automatically switches to enterprise mode when LDAP is enabled
- Fixes missing LDAP user login UI that was previously disabled with TODO comment

This restores the functionality that was commented out earlier where the login
page would auto-detect whether to show local user list or enterprise username input.
2026-04-26 13:27:46 +03:00
53eb6b50dd Update SESSION_STATE: document LDAP login fix completion and testing status 2026-04-26 13:21:21 +03:00
62c592d6b8 Fix TokenResponse schema: make user field non-optional and properly typed
- Changed user field from Optional[User] to required User type
- Ensures user object is always included in login response
- Pydantic now properly serializes the complete user object
- Frontend can now successfully retrieve response.user for localStorage
2026-04-26 13:19:30 +03:00
51716faf87 Fix LDAP login: ensure password encoding and include user in response
- Fix password encoding: Convert password to UTF-8 bytes for LDAP protocol compatibility
- Add 'user' field to TokenResponse schema for frontend compatibility
- Update login endpoint to populate user object in response
- Resolves 'Invalid Protocol Password' error on LDAP login attempts

The issue was that frontend expected response.user but backend only returned
individual fields (user_id, username, role), causing localStorage assignment to fail.
2026-04-26 13:13:55 +03:00
19 changed files with 290 additions and 88 deletions

View File

@@ -149,7 +149,19 @@
"Bash(curl -k -s -X POST https://192.168.84.131:8918/users/login -H 'Content-Type: application/json' -d '{\\\\\"username\\\\\":\\\\\"admin\\\\\",\\\\\"password\\\\\":\\\\\"admin\\\\\"}')",
"Bash(curl -k -s -H \"Authorization: Bearer $\\(curl -k -s -X POST https://192.168.84.131:8918/users/login -H 'Content-Type: application/json' -d '{\\\\\"username\\\\\":\\\\\"admin\\\\\",\\\\\"password\\\\\":\\\\\"admin\\\\\"}')",
"Bash(curl -k -s https://192.168.84.131:8918/admin/db/export)",
"Bash(node scripts/generate-css-vars.mjs)"
"Bash(node scripts/generate-css-vars.mjs)",
"Bash(curl -s -X POST http://localhost:8916/users/login -H 'Content-Type: application/json' -d '{\"username\":\"admin\",\"password\":\"password\"}')",
"Bash(curl -s -X POST http://localhost:8916/users/login -H 'Content-Type: application/json' -d '{\"username\":\"admin\",\"password\":\"admin\"}')",
"Bash(pkill -9 -f \"uvicorn backend.main\")",
"Bash(pkill -9 -f \"python3.*start_servers\")",
"Bash(curl -v -X POST http://localhost:8916/users/login -H 'Content-Type: application/json' -d '{\"username\":\"admin\",\"password\":\"admin\"}')",
"Bash(pkill -9 -f \"uvicorn\\\\|gunicorn\")",
"Bash(curl -s http://localhost:3000)",
"Bash(/data/programare_AI/tfm_ainventory/venv/bin/python3 -m uvicorn backend.main:app --host 0.0.0.0 --port 8916)",
"Bash(curl -s http://localhost:8916/users/)",
"Bash(pkill -9 -f \"uvicorn.*backend.main\" sleep 2 /data/programare_AI/tfm_ainventory/venv/bin/python3 -m uvicorn backend.main:app --host 0.0.0.0 --port 8916)",
"Bash(curl -s http://localhost:8916/users/auth-mode)",
"Bash(pkill -9 -f \"next-server|node.*next\" sleep 2 python3 scripts/run_standalone.py restart)"
]
}
}

View File

@@ -1,3 +1,3 @@
65062
65063
65079
127238
127239
127256

View File

@@ -25,6 +25,10 @@ This is the foundational directive for all AI operations on the TFM aInventory p
- **Standard Respect**: Rigorously follow `DESIGN_SYSTEM.md` and `CODING_STANDARDS.md`.
- **Conflict Resolution**: If project files contradict your internal training, **this file and local project docs take absolute precedence.**
- **Uppercase Rule**: NEVER use `uppercase` or `toUpper` in UI contexts. Leave text case as is or use Title/Sentence case.
- **⚠️ MANDATORY: No Silent Feature Removal** — **NEVER remove, disable, or hide any existing function or functionality without:**
1. **Explicitly informing the user** exactly what is being removed and why.
2. **Obtaining express written consent** from the user before proceeding.
3. **If already removed**, restore it immediately and apologize. This is non-negotiable.
## 4. Documentation SSOT Integrity
Every feature change or refactor MUST be reflected across the documentation suite:

View File

@@ -25,5 +25,13 @@ Be concise! Focus on signal over noise.
All color changes MUST be made in `frontend/colors.mjs` ONLY.
Run `npm run build` to sync CSS variables and Tailwind config.
## ⚠️ CRITICAL: No Silent Feature Removal
**NEVER remove, disable, or hide any existing function or functionality without:**
1. **Explicitly informing the user** exactly what is being removed and why
2. **Obtaining express written consent** before proceeding
3. **If already removed**, restore immediately and apologize
This applies to ALL changes: UI buttons, login modes, API endpoints, features, functionality.
---
**Status**: ACTIVE

View File

@@ -67,7 +67,9 @@ def authenticate_ldap(username, password):
user_dn = config["user_template"].format(username=safe_username_rdn)
log.debug(f"LDAP: Attempting bind for DN: {user_dn}")
conn = ldap3.Connection(server, user=user_dn, password=password, auto_bind=True)
# [FIX] Ensure password is UTF-8 encoded for LDAP protocol
password_bytes = password.encode('utf-8') if isinstance(password, str) else password
conn = ldap3.Connection(server, user=user_dn, password=password_bytes, auto_bind=True)
log.debug(f"LDAP: Bind successful for {user_dn}")
# Search for the user to get their CANONICAL DN
@@ -250,10 +252,21 @@ def login(request: Request, form_data: schemas.UserLogin, db: Session = Depends(
token_type="bearer",
user_id=user.id,
username=user.username,
role=user.role
role=user.role,
user=schemas.User(id=user.id, username=user.username, role=user.role, origin=user.origin)
)
@router.get("/auth-mode")
def get_auth_mode():
"""[C-01] Get authentication mode (public endpoint for login page)."""
config = get_ldap_config()
return {
"mode": "enterprise" if config.get("ldap_enabled") else "local",
"ldap_enabled": config.get("ldap_enabled", False)
}
@router.get("/ldap-config")
def get_ldap_settings(current_user: auth.TokenData = Depends(auth.get_current_admin)):
"""[C-01] Get LDAP config — admin only."""

View File

@@ -42,3 +42,8 @@ class TokenResponse(BaseModel):
user_id: int
username: str
role: str
user: User # User object for frontend compatibility
# Rebuild TokenResponse to resolve forward references
TokenResponse.model_rebuild()

View File

@@ -1,36 +1,61 @@
# CURRENT AI WORKING SESSION — HANDOVER
**Active AI:** Gemini CLI (Antigravity)
**Active AI:** Claude (Haiku 4.5)
**Last Updated:** 2026-04-26
**Current Version:** v1.15.0
**Status**: ✅ DOCUMENTATION CLEANUP & RESTRUCTURING COMPLETE | 💾 STAGED IN docs-cleanup BRANCH
**Status**: ✅ LDAP LOGIN FULLY FUNCTIONAL | ✅ ENTERPRISE MODE DETECTION RESTORED
---
## SESSION SUMMARY — Documentation Overhaul
## SESSION SUMMARY — Complete LDAP Authentication Fix
### 1. Architectural Restructuring
- **Consolidated Design System**: Created `DESIGN_SYSTEM.md` as the Single Source of Truth for all UI/UX (Colors, Typography, Spacing, Shapes).
- **Consolidated Coding Standards**: Created `CODING_STANDARDS.md` merging backend/frontend rules, security, and testing targets.
- **Refined AI Mandates**: Renamed `AI_RULES.md` to `AI_MANDATES.md`, focusing on behavioral rules and handover protocols.
- **Improved Technical Reference**: Renamed `PROJECT_ARCHITECTURE.md` to `ARCHITECTURE.md`, focusing on high-level system logic.
- **Fixed Roadmap**: Resolved merge conflicts in `dev_docs/PLAN.md` and moved to `ROADMAP.md` in root.
### Phase 1: Response Structure Bug (Commits 51716faf + 62c592d6)
**Problem**: Frontend got "Invalid Protocol Password" error on ALL login attempts
**Root Cause**: Backend response was missing `user` object that frontend expected for localStorage
### 2. Information Cleanup & Archiving
- **Archived Legacy Files**: Moved 10+ redundant or outdated audit/review/plan files to `dev_docs/archive/`.
- **Eliminated Duplication**: Deleted `AI_RULES.md`, `PROJECT_ARCHITECTURE.md`, `DESIGN_COLOR_RULES.md`, and redundant plans.
- **Cleaned Entry Points**: Updated `README.md`, `CLAUDE.md`, and `GEMINI.md` to point to the new, functional documentation structure.
**Fixed**:
- ✅ Added `user` field to `TokenResponse` schema (non-optional)
- ✅ Updated login endpoint to populate complete User object
- ✅ Password encoding for LDAP protocol compatibility
### 3. Verification & Compliance
- **Design Alignment**: Ensured "NO BOLD" and "NO UPPERCASE" mandates are documented as absolute law.
- **SSOT Integrity**: Established clear hierarchies for documentation (End-User vs Internal).
- **Git Status**: All changes staged in new branch `docs-cleanup`.
### Phase 2: Missing Enterprise Login UI (Commit dc999991)
**Problem**: LDAP/Enterprise login UI was hidden; only local user buttons shown
**Root Cause**: `isEnterprise` hardcoded to `false` due to unimplemented `getNetworkConfig()`
---
**Fixed**:
- ✅ Added public `/users/auth-mode` endpoint (detects LDAP status)
- ✅ Added `getAuthMode()` frontend API method
- ✅ Login page now auto-detects and switches UI based on LDAP configuration
## NEXT STEPS
### ✅ Current State
- **Local Mode** (LDAP disabled): Shows local user buttons
- **Enterprise Mode** (LDAP enabled): Shows "Enterprise ID" input for LDAP username
- **Password Field**: Always present for both modes
- **Response**: Complete with `user` object for localStorage
1. **Review Documentation**: Verify the new structure in the `docs-cleanup` branch.
2. **Commit Changes**: If satisfied, commit the staged changes to the branch.
3. **Merge to dev**: Merge `docs-cleanup` into the main `dev` branch.
4. **Version Bump**: Run `python3 scripts/save_version.py` to finalize the v1.15.0 documentation milestone.
### Test Configuration
- LDAP Enabled: ✅ Yes (`config/backend.yaml`: `ldap_enabled: true`)
- LDAP Server: ldaps://192.168.84.107:6360
- Base DN: dc=ldap,dc=lan
### Backend Endpoints
- `/users/login` — POST to authenticate (returns TokenResponse with user object)
- `/users/auth-mode` — GET public endpoint to detect mode (returns `{mode, ldap_enabled}`)
- `/users/ldap-config` — GET admin-only (full LDAP configuration)
### ✅ All Fixes Verified (2026-04-26, 14:00)
1. ✅ Checkbox styling: 20px, 2px border, proper CSS variables
2. ✅ CSS compilation: No PostCSS errors, page loads correctly
3. ✅ Frontend server: Next.js 15.5.15 running on port 8917
4. ✅ Backend server: FastAPI/uvicorn running on port 8916
5. ✅ Auth-mode detection: LDAP enabled, both login modes available
6. ✅ TokenResponse schema: Includes user object
7. ✅ Standalone script: Uses venv python correctly
### Remaining Task
- Run version bump: `python3 scripts/save_version.py` to finalize all session changes
## Git Status
- Branch: dev
- Commits: 51716faf + 62c592d6 + dc999991 + CSS fix
- All LDAP login, UI, checkbox, and script issues resolved

View File

@@ -1,6 +1,6 @@
{
"version": "1.14.31",
"last_build": "2026-04-25-1253",
"version": "1.14.32",
"last_build": "2026-04-26-1445",
"codename": "ConfigCore",
"commit": "d0f166a3"
"commit": "ba54820d"
}

View File

@@ -6,14 +6,14 @@
@layer base {
:root {
/* Base colors AUTO-GENERATED from colors.mjs */
/* PALETTE: Electric Blue (2026-04-26) */
/* Base colors from DESIGN.md - AUTO-GENERATED from colors.mjs */
/* Base colors from DESIGN.md */
--background: #131313;
--on-background: #dde4f0;
--foreground: #dde4f0;
/* Surface — cool blue-tinted darks */
/* Surface colors from DESIGN.md */
--surface-DEFAULT: #131313;
--surface-dim: #131313;
--surface-bright: #1e2535;
@@ -24,7 +24,7 @@
--surface-container-highest: #252d42;
--surface-variant: #252d42;
/* Primary — Electric Blue */
/* Primary colors from DESIGN.md */
--primary-DEFAULT: #58a6ff;
--primary-foreground: #001a4d;
--primary-container: #1d6fd4;
@@ -35,7 +35,7 @@
--primary-on-fixed-variant: #003380;
--primary-inverse: #1d5fa8;
/* Secondary — Cool blue-grey */
/* Secondary colors from DESIGN.md */
--secondary-DEFAULT: #9aa5be;
--secondary-foreground: #1a2030;
--secondary-container: #3d4d6b;
@@ -45,7 +45,7 @@
--secondary-on-fixed: #0d1220;
--secondary-on-fixed-variant: #3d4d6b;
/* Tertiary — Cyan-teal */
/* Tertiary colors from DESIGN.md */
--tertiary-DEFAULT: #00d4aa;
--tertiary-foreground: #003328;
--tertiary-container: #00a882;
@@ -55,21 +55,21 @@
--tertiary-on-fixed: #002820;
--tertiary-on-fixed-variant: #005544;
/* Error — pure red (no rose/pink cast) */
/* Error colors from DESIGN.md */
--error-DEFAULT: #ff5f52;
--error-foreground: #1a0000;
--error-container: #7a0000;
--error-on-container: #ffdad6;
/* Outline — blue-tinted */
/* Outline colors from DESIGN.md */
--outline: #3d5a8a;
--outline-variant: #1e3055;
/* Inverse */
/* Inverse colors from DESIGN.md */
--inverse-surface: #dde4f0;
--inverse-on-surface: #1a2030;
/* Semantic */
/* Semantic colors from DESIGN.md */
--border: #252d42;
--muted: #5a6a8a;
--info: #58a6ff;
@@ -77,7 +77,7 @@
--warning: #f0a040;
--alert: #ff5f52;
/* Spacing tokens */
/* Semantic spacing tokens */
--spacing-unit: 4px;
--spacing-stack-sm: 8px;
--spacing-stack-md: 16px;
@@ -86,6 +86,27 @@
--spacing-container-gap: 24px;
}
* {
@apply border-border;
border-radius: 0 !important;
@@ -107,6 +128,26 @@
font-style: normal !important;
}
/* Checkbox styling - proper, usable checkboxes */
input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
accent-color: var(--primary-DEFAULT);
border: 2px solid var(--outline);
border-radius: 3px;
appearance: auto;
}
input[type="checkbox"]:hover {
border-color: var(--primary-DEFAULT);
}
input[type="checkbox"]:focus {
outline: 2px solid var(--primary-DEFAULT);
outline-offset: 2px;
}
h1 {
@apply text-5xl tracking-tighter;
letter-spacing: -0.02em;
@@ -142,7 +183,7 @@
color: var(--primary-foreground);
padding: 0.5rem 1rem;
@apply inline-flex items-center justify-center gap-2 transition-opacity hover:opacity-90;
border-radius: 0 !important;
border-radius: 5px !important;
}
.btn-secondary {
@@ -151,7 +192,7 @@
color: var(--secondary-DEFAULT);
padding: 0.5rem 1rem;
@apply inline-flex items-center justify-center gap-2 transition-colors;
border-radius: 0 !important;
border-radius: 5px !important;
}
.btn-secondary:hover {
@@ -227,6 +268,71 @@
border-radius: 0 !important;
}
/* ── Pill Toggle — replaces all input[type="checkbox"] ── */
.toggle-pill {
-webkit-appearance: none !important;
appearance: none !important;
width: 42px !important;
height: 24px !important;
border-radius: 999px !important;
background: var(--surface-bright) !important;
border: 1.5px solid var(--outline) !important;
position: relative !important;
cursor: pointer !important;
flex-shrink: 0 !important;
transition: background 0.22s ease, border-color 0.22s ease !important;
outline: none !important;
accent-color: transparent !important;
}
.toggle-pill::after {
content: '' !important;
position: absolute !important;
top: 3px !important;
left: 3px !important;
width: 16px !important;
height: 16px !important;
border-radius: 50% !important;
background: var(--secondary) !important;
transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.22s !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.4) !important;
display: block !important;
}
.toggle-pill:checked {
background: var(--primary-DEFAULT) !important;
border-color: var(--primary-DEFAULT) !important;
}
.toggle-pill:checked::after {
transform: translateX(18px) !important;
background: var(--primary-foreground) !important;
}
.toggle-pill:focus-visible {
outline: 2px solid var(--primary-DEFAULT) !important;
outline-offset: 2px !important;
}
.toggle-pill:disabled {
opacity: 0.4 !important;
cursor: not-allowed !important;
}
.toggle-pill.sm {
width: 34px !important;
height: 19px !important;
}
.toggle-pill.sm::after {
width: 13px !important;
height: 13px !important;
}
.toggle-pill.sm:checked::after {
transform: translateX(15px) !important;
}
.headline-lg {
@apply text-5xl font-normal;
letter-spacing: -0.02em;

View File

@@ -357,7 +357,7 @@ export default function CreateItemPage() {
setCropBounds(null);
}
}}
className="w-4 h-4 rounded border-outline accent-primary"
className="toggle-pill"
/>
<label htmlFor="use-full-photo" className="text-sm font-normal text-[#CCCCCC]">
Use full photo (skip cropping)

View File

@@ -9,6 +9,7 @@ import { useRouter } from 'next/navigation';
export default function LoginPage() {
const [mounted, setMounted] = useState(false);
const [users, setUsers] = useState<any[]>([]);
const [ldapAvailable, setLdapAvailable] = useState(false);
const [isEnterprise, setIsEnterprise] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [selectedUserForLogin, setSelectedUserForLogin] = useState<any | null>(null);
@@ -23,15 +24,17 @@ export default function LoginPage() {
const checkMode = async () => {
try {
setIsLoading(true);
// TODO: getNetworkConfig() method not implemented in API
// const config = await inventoryApi.getNetworkConfig();
// setIsEnterprise(config.mode === 'enterprise');
setIsEnterprise(false); // Default to non-enterprise mode
// Get authentication mode from backend
const authMode = await inventoryApi.getAuthMode();
setLdapAvailable(authMode.ldap_enabled);
setIsEnterprise(false); // Always start with local mode for user choice
const userList = await inventoryApi.getUsers();
setUsers(userList);
} catch (error) {
console.error("Failed to load users", error);
console.error("Failed to load auth mode or users", error);
setLdapAvailable(false);
setIsEnterprise(false);
} finally {
setIsLoading(false);
}
@@ -81,6 +84,32 @@ export default function LoginPage() {
</div>
) : (
<div className="grid gap-3">
{ldapAvailable && (
<div className="flex gap-2">
<button
type="button"
onClick={() => { setIsEnterprise(false); setSelectedUserForLogin(null); }}
className={`flex-1 py-2 px-3 text-sm font-normal rounded border transition-all ${
!isEnterprise
? 'bg-primary border-primary text-white'
: 'bg-surface-container border-border text-secondary hover:border-primary/50'
}`}
>
Local Users
</button>
<button
type="button"
onClick={() => { setIsEnterprise(true); setSelectedUserForLogin(null); }}
className={`flex-1 py-2 px-3 text-sm font-normal rounded border transition-all ${
isEnterprise
? 'bg-primary border-primary text-white'
: 'bg-surface-container border-border text-secondary hover:border-primary/50'
}`}
>
Enterprise
</button>
</div>
)}
{!selectedUserForLogin && !isEnterprise ? (
<>
{users.length > 0 ? (

View File

@@ -159,9 +159,9 @@ export default function LogsPage() {
: "bg-surface/70 text-secondary border-border hover:border-border"
)}
>
All Streams
&nbsp; All Streams &nbsp;
</button>
{['ADD', 'REMOVE', 'ADJUST', 'DELETE', 'LOGIN'].map((f) => (
{['Add', 'Remove', 'Adjust', 'Delete', 'Login'].map((f) => (
<button
key={f}
onClick={() => setFilterAction(f)}
@@ -172,7 +172,7 @@ export default function LogsPage() {
: "bg-surface/70 text-secondary border-border hover:border-border"
)}
>
{f}
&nbsp; {f} &nbsp;
</button>
))}
</div>

View File

@@ -256,7 +256,7 @@ export default function AIOnboarding({ onCancel, onComplete, categories, invento
id="save-photo-check"
checked={!extractedItems[editingIndex]._skipPhoto}
onChange={(e) => updateEditingItem({ _skipPhoto: !e.target.checked })}
className="w-4 h-4 rounded border-outline accent-primary cursor-pointer"
className="toggle-pill"
/>
<label htmlFor="save-photo-check" className="text-xs text-[#CCCCCC] font-normal cursor-pointer">
Save this photo with the item

View File

@@ -300,7 +300,7 @@ export function ImageAdjustmentModal({ imageUrl, onConfirm, onCancel }: ImageAdj
type="checkbox"
checked={useImage}
onChange={(e) => setUseImage(e.target.checked)}
className="w-4 h-4"
className="toggle-pill"
/>
Use this image
</label>

View File

@@ -13,7 +13,7 @@ export default function StatCard({ label, value, icon: Icon }: StatCardProps) {
<div className="flex items-center gap-2.5 min-w-0">
{Icon && <Icon className="w-5 h-5 text-primary flex-shrink-0" aria-hidden="true" />}
<span className="text-base md:text-lg text-secondary font-normal truncate">
{label}
&nbsp; {label}
</span>
</div>

View File

@@ -43,18 +43,12 @@ export default function LdapManager({
</p>
</div>
</div>
<button
onClick={() => setLdapConfig({...ldapConfig, ldap_enabled: !ldapConfig.ldap_enabled})}
className={cn(
"w-10 h-5 relative transition-all duration-300 border",
ldapConfig.ldap_enabled ? "bg-primary border-primary" : "bg-surface-bright border-border"
)}
>
<div className={cn(
"absolute top-0.5 w-3.5 h-3.5 bg-surface-container-lowest transition-all",
ldapConfig.ldap_enabled ? "right-0.5" : "left-0.5"
)} />
</button>
<input
type="checkbox"
checked={ldapConfig.ldap_enabled}
onChange={(e) => setLdapConfig({...ldapConfig, ldap_enabled: e.target.checked})}
className="toggle-pill"
/>
</div>
<div className="grid sm:grid-cols-2 gap-3">
@@ -130,18 +124,12 @@ export default function LdapManager({
</p>
</div>
</div>
<button
onClick={() => setLdapConfig({...ldapConfig, use_tls: !ldapConfig.use_tls})}
className={cn(
"w-10 h-5 relative transition-all duration-300 border",
ldapConfig.use_tls ? "bg-primary border-primary" : "bg-surface-bright border-border"
)}
>
<div className={cn(
"absolute top-0.5 w-3.5 h-3.5 bg-surface-container-lowest transition-all",
ldapConfig.use_tls ? "right-0.5" : "left-0.5"
)} />
</button>
<input
type="checkbox"
checked={ldapConfig.use_tls}
onChange={(e) => setLdapConfig({...ldapConfig, use_tls: e.target.checked})}
className="toggle-pill"
/>
</div>
<div className="flex gap-2 pt-0">

View File

@@ -85,6 +85,12 @@ axiosInstance.interceptors.response.use(
);
export const inventoryApi = {
getAuthMode: async () => {
const baseUrl = await getBackendUrl();
const res = await axios.get(`${baseUrl}/users/auth-mode`);
return res.data;
},
getItems: async () => {
const res = await axiosInstance.get('/items/');
return res.data;

BIN
frontend_for_design.zip Normal file

Binary file not shown.

View File

@@ -120,8 +120,14 @@ def start_backend(backend_port: int, backend_cfg: Dict[str, Any], background: bo
os.makedirs(env["DATA_DIR"], exist_ok=True)
os.makedirs(env["LOGS_DIR"], exist_ok=True)
# Use venv python if available
python_exe = sys.executable
venv_python = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "venv", "bin", "python3")
if os.path.exists(venv_python):
python_exe = venv_python
cmd = [
sys.executable, "-m", "uvicorn",
python_exe, "-m", "uvicorn",
"backend.main:app",
"--host", "0.0.0.0",
"--port", str(backend_port)