Parcourir la source

Added back navigation to user management page

maziggy il y a 4 mois
Parent
commit
fa9a154c5d

+ 32 - 13
frontend/src/pages/SettingsPage.tsx

@@ -1,7 +1,7 @@
 import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
 import { Loader2, Plus, Plug, AlertTriangle, RotateCcw, Bell, Download, RefreshCw, ExternalLink, Globe, Droplets, Thermometer, FileText, Edit2, Send, CheckCircle, XCircle, History, Trash2, Upload, Zap, TrendingUp, Calendar, DollarSign, Power, PowerOff, Key, Copy, Database, Info, X, Shield, Printer, Cylinder, Wifi, Home, Video, Users, Lock, Unlock } from 'lucide-react';
 import { useTranslation } from 'react-i18next';
-import { useNavigate } from 'react-router-dom';
+import { useNavigate, useSearchParams } from 'react-router-dom';
 import { api } from '../api/client';
 import { useAuth } from '../contexts/AuthContext';
 import { formatDateOnly } from '../utils/date';
@@ -29,9 +29,13 @@ import { useTheme, type ThemeStyle, type DarkBackground, type LightBackground, t
 import { useState, useEffect, useRef, useCallback } from 'react';
 import { Palette } from 'lucide-react';
 
+const validTabs = ['general', 'network', 'plugs', 'notifications', 'filament', 'apikeys', 'virtual-printer', 'users'] as const;
+type TabType = typeof validTabs[number];
+
 export function SettingsPage() {
   const queryClient = useQueryClient();
   const navigate = useNavigate();
+  const [searchParams, setSearchParams] = useSearchParams();
   const { t, i18n } = useTranslation();
   const { showToast, showPersistentToast, dismissToast } = useToast();
   const { authEnabled, user, refreshAuth } = useAuth();
@@ -50,7 +54,22 @@ export function SettingsPage() {
   const [editingTemplate, setEditingTemplate] = useState<NotificationTemplate | null>(null);
   const [showLogViewer, setShowLogViewer] = useState(false);
   const [defaultView, setDefaultViewState] = useState<string>(getDefaultView());
-  const [activeTab, setActiveTab] = useState<'general' | 'network' | 'plugs' | 'notifications' | 'filament' | 'apikeys' | 'virtual-printer' | 'users'>('general');
+
+  // Initialize tab from URL params
+  const tabParam = searchParams.get('tab');
+  const initialTab = tabParam && validTabs.includes(tabParam as TabType) ? tabParam as TabType : 'general';
+  const [activeTab, setActiveTab] = useState<TabType>(initialTab);
+
+  // Update URL when tab changes
+  const handleTabChange = (tab: TabType) => {
+    setActiveTab(tab);
+    if (tab === 'general') {
+      searchParams.delete('tab');
+    } else {
+      searchParams.set('tab', tab);
+    }
+    setSearchParams(searchParams, { replace: true });
+  };
   const [showCreateAPIKey, setShowCreateAPIKey] = useState(false);
   const [newAPIKeyName, setNewAPIKeyName] = useState('');
   const [newAPIKeyPermissions, setNewAPIKeyPermissions] = useState({
@@ -481,7 +500,7 @@ export function SettingsPage() {
       {/* Tab Navigation */}
       <div className="flex gap-1 mb-6 border-b border-bambu-dark-tertiary overflow-x-auto">
         <button
-          onClick={() => setActiveTab('general')}
+          onClick={() => handleTabChange('general')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
             activeTab === 'general'
               ? 'text-bambu-green border-bambu-green'
@@ -491,7 +510,7 @@ export function SettingsPage() {
           General
         </button>
         <button
-          onClick={() => setActiveTab('plugs')}
+          onClick={() => handleTabChange('plugs')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'plugs'
               ? 'text-bambu-green border-bambu-green'
@@ -507,7 +526,7 @@ export function SettingsPage() {
           )}
         </button>
         <button
-          onClick={() => setActiveTab('notifications')}
+          onClick={() => handleTabChange('notifications')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'notifications'
               ? 'text-bambu-green border-bambu-green'
@@ -523,7 +542,7 @@ export function SettingsPage() {
           )}
         </button>
         <button
-          onClick={() => setActiveTab('filament')}
+          onClick={() => handleTabChange('filament')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'filament'
               ? 'text-bambu-green border-bambu-green'
@@ -534,7 +553,7 @@ export function SettingsPage() {
           Filament
         </button>
         <button
-          onClick={() => setActiveTab('network')}
+          onClick={() => handleTabChange('network')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'network'
               ? 'text-bambu-green border-bambu-green'
@@ -546,7 +565,7 @@ export function SettingsPage() {
           <span className={`w-2 h-2 rounded-full ${mqttStatus?.enabled ? 'bg-green-400' : 'bg-gray-500'}`} />
         </button>
         <button
-          onClick={() => setActiveTab('apikeys')}
+          onClick={() => handleTabChange('apikeys')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'apikeys'
               ? 'text-bambu-green border-bambu-green'
@@ -562,7 +581,7 @@ export function SettingsPage() {
           )}
         </button>
         <button
-          onClick={() => setActiveTab('virtual-printer')}
+          onClick={() => handleTabChange('virtual-printer')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'virtual-printer'
               ? 'text-bambu-green border-bambu-green'
@@ -574,7 +593,7 @@ export function SettingsPage() {
           <span className={`w-2 h-2 rounded-full ${virtualPrinterRunning ? 'bg-green-400' : 'bg-gray-500'}`} />
         </button>
         <button
-          onClick={() => setActiveTab('users')}
+          onClick={() => handleTabChange('users')}
           className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px flex items-center gap-2 ${
             activeTab === 'users'
               ? 'text-bambu-green border-bambu-green'
@@ -2973,8 +2992,8 @@ export function SettingsPage() {
                             </p>
                           </div>
                           <div className={`px-3 py-1 rounded-full text-xs font-medium ${
-                            user.role === 'admin' 
-                              ? 'bg-purple-500/20 text-purple-300' 
+                            user.role === 'admin'
+                              ? 'bg-purple-500/20 text-purple-300'
                               : 'bg-blue-500/20 text-blue-300'
                           }`}>
                             {user.role === 'admin' ? 'Admin' : 'User'}
@@ -2992,7 +3011,7 @@ export function SettingsPage() {
                         <Users className="w-4 h-4" />
                         Manage Users
                       </Button>
-                      
+
                       {user?.role === 'admin' && (
                         <Button
                           onClick={() => setShowDisableAuthConfirm(true)}

+ 24 - 13
frontend/src/pages/UsersPage.tsx

@@ -1,6 +1,7 @@
 import { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { X, Plus, Edit2, Trash2, Save, Loader2, Users as UsersIcon, Shield } from 'lucide-react';
+import { X, Plus, Edit2, Trash2, Save, Loader2, Users as UsersIcon, Shield, ArrowLeft } from 'lucide-react';
 import { api } from '../api/client';
 import type { UserCreate, UserUpdate } from '../api/client';
 import { useAuth } from '../contexts/AuthContext';
@@ -10,6 +11,7 @@ import { Card, CardContent, CardHeader } from '../components/Card';
 import { ConfirmModal } from '../components/ConfirmModal';
 
 export function UsersPage() {
+  const navigate = useNavigate();
   const { user: currentUser } = useAuth();
   const { showToast } = useToast();
   const queryClient = useQueryClient();
@@ -128,14 +130,23 @@ export function UsersPage() {
   return (
     <div className="p-6">
       <div className="flex justify-between items-center mb-6">
-        <div>
-          <h1 className="text-2xl font-bold text-white flex items-center gap-2">
-            <UsersIcon className="w-6 h-6 text-bambu-green" />
-            User Management
-          </h1>
-          <p className="text-sm text-bambu-gray mt-1">
-            Manage users and their access to your Bambuddy instance
-          </p>
+        <div className="flex items-center gap-4">
+          <button
+            onClick={() => navigate('/settings?tab=users')}
+            className="p-2 rounded-lg bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors"
+            title="Back to Settings"
+          >
+            <ArrowLeft className="w-5 h-5" />
+          </button>
+          <div>
+            <h1 className="text-2xl font-bold text-white flex items-center gap-2">
+              <UsersIcon className="w-6 h-6 text-bambu-green" />
+              User Management
+            </h1>
+            <p className="text-sm text-bambu-gray mt-1">
+              Manage users and their access to your Bambuddy instance
+            </p>
+          </div>
         </div>
         <Button
           onClick={() => {
@@ -199,8 +210,8 @@ export function UsersPage() {
                         </select>
                       ) : (
                         <span className={`px-3 py-1 rounded-full text-xs font-medium ${
-                          user.role === 'admin' 
-                            ? 'bg-purple-500/20 text-purple-300' 
+                          user.role === 'admin'
+                            ? 'bg-purple-500/20 text-purple-300'
                             : 'bg-blue-500/20 text-blue-300'
                         }`}>
                           {user.role}
@@ -209,8 +220,8 @@ export function UsersPage() {
                     </td>
                     <td className="px-6 py-4 whitespace-nowrap text-sm">
                       <span className={`px-3 py-1 rounded-full text-xs font-medium ${
-                        user.is_active 
-                          ? 'bg-bambu-green/20 text-bambu-green' 
+                        user.is_active
+                          ? 'bg-bambu-green/20 text-bambu-green'
                           : 'bg-red-500/20 text-red-400'
                       }`}>
                         {user.is_active ? 'Active' : 'Inactive'}

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/assets/index-BK0uiRXP.js


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
static/assets/index-BNJwArDp.js


+ 1 - 1
static/index.html

@@ -23,7 +23,7 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-BK0uiRXP.js"></script>
+    <script type="module" crossorigin src="/assets/index-BNJwArDp.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-COZJGA_d.css">
   </head>
   <body>

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff