Skip to content

Commit 48e1569

Browse files
committed
feat: add routing and authentication pages, update dependencies
- Introduced a new routing structure with AppRoutes for better navigation. - Added authentication page (AuthPage) for user login via GitHub and Google. - Implemented categories page for server management and discovery. - Enhanced Dashboard and Favorites pages for improved user experience. - Updated package.json and bun.lock to include new dependencies for Radix UI tooltip. - Removed obsolete ContentArea component and refactored Layout to streamline rendering. - Added new translations for submit and view detail actions. - Cleaned up unused components and improved overall code organization.
1 parent bc65246 commit 48e1569

38 files changed

+411
-369
lines changed

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
src/components/ui
2+
src-tauri

bun.lock

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@radix-ui/react-select": "^2.1.6",
1414
"@radix-ui/react-slot": "^1.2.3",
1515
"@radix-ui/react-tabs": "^1.1.3",
16+
"@radix-ui/react-tooltip": "^1.2.7",
1617
"@supabase/supabase-js": "^2.49.4",
1718
"@tanstack/react-query": "^5.69.0",
1819
"@tauri-apps/api": "^2.5.0",
@@ -218,6 +219,8 @@
218219

219220
"@radix-ui/react-tabs": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-roving-focus": "1.1.7", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-KIjtwciYvquiW/wAFkELZCVnaNLBsYNhTNcvl+zfMAbMhRkcvNuCLXDDd22L0j7tagpzVh/QwbFpwAATg7ILPw=="],
220221

222+
"@radix-ui/react-tooltip": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.10", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.7", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw=="],
223+
221224
"@radix-ui/react-use-callback-ref": ["@radix-ui/[email protected]", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
222225

223226
"@radix-ui/react-use-controllable-state": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
@@ -672,6 +675,16 @@
672675

673676
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="],
674677

678+
"@radix-ui/react-tooltip/@radix-ui/react-dismissable-layer": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ=="],
679+
680+
"@radix-ui/react-tooltip/@radix-ui/react-popper": ["@radix-ui/[email protected]", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ=="],
681+
682+
"@radix-ui/react-tooltip/@radix-ui/react-portal": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
683+
684+
"@radix-ui/react-tooltip/@radix-ui/react-primitive": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
685+
686+
"@radix-ui/react-tooltip/@radix-ui/react-visually-hidden": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
687+
675688
"@tailwindcss/node/lightningcss": ["[email protected]", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
676689

677690
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/[email protected]", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
@@ -690,6 +703,8 @@
690703

691704
"vite/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.3", "@esbuild/android-arm": "0.25.3", "@esbuild/android-arm64": "0.25.3", "@esbuild/android-x64": "0.25.3", "@esbuild/darwin-arm64": "0.25.3", "@esbuild/darwin-x64": "0.25.3", "@esbuild/freebsd-arm64": "0.25.3", "@esbuild/freebsd-x64": "0.25.3", "@esbuild/linux-arm": "0.25.3", "@esbuild/linux-arm64": "0.25.3", "@esbuild/linux-ia32": "0.25.3", "@esbuild/linux-loong64": "0.25.3", "@esbuild/linux-mips64el": "0.25.3", "@esbuild/linux-ppc64": "0.25.3", "@esbuild/linux-riscv64": "0.25.3", "@esbuild/linux-s390x": "0.25.3", "@esbuild/linux-x64": "0.25.3", "@esbuild/netbsd-arm64": "0.25.3", "@esbuild/netbsd-x64": "0.25.3", "@esbuild/openbsd-arm64": "0.25.3", "@esbuild/openbsd-x64": "0.25.3", "@esbuild/sunos-x64": "0.25.3", "@esbuild/win32-arm64": "0.25.3", "@esbuild/win32-ia32": "0.25.3", "@esbuild/win32-x64": "0.25.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q=="],
692705

706+
"@radix-ui/react-tooltip/@radix-ui/react-popper/@radix-ui/react-arrow": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
707+
693708
"@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
694709

695710
"@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@radix-ui/react-select": "^2.1.6",
2727
"@radix-ui/react-slot": "^1.2.3",
2828
"@radix-ui/react-tabs": "^1.1.3",
29+
"@radix-ui/react-tooltip": "^1.2.7",
2930
"@supabase/supabase-js": "^2.49.4",
3031
"@tanstack/react-query": "^5.69.0",
3132
"@tauri-apps/api": "^2.5.0",

src-tauri/src/client.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl ClientConfig {
5959
}
6060
("mcphub", None) => PathBuf::from(home).join(".config/mcphub/servers.json"),
6161
("windsurf", _) => PathBuf::from(home).join(".codeium/windsurf/mcp_config.json"),
62+
("mcplinker", _) => PathBuf::from(home).join(".config/mcplinker/mcp.json"),
6263
(_, Some(path_str)) => {
6364
// For any other app, use the provided path + mcp.json
6465
// If path is empty, use home directory
@@ -73,10 +74,7 @@ impl ClientConfig {
7374
PathBuf::from("")
7475
}
7576
};
76-
println!(
77-
"Creating ClientConfig with name: {}, path: {:?}",
78-
name, path
79-
);
77+
8078
Self {
8179
name: name.to_string(),
8280
path,

src-tauri/src/git.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::fs;
2-
use git2::Repository;
31
use anyhow::Result;
42
use dirs::home_dir;
3+
use git2::Repository;
4+
use std::fs;
55
use url::Url;
66

77
#[tauri::command]
@@ -14,7 +14,8 @@ pub async fn git_clone(url: String) -> Result<String, String> {
1414
}
1515

1616
// path_segments should be /owner/repo
17-
let segments: Vec<&str> = parsed_url.path_segments()
17+
let segments: Vec<&str> = parsed_url
18+
.path_segments()
1819
.ok_or("URL missing path")?
1920
.filter(|s| !s.is_empty())
2021
.collect();
@@ -36,13 +37,17 @@ pub async fn git_clone(url: String) -> Result<String, String> {
3637

3738
tauri::async_runtime::spawn_blocking(move || {
3839
if target_dir.exists() {
39-
return Ok(format!("Repository already exists at {}", target_dir.display()));
40+
return Ok(format!(
41+
"Repository already exists at {}",
42+
target_dir.display()
43+
));
4044
}
4145

4246
// Create parent directory ~/.cache/mcp-linker/owner
4347
if let Some(parent) = target_dir.parent() {
4448
if !parent.exists() {
45-
fs::create_dir_all(parent).map_err(|e| format!("Failed to create directory: {}", e))?;
49+
fs::create_dir_all(parent)
50+
.map_err(|e| format!("Failed to create directory: {}", e))?;
4651
}
4752
}
4853

@@ -56,4 +61,4 @@ pub async fn git_clone(url: String) -> Result<String, String> {
5661
})
5762
.await
5863
.map_err(|e| format!("Thread error: {}", e))?
59-
}
64+
}

src-tauri/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ use serde_json::Value;
1212

1313
mod client;
1414
mod cmd;
15+
mod git;
1516
mod installer;
1617
mod json_manager;
17-
mod git;
1818

1919
#[derive(Debug, Serialize, Deserialize)]
2020
struct Config {
2121
#[serde(rename = "mcpServers", alias = "servers")]
2222
mcp_servers: Value,
2323
}
2424

25-
2625
fn update_env_path() {
2726
let home = home_dir().unwrap().to_str().unwrap().to_string();
2827
let local_bin = format!("{}/.local/bin", home);

src/App.tsx

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1+
import CommandChecker from "@/components/CommandChecker";
12
import { ThemeProvider } from "@/components/theme-provider";
2-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3-
import { lazy, Suspense, useEffect, useState } from "react";
4-
import { checkForUpdate, UpdateInfo } from "./lib/update";
5-
63
import { useUnifiedDeepLink } from "@/hooks/useUnifiedDeepLink";
4+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5+
import { useEffect, useState } from "react";
76
import "./App.css";
8-
import { AppLoadingFallback } from "./components/common/LoadingConfig";
7+
import Layout from "./components/Layout";
98
import { TriggerOnMount } from "./components/TriggerOnMount";
109
import { UpdateDialog } from "./components/UpdateDialog";
10+
import { checkForUpdate, UpdateInfo } from "./lib/update";
1111

1212
declare global {
1313
interface Window {
1414
__TAURI__?: any;
1515
}
1616
}
1717

18-
const Layout = lazy(() => import("./components/Layout"));
19-
const CommandChecker = lazy(() => import("@/components/CommandChecker"));
20-
2118
const queryClient = new QueryClient({
2219
defaultOptions: {
2320
queries: {
@@ -31,49 +28,34 @@ const queryClient = new QueryClient({
3128
function App() {
3229
const { triggerPendingDeepLink } = useUnifiedDeepLink();
3330
const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);
34-
const [showUpdateDialog, setShowUpdateDialog] = useState(false);
35-
const isTauri = window.__TAURI__ !== undefined;
31+
const isTauri = window.__TAURI__ !== "undefined";
3632

3733
useEffect(() => {
38-
const handleCheckForUpdate = async () => {
39-
if (import.meta.env.VITE_IS_CHECK_UPDATE === "true") {
40-
const update = await checkForUpdate();
34+
if (import.meta.env.VITE_IS_CHECK_UPDATE === "true") {
35+
checkForUpdate().then((update) => {
4136
if (update?.hasUpdate) {
4237
setUpdateInfo(update);
43-
setShowUpdateDialog(true);
4438
}
45-
}
46-
};
47-
48-
handleCheckForUpdate();
39+
});
40+
}
4941
}, []);
5042

51-
const handleCloseUpdateDialog = () => {
52-
setShowUpdateDialog(false);
53-
setUpdateInfo(null);
54-
};
55-
5643
return (
5744
<QueryClientProvider client={queryClient}>
5845
<ThemeProvider storageKey="vite-ui-theme">
59-
<Suspense fallback={<AppLoadingFallback />}>
60-
{isTauri && <CommandChecker />}
61-
{/* deep link */}
62-
<TriggerOnMount onReady={triggerPendingDeepLink} />
63-
64-
<Layout />
46+
{isTauri && <CommandChecker />}
47+
<TriggerOnMount onReady={triggerPendingDeepLink} />
48+
<Layout />
6549

66-
{/* Update dialog */}
67-
{updateInfo && (
68-
<UpdateDialog
69-
isOpen={showUpdateDialog}
70-
onClose={handleCloseUpdateDialog}
71-
latestVersion={updateInfo.latestVersion}
72-
releaseNotes={updateInfo.releaseNotes}
73-
releaseUrl={updateInfo.releaseUrl}
74-
/>
75-
)}
76-
</Suspense>
50+
{updateInfo && (
51+
<UpdateDialog
52+
isOpen={true}
53+
onClose={() => setUpdateInfo(null)}
54+
latestVersion={updateInfo.latestVersion}
55+
releaseNotes={updateInfo.releaseNotes}
56+
releaseUrl={updateInfo.releaseUrl}
57+
/>
58+
)}
7759
</ThemeProvider>
7860
</QueryClientProvider>
7961
);

src/components/CommandChecker.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { invoke } from "@tauri-apps/api/core";
2+
import { open } from "@tauri-apps/plugin-shell";
23
import { useEffect, useState } from "react";
34
import { useTranslation } from "react-i18next";
45
import { Notification, Notifications } from "./ui/Notifications";
@@ -284,10 +285,7 @@ export default function CommandChecker() {
284285
? {
285286
label: "Manual Install",
286287
onClick: () => {
287-
// Use Tauri's shell open instead of window.open for security
288-
import("@tauri-apps/plugin-shell").then(({ open }) => {
289-
open(tool.fallbackUrl!);
290-
});
288+
open(tool.fallbackUrl!);
291289
},
292290
}
293291
: undefined,

src/components/ContentArea.tsx

Lines changed: 0 additions & 64 deletions
This file was deleted.

src/components/Layout/Sidebar.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ export const Sidebar = ({ navs }: SidebarProps) => {
5757

5858
<div className="flex flex-col gap-2">
5959
{navs.map((nav) => (
60-
<Link key={nav.id} to={`/${nav.id}`} className="w-full">
60+
<Link key={nav.id} to={nav.path || `/${nav.id}`} className="w-full">
6161
<Button
6262
variant={
63-
location.pathname === `/${nav.id}` ? "secondary" : "ghost"
63+
location.pathname === (nav.path || `/${nav.id}`)
64+
? "secondary"
65+
: "ghost"
6466
}
6567
className={`w-full justify-start p-2 ${isCollapsed ? "justify-center" : ""}`}
6668
>

0 commit comments

Comments
 (0)