|
@@ -1,5 +1,5 @@
|
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
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, Zap, TrendingUp, Calendar, DollarSign, Power, PowerOff, Key, Copy, Database, X, Shield, Printer, Cylinder, Wifi, Home, Video, Users, Lock, Unlock, ChevronDown, Save, Mail, Flame, Layers, ListOrdered, Code, Search, Settings as SettingsIcon } from 'lucide-react';
|
|
|
|
|
|
|
+import { Loader2, Plus, Plug, AlertTriangle, RotateCcw, Bell, Download, RefreshCw, ExternalLink, Globe, Droplets, Thermometer, FileText, Edit2, Send, CheckCircle, XCircle, History, Trash2, Zap, TrendingUp, Calendar, DollarSign, Power, PowerOff, Key, Copy, Database, X, Shield, Printer, Cylinder, Wifi, Home, Video, Users, Lock, Unlock, ChevronDown, Save, Mail, Flame, Layers, ListOrdered, Code, Search, Scale, Settings as SettingsIcon } from 'lucide-react';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
|
|
import { api } from '../api/client';
|
|
import { api } from '../api/client';
|
|
@@ -23,12 +23,13 @@ import { SpoolCatalogSettings } from '../components/SpoolCatalogSettings';
|
|
|
import { ColorCatalogSettings } from '../components/ColorCatalogSettings';
|
|
import { ColorCatalogSettings } from '../components/ColorCatalogSettings';
|
|
|
import { ExternalLinksSettings } from '../components/ExternalLinksSettings';
|
|
import { ExternalLinksSettings } from '../components/ExternalLinksSettings';
|
|
|
import { VirtualPrinterList } from '../components/VirtualPrinterList';
|
|
import { VirtualPrinterList } from '../components/VirtualPrinterList';
|
|
|
|
|
+import { SpoolBuddySettings } from '../components/SpoolBuddySettings';
|
|
|
import { GitHubBackupSettings } from '../components/GitHubBackupSettings';
|
|
import { GitHubBackupSettings } from '../components/GitHubBackupSettings';
|
|
|
import { EmailSettings } from '../components/EmailSettings';
|
|
import { EmailSettings } from '../components/EmailSettings';
|
|
|
import { LDAPSettings } from '../components/LDAPSettings';
|
|
import { LDAPSettings } from '../components/LDAPSettings';
|
|
|
import { APIBrowser } from '../components/APIBrowser';
|
|
import { APIBrowser } from '../components/APIBrowser';
|
|
|
import { Toggle } from '../components/Toggle';
|
|
import { Toggle } from '../components/Toggle';
|
|
|
-import { virtualPrinterApi } from '../api/client';
|
|
|
|
|
|
|
+import { virtualPrinterApi, spoolbuddyApi } from '../api/client';
|
|
|
import { defaultNavItems, getDefaultView, setDefaultView } from '../components/Layout';
|
|
import { defaultNavItems, getDefaultView, setDefaultView } from '../components/Layout';
|
|
|
import { availableLanguages } from '../i18n';
|
|
import { availableLanguages } from '../i18n';
|
|
|
import { useToast } from '../contexts/ToastContext';
|
|
import { useToast } from '../contexts/ToastContext';
|
|
@@ -36,7 +37,7 @@ import { useTheme, type ThemeStyle, type DarkBackground, type LightBackground, t
|
|
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
|
import { Palette } from 'lucide-react';
|
|
import { Palette } from 'lucide-react';
|
|
|
|
|
|
|
|
-const validTabs = ['general', 'plugs', 'notifications', 'queue', 'filament', 'network', 'apikeys', 'virtual-printer', 'users', 'backup'] as const;
|
|
|
|
|
|
|
+const validTabs = ['general', 'plugs', 'notifications', 'queue', 'filament', 'network', 'apikeys', 'virtual-printer', 'spoolbuddy', 'users', 'backup'] as const;
|
|
|
type TabType = typeof validTabs[number];
|
|
type TabType = typeof validTabs[number];
|
|
|
type UsersSubTab = 'users' | 'email' | 'ldap';
|
|
type UsersSubTab = 'users' | 'email' | 'ldap';
|
|
|
|
|
|
|
@@ -356,6 +357,15 @@ export function SettingsPage() {
|
|
|
});
|
|
});
|
|
|
const virtualPrinterRunning = virtualPrinterSettings?.status?.running ?? false;
|
|
const virtualPrinterRunning = virtualPrinterSettings?.status?.running ?? false;
|
|
|
|
|
|
|
|
|
|
+ // SpoolBuddy devices for tab indicator
|
|
|
|
|
+ const { data: spoolbuddyDevices } = useQuery({
|
|
|
|
|
+ queryKey: ['spoolbuddy-devices'],
|
|
|
|
|
+ queryFn: () => spoolbuddyApi.getDevices(),
|
|
|
|
|
+ refetchInterval: 15000,
|
|
|
|
|
+ });
|
|
|
|
|
+ const spoolbuddyDeviceCount = spoolbuddyDevices?.length ?? 0;
|
|
|
|
|
+ const spoolbuddyAnyOnline = spoolbuddyDevices?.some((d) => d.online) ?? false;
|
|
|
|
|
+
|
|
|
const { data: ffmpegStatus } = useQuery({
|
|
const { data: ffmpegStatus } = useQuery({
|
|
|
queryKey: ['ffmpeg-status'],
|
|
queryKey: ['ffmpeg-status'],
|
|
|
queryFn: api.checkFfmpeg,
|
|
queryFn: api.checkFfmpeg,
|
|
@@ -1011,6 +1021,8 @@ export function SettingsPage() {
|
|
|
{ label: t('settings.apiBrowser'), tab: 'apikeys', keywords: 'api browser endpoint documentation test', anchor: 'card-apibrowser' },
|
|
{ label: t('settings.apiBrowser'), tab: 'apikeys', keywords: 'api browser endpoint documentation test', anchor: 'card-apibrowser' },
|
|
|
// Virtual Printer
|
|
// Virtual Printer
|
|
|
{ label: t('settings.tabs.virtualPrinter'), tab: 'virtual-printer', keywords: 'virtual printer proxy archive slicer bambustudio orcaslicer ip bind', anchor: 'card-vp' },
|
|
{ label: t('settings.tabs.virtualPrinter'), tab: 'virtual-printer', keywords: 'virtual printer proxy archive slicer bambustudio orcaslicer ip bind', anchor: 'card-vp' },
|
|
|
|
|
+ // SpoolBuddy
|
|
|
|
|
+ { label: t('settings.tabs.spoolbuddy'), tab: 'spoolbuddy', keywords: 'spoolbuddy device scale nfc rfid kiosk unregister', anchor: 'card-spoolbuddy' },
|
|
|
// Users / Auth
|
|
// Users / Auth
|
|
|
{ label: t('settings.currentUser'), tab: 'users', subTab: 'users', keywords: 'current user profile password change', anchor: 'card-currentuser' },
|
|
{ label: t('settings.currentUser'), tab: 'users', subTab: 'users', keywords: 'current user profile password change', anchor: 'card-currentuser' },
|
|
|
{ label: t('settings.users'), tab: 'users', subTab: 'users', keywords: 'users accounts list', anchor: 'card-users' },
|
|
{ label: t('settings.users'), tab: 'users', subTab: 'users', keywords: 'users accounts list', anchor: 'card-users' },
|
|
@@ -1207,6 +1219,23 @@ export function SettingsPage() {
|
|
|
{t('settings.tabs.virtualPrinter')}
|
|
{t('settings.tabs.virtualPrinter')}
|
|
|
<span className={`w-2 h-2 rounded-full ${virtualPrinterRunning ? 'bg-green-400' : 'bg-gray-500'}`} />
|
|
<span className={`w-2 h-2 rounded-full ${virtualPrinterRunning ? 'bg-green-400' : 'bg-gray-500'}`} />
|
|
|
</button>
|
|
</button>
|
|
|
|
|
+ <button
|
|
|
|
|
+ onClick={() => handleTabChange('spoolbuddy')}
|
|
|
|
|
+ className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${
|
|
|
|
|
+ activeTab === 'spoolbuddy'
|
|
|
|
|
+ ? 'text-bambu-green border-bambu-green'
|
|
|
|
|
+ : 'text-bambu-gray hover:text-gray-900 dark:hover:text-white border-transparent'
|
|
|
|
|
+ }`}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Scale className="w-4 h-4" />
|
|
|
|
|
+ {t('settings.tabs.spoolbuddy')}
|
|
|
|
|
+ {spoolbuddyDeviceCount > 0 && (
|
|
|
|
|
+ <span className="text-xs bg-bambu-dark-tertiary px-1.5 py-0.5 rounded-full">
|
|
|
|
|
+ {spoolbuddyDeviceCount}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ <span className={`w-2 h-2 rounded-full ${spoolbuddyAnyOnline ? 'bg-green-400' : 'bg-gray-500'}`} />
|
|
|
|
|
+ </button>
|
|
|
<button
|
|
<button
|
|
|
onClick={() => handleTabChange('users')}
|
|
onClick={() => handleTabChange('users')}
|
|
|
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${
|
|
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px lg:border-b-0 lg:border-l-2 lg:-ml-px lg:mb-0 lg:justify-start flex items-center gap-2 ${
|
|
@@ -3528,6 +3557,13 @@ export function SettingsPage() {
|
|
|
</div>
|
|
</div>
|
|
|
)}
|
|
)}
|
|
|
|
|
|
|
|
|
|
+ {/* SpoolBuddy Tab */}
|
|
|
|
|
+ {activeTab === 'spoolbuddy' && (
|
|
|
|
|
+ <div id="card-spoolbuddy">
|
|
|
|
|
+ <SpoolBuddySettings />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
{/* Filament Tab */}
|
|
{/* Filament Tab */}
|
|
|
{/* Queue Tab */}
|
|
{/* Queue Tab */}
|
|
|
{activeTab === 'queue' && localSettings && (
|
|
{activeTab === 'queue' && localSettings && (
|