From 003fbee20f74d55bd00ab3f108bad9374d3c031e Mon Sep 17 00:00:00 2001 From: curo1305 Date: Sat, 18 Apr 2026 02:31:12 +0200 Subject: [PATCH] Move plugin settings access from sidebar to app card Remove the "Extensions" section from the sidebar nav. Instead, each app card on the Apps page shows an "Extension" button when the current user has access to that app's plugin (matched by service ID). The button links to /settings/plugins/:id alongside the existing admin Settings button. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 2 +- frontend/STATUS.md | 10 +++---- frontend/src/components/Sidebar.tsx | 45 +---------------------------- frontend/src/pages/AppsPage.tsx | 25 +++++++++++++++- 4 files changed, 31 insertions(+), 51 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 95aeb13..c91b3c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -169,7 +169,7 @@ docker compose up --build -d │ │ └── useTheme.ts ← Theme toggle │ ├── components/ │ │ ├── AppShell.tsx ← Layout: Sidebar + scrollable main - │ │ ├── Sidebar.tsx ← Collapsible nav; "Extensions" section auto-populated from /api/plugins + │ │ ├── Sidebar.tsx ← Collapsible nav (icons ↔ icons+labels) │ │ ├── ThemeToggle.tsx ← Light/dark mode toggle │ │ ├── PluginSchemaForm.tsx ← JSON Schema → React form (boolean/string/number/readOnly) │ │ └── ui/ ← shadcn/ui components (Button, Input, …) diff --git a/frontend/STATUS.md b/frontend/STATUS.md index e6cd707..59e1eda 100644 --- a/frontend/STATUS.md +++ b/frontend/STATUS.md @@ -61,11 +61,11 @@ Cards are rendered dynamically from `GET /api/services` (polled every 30 s via T - Sections auto-open when navigating to their route - In collapsed (icons-only) mode, clicking the Apps icon navigates to `/apps` -**Extensions** section (dynamic): -- Populated from `GET /api/plugins` (polled via TanStack Query, `retry: false`) -- Only shown when the user has access to at least one plugin -- Each entry links to `/settings/plugins/:id` -- No code changes needed to add future plugin-enabled feature containers +**App cards — Extension button:** +- `GET /api/plugins` is queried on the Apps page (already user-filtered by backend) +- If an app's `id` matches a plugin `id`, an "Extension" button is shown on that card +- Button links to `/settings/plugins/:id` alongside the existing admin "Settings" button +- Only users with plugin access see the button (backend filters `GET /api/plugins`) ### Documents page (`/apps/documents`) diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 707cdc4..7cdb440 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -16,12 +16,11 @@ import { Users, UsersRound, Palette, - Puzzle, } from "lucide-react"; import { Button } from "@/components/ui/button"; import ThemeToggle from "@/components/ThemeToggle"; import { useAuth } from "@/hooks/useAuth"; -import { getMe, getPlugins, listCategories } from "@/api/client"; +import { getMe, listCategories } from "@/api/client"; import { cn } from "@/lib/utils"; export default function Sidebar() { @@ -57,14 +56,6 @@ export default function Sidebar() { enabled: appsOpen && docsOpen && !!user, }); - const { data: plugins = [] } = useQuery({ - queryKey: ["plugins"], - queryFn: getPlugins, - enabled: !!user, - // Empty array on 404/error — regular users simply see no plugins - retry: false, - }); - const navItemClass = (isActive: boolean) => cn( "flex items-center rounded-lg transition-colors", @@ -218,40 +209,6 @@ export default function Sidebar() { )} - {/* Extensions — visible only when the user has accessible plugins */} - {plugins.length > 0 && ( -
- {sidebarExpanded ? ( - <> -
- - Extensions - -
-
- {plugins.map((plugin) => ( - subItemClass(isActive)} - > - - {plugin.name} - - ))} -
- - ) : ( - navItemClass(isActive)} - > - - - )} -
- )} - {/* Admin — expandable */} {user?.is_admin && (
diff --git a/frontend/src/pages/AppsPage.tsx b/frontend/src/pages/AppsPage.tsx index ef367b7..eb0f458 100644 --- a/frontend/src/pages/AppsPage.tsx +++ b/frontend/src/pages/AppsPage.tsx @@ -1,6 +1,6 @@ import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; -import { getMe, getServices } from "../api/client"; +import { getMe, getPlugins, getServices } from "../api/client"; const cardBase: React.CSSProperties = { backgroundColor: "rgb(var(--color-surface))", @@ -34,6 +34,12 @@ export default function AppsPage() { refetchInterval: 30_000, refetchIntervalInBackground: true, }); + const { data: plugins = [] } = useQuery({ + queryKey: ["plugins"], + queryFn: getPlugins, + retry: false, + }); + const pluginIds = new Set(plugins.map((p) => p.id)); return (
@@ -93,6 +99,23 @@ export default function AppsPage() { Settings )} + {pluginIds.has(svc.id) && ( + e.stopPropagation()} + style={{ + padding: "6px 14px", + border: "1px solid #ccc", + borderRadius: 4, + textDecoration: "none", + fontSize: 14, + color: "#333", + }} + title="Extension settings" + > + Extension + + )}
);