Commit graph

22 commits

Author SHA1 Message Date
4b083f6fa5 fix: store fetch côté navigateur (backend sans internet)
Le container backend n'a pas accès sortant vers git.geronzi.fr.
loadStore() appelle maintenant directement l'API Forgejo depuis le
navigateur (qui a internet). Le backend n'est plus sollicité que pour
l'installation (POST /api/registry/modules/:id/install).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 17:08:43 +01:00
22a5fed8cc fix: store 502, refresh button, rebuild UX pour modules
- GetRegistryModules: endpoint /api/v1/orgs/{org}/repos + timeout 10s
  répond toujours HTTP 200 avec {modules, error} au lieu de 502
- InstallRegistryModule: essaie branche master puis main pour module.json
- Ajouter FORGEJO_URL / FORGEJO_ORG dans docker-compose.yml
- Frontend: bouton rafraîchir store + affichage erreur
- Frontend: bannière rebuild en cours + bannière rebuild terminé
- Frontend: polling /api/health toutes les 3s après rebuild/restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 17:03:42 +01:00
ec7d120ef6 refactor: architecture modules indépendants — nettoyage CORE, registry enrichi, page modules dynamique
- Supprimer les modules services et logs du CORE (déplacés dans viewServices et viewLogs)
- Enrichir modules/module.go : interface Registry avec NavItemDef, RunOnTarget, StreamOnTarget
- Réécrire modules/loader.go : NewLoader accepte *db.DB, *sshpool.Pool, *crypto.Encryptor
- Ajouter migration 005 : colonnes nav_* sur la table modules + suppression services/logs DB
- Mettre à jour db.go (repairSchema) pour ajout idempotent des colonnes nav_*
- Mettre à jour settings.go : GetModules retourne les champs nav, ajout GetRegistryModules et InstallRegistryModule
- Mettre à jour main.go : NewLoader avec les bons arguments, ajout routes /api/registry/modules
- Mettre à jour modules.html : section Store avec liste des modules Forgejo
- Mettre à jour app.js : sidebar dynamique (nav_href depuis DB), modulesPage avec store
- Mettre à jour pages.css : styles pour store de modules

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 03:34:17 +01:00
91cf788221 refactor: sidebar nav items modules dynamiques selon is_enabled
Les items CORE (dashboard, proxmox, updates, settings, modules) sont
toujours affichés. Les modules optionnels (terminal, files, services,
logs) n'apparaissent dans la sidebar que si leur module est activé
en base de données — conformément à l'instruction.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 02:55:39 +01:00
6666d931c9 fix: use valid LineIcons class names for services and logs nav items
lnid-gear-loading and lnid-scroll-document-1 don't exist in the font.
Replace with lnid-gear-2 (services) and lnid-scroll-angular-1 (logs).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 02:34:57 +01:00
5836f2201a feat: add Services and Logs modules (systemctl + journalctl via SSH)
Backend:
- modules/services: list, status, start/stop/restart systemctl services
  with pct exec support for LXC targets
- modules/logs: journalctl unit listing + WebSocket live streaming
  (direct SSH connection, journalctl -f, graceful teardown on WS close)
- migrations/003: seed services and logs modules in DB
- main.go: register services.New() and logs.New() in module loader

Frontend:
- services.html: target selector, search/filter, services table with
  active state indicators and start/stop/restart buttons
- logs.html: target + unit selectors, live follow toggle, scrollable
  terminal output with 3000-line cap
- app.js: servicePage() and logsPage() Alpine components + navItems
- locales: services and logs i18n keys (fr + en)
- pages.css: services table, state dots, logs output styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 02:03:55 +01:00
98cdabf3e1 feat: label session actuelle + fix bouton révoquer
- GetSessions: retourne is_current=true pour la session correspondant au cookie courant
- GetSessions: select token_hash pour la comparaison (non exposé dans le JSON)
- profile.html: badge "Session actuelle" + désactive révoquer pour la session courante
  (utiliser le bouton Déconnexion à la place)
- app.js: revokeSession utilise finally pour reset + isRevoking() helper
- pages.css: styles .badge-current + .session-current

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 01:45:09 +01:00
1cbd7e9d17 fix: GetSessions scan robuste (sql.NullString) + formatDate adaptatif
- Scan des colonnes datetime via sql.NullString au lieu de time.Time pour éviter
  les échecs silencieux dus aux formats mixtes SQLite (CURRENT_TIMESTAMP vs RFC3339)
- Log explicite si un scan échoue (au lieu du continue silencieux)
- formatDate frontend adapte le format SQLite "YYYY-MM-DD HH:MM:SS" en ISO pour new Date()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 01:39:37 +01:00
95757124de fix: corriger bug multi-sessions (upsertUser wrong ID + schema repair + logs refresh)
- auth.go: upsertUser utilise toujours SELECT explicite au lieu de LastInsertId()
  qui retournait un rowid obsolète pour ON CONFLICT DO UPDATE sur ligne existante
