mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-30 14:17:14 +00:00
feat: add mcp and skills
This commit is contained in:
@@ -14,6 +14,7 @@ export interface IPluginCardVO {
|
|||||||
components: PluginComponent[];
|
components: PluginComponent[];
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
hasUpdate?: boolean;
|
hasUpdate?: boolean;
|
||||||
|
type?: 'plugin' | 'mcp' | 'skill';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PluginCardVO implements IPluginCardVO {
|
export class PluginCardVO implements IPluginCardVO {
|
||||||
@@ -30,6 +31,7 @@ export class PluginCardVO implements IPluginCardVO {
|
|||||||
status: string;
|
status: string;
|
||||||
components: PluginComponent[];
|
components: PluginComponent[];
|
||||||
hasUpdate?: boolean;
|
hasUpdate?: boolean;
|
||||||
|
type?: 'plugin' | 'mcp' | 'skill';
|
||||||
|
|
||||||
constructor(prop: IPluginCardVO) {
|
constructor(prop: IPluginCardVO) {
|
||||||
this.author = prop.author;
|
this.author = prop.author;
|
||||||
@@ -45,5 +47,6 @@ export class PluginCardVO implements IPluginCardVO {
|
|||||||
this.install_source = prop.install_source;
|
this.install_source = prop.install_source;
|
||||||
this.install_info = prop.install_info;
|
this.install_info = prop.install_info;
|
||||||
this.hasUpdate = prop.hasUpdate;
|
this.hasUpdate = prop.hasUpdate;
|
||||||
|
this.type = prop.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ const PluginInstalledComponent = forwardRef<PluginInstalledComponentRef>(
|
|||||||
|
|
||||||
// 转换并比较版本号
|
// 转换并比较版本号
|
||||||
const pluginCards = installedPlugins.map((plugin) => {
|
const pluginCards = installedPlugins.map((plugin) => {
|
||||||
|
const marketplaceKey = `${plugin.manifest.manifest.metadata.author}/${plugin.manifest.manifest.metadata.name}`;
|
||||||
|
const marketplacePlugin = marketplacePluginMap.get(marketplaceKey);
|
||||||
const cardVO = new PluginCardVO({
|
const cardVO = new PluginCardVO({
|
||||||
author: plugin.manifest.manifest.metadata.author ?? '',
|
author: plugin.manifest.manifest.metadata.author ?? '',
|
||||||
label: extractI18nObject(plugin.manifest.manifest.metadata.label),
|
label: extractI18nObject(plugin.manifest.manifest.metadata.label),
|
||||||
@@ -106,13 +108,12 @@ const PluginInstalledComponent = forwardRef<PluginInstalledComponentRef>(
|
|||||||
priority: plugin.priority,
|
priority: plugin.priority,
|
||||||
install_source: plugin.install_source,
|
install_source: plugin.install_source,
|
||||||
install_info: plugin.install_info,
|
install_info: plugin.install_info,
|
||||||
|
type: marketplacePlugin?.type,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 检查是否来自市场且有更新
|
// 检查是否来自市场且有更新
|
||||||
if (cardVO.install_source === 'marketplace') {
|
if (cardVO.install_source === 'marketplace' && marketplacePlugin) {
|
||||||
const marketplaceKey = `${cardVO.author}/${cardVO.name}`;
|
if (marketplacePlugin.latest_version) {
|
||||||
const marketplacePlugin = marketplacePluginMap.get(marketplaceKey);
|
|
||||||
if (marketplacePlugin && marketplacePlugin.latest_version) {
|
|
||||||
cardVO.hasUpdate = isNewerVersion(
|
cardVO.hasUpdate = isNewerVersion(
|
||||||
marketplacePlugin.latest_version,
|
marketplacePlugin.latest_version,
|
||||||
cardVO.version,
|
cardVO.version,
|
||||||
|
|||||||
+18
@@ -60,6 +60,24 @@ export default function PluginCardComponent({
|
|||||||
>
|
>
|
||||||
v{cardVO.version}
|
v{cardVO.version}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
{cardVO.type && (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={`text-[0.7rem] flex-shrink-0 ${
|
||||||
|
cardVO.type === 'mcp'
|
||||||
|
? 'border-sky-500 text-sky-600 dark:border-sky-400 dark:text-sky-300'
|
||||||
|
: cardVO.type === 'skill'
|
||||||
|
? 'border-emerald-500 text-emerald-600 dark:border-emerald-400 dark:text-emerald-300'
|
||||||
|
: 'border-violet-500 text-violet-600 dark:border-violet-400 dark:text-violet-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{cardVO.type === 'mcp'
|
||||||
|
? 'MCP'
|
||||||
|
: cardVO.type === 'skill'
|
||||||
|
? t('common.skill')
|
||||||
|
: t('market.typePlugin')}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
{cardVO.debug && (
|
{cardVO.debug && (
|
||||||
<Badge
|
<Badge
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ function MarketPageContent({
|
|||||||
'Parser',
|
'Parser',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const validTypes = ['plugin', 'mcp', 'skill'];
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [componentFilter, setComponentFilter] = useState<string>(() => {
|
const [componentFilter, setComponentFilter] = useState<string>(() => {
|
||||||
const category = searchParams.get('category');
|
const category = searchParams.get('category');
|
||||||
@@ -63,6 +65,13 @@ function MarketPageContent({
|
|||||||
}
|
}
|
||||||
return 'all';
|
return 'all';
|
||||||
});
|
});
|
||||||
|
const [typeFilter, setTypeFilter] = useState<string>(() => {
|
||||||
|
const type = searchParams.get('type');
|
||||||
|
if (type && validTypes.includes(type)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
return 'all';
|
||||||
|
});
|
||||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||||
const [availableTags, setAvailableTags] = useState<PluginTag[]>([]);
|
const [availableTags, setAvailableTags] = useState<PluginTag[]>([]);
|
||||||
const [tagNames, setTagNames] = useState<Record<string, string>>({});
|
const [tagNames, setTagNames] = useState<Record<string, string>>({});
|
||||||
@@ -136,6 +145,7 @@ function MarketPageContent({
|
|||||||
version: plugin.latest_version,
|
version: plugin.latest_version,
|
||||||
components: plugin.components,
|
components: plugin.components,
|
||||||
tags: plugin.tags || [],
|
tags: plugin.tags || [],
|
||||||
|
type: plugin.type,
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -152,6 +162,7 @@ function MarketPageContent({
|
|||||||
const { sortBy, sortOrder } = getCurrentSort();
|
const { sortBy, sortOrder } = getCurrentSort();
|
||||||
const filterValue =
|
const filterValue =
|
||||||
componentFilter === 'all' ? undefined : componentFilter;
|
componentFilter === 'all' ? undefined : componentFilter;
|
||||||
|
const typeFilterValue = typeFilter === 'all' ? undefined : typeFilter;
|
||||||
|
|
||||||
// Always use searchMarketplacePlugins to support component filtering and tags filtering
|
// Always use searchMarketplacePlugins to support component filtering and tags filtering
|
||||||
const response =
|
const response =
|
||||||
@@ -163,6 +174,7 @@ function MarketPageContent({
|
|||||||
sortOrder,
|
sortOrder,
|
||||||
filterValue,
|
filterValue,
|
||||||
selectedTags.length > 0 ? selectedTags : undefined,
|
selectedTags.length > 0 ? selectedTags : undefined,
|
||||||
|
typeFilterValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
const data: ApiRespMarketplacePlugins = response;
|
const data: ApiRespMarketplacePlugins = response;
|
||||||
@@ -313,10 +325,29 @@ function MarketPageContent({
|
|||||||
// fetchPlugins will be called by useEffect when componentFilter changes
|
// fetchPlugins will be called by useEffect when componentFilter changes
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Handle type filter change
|
||||||
|
const handleTypeFilterChange = useCallback((value: string) => {
|
||||||
|
setTypeFilter(value);
|
||||||
|
setCurrentPage(1);
|
||||||
|
setPlugins([]);
|
||||||
|
|
||||||
|
// Update URL query param to keep it in sync
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (value === 'all') {
|
||||||
|
params.delete('type');
|
||||||
|
} else {
|
||||||
|
params.set('type', value);
|
||||||
|
}
|
||||||
|
const newUrl = params.toString()
|
||||||
|
? `${window.location.pathname}?${params.toString()}`
|
||||||
|
: window.location.pathname;
|
||||||
|
window.history.replaceState({}, '', newUrl);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 当排序选项或组件筛选变化时重新加载数据
|
// 当排序选项或组件筛选变化时重新加载数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchPlugins(1, !!searchQuery.trim(), true);
|
fetchPlugins(1, !!searchQuery.trim(), true);
|
||||||
}, [sortOption, componentFilter]);
|
}, [sortOption, componentFilter, typeFilter]);
|
||||||
|
|
||||||
// Tags 筛选变化时重新搜索
|
// Tags 筛选变化时重新搜索
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -534,6 +565,54 @@ function MarketPageContent({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Type filter */}
|
||||||
|
<div className="flex flex-col sm:flex-row items-center gap-2 min-w-0 max-w-full">
|
||||||
|
<span className="text-xs sm:text-sm text-muted-foreground whitespace-nowrap">
|
||||||
|
{t('market.filterByType')}:
|
||||||
|
</span>
|
||||||
|
<div className="overflow-x-auto max-w-full [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
|
||||||
|
<ToggleGroup
|
||||||
|
type="single"
|
||||||
|
spacing={2}
|
||||||
|
size="sm"
|
||||||
|
value={typeFilter}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
if (value) handleTypeFilterChange(value);
|
||||||
|
}}
|
||||||
|
className="justify-start flex-nowrap"
|
||||||
|
>
|
||||||
|
<ToggleGroupItem
|
||||||
|
value="all"
|
||||||
|
aria-label="All types"
|
||||||
|
className="text-xs sm:text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('market.allTypes')}
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem
|
||||||
|
value="plugin"
|
||||||
|
aria-label="Plugin"
|
||||||
|
className="text-xs sm:text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('market.typePlugin')}
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem
|
||||||
|
value="mcp"
|
||||||
|
aria-label="MCP"
|
||||||
|
className="text-xs sm:text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('market.typeMCP')}
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem
|
||||||
|
value="skill"
|
||||||
|
aria-label="Skill"
|
||||||
|
className="text-xs sm:text-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
{t('market.typeSkill')}
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Sort dropdown */}
|
{/* Sort dropdown */}
|
||||||
<div className="flex items-center gap-2 sm:gap-3">
|
<div className="flex items-center gap-2 sm:gap-3">
|
||||||
<span className="text-xs sm:text-sm text-muted-foreground whitespace-nowrap">
|
<span className="text-xs sm:text-sm text-muted-foreground whitespace-nowrap">
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ function pluginToVO(
|
|||||||
version: plugin.latest_version,
|
version: plugin.latest_version,
|
||||||
components: plugin.components,
|
components: plugin.components,
|
||||||
tags: plugin.tags || [],
|
tags: plugin.tags || [],
|
||||||
|
type: plugin.type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
@@ -107,6 +107,24 @@ export default function PluginMarketCardComponent({
|
|||||||
<div className="text-base sm:text-[1.2rem] text-black dark:text-[#f0f0f0] truncate">
|
<div className="text-base sm:text-[1.2rem] text-black dark:text-[#f0f0f0] truncate">
|
||||||
{cardVO.label}
|
{cardVO.label}
|
||||||
</div>
|
</div>
|
||||||
|
{cardVO.type && (
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={`text-[0.6rem] px-1.5 py-0 h-4 flex-shrink-0 gap-0.5 ${
|
||||||
|
cardVO.type === 'mcp'
|
||||||
|
? 'border-sky-500 text-sky-600 dark:border-sky-400 dark:text-sky-300'
|
||||||
|
: cardVO.type === 'skill'
|
||||||
|
? 'border-emerald-500 text-emerald-600 dark:border-emerald-400 dark:text-emerald-300'
|
||||||
|
: 'border-violet-500 text-violet-600 dark:border-violet-400 dark:text-violet-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{cardVO.type === 'mcp'
|
||||||
|
? 'MCP'
|
||||||
|
: cardVO.type === 'skill'
|
||||||
|
? t('common.skill')
|
||||||
|
: t('market.typePlugin')}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+3
@@ -10,6 +10,7 @@ export interface IPluginMarketCardVO {
|
|||||||
version: string;
|
version: string;
|
||||||
components?: Record<string, number>;
|
components?: Record<string, number>;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
|
type?: 'plugin' | 'mcp' | 'skill';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PluginMarketCardVO implements IPluginMarketCardVO {
|
export class PluginMarketCardVO implements IPluginMarketCardVO {
|
||||||
@@ -24,6 +25,7 @@ export class PluginMarketCardVO implements IPluginMarketCardVO {
|
|||||||
version: string;
|
version: string;
|
||||||
components?: Record<string, number>;
|
components?: Record<string, number>;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
|
type?: 'plugin' | 'mcp' | 'skill';
|
||||||
|
|
||||||
constructor(prop: IPluginMarketCardVO) {
|
constructor(prop: IPluginMarketCardVO) {
|
||||||
this.description = prop.description;
|
this.description = prop.description;
|
||||||
@@ -37,5 +39,6 @@ export class PluginMarketCardVO implements IPluginMarketCardVO {
|
|||||||
this.version = prop.version;
|
this.version = prop.version;
|
||||||
this.components = prop.components;
|
this.components = prop.components;
|
||||||
this.tags = prop.tags;
|
this.tags = prop.tags;
|
||||||
|
this.type = prop.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export interface PluginV4 {
|
|||||||
latest_version: string;
|
latest_version: string;
|
||||||
components: Record<string, number>;
|
components: Record<string, number>;
|
||||||
status: PluginV4Status;
|
status: PluginV4Status;
|
||||||
|
type?: 'plugin' | 'mcp' | 'skill';
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export class CloudServiceClient extends BaseHttpClient {
|
|||||||
sort_order?: string,
|
sort_order?: string,
|
||||||
component_filter?: string,
|
component_filter?: string,
|
||||||
tags_filter?: string[],
|
tags_filter?: string[],
|
||||||
|
type_filter?: string,
|
||||||
): Promise<ApiRespMarketplacePlugins> {
|
): Promise<ApiRespMarketplacePlugins> {
|
||||||
return this.post<ApiRespMarketplacePlugins>(
|
return this.post<ApiRespMarketplacePlugins>(
|
||||||
'/api/v1/marketplace/plugins/search',
|
'/api/v1/marketplace/plugins/search',
|
||||||
@@ -49,6 +50,7 @@ export class CloudServiceClient extends BaseHttpClient {
|
|||||||
sort_order,
|
sort_order,
|
||||||
component_filter,
|
component_filter,
|
||||||
tags_filter,
|
tags_filter,
|
||||||
|
type_filter,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const enUS = {
|
|||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
add: 'Add',
|
add: 'Add',
|
||||||
select: 'Select',
|
select: 'Select',
|
||||||
|
skill: 'Skill',
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
submit: 'Submit',
|
submit: 'Submit',
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
@@ -617,6 +618,11 @@ const enUS = {
|
|||||||
markAsReadFailed: 'Mark as read failed',
|
markAsReadFailed: 'Mark as read failed',
|
||||||
filterByComponent: 'Component',
|
filterByComponent: 'Component',
|
||||||
allComponents: 'All Components',
|
allComponents: 'All Components',
|
||||||
|
filterByType: 'Type',
|
||||||
|
allTypes: 'All Types',
|
||||||
|
typePlugin: 'Plugin',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'Skill',
|
||||||
requestPlugin: 'Request Plugin',
|
requestPlugin: 'Request Plugin',
|
||||||
viewDetails: 'View Details',
|
viewDetails: 'View Details',
|
||||||
deprecated: 'Deprecated',
|
deprecated: 'Deprecated',
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ const esES = {
|
|||||||
delete: 'Eliminar',
|
delete: 'Eliminar',
|
||||||
add: 'Añadir',
|
add: 'Añadir',
|
||||||
select: 'Seleccionar',
|
select: 'Seleccionar',
|
||||||
|
skill: 'Habilidad',
|
||||||
cancel: 'Cancelar',
|
cancel: 'Cancelar',
|
||||||
submit: 'Enviar',
|
submit: 'Enviar',
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
@@ -630,6 +631,11 @@ const esES = {
|
|||||||
markAsReadFailed: 'Error al marcar como leído',
|
markAsReadFailed: 'Error al marcar como leído',
|
||||||
filterByComponent: 'Componente',
|
filterByComponent: 'Componente',
|
||||||
allComponents: 'Todos los componentes',
|
allComponents: 'Todos los componentes',
|
||||||
|
filterByType: 'Tipo',
|
||||||
|
allTypes: 'Todos los tipos',
|
||||||
|
typePlugin: 'Plugin',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'Habilidad',
|
||||||
requestPlugin: 'Solicitar plugin',
|
requestPlugin: 'Solicitar plugin',
|
||||||
viewDetails: 'Ver detalles',
|
viewDetails: 'Ver detalles',
|
||||||
deprecated: 'Obsoleto',
|
deprecated: 'Obsoleto',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const jaJP = {
|
const jaJP = {
|
||||||
sidebar: {
|
sidebar: {
|
||||||
home: 'ホーム',
|
home: 'ホーム',
|
||||||
extensions: '拡張機能',
|
extensions: '拡張機能',
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
delete: '削除',
|
delete: '削除',
|
||||||
add: '追加',
|
add: '追加',
|
||||||
select: '選択してください',
|
select: '選択してください',
|
||||||
|
skill: 'スキル',
|
||||||
cancel: 'キャンセル',
|
cancel: 'キャンセル',
|
||||||
submit: '送信',
|
submit: '送信',
|
||||||
error: 'エラー',
|
error: 'エラー',
|
||||||
@@ -622,6 +623,11 @@
|
|||||||
markAsReadFailed: '既読に設定に失敗しました',
|
markAsReadFailed: '既読に設定に失敗しました',
|
||||||
filterByComponent: 'コンポーネント',
|
filterByComponent: 'コンポーネント',
|
||||||
allComponents: '全部コンポーネント',
|
allComponents: '全部コンポーネント',
|
||||||
|
filterByType: 'タイプ',
|
||||||
|
allTypes: '全部',
|
||||||
|
typePlugin: 'プラグイン',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'スキル',
|
||||||
requestPlugin: 'プラグインをリクエスト',
|
requestPlugin: 'プラグインをリクエスト',
|
||||||
tags: {
|
tags: {
|
||||||
filterByTags: 'タグで絞り込み',
|
filterByTags: 'タグで絞り込み',
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const ruRU = {
|
|||||||
delete: 'Удалить',
|
delete: 'Удалить',
|
||||||
add: 'Добавить',
|
add: 'Добавить',
|
||||||
select: 'Выбрать',
|
select: 'Выбрать',
|
||||||
|
skill: 'Навык',
|
||||||
cancel: 'Отмена',
|
cancel: 'Отмена',
|
||||||
submit: 'Отправить',
|
submit: 'Отправить',
|
||||||
error: 'Ошибка',
|
error: 'Ошибка',
|
||||||
@@ -627,6 +628,11 @@ const ruRU = {
|
|||||||
markAsReadFailed: 'Не удалось отметить как прочитанное',
|
markAsReadFailed: 'Не удалось отметить как прочитанное',
|
||||||
filterByComponent: 'Компонент',
|
filterByComponent: 'Компонент',
|
||||||
allComponents: 'Все компоненты',
|
allComponents: 'Все компоненты',
|
||||||
|
filterByType: 'Тип',
|
||||||
|
allTypes: 'Все типы',
|
||||||
|
typePlugin: 'Плагин',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'Навык',
|
||||||
requestPlugin: 'Запросить плагин',
|
requestPlugin: 'Запросить плагин',
|
||||||
viewDetails: 'Подробнее',
|
viewDetails: 'Подробнее',
|
||||||
deprecated: 'Устаревший',
|
deprecated: 'Устаревший',
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const thTH = {
|
|||||||
delete: 'ลบ',
|
delete: 'ลบ',
|
||||||
add: 'เพิ่ม',
|
add: 'เพิ่ม',
|
||||||
select: 'เลือก',
|
select: 'เลือก',
|
||||||
|
skill: 'สกิล',
|
||||||
cancel: 'ยกเลิก',
|
cancel: 'ยกเลิก',
|
||||||
submit: 'ส่ง',
|
submit: 'ส่ง',
|
||||||
error: 'ข้อผิดพลาด',
|
error: 'ข้อผิดพลาด',
|
||||||
@@ -609,6 +610,11 @@ const thTH = {
|
|||||||
markAsReadFailed: 'ทำเครื่องหมายว่าอ่านแล้วล้มเหลว',
|
markAsReadFailed: 'ทำเครื่องหมายว่าอ่านแล้วล้มเหลว',
|
||||||
filterByComponent: 'ส่วนประกอบ',
|
filterByComponent: 'ส่วนประกอบ',
|
||||||
allComponents: 'ส่วนประกอบทั้งหมด',
|
allComponents: 'ส่วนประกอบทั้งหมด',
|
||||||
|
filterByType: 'ประเภท',
|
||||||
|
allTypes: 'ทุกประเภท',
|
||||||
|
typePlugin: 'ปลั๊กอิน',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'สกิล',
|
||||||
requestPlugin: 'ขอปลั๊กอิน',
|
requestPlugin: 'ขอปลั๊กอิน',
|
||||||
viewDetails: 'ดูรายละเอียด',
|
viewDetails: 'ดูรายละเอียด',
|
||||||
deprecated: 'เลิกใช้แล้ว',
|
deprecated: 'เลิกใช้แล้ว',
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const viVN = {
|
|||||||
delete: 'Xóa',
|
delete: 'Xóa',
|
||||||
add: 'Thêm',
|
add: 'Thêm',
|
||||||
select: 'Chọn',
|
select: 'Chọn',
|
||||||
|
skill: 'Kỹ năng',
|
||||||
cancel: 'Hủy',
|
cancel: 'Hủy',
|
||||||
submit: 'Gửi',
|
submit: 'Gửi',
|
||||||
error: 'Lỗi',
|
error: 'Lỗi',
|
||||||
@@ -621,6 +622,11 @@ const viVN = {
|
|||||||
markAsReadFailed: 'Đánh dấu đã đọc thất bại',
|
markAsReadFailed: 'Đánh dấu đã đọc thất bại',
|
||||||
filterByComponent: 'Thành phần',
|
filterByComponent: 'Thành phần',
|
||||||
allComponents: 'Tất cả thành phần',
|
allComponents: 'Tất cả thành phần',
|
||||||
|
filterByType: 'Loại',
|
||||||
|
allTypes: 'Tất cả loại',
|
||||||
|
typePlugin: 'Plugin',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: 'Kỹ năng',
|
||||||
requestPlugin: 'Yêu cầu Plugin',
|
requestPlugin: 'Yêu cầu Plugin',
|
||||||
viewDetails: 'Xem chi tiết',
|
viewDetails: 'Xem chi tiết',
|
||||||
deprecated: 'Không còn hỗ trợ',
|
deprecated: 'Không còn hỗ trợ',
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const zhHans = {
|
|||||||
delete: '删除',
|
delete: '删除',
|
||||||
add: '添加',
|
add: '添加',
|
||||||
select: '请选择',
|
select: '请选择',
|
||||||
|
skill: '技能',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
submit: '提交',
|
submit: '提交',
|
||||||
error: '错误',
|
error: '错误',
|
||||||
@@ -590,6 +591,11 @@ const zhHans = {
|
|||||||
markAsReadFailed: '标记为已读失败',
|
markAsReadFailed: '标记为已读失败',
|
||||||
filterByComponent: '组件',
|
filterByComponent: '组件',
|
||||||
allComponents: '全部组件',
|
allComponents: '全部组件',
|
||||||
|
filterByType: '类型',
|
||||||
|
allTypes: '全部类型',
|
||||||
|
typePlugin: '插件',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: '技能',
|
||||||
requestPlugin: '请求插件',
|
requestPlugin: '请求插件',
|
||||||
tags: {
|
tags: {
|
||||||
filterByTags: '按标签筛选',
|
filterByTags: '按标签筛选',
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const zhHant = {
|
|||||||
delete: '刪除',
|
delete: '刪除',
|
||||||
add: '新增',
|
add: '新增',
|
||||||
select: '請選擇',
|
select: '請選擇',
|
||||||
|
skill: '技能',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
submit: '提交',
|
submit: '提交',
|
||||||
error: '錯誤',
|
error: '錯誤',
|
||||||
@@ -590,6 +591,11 @@ const zhHant = {
|
|||||||
markAsReadFailed: '標記為已讀失敗',
|
markAsReadFailed: '標記為已讀失敗',
|
||||||
filterByComponent: '組件',
|
filterByComponent: '組件',
|
||||||
allComponents: '全部組件',
|
allComponents: '全部組件',
|
||||||
|
filterByType: '類型',
|
||||||
|
allTypes: '全部類型',
|
||||||
|
typePlugin: '插件',
|
||||||
|
typeMCP: 'MCP',
|
||||||
|
typeSkill: '技能',
|
||||||
requestPlugin: '請求插件',
|
requestPlugin: '請求插件',
|
||||||
tags: {
|
tags: {
|
||||||
filterByTags: '按標籤篩選',
|
filterByTags: '按標籤篩選',
|
||||||
|
|||||||
Reference in New Issue
Block a user