From cd1f04a5197ab0fdb3040b64896dd546e1de7614 Mon Sep 17 00:00:00 2001 From: Leo Date: Fri, 22 May 2026 16:08:07 -0400 Subject: [PATCH] fix(admin): sidebar hamburger menu for mobile, remove auto Cantaloupe sync - Replace broken icon-only sidebar collapse with off-canvas hamburger menu that slides in from left (hidden by default on <768px) - Add sidebar overlay backdrop, auto-close on nav/logout - Rename 'Cantaloupe Sync' to 'Import' in sidebar and 'Excel Import' in page - Remove 'Sync Now' button and backend subprocess auto-export entirely - Keep manual Excel file upload as the only import path - Update empty-state text and upload handler to work without Sync Now btn --- cantaloupe_sync.py | 42 ++--------------- static/index.html | 114 +++++++++++++++++++++++++++------------------ 2 files changed, 73 insertions(+), 83 deletions(-) diff --git a/cantaloupe_sync.py b/cantaloupe_sync.py index f118777..f211203 100644 --- a/cantaloupe_sync.py +++ b/cantaloupe_sync.py @@ -386,7 +386,7 @@ async def run_sync( file_path: Optional[str] = Query(None, description="Server-side path to Excel file"), ): """ - Run a full Cantaloupe sync from an Excel file. + Import an Excel file into a staged batch for review. Accepts either: - An uploaded Excel file (multipart form) @@ -416,42 +416,10 @@ async def run_sync( excel_path = str(p) display_path = file_path else: - # Try subprocess call to cantaloupe export - try: - import subprocess - import sys - cantaloupe_dir = os.path.expanduser("~/projects/cantaloupe-downloader") - result = subprocess.run( - [sys.executable, "-m", "cantaloupe", "export", "--scheduled"], - capture_output=True, text=True, timeout=120, - cwd=cantaloupe_dir, - ) - if result.returncode != 0: - raise HTTPException( - status_code=400, - detail=f"Cantaloupe export failed: {result.stderr[:500]}" - ) - # Parse output to find the exported file path - for line in result.stdout.splitlines() + result.stderr.splitlines(): - line = line.strip() - if line and Path(line).exists() and line.endswith((".xlsx", ".xls")): - excel_path = line - display_path = line - break - else: - raise HTTPException( - status_code=400, - detail="Cantaloupe export ran but produced no recognizable file path. Provide file upload or file_path parameter." - ) - except FileNotFoundError: - raise HTTPException( - status_code=400, - detail="No file provided and cantaloupe module not found. Upload an Excel file or provide file_path." - ) - except HTTPException: - raise - except Exception as e: - raise HTTPException(status_code=500, detail=f"Cantaloupe export error: {e}") + raise HTTPException( + status_code=400, + detail="No file provided. Upload an Excel file to import asset data." + ) conn = _get_db() try: diff --git a/static/index.html b/static/index.html index 30d39e8..5717b30 100644 --- a/static/index.html +++ b/static/index.html @@ -514,30 +514,51 @@ .hidden { display: none !important; } .mono { font-family: 'Courier New', monospace; font-size: 12px; } - /* Responsive: collapse sidebar on narrow screens */ + /* ═══════════════════════════════════════════════════════════════════════ + HAMBURGER BUTTON & SIDEBAR OVERLAY (mobile) + ═══════════════════════════════════════════════════════════════════════ */ + .hamburger { + display: none; + background: none; border: none; color: var(--text); font-size: 24px; + cursor: pointer; padding: 6px; margin-right: 10px; + line-height: 1; flex-shrink: 0; + } + .hamburger:hover { color: var(--accent2); } + .sidebar-overlay { + display: none; + position: fixed; inset: 0; background: rgba(0,0,0,0.5); + z-index: 99; opacity: 0; transition: opacity 0.25s; + pointer-events: none; + } + .sidebar-overlay.open { opacity: 1; pointer-events: auto; } + + /* Responsive: off-canvas sidebar on narrow screens */ @media (max-width: 768px) { + .hamburger { display: inline-flex; align-items: center; } + .sidebar-overlay { display: block; } + .sidebar { - width: 56px; - overflow: hidden; + transform: translateX(-100%); + transition: transform 0.25s ease; + z-index: 100; } - .sidebar .sidebar-header span, - .sidebar .sidebar-user, - .sidebar .nav-item span, - .sidebar .nav-item .ni-badge, - .sidebar .sidebar-footer span, - .sidebar .sidebar-footer .logout-btn { display: none; } - .sidebar .nav-item { justify-content: center; padding: 11px 0; } - .sidebar .nav-item .ni-icon { font-size: 20px; width: auto; } - .sidebar .sidebar-header { justify-content: center; } - .sidebar .sidebar-header .sh-icon { font-size: 22px; } - .main { margin-left: 56px; padding: 16px; max-width: calc(100vw - 56px); } + .sidebar.open { transform: translateX(0); } + + .main { + margin-left: 0; + padding: 16px; + max-width: 100vw; + } + + .page-title .pt-actions .btn .btn-label { display: none; } + .page-title .pt-actions .btn { min-width: 36px; justify-content: center; } /* Stats grid: tighter cards */ .stats-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 6px; } .stat-card { padding: 10px; } .stat-card .stat-value { font-size: 22px; } - /* Cantaloupe Sync batch rows stack */ + /* Import batch rows stack */ .cs-batch-row .csb-status { width: 60px; } .cs-batch-row .csb-time { width: auto; font-size: 11px; } .cs-batch-row .csb-rows { width: auto; text-align: left; margin-left: auto; } @@ -567,7 +588,7 @@ .page-title .pt-actions { width: 100%; } .page-title .pt-actions button { flex: 1; } - /* Cantaloupe diff badges stack 2x2 */ + /* Import diff badges stack 2x2 */ .cs-diff-summary { grid-template-columns: repeat(2, 1fr); } .cs-diff-badge { padding: 8px; } .cs-diff-badge .csd-val { font-size: 18px; } @@ -586,7 +607,7 @@ } /* ═══════════════════════════════════════════════════════════════════════ - CANTALOUPE SYNC + EXCEL IMPORT ═══════════════════════════════════════════════════════════════════════ */ .cs-diff-summary { display: grid; @@ -657,8 +678,11 @@ + + + -