- auth.go: vérifier l'erreur de l'INSERT refresh_tokens (était silencieusement ignorée)
- auth.go: logs détaillés dans Refresh handler pour diagnostiquer les 401
- db.go: repairSchema() ajoute les colonnes manquantes (ip, last_used_at) dans les
  bases où migration 002 était partiellement appliquée (ancien bug multi-statements)
- app.js: tryRefresh et fetchMe affichent le vrai message d'erreur du backend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 01:32:01 +01:00
dc0c67b89c fix: multi-sessions + système de toasts pour erreurs visibles
Sessions:
- Cookie pxp_refresh path: /api/auth/refresh → /api/auth/ pour être envoyé au logout
- Logout supprime uniquement le token de la session courante (via cookie hash)
  si pas de cookie = fallback suppression globale (rétro-compat)

Toasts:
- Store Alpine.store('toasts') avec error/success/warn/info + auto-dismiss
- Conteneur #pxp-toasts injecté dans <body>, persiste à travers les navigations Swup
- fetchMe(): HTTP non-401 → toast explicite (ex: HTTP 404 backend down)
- tryRefresh(): session expirée → sessionStorage → toast orange sur la page login
- logout(): message "Déconnexion réussie" sur la page login
- proxmoxPage.action(): toast succès/erreur pour start/stop LXC
- profilePage.revokeSession(): toast confirmation révocation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 01:04:37 +01:00
21e1e0ed1e feat: sync DB prefs, update history tab, configurable dashboard shortcuts
- auth store fetchMe(): sync theme/sidebar_position/lang from DB to localStorage+stores on login/refresh
- profilePage setters: PATCH /api/auth/preferences on every preference change
- updatesPage: add history tab (GET /api/updates/history) with job list, click to view output
- dashboardPage: load shortcuts from settings API, fall back to defaults if none configured
- settingsPage: new Raccourcis tab to add/remove/configure dashboard shortcuts (saved as JSON)
- settings.go: expose dashboard_shortcuts in publicSettings for GET/PUT access
- pages.css: add .history-table, .shortcut-row styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 00:35:24 +01:00
780e5ec81d fix: auth redirect bug + cookie Secure + migration multi-statements
- fetchMe: handle ALL non-ok responses (not just 401) by calling tryRefresh
  → avoids user=null when backend returns 404/500/any error
- DOMContentLoaded guard: check isAuthenticated instead of localStorage token
  → immediate redirect if fetchMe+tryRefresh both fail, no more flash of dashboard
- Cookie Secure flag: check X-Forwarded-Proto header for Traefik/proxy setup
  → cookie gets Secure=true when behind TLS-terminating reverse proxy
- db.go migrate(): split SQL by ; and exec each statement separately
  → fixes SQLite multi-statement limitation (only first stmt was executed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 22:29:22 +01:00
97212b7ffa feat: sessions management, web manifest, square icon-only buttons, remove lang select
- Backend: migration 002 adds user_agent/ip/last_used_at to refresh_tokens
- Backend: GET /api/auth/sessions + DELETE /api/auth/sessions/{id} endpoints
- Frontend: profile page — sessions section (browser, IP, datetime, revoke)
- Frontend: web manifest + SVG icon for PWA support
- Frontend: remove language selector from all navbars (moved to profile page)
- Frontend: neu-btn--icon-sm class for square icon-only buttons (theme/logout/edit)
- Frontend: manifest link added to all 9 HTML pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 20:14:11 +01:00
b851dc61af fix: couleurs icônes, boutons carrés, sidebar collapsée, langue, SW scope, LXC arrêté
Icônes :
- Sidebar navItems : couleur distincte par section (iconStyle via data-binding)
- Sidebar footer user : couleur primary
- Navbar : logout → danger, soleil → amber, lune → blue
- Panel widgets : œil visible → success, caché → muted

Boutons :
- `.neu-btn--sm:has(> i:only-child)` → carré 2rem×2rem automatiquement
  (theme, logout, mode édition) sans modifier le HTML

Sidebar :
- --sidebar-width-collapsed : 64px → 52px
- Sidebar réduite : icônes centrées (justify-content center)

Langue :
- Setter vide sur `lang` dans navbar() pour corriger x-model avec getter
  (le @change gère la vraie mise à jour du store)

Service Worker :
- Enregistrement depuis /ws.sw.js (scope /) au lieu de /js/ws.sw.js (scope /js/)
- build.mjs : copie ws.sw.js vers dist/ root en plus de dist/js/

LXC arrêté :
- checkTarget() : skip si target.status !== 'running' → évite les 502 SSH

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 19:50:58 +01:00
7c57b0ff84 feat(dashboard): resize souris, DnD live, panel widgets, icônes corrigées
- Resize widget via drag sur le coin bas-droit (mousedown → mousemove →
  snap à taille 1 ou 2 colonnes selon distance)
- DnD live : les autres widgets se déplacent pendant le drag (onDragEnter
  réordonne le tableau + onDragEnd restaure si annulé)
- Mode édition : panel latéral avec tous les widgets (œil toggle visible/masqué),
  survol d'une entrée met en avant (outline) le widget correspondant dans la grille
- Bouton mode édition : icône seule (lnid-pencil-1)
- Correction noms d'icônes LineIcons (lnid-pencil-1, lnid-eye, lnid-eye-closed,
  lnid-cross → supprimé en faveur de toggles dans le panel)
- Suppression des classes CSS obsolètes (edit-mode-banner, widget-add-btn, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 19:30:35 +01:00
cbfb20505d feat(frontend): Service Worker WS, mode édition dashboard, sidebar click-to-toggle
- WebSocket via Service Worker (ws.sw.js) : connexions persistantes entre navigations
  Swup, reconnexion exponentielle, protocole WS_SUBSCRIBE/WS_UNSUBSCRIBE/WS_SEND
- WsProxy dans app.js : abstraction SW + fallback WebSocket direct
- proxmoxPage migré vers WsProxy (identique au dashboardPage)
- Dashboard : mode édition toggle — DnD, resize (x1/x2), masquer/afficher widget
  uniquement actifs en mode édition ; preview drag (is-dragging/drag-over)
- Sidebar : suppression bouton hamburger, clic sur sidebar-header pour replier
- pages.css : targets-grid 350px, styles edit mode, widget-size-2, drag preview
- neu.css : sidebar-header cursor pointer, suppression .sidebar-toggle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 19:09:58 +01:00
5f6681dd17 feat: LineIcons Duotone, page profil, widgets dashboard, sidebar gauche/droite
- Intégration LineIcons Duotone (css/ + toutes les pages)
- Remplacement de tous les symboles Unicode par des icônes lnid-*
- Page profile.html : préférences thème, position sidebar, langue
- Dashboard : système de widgets add/remove + drag-and-drop natif
- Sidebar gauche/droite configurable per-user (data-sidebar CSS + FOUC script)
- Store ui : sidebarPosition, applySidebarPosition(), setSidebarPosition()
- Composant profilePage() dans app.js
- nav.profile ajouté dans fr.json et en.json
- SUIVI.md mis à jour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 18:38:48 +01:00
9739dbaee8 Correction CSS Swup, types WS et création fichier de suivi
- Extraction de tous les styles inline en css/pages.css (chargé globalement)
  pour corriger le CSS cassé lors des navigations Swup
- Correction types WebSocket : proxmox_resources → resources_update
  et msg.data → msg.payload (format réel du hub Go)
- Ajout d'un fetch HTTP immédiat dans dashboardPage/proxmoxPage
  pour éviter l'attente du premier tick (10s) du polling WS
- Correction msg.payload pour les updates (update_output/done/error)
- Ajout class terminal-wrapper sur .main-layout de terminal.html
  pour le fullscreen height sans affecter les autres pages
- Création SUIVI.md : état d'implémentation vs instruction.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:49:33 +01:00
a4b5b06f04 fix: CSS reset, settings API, modules champs, proxmox token
- CSS: ajout reset (box-sizing, margin, font-family, body background)
- Settings: save par PUT /api/settings/{key} (pas bulk), un appel par clé
- Settings: proxmox_token champ unique (format user@realm!id=secret)
- Modules: is_enabled/is_core (champs backend réels, pas enabled/core)
- Proxmox: supprime bouton reboot (route inexistante)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 17:28:55 +01:00
65c8bf332f fix: access_token (pas token) dans la réponse login/refresh
Le backend retourne { access_token: "...", user: {...} } pas { token: "..." }.
Le store Alpine lisait data.token → undefined → stockait "undefined" en localStorage
→ toutes les requêtes API échouaient avec 401.

Corrigé dans login() et tryRefresh().
Ajout d'un guard synchrone immédiat (pas de token → redirect login sans attendre fetchMe).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 16:50:52 +01:00
562eff8863 fix: CSS variables neu-*, WebSocket token, thème initial
- CSS: remplace var(--bg-*)/var(--text-*)/var(--accent-*)/var(--color-*)
  par les vraies variables --neu-* (neu-bg, neu-surface, neu-text, neu-primary…)
- CSS: supprime body{overflow:hidden} qui bloquait le scroll
- CSS: .auth-layout déplacé dans neu.css pour login/install
- WS: ajoute ?token= aux connexions /ws/proxmox (dashboardPage + proxmoxPage)
- HTML: script inline pour appliquer data-theme avant Alpine (évite FOUC)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 16:39:23 +01:00
2098c80ec1 feat: réécriture frontend Alpine.js + HTMX + Swup (branche frontend/alpine)
Remplace Vue 3 / Vite / TypeScript par une stack légère statique :
- Alpine.js v3 : réactivité inline, stores auth/ui/i18n, composants par page
- HTMX v2 : interactions serveur via attributs HTML
- Swup v4 : transitions de page (bundlé via esbuild, IIFE browser-loadable)
- xterm.js v5 : terminal PTY (bundlé via esbuild)

Structure : HTML statiques + js/app.js + js/terminal.js + css/ + locales/
Build : esbuild (bundle Swup + xterm seulement) → dist/ → Nginx
Dockerfile simplifié : node:22-alpine build → nginx:1.27-alpine serve

Pages : index, install, login, dashboard, proxmox, updates, terminal, settings, modules
URLs propres via nginx try_files $uri.html

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 16:19:24 +01:00