feat(dashboard): add hide/show toggle for dashboard plugins in sidebar

- New config key: dashboard.hidden_plugins (list of plugin names)
- GET /api/dashboard/plugins now filters out hidden plugins from sidebar
- POST /api/dashboard/plugins/{name}/visibility toggles visibility
- Hub response includes user_hidden boolean per plugin row
- Eye/EyeOff toggle on plugin cards with dashboard manifests
- i18n: 'Show in sidebar' / 'Hide from sidebar' (en/zh)
This commit is contained in:
Austin Pickett 2026-04-30 20:02:15 -04:00
parent a52363231f
commit c73b799de7
6 changed files with 77 additions and 3 deletions

View file

@ -295,6 +295,8 @@ export const en: Translations = {
authRequiredHint: "Run this command to authenticate:",
updateGit: "Git pull",
versionBadge: "Version",
showInSidebar: "Show in sidebar",
hideFromSidebar: "Hide from sidebar",
},
skills: {

View file

@ -266,6 +266,8 @@ export interface Translations {
authRequiredHint: string;
updateGit: string;
versionBadge: string;
showInSidebar: string;
hideFromSidebar: string;
};
// ── Profiles page ──

View file

@ -291,6 +291,8 @@ export const zh: Translations = {
authRequiredHint: "运行此命令以完成认证:",
updateGit: "git pull",
versionBadge: "版本",
showInSidebar: "在侧边栏显示",
hideFromSidebar: "从侧边栏隐藏",
},
skills: {

View file

@ -299,6 +299,16 @@ export const api = {
body: JSON.stringify(body),
}),
setPluginVisibility: (name: string, hidden: boolean) =>
fetchJSON<{ ok: boolean; name: string; hidden: boolean }>(
`/api/dashboard/plugins/${encodeURIComponent(name)}/visibility`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ hidden }),
},
),
// Dashboard themes
getThemes: () =>
fetchJSON<DashboardThemesResponse>("/api/dashboard/themes"),
@ -728,6 +738,7 @@ export interface HubAgentPluginRow {
can_update_git: boolean;
auth_required: boolean;
auth_command: string;
user_hidden: boolean;
}
export interface PluginsHubProviders {

View file

@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { ExternalLink, RefreshCw, Puzzle, Trash2 } from "lucide-react";
import { ExternalLink, RefreshCw, Puzzle, Trash2, Eye, EyeOff } from "lucide-react";
import type { Translations } from "@/i18n/types";
import { Link } from "react-router-dom";
import { api } from "@/lib/api";
@ -504,6 +504,27 @@ function PluginRowCard(props: PluginRowCardProps) {
</Button>
) : null}
{row.has_dashboard_manifest ? (
<Button
disabled={busy}
ghost
size="sm"
title={row.user_hidden ? t.pluginsPage.showInSidebar : t.pluginsPage.hideFromSidebar}
onClick={() => {
void setRuntimeLoading(row.name, async () => {
await api.setPluginVisibility(row.name, !row.user_hidden);
});
}}
>
{row.user_hidden ? (
<EyeOff className="h-3.5 w-3.5" />
) : (
<Eye className="h-3.5 w-3.5" />
)}
{row.user_hidden ? t.pluginsPage.showInSidebar : t.pluginsPage.hideFromSidebar}
</Button>
) : null}
{row.can_remove ? (