mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-17 18:06:06 +00:00
feat(web): sidebar extensions refresh button + full-name tooltip
- Add a refresh button to the installed-extensions category header in the sidebar; it re-fetches plugins + MCP servers + skills and spins while loading. - The sidebar item tooltip now shows the extension's full name (with the description below when present), so truncated MCP/extension names are readable on hover. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
|||||||
HardDrive,
|
HardDrive,
|
||||||
Server,
|
Server,
|
||||||
Puzzle,
|
Puzzle,
|
||||||
|
RefreshCcw,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useTheme } from '@/components/providers/theme-provider';
|
import { useTheme } from '@/components/providers/theme-provider';
|
||||||
|
|
||||||
@@ -325,6 +326,23 @@ function NavItems({
|
|||||||
);
|
);
|
||||||
// Track popover open state for collapsed sidebar entity categories
|
// Track popover open state for collapsed sidebar entity categories
|
||||||
const [popoverOpen, setPopoverOpen] = useState<Record<string, boolean>>({});
|
const [popoverOpen, setPopoverOpen] = useState<Record<string, boolean>>({});
|
||||||
|
// Spin state for the installed-extensions refresh button
|
||||||
|
const [extRefreshing, setExtRefreshing] = useState(false);
|
||||||
|
|
||||||
|
const handleRefreshExtensions = async (e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (extRefreshing) return;
|
||||||
|
setExtRefreshing(true);
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
sidebarData.refreshPlugins(),
|
||||||
|
sidebarData.refreshMCPServers(),
|
||||||
|
sidebarData.refreshSkills(),
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
setExtRefreshing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Plugin operation state
|
// Plugin operation state
|
||||||
const [showPluginOpModal, setShowPluginOpModal] = useState(false);
|
const [showPluginOpModal, setShowPluginOpModal] = useState(false);
|
||||||
@@ -694,17 +712,21 @@ function NavItems({
|
|||||||
</a>
|
</a>
|
||||||
</SidebarMenuSubButton>
|
</SidebarMenuSubButton>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
{item.description && (
|
<TooltipContent
|
||||||
<TooltipContent
|
side="right"
|
||||||
side="right"
|
align="center"
|
||||||
align="center"
|
className="max-w-64"
|
||||||
className="max-w-64"
|
>
|
||||||
>
|
{/* Full name — so truncated sidebar items are readable on hover */}
|
||||||
{item.description.length > 80
|
<div className="break-words font-medium">{item.name}</div>
|
||||||
? item.description.slice(0, 80) + '…'
|
{item.description && (
|
||||||
: item.description}
|
<div className="mt-0.5 break-words text-xs text-muted-foreground">
|
||||||
</TooltipContent>
|
{item.description.length > 80
|
||||||
)}
|
? item.description.slice(0, 80) + '…'
|
||||||
|
: item.description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{/* Plugin context menu - shown on hover (not for debug plugins) */}
|
{/* Plugin context menu - shown on hover (not for debug plugins) */}
|
||||||
{itemIsPluginType && !item.debug && (
|
{itemIsPluginType && !item.debug && (
|
||||||
@@ -973,6 +995,21 @@ function NavItems({
|
|||||||
{config.name}
|
{config.name}
|
||||||
</span>
|
</span>
|
||||||
<div className="ml-auto flex items-center gap-0.5 -mr-1">
|
<div className="ml-auto flex items-center gap-0.5 -mr-1">
|
||||||
|
{isExtensionsCategory && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title={t('common.refresh', '刷新')}
|
||||||
|
className="p-1 rounded-sm text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [@media(hover:hover)]:opacity-0 group-hover/category-header:opacity-100 transition-all"
|
||||||
|
onClick={handleRefreshExtensions}
|
||||||
|
>
|
||||||
|
<RefreshCcw
|
||||||
|
className={cn(
|
||||||
|
'size-3.5',
|
||||||
|
extRefreshing && 'animate-spin',
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
{canCreate &&
|
{canCreate &&
|
||||||
(isPlugin ? (
|
(isPlugin ? (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
Reference in New Issue
Block a user