mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-16 17:36:07 +00:00
feat(sidebar): add group-by-type toggle to installed extensions section
- Add group-by-type button to extensions category header (mirrors the agent group-by-kind pattern) — syncs with the extensions page Switch via shared SidebarDataContext state - Relocate both group and refresh controls to sit left-aligned immediately after the title for both Agent and Extensions sections - Add plugins.groupByTypeShort i18n key to all 8 locales Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
huanghuoguoguo
parent
1a3599eb7a
commit
0027ea8f68
@@ -34,7 +34,7 @@ import {
|
|||||||
RefreshCcw,
|
RefreshCcw,
|
||||||
Bot,
|
Bot,
|
||||||
Workflow,
|
Workflow,
|
||||||
Group,
|
ListTree,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useTheme } from '@/components/providers/theme-provider';
|
import { useTheme } from '@/components/providers/theme-provider';
|
||||||
|
|
||||||
@@ -1112,42 +1112,69 @@ function NavItems({
|
|||||||
<span className="cursor-pointer select-none">
|
<span className="cursor-pointer select-none">
|
||||||
{config.name}
|
{config.name}
|
||||||
</span>
|
</span>
|
||||||
<div className="ml-auto flex items-center gap-0.5 -mr-1">
|
{/* Group/refresh controls — left-aligned, hugging the title */}
|
||||||
{isAgents && (
|
{(isAgents || isExtensionsCategory) && (
|
||||||
<button
|
<div className="flex items-center gap-0.5">
|
||||||
type="button"
|
{isAgents && (
|
||||||
title={t('agents.groupByKind')}
|
<button
|
||||||
className={cn(
|
type="button"
|
||||||
'p-1 rounded-sm transition-all',
|
title={t('agents.groupByKind')}
|
||||||
sidebarData.agentsGroupByKind
|
|
||||||
? 'text-sidebar-accent-foreground bg-sidebar-accent'
|
|
||||||
: 'text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [@media(hover:hover)]:opacity-0 group-hover/category-header:opacity-100',
|
|
||||||
)}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
sidebarData.setAgentsGroupByKind(
|
|
||||||
!sidebarData.agentsGroupByKind,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Group className="size-3.5" />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{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(
|
className={cn(
|
||||||
'size-3.5',
|
'flex items-center gap-1 px-1.5 py-1 rounded-sm text-[10px] transition-all',
|
||||||
extRefreshing && 'animate-spin',
|
sidebarData.agentsGroupByKind
|
||||||
|
? 'text-sidebar-accent-foreground bg-sidebar-accent'
|
||||||
|
: 'text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
||||||
)}
|
)}
|
||||||
/>
|
onClick={(e) => {
|
||||||
</button>
|
e.stopPropagation();
|
||||||
)}
|
sidebarData.setAgentsGroupByKind(
|
||||||
|
!sidebarData.agentsGroupByKind,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListTree className="size-3.5" />
|
||||||
|
<span>{t('agents.groupByKindShort')}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{isExtensionsCategory && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
title={t('plugins.groupByType')}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-1 px-1.5 py-1 rounded-sm text-[10px] transition-all',
|
||||||
|
sidebarData.extensionsGroupByType
|
||||||
|
? 'text-sidebar-accent-foreground bg-sidebar-accent'
|
||||||
|
: 'text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
sidebarData.setExtensionsGroupByType(
|
||||||
|
!sidebarData.extensionsGroupByType,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListTree className="size-3.5" />
|
||||||
|
<span>{t('plugins.groupByTypeShort')}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{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>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="ml-auto flex items-center gap-0.5 -mr-1">
|
||||||
{canCreate &&
|
{canCreate &&
|
||||||
(isPlugin ? (
|
(isPlugin ? (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
@@ -540,6 +540,7 @@ const enUS = {
|
|||||||
kindBadgeAgent: 'Agent',
|
kindBadgeAgent: 'Agent',
|
||||||
kindBadgePipeline: 'Pipeline',
|
kindBadgePipeline: 'Pipeline',
|
||||||
groupByKind: 'Group by type',
|
groupByKind: 'Group by type',
|
||||||
|
groupByKindShort: 'Group',
|
||||||
pipelineTypeDescription:
|
pipelineTypeDescription:
|
||||||
'Keep the existing no-code message pipeline for backward compatibility. It only handles message events.',
|
'Keep the existing no-code message pipeline for backward compatibility. It only handles message events.',
|
||||||
allEvents: 'Supports all EBA events',
|
allEvents: 'Supports all EBA events',
|
||||||
@@ -602,6 +603,7 @@ const enUS = {
|
|||||||
noExtensionInstalled: 'No extensions installed',
|
noExtensionInstalled: 'No extensions installed',
|
||||||
loadingExtensions: 'Loading extensions...',
|
loadingExtensions: 'Loading extensions...',
|
||||||
groupByType: 'Group by format',
|
groupByType: 'Group by format',
|
||||||
|
groupByTypeShort: 'Group',
|
||||||
pluginConfig: 'Plugin Configuration',
|
pluginConfig: 'Plugin Configuration',
|
||||||
pluginSort: 'Plugin Sort',
|
pluginSort: 'Plugin Sort',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -506,6 +506,7 @@ const esES = {
|
|||||||
noExtensionInstalled: 'No hay extensiones instaladas',
|
noExtensionInstalled: 'No hay extensiones instaladas',
|
||||||
loadingExtensions: 'Cargando extensiones...',
|
loadingExtensions: 'Cargando extensiones...',
|
||||||
groupByType: 'Agrupar por formato',
|
groupByType: 'Agrupar por formato',
|
||||||
|
groupByTypeShort: 'Agrupar',
|
||||||
pluginConfig: 'Configuración del plugin',
|
pluginConfig: 'Configuración del plugin',
|
||||||
pluginSort: 'Orden de plugins',
|
pluginSort: 'Orden de plugins',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ const jaJP = {
|
|||||||
kindBadgeAgent: 'Agent',
|
kindBadgeAgent: 'Agent',
|
||||||
kindBadgePipeline: 'パイプライン',
|
kindBadgePipeline: 'パイプライン',
|
||||||
groupByKind: 'タイプ別にグループ化',
|
groupByKind: 'タイプ別にグループ化',
|
||||||
|
groupByKindShort: 'グループ',
|
||||||
pipelineTypeDescription:
|
pipelineTypeDescription:
|
||||||
'既存のノーコードメッセージ Pipeline を互換性のため保持します。メッセージイベントのみ処理できます。',
|
'既存のノーコードメッセージ Pipeline を互換性のため保持します。メッセージイベントのみ処理できます。',
|
||||||
allEvents: 'すべての EBA イベントに対応',
|
allEvents: 'すべての EBA イベントに対応',
|
||||||
@@ -584,6 +585,7 @@ const jaJP = {
|
|||||||
noExtensionInstalled: '拡張機能がインストールされていません',
|
noExtensionInstalled: '拡張機能がインストールされていません',
|
||||||
loadingExtensions: '拡張機能を読み込み中...',
|
loadingExtensions: '拡張機能を読み込み中...',
|
||||||
groupByType: '形式でグループ化',
|
groupByType: '形式でグループ化',
|
||||||
|
groupByTypeShort: 'グループ',
|
||||||
pluginConfig: 'プラグイン設定',
|
pluginConfig: 'プラグイン設定',
|
||||||
pluginSort: 'プラグインの並び替え',
|
pluginSort: 'プラグインの並び替え',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -505,6 +505,7 @@ const ruRU = {
|
|||||||
noExtensionInstalled: 'Расширения не установлены',
|
noExtensionInstalled: 'Расширения не установлены',
|
||||||
loadingExtensions: 'Загрузка расширений...',
|
loadingExtensions: 'Загрузка расширений...',
|
||||||
groupByType: 'Группировать по формату',
|
groupByType: 'Группировать по формату',
|
||||||
|
groupByTypeShort: 'Группа',
|
||||||
pluginConfig: 'Настройка плагина',
|
pluginConfig: 'Настройка плагина',
|
||||||
pluginSort: 'Порядок плагинов',
|
pluginSort: 'Порядок плагинов',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -490,6 +490,7 @@ const thTH = {
|
|||||||
noExtensionInstalled: 'ยังไม่มีส่วนขยายที่ติดตั้ง',
|
noExtensionInstalled: 'ยังไม่มีส่วนขยายที่ติดตั้ง',
|
||||||
loadingExtensions: 'กำลังโหลดส่วนขยาย...',
|
loadingExtensions: 'กำลังโหลดส่วนขยาย...',
|
||||||
groupByType: 'จัดกลุ่มตามรูปแบบ',
|
groupByType: 'จัดกลุ่มตามรูปแบบ',
|
||||||
|
groupByTypeShort: 'จัดกลุ่ม',
|
||||||
pluginConfig: 'การกำหนดค่าปลั๊กอิน',
|
pluginConfig: 'การกำหนดค่าปลั๊กอิน',
|
||||||
pluginSort: 'เรียงลำดับปลั๊กอิน',
|
pluginSort: 'เรียงลำดับปลั๊กอิน',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -500,6 +500,7 @@ const viVN = {
|
|||||||
noExtensionInstalled: 'Chưa cài đặt tiện ích mở rộng nào',
|
noExtensionInstalled: 'Chưa cài đặt tiện ích mở rộng nào',
|
||||||
loadingExtensions: 'Đang tải tiện ích mở rộng...',
|
loadingExtensions: 'Đang tải tiện ích mở rộng...',
|
||||||
groupByType: 'Nhóm theo định dạng',
|
groupByType: 'Nhóm theo định dạng',
|
||||||
|
groupByTypeShort: 'Nhóm',
|
||||||
pluginConfig: 'Cấu hình Plugin',
|
pluginConfig: 'Cấu hình Plugin',
|
||||||
pluginSort: 'Sắp xếp Plugin',
|
pluginSort: 'Sắp xếp Plugin',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
|
|||||||
@@ -519,6 +519,7 @@ const zhHans = {
|
|||||||
kindBadgeAgent: 'Agent',
|
kindBadgeAgent: 'Agent',
|
||||||
kindBadgePipeline: '流水线',
|
kindBadgePipeline: '流水线',
|
||||||
groupByKind: '按类型分组',
|
groupByKind: '按类型分组',
|
||||||
|
groupByKindShort: '分组',
|
||||||
pipelineTypeDescription:
|
pipelineTypeDescription:
|
||||||
'保留现有无代码消息流水线,兼容旧配置,只能处理消息事件。',
|
'保留现有无代码消息流水线,兼容旧配置,只能处理消息事件。',
|
||||||
allEvents: '支持全部 EBA 事件',
|
allEvents: '支持全部 EBA 事件',
|
||||||
@@ -578,6 +579,7 @@ const zhHans = {
|
|||||||
noExtensionInstalled: '暂未安装任何扩展',
|
noExtensionInstalled: '暂未安装任何扩展',
|
||||||
loadingExtensions: '正在加载扩展...',
|
loadingExtensions: '正在加载扩展...',
|
||||||
groupByType: '按格式分组',
|
groupByType: '按格式分组',
|
||||||
|
groupByTypeShort: '分组',
|
||||||
pluginSort: '插件排序',
|
pluginSort: '插件排序',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
'插件顺序会影响同一事件内的处理顺序,请拖动插件卡片排序',
|
'插件顺序会影响同一事件内的处理顺序,请拖动插件卡片排序',
|
||||||
|
|||||||
@@ -476,6 +476,7 @@ const zhHant = {
|
|||||||
noExtensionInstalled: '暫未安裝任何擴充功能',
|
noExtensionInstalled: '暫未安裝任何擴充功能',
|
||||||
loadingExtensions: '正在載入擴充功能...',
|
loadingExtensions: '正在載入擴充功能...',
|
||||||
groupByType: '依格式分組',
|
groupByType: '依格式分組',
|
||||||
|
groupByTypeShort: '分組',
|
||||||
pluginSort: '外掛排序',
|
pluginSort: '外掛排序',
|
||||||
pluginSortDescription:
|
pluginSortDescription:
|
||||||
'外掛順序會影響同一事件內的處理順序,請拖曳外掛卡片排序',
|
'外掛順序會影響同一事件內的處理順序,請拖曳外掛卡片排序',
|
||||||
|
|||||||
Reference in New Issue
Block a user