mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-22 12:26:08 +00:00
perf: add component list in plugin detail dialog
This commit is contained in:
@@ -0,0 +1,75 @@
|
|||||||
|
import { PluginComponent } from '@/app/infra/entities/plugin';
|
||||||
|
import { TFunction } from 'i18next';
|
||||||
|
import { Wrench, AudioWaveform, Hash } from 'lucide-react';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
|
||||||
|
export default function PluginComponentList({
|
||||||
|
components,
|
||||||
|
showComponentName,
|
||||||
|
showTitle,
|
||||||
|
useBadge,
|
||||||
|
t,
|
||||||
|
}: {
|
||||||
|
components: PluginComponent[];
|
||||||
|
showComponentName: boolean;
|
||||||
|
showTitle: boolean;
|
||||||
|
useBadge: boolean;
|
||||||
|
t: TFunction;
|
||||||
|
}) {
|
||||||
|
const componentKindCount: Record<string, number> = {};
|
||||||
|
|
||||||
|
for (const component of components) {
|
||||||
|
const kind = component.manifest.manifest.kind;
|
||||||
|
if (componentKindCount[kind]) {
|
||||||
|
componentKindCount[kind]++;
|
||||||
|
} else {
|
||||||
|
componentKindCount[kind] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const kindIconMap: Record<string, React.ReactNode> = {
|
||||||
|
Tool: <Wrench className="w-5 h-5" />,
|
||||||
|
EventListener: <AudioWaveform className="w-5 h-5" />,
|
||||||
|
Command: <Hash className="w-5 h-5" />,
|
||||||
|
};
|
||||||
|
|
||||||
|
const componentKindList = Object.keys(componentKindCount);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{showTitle && <div>{t('plugins.componentsList')}</div>}
|
||||||
|
{componentKindList.length > 0 && (
|
||||||
|
<>
|
||||||
|
{componentKindList.map((kind) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{useBadge && (
|
||||||
|
<Badge variant="outline">
|
||||||
|
{kindIconMap[kind]}
|
||||||
|
{showComponentName &&
|
||||||
|
t('plugins.componentName.' + kind) + ' '}
|
||||||
|
{componentKindCount[kind]}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!useBadge && (
|
||||||
|
<div
|
||||||
|
key={kind}
|
||||||
|
className="flex flex-row items-center justify-start gap-[0.2rem]"
|
||||||
|
>
|
||||||
|
{kindIconMap[kind]}
|
||||||
|
{showComponentName &&
|
||||||
|
t('plugins.componentName.' + kind) + ' '}
|
||||||
|
{componentKindCount[kind]}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{componentKindList.length === 0 && <div>{t('plugins.noComponents')}</div>}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
import { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||||
import { PluginCardVO } from '@/app/home/plugins/plugin-installed/PluginCardVO';
|
import { PluginCardVO } from '@/app/home/plugins/components/plugin-installed/PluginCardVO';
|
||||||
import PluginCardComponent from '@/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent';
|
import PluginCardComponent from '@/app/home/plugins/components/plugin-installed/plugin-card/PluginCardComponent';
|
||||||
import PluginForm from '@/app/home/plugins/plugin-installed/plugin-form/PluginForm';
|
import PluginForm from '@/app/home/plugins/components/plugin-installed/plugin-form/PluginForm';
|
||||||
import styles from '@/app/home/plugins/plugins.module.css';
|
import styles from '@/app/home/plugins/plugins.module.css';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
import {
|
import {
|
||||||
+10
-57
@@ -1,21 +1,10 @@
|
|||||||
import { PluginCardVO } from '@/app/home/plugins/plugin-installed/PluginCardVO';
|
import { PluginCardVO } from '@/app/home/plugins/components/plugin-installed/PluginCardVO';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { TFunction } from 'i18next';
|
import { BugIcon, ExternalLink, Ellipsis, Trash, ArrowUp } from 'lucide-react';
|
||||||
import {
|
|
||||||
AudioWaveform,
|
|
||||||
Wrench,
|
|
||||||
Hash,
|
|
||||||
BugIcon,
|
|
||||||
ExternalLink,
|
|
||||||
Ellipsis,
|
|
||||||
Trash,
|
|
||||||
ArrowUp,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { getCloudServiceClientSync } from '@/app/infra/http';
|
import { getCloudServiceClientSync } from '@/app/infra/http';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
import { PluginComponent } from '@/app/infra/entities/plugin';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -23,49 +12,7 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
|
import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList';
|
||||||
function getComponentList(components: PluginComponent[], t: TFunction) {
|
|
||||||
const componentKindCount: Record<string, number> = {};
|
|
||||||
|
|
||||||
for (const component of components) {
|
|
||||||
const kind = component.manifest.manifest.kind;
|
|
||||||
if (componentKindCount[kind]) {
|
|
||||||
componentKindCount[kind]++;
|
|
||||||
} else {
|
|
||||||
componentKindCount[kind] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const kindIconMap: Record<string, React.ReactNode> = {
|
|
||||||
Tool: <Wrench className="w-5 h-5" />,
|
|
||||||
EventListener: <AudioWaveform className="w-5 h-5" />,
|
|
||||||
Command: <Hash className="w-5 h-5" />,
|
|
||||||
};
|
|
||||||
|
|
||||||
const componentKindList = Object.keys(componentKindCount);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div>{t('plugins.componentsList')}</div>
|
|
||||||
{componentKindList.length > 0 && (
|
|
||||||
<>
|
|
||||||
{componentKindList.map((kind) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={kind}
|
|
||||||
className="flex flex-row items-center justify-start gap-[0.4rem]"
|
|
||||||
>
|
|
||||||
{kindIconMap[kind]} {componentKindCount[kind]}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{componentKindList.length === 0 && <div>{t('plugins.noComponents')}</div>}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PluginCardComponent({
|
export default function PluginCardComponent({
|
||||||
cardVO,
|
cardVO,
|
||||||
@@ -180,7 +127,13 @@ export default function PluginCardComponent({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex flex-row items-start justify-start gap-[0.6rem]">
|
<div className="w-full flex flex-row items-start justify-start gap-[0.6rem]">
|
||||||
{getComponentList(cardVO.components, t)}
|
<PluginComponentList
|
||||||
|
components={cardVO.components}
|
||||||
|
showComponentName={false}
|
||||||
|
showTitle={true}
|
||||||
|
useBadge={false}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
+12
@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { extractI18nObject } from '@/i18n/I18nProvider';
|
import { extractI18nObject } from '@/i18n/I18nProvider';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList';
|
||||||
|
|
||||||
export default function PluginForm({
|
export default function PluginForm({
|
||||||
pluginAuthor,
|
pluginAuthor,
|
||||||
@@ -78,6 +79,17 @@ export default function PluginForm({
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-4 flex flex-row items-center justify-start gap-[0.4rem]">
|
||||||
|
<PluginComponentList
|
||||||
|
components={pluginInfo.components}
|
||||||
|
showComponentName={true}
|
||||||
|
showTitle={false}
|
||||||
|
useBadge={true}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{pluginInfo.manifest.manifest.spec.config.length > 0 && (
|
{pluginInfo.manifest.manifest.spec.config.length > 0 && (
|
||||||
<DynamicFormComponent
|
<DynamicFormComponent
|
||||||
itemConfigList={pluginInfo.manifest.manifest.spec.config}
|
itemConfigList={pluginInfo.manifest.manifest.spec.config}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import PluginInstalledComponent, {
|
import PluginInstalledComponent, {
|
||||||
PluginInstalledComponentRef,
|
PluginInstalledComponentRef,
|
||||||
} from '@/app/home/plugins/plugin-installed/PluginInstalledComponent';
|
} from '@/app/home/plugins/components/plugin-installed/PluginInstalledComponent';
|
||||||
import MarketPage from '@/app/home/plugins/plugin-market/PluginMarketComponent';
|
import MarketPage from '@/app/home/plugins/components/plugin-market/PluginMarketComponent';
|
||||||
|
|
||||||
import MCPServerComponent from '@/app/home/plugins/mcp-server/MCPServerComponent';
|
import MCPServerComponent from '@/app/home/plugins/mcp-server/MCPServerComponent';
|
||||||
import MCPFormDialog from '@/app/home/plugins/mcp-server/mcp-form/MCPFormDialog';
|
import MCPFormDialog from '@/app/home/plugins/mcp-server/mcp-form/MCPFormDialog';
|
||||||
import MCPDeleteConfirmDialog from '@/app/home/plugins/mcp-server/mcp-form/MCPDeleteConfirmDialog';
|
import MCPDeleteConfirmDialog from '@/app/home/plugins/mcp-server/mcp-form/MCPDeleteConfirmDialog';
|
||||||
|
|||||||
@@ -206,9 +206,11 @@ const enUS = {
|
|||||||
deleteConfirm: 'Delete Confirmation',
|
deleteConfirm: 'Delete Confirmation',
|
||||||
deleteSuccess: 'Delete successful',
|
deleteSuccess: 'Delete successful',
|
||||||
modifyFailed: 'Modify failed: ',
|
modifyFailed: 'Modify failed: ',
|
||||||
eventCount: 'Events: {{count}}',
|
componentName: {
|
||||||
toolCount: 'Tools: {{count}}',
|
Tool: 'Tool',
|
||||||
starCount: 'Stars: {{count}}',
|
EventListener: 'Event Listener',
|
||||||
|
Command: 'Command',
|
||||||
|
},
|
||||||
uploadLocal: 'Upload Local',
|
uploadLocal: 'Upload Local',
|
||||||
debugging: 'Debugging',
|
debugging: 'Debugging',
|
||||||
uploadLocalPlugin: 'Upload Local Plugin',
|
uploadLocalPlugin: 'Upload Local Plugin',
|
||||||
|
|||||||
@@ -207,9 +207,11 @@ const jaJP = {
|
|||||||
deleteConfirm: '削除の確認',
|
deleteConfirm: '削除の確認',
|
||||||
deleteSuccess: '削除に成功しました',
|
deleteSuccess: '削除に成功しました',
|
||||||
modifyFailed: '変更に失敗しました:',
|
modifyFailed: '変更に失敗しました:',
|
||||||
eventCount: 'イベント:{{count}}',
|
componentName: {
|
||||||
toolCount: 'ツール:{{count}}',
|
Tool: 'ツール',
|
||||||
starCount: 'スター:{{count}}',
|
EventListener: 'イベント監視器',
|
||||||
|
Command: 'コマンド',
|
||||||
|
},
|
||||||
uploadLocal: 'ローカルアップロード',
|
uploadLocal: 'ローカルアップロード',
|
||||||
debugging: 'デバッグ中',
|
debugging: 'デバッグ中',
|
||||||
uploadLocalPlugin: 'ローカルプラグインのアップロード',
|
uploadLocalPlugin: 'ローカルプラグインのアップロード',
|
||||||
|
|||||||
@@ -199,9 +199,11 @@ const zhHans = {
|
|||||||
deleteConfirm: '删除确认',
|
deleteConfirm: '删除确认',
|
||||||
deleteSuccess: '删除成功',
|
deleteSuccess: '删除成功',
|
||||||
modifyFailed: '修改失败:',
|
modifyFailed: '修改失败:',
|
||||||
eventCount: '事件:{{count}}',
|
componentName: {
|
||||||
toolCount: '工具:{{count}}',
|
Tool: '工具',
|
||||||
starCount: '星标:{{count}}',
|
EventListener: '事件监听器',
|
||||||
|
Command: '命令',
|
||||||
|
},
|
||||||
uploadLocal: '本地上传',
|
uploadLocal: '本地上传',
|
||||||
debugging: '调试中',
|
debugging: '调试中',
|
||||||
uploadLocalPlugin: '上传本地插件',
|
uploadLocalPlugin: '上传本地插件',
|
||||||
|
|||||||
@@ -197,9 +197,11 @@ const zhHant = {
|
|||||||
close: '關閉',
|
close: '關閉',
|
||||||
deleteConfirm: '刪除確認',
|
deleteConfirm: '刪除確認',
|
||||||
modifyFailed: '修改失敗:',
|
modifyFailed: '修改失敗:',
|
||||||
eventCount: '事件:{{count}}',
|
componentName: {
|
||||||
toolCount: '工具:{{count}}',
|
Tool: '工具',
|
||||||
starCount: '星標:{{count}}',
|
EventListener: '事件監聽器',
|
||||||
|
Command: '命令',
|
||||||
|
},
|
||||||
uploadLocal: '本地上傳',
|
uploadLocal: '本地上傳',
|
||||||
debugging: '調試中',
|
debugging: '調試中',
|
||||||
uploadLocalPlugin: '上傳本地插件',
|
uploadLocalPlugin: '上傳本地插件',
|
||||||
|
|||||||
Reference in New Issue
Block a user