refactor: plugin routes

This commit is contained in:
Haileyesus
2026-04-08 11:31:20 +03:00
parent bdf24092ff
commit 7c8819cf34
3 changed files with 42 additions and 11 deletions

View File

@@ -4,6 +4,7 @@ import {
Outlet,
RouterProvider,
createBrowserRouter,
useLocation,
useParams,
} from 'react-router-dom';
import { AuthProvider, ProtectedRoute } from './components/auth';
@@ -28,6 +29,7 @@ const isValidRouteTab = (value: string | undefined): boolean => {
normalizedValue === 'files' ||
normalizedValue === 'git' ||
normalizedValue === 'tasks' ||
normalizedValue === 'plugins' ||
normalizedValue === 'preview' ||
normalizedValue.startsWith('plugin:')
);
@@ -60,6 +62,7 @@ function WorkspaceLayout() {
}
function WorkspaceTabRoute() {
const location = useLocation();
const { workspaceId, sessionId, tab } = useParams<{
workspaceId: string;
sessionId?: string;
@@ -77,11 +80,13 @@ function WorkspaceTabRoute() {
const decodedWorkspaceId = workspaceId ? decodeURIComponent(workspaceId) : null;
const decodedSessionId = sessionId ? decodeURIComponent(sessionId) : null;
const decodedTab = tab ? decodeURIComponent(tab) : 'chat';
const pluginName = decodeURIComponent(new URLSearchParams(location.search).get('name') || '');
const tabLabel = decodedTab === 'plugins' && pluginName ? `plugin:${pluginName}` : decodedTab;
return (
<div className="h-full p-6">
<div className="rounded-xl border border-border/70 bg-card/30 p-5">
<h2 className="text-lg font-semibold">{decodedTab} view</h2>
<h2 className="text-lg font-semibold">{tabLabel} view</h2>
<p className="mt-2 text-sm text-muted-foreground">
Workspace:{' '}
<span className="font-medium text-foreground">

View File

@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import type { AppTab } from '@/types/app';
import { usePlugins } from '@/contexts/PluginsContext';
@@ -56,6 +56,7 @@ export function MainHeading() {
const { isMobile } = useDeviceSettings({ trackPWA: false });
const { sidebarIsCollapsed, setSidebarIsCollapsed } = useSystemUI();
const { workspaceId, sessionId, tab } = useParams<MainHeadingRouteParams>();
const location = useLocation();
const scrollRef = useRef<HTMLDivElement>(null);
const [canScrollLeft, setCanScrollLeft] = useState(false);
@@ -63,10 +64,18 @@ export function MainHeading() {
const decodedWorkspaceId = useMemo(() => decodeValue(workspaceId), [workspaceId]);
const decodedSessionId = useMemo(() => decodeValue(sessionId), [sessionId]);
const pluginName = useMemo(() => {
const params = new URLSearchParams(location.search);
return decodeValue(params.get('name') ?? undefined);
}, [location.search]);
const activeTab = useMemo<AppTab>(() => {
const routeTab = decodeValue(tab);
if (routeTab === 'plugins' && pluginName) {
return `plugin:${pluginName}` as AppTab;
}
return (routeTab || 'chat') as AppTab;
}, [tab]);
}, [pluginName, tab]);
const pluginDisplayName = useMemo(
() =>
@@ -117,15 +126,19 @@ export function MainHeading() {
const handleTabSelect = (nextTab: AppTab) => {
// Preserve route context while switching only the active tab path segment.
const encodedTab = encodeURIComponent(nextTab);
const isPluginTab = nextTab.startsWith('plugin:');
const pluginTabName = isPluginTab ? nextTab.replace('plugin:', '') : '';
const targetTab = isPluginTab ? 'plugins' : nextTab;
const encodedTargetTab = encodeURIComponent(targetTab);
const pluginQuery = isPluginTab ? `?name=${encodeURIComponent(pluginTabName)}` : '';
if (decodedSessionId) {
navigate(`/sessions/${encodeURIComponent(decodedSessionId)}/${encodedTab}`);
navigate(`/sessions/${encodeURIComponent(decodedSessionId)}/${encodedTargetTab}${pluginQuery}`);
return;
}
const encodedWorkspaceId = encodeURIComponent(decodedWorkspaceId);
navigate(`/workspaces/${encodedWorkspaceId}/${encodedTab}`);
navigate(`/workspaces/${encodedWorkspaceId}/${encodedTargetTab}${pluginQuery}`);
};
return (

View File

@@ -1,5 +1,5 @@
import { useState, useRef, useEffect, useMemo } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
MessageSquare,
@@ -58,6 +58,7 @@ export function MobileNav() {
const { isMobile } = useDeviceSettings({ trackPWA: false });
const { isChatInputFocused } = useSystemUI();
const { workspaceId, sessionId, tab } = useParams<MobileNavRouteParams>();
const location = useLocation();
const { tasksEnabled, isTaskMasterInstalled } = useTasksSettings();
const shouldShowTasksTab = Boolean(tasksEnabled && isTaskMasterInstalled);
const { plugins } = usePlugins();
@@ -66,10 +67,18 @@ export function MobileNav() {
const enabledPlugins = plugins.filter((plugin) => plugin.enabled);
const hasPlugins = enabledPlugins.length > 0;
const pluginName = useMemo(() => {
const params = new URLSearchParams(location.search);
return decodeValue(params.get('name') ?? undefined);
}, [location.search]);
const activeTab = useMemo<AppTab>(() => {
const routeTab = decodeValue(tab);
if (routeTab === 'plugins' && pluginName) {
return `plugin:${pluginName}` as AppTab;
}
return (routeTab || 'chat') as AppTab;
}, [tab]);
}, [pluginName, tab]);
const isPluginActive = activeTab.startsWith('plugin:');
useEffect(() => {
@@ -93,16 +102,20 @@ export function MobileNav() {
return;
}
const encodedTab = encodeURIComponent(nextTab);
const isPluginTab = nextTab.startsWith('plugin:');
const pluginTabName = isPluginTab ? nextTab.replace('plugin:', '') : '';
const targetTab = isPluginTab ? 'plugins' : nextTab;
const encodedTargetTab = encodeURIComponent(targetTab);
const pluginQuery = isPluginTab ? `?name=${encodeURIComponent(pluginTabName)}` : '';
const decodedSessionId = decodeValue(sessionId);
if (decodedSessionId) {
navigate(`/sessions/${encodeURIComponent(decodedSessionId)}/${encodedTab}`);
navigate(`/sessions/${encodeURIComponent(decodedSessionId)}/${encodedTargetTab}${pluginQuery}`);
return;
}
const encodedWorkspaceId = encodeURIComponent(decodeValue(workspaceId));
navigate(`/workspaces/${encodedWorkspaceId}/${encodedTab}`);
navigate(`/workspaces/${encodedWorkspaceId}/${encodedTargetTab}${pluginQuery}`);
};
const selectPlugin = (name: string) => {