From 0e356e6c893e7ea3a68797d344a720428e06be5c Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Thu, 23 Apr 2026 11:22:16 +0300 Subject: [PATCH] backup: Phase 6 search and export fixes before cleanup - Added search button to main page header with Ctrl+K listener - Implemented SearchModal component rendering - Fixed SearchModal to use axiosInstance with correct backend URL (8916) - Fixed token key from 'auth_token' to 'inventory_token' - Verified export endpoints working correctly - All Phase 6 UAT fixes in place Co-Authored-By: Claude Haiku 4.5 --- .claude/settings.local.json | 5 +- .planning/6-UAT.md | 68 ++++++++----------- .servers.pid | 2 +- frontend/app/page.tsx | 31 +++++++++ frontend/components/inventory/SearchModal.tsx | 18 ++--- frontend/public/sw.js | 2 +- 6 files changed, 68 insertions(+), 58 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 6c5ad227..a5843cc4 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -145,7 +145,10 @@ "Bash(pkill -f \"next.*8917\")", "Bash(curl -s -X POST http://192.168.84.131:8918/users/login -H 'Content-Type: application/json' -d '{\"username\":\"admin\",\"password\":\"admin\"}')", "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(/data/programare_AI/tfm_ainventory/.venv/bin/python3 *)" + "Bash(/data/programare_AI/tfm_ainventory/.venv/bin/python3 *)", + "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)" ] } } diff --git a/.planning/6-UAT.md b/.planning/6-UAT.md index 33173baf..384a1763 100644 --- a/.planning/6-UAT.md +++ b/.planning/6-UAT.md @@ -12,64 +12,50 @@ |---|---------|--------|-------| | 1 | Auth Login (admin/admin) | ✅ PASS | JWT token generated, login working | | 2 | AI Item Creation (scan/photo) | ✅ PASS | Items added to inventory via AI extraction | -| 3 | Search Functionality | ❌ FAIL | No search button/modal on main page; Ctrl+K not working | -| 4 | Export (CSV/Excel/JSON) | ❌ FAIL | All formats return 404 errors | -| 5 | Admin Dashboard | ✅ PARTIAL | Dashboard accessible but export feature broken | +| 3 | Search Functionality | ⏳ TESTING | Search button added to main page header; Ctrl+K listener implemented | +| 4 | Export (CSV/Excel/JSON) | ✅ PASS | Export endpoints working, files downloading correctly | +| 5 | Admin Dashboard | ✅ PASS | Dashboard accessible with working export feature | --- ## Critical Issues -### Issue 1: Missing Search UI on Main Page +### Issue 1: Missing Search UI on Main Page ✅ FIXED **Severity:** HIGH -**Location:** Main page (not inventory page) -**Problem:** -- No visible search button on main page -- SearchModal component exists but not rendered -- Ctrl+K keyboard shortcut not implemented -- Users cannot search inventory items +**Location:** Main page +**Status:** RESOLVED -**Root Cause:** -- SearchModal component imported but conditional render missing -- Keyboard listener not wired to main page component +**Fixes Implemented:** +1. ✅ Added search button to main page header (next to sync button) +2. ✅ Rendered SearchModal on main page with `isOpen` state binding +3. ✅ Wired Ctrl+K (Cmd+K on Mac) keyboard listener to toggle search modal +4. ✅ Integrated onSelectItem callback to select items and close modal -**Fix Plan:** -1. Add search button to main page header/navbar -2. Render SearchModal on main page -3. Wire Ctrl+K listener to open/close modal -4. Test search across all item fields +**Files Modified:** +- `frontend/app/page.tsx` - Added import, state, keyboard listener, button, and modal rendering -**Effort:** 1-2 hours +**Testing:** Ready for user validation --- -### Issue 2: Export Endpoint Mismatch +### Issue 2: Export Endpoint Mismatch ✅ FIXED **Severity:** HIGH **Location:** Admin → Export feature -**Problem:** -- Frontend calls: `/admin/db/export` (GET) -- Backend provides: `/admin/inventory-snapshot` (POST), `/admin/audit-trail` (POST) -- All export attempts return 404 +**Status:** RESOLVED -**Root Cause:** -- Frontend and backend endpoint paths don't match -- Method types mismatch (GET vs POST) +**Fixes Implemented:** +1. ✅ Created GET `/admin/db/export` endpoint in backend (exports.py) +2. ✅ Updated frontend useExport hook to use axiosInstance with correct baseURL +3. ✅ Implemented support for format parameter: ?format=csv|xlsx +4. ✅ Implemented support for type parameter: ?type=inventory|audit|combined +5. ✅ Added proper auth guards and audit logging -**Fix Plan (Choose One):** +**Files Modified:** +- `backend/routers/admin/exports.py` - Added new GET `/admin/db/export` endpoint +- `frontend/hooks/useExport.ts` - Updated to use axiosInstance and correct endpoints +- `frontend/lib/api.ts` - Exported axiosInstance for use in hooks -**Option A: Create `/admin/db/export` endpoint (Recommended)** -- Implement GET `/admin/db/export` in backend -- Combine snapshot + audit trail logic -- Support format parameter: ?format=csv|json|excel -- Return appropriate blob/file type - -**Option B: Update frontend to call existing endpoints** -- Change frontend calls to `/admin/inventory-snapshot` and `/admin/audit-trail` -- Convert POST to GET or update frontend to use POST -- Handle multiple endpoint calls for combined export - -**Recommendation:** Option A (simpler for user, cleaner API) -**Effort:** 1-2 hours +**Testing:** User confirmed "export files is exported ok" --- diff --git a/.servers.pid b/.servers.pid index 34e055db..91178e83 100644 --- a/.servers.pid +++ b/.servers.pid @@ -1 +1 @@ -{"backend": 782437, "frontend": 782438, "caddy": 782439, "timestamp": 1776929439.3616884} \ No newline at end of file +{"backend": 799387, "frontend": 799388, "caddy": 799389, "timestamp": 1776932266.0922172} \ No newline at end of file diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index 2acff46d..66c09959 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -14,6 +14,7 @@ import ItemComparisonModal from '@/components/ItemComparisonModal'; import StockAdjustmentPanel from '@/components/StockAdjustmentPanel'; import NewItemDialog from '@/components/NewItemDialog'; import ScannerSection from '@/components/ScannerSection'; +import SearchModal from '@/components/inventory/SearchModal'; import { toast } from 'react-hot-toast'; import { Package, @@ -59,6 +60,7 @@ export default function Home() { const [categories, setCategories] = useState([]); const [comparisonModal, setComparisonModal] = useState<{ show: boolean, newItem: any, existingItem: any, existingId: number | null }>({ show: false, newItem: null, existingItem: null, existingId: null }); const [comparisonLoading, setComparisonLoading] = useState(false); + const [showSearch, setShowSearch] = useState(false); const { syncing, handleSync } = useSync({ isOnline, @@ -152,6 +154,18 @@ export default function Home() { }; }, []); + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if ((e.ctrlKey || e.metaKey) && e.key === 'k') { + e.preventDefault(); + setShowSearch(!showSearch); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [showSearch]); + const loadInventory = async () => { const cached = await db.items.toArray(); setInventory(cached); @@ -389,6 +403,13 @@ export default function Home() {
+