Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"[rust]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
],
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"editor.formatOnSave": true
"[rust]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
"rust-analyzer.rustfmt.extraArgs": [
"+nightly"
],
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"editor.formatOnSave": true
}
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"@monaco-editor/react": "^4.7.0",
"@tauri-apps/api": "^2.10.1",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-process": "^2",
"@tauri-apps/plugin-updater": "^2",
"immer": "^11.0.1",
"lucide-react": "^0.561.0",
"react": "^19.1.0",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
// This callback is called when a second instance is launched
info!("Second instance detected, focusing existing window");
Expand Down
146 changes: 21 additions & 125 deletions apps/desktop/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { FeatureSetsPage } from '@/features/featuresets';
import { ClientsPage } from '@/features/clients';
import { ServersPage } from '@/features/servers';
import { SpacesPage } from '@/features/spaces';
import { SettingsPage } from '@/features/settings';
import { useGatewayEvents, useServerStatusEvents } from '@/hooks/useDomainEvents';

type NavItem = 'home' | 'registry' | 'servers' | 'spaces' | 'featuresets' | 'clients' | 'settings';
Expand All @@ -46,6 +47,25 @@ function AppContent() {

const [activeNav, setActiveNav] = useState<NavItem>('home');

// Auto-check for updates on startup (silent check after 5 seconds)
useEffect(() => {
const checkForUpdates = async () => {
try {
const { check } = await import('@tauri-apps/plugin-updater');
const update = await check();
if (update) {
console.log(`[Auto-Update] Update available: ${update.version}`);
// User can check Settings page to see the update
}
} catch (error) {
console.error('[Auto-Update] Failed to check for updates:', error);
}
};

const timer = setTimeout(checkForUpdates, 5000);
return () => clearTimeout(timer);
}, []);

// Get state from store
const theme = useTheme();
const setTheme = useAppStore((state) => state.setTheme);
Expand Down Expand Up @@ -171,7 +191,7 @@ function AppContent() {
{activeNav === 'spaces' && <SpacesPage />}
{activeNav === 'featuresets' && <FeatureSetsPage />}
{activeNav === 'clients' && <ClientsPage />}
{activeNav === 'settings' && <SettingsView />}
{activeNav === 'settings' && <SettingsPage />}
</div>
</AppShell>
);
Expand Down Expand Up @@ -425,128 +445,4 @@ function DashboardView() {
);
}

function SettingsView() {
const theme = useTheme();
const setTheme = useAppStore((state) => state.setTheme);
const [logsPath, setLogsPath] = useState<string>('');
const [openingLogs, setOpeningLogs] = useState(false);

// Load logs path on mount
useEffect(() => {
const loadLogsPath = async () => {
try {
const { invoke } = await import('@tauri-apps/api/core');
const path = await invoke<string>('get_logs_path');
setLogsPath(path);
} catch (error) {
console.error('Failed to get logs path:', error);
}
};
loadLogsPath();
}, []);

const handleOpenLogs = async () => {
setOpeningLogs(true);
try {
const { invoke } = await import('@tauri-apps/api/core');
await invoke('open_logs_folder');
} catch (error) {
console.error('Failed to open logs folder:', error);
} finally {
setOpeningLogs(false);
}
};

return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">Settings</h1>
<p className="text-[rgb(var(--muted))]">Configure McpMux preferences.</p>
</div>

<Card>
<CardHeader>
<CardTitle>Appearance</CardTitle>
<CardDescription>Customize the look and feel of McpMux.</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<label className="text-sm font-medium">Theme</label>
<div className="flex gap-2 mt-2" data-testid="theme-buttons">
<Button
variant={theme === 'light' ? 'primary' : 'secondary'}
size="sm"
onClick={() => setTheme('light')}
data-testid="theme-light-btn"
>
<Sun className="h-4 w-4 mr-2" />
Light
</Button>
<Button
variant={theme === 'dark' ? 'primary' : 'secondary'}
size="sm"
onClick={() => setTheme('dark')}
data-testid="theme-dark-btn"
>
<Moon className="h-4 w-4 mr-2" />
Dark
</Button>
<Button
variant={theme === 'system' ? 'primary' : 'secondary'}
size="sm"
onClick={() => setTheme('system')}
data-testid="theme-system-btn"
>
<Monitor className="h-4 w-4 mr-2" />
System
</Button>
</div>
</div>
</div>
</CardContent>
</Card>

<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="h-5 w-5" />
Logs
</CardTitle>
<CardDescription>View application logs for debugging and troubleshooting.</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<label className="text-sm font-medium">Log Files Location</label>
<p className="text-sm text-[rgb(var(--muted))] mt-1 font-mono bg-surface-secondary rounded px-2 py-1" data-testid="logs-path">
{logsPath || 'Loading...'}
</p>
</div>
<div className="flex items-center gap-2">
<Button
variant="secondary"
size="sm"
onClick={handleOpenLogs}
disabled={openingLogs}
data-testid="open-logs-btn"
>
{openingLogs ? (
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
) : (
<FolderOpen className="h-4 w-4 mr-2" />
)}
Open Logs Folder
</Button>
</div>
<p className="text-xs text-[rgb(var(--muted))]">
Logs are rotated daily. Each file contains detailed debug information including thread IDs and source locations.
</p>
</div>
</CardContent>
</Card>
</div>
);
}

export default App;
Loading
Loading