fix: refresh enable backend state

This commit is contained in:
jialin
2026-02-04 14:58:48 +08:00
parent 05c05419fc
commit 7fd2b43704
14 changed files with 74 additions and 27 deletions
+3
View File
@@ -0,0 +1,3 @@
import { atom } from 'jotai';
export const enabledBackendsAtom = atom<any>(null);
+1
View File
@@ -430,6 +430,7 @@ export default function useTableFetch<T>(
extraStatus,
TABLE_SORT_DIRECTIONS,
debounceFetchData,
setDataSource,
setQueryParams,
handleDelete,
handleDeleteBatch,
+1 -1
View File
@@ -44,5 +44,5 @@ export default {
'backend.filter.source': 'Filter by source',
'backend.add.custom': 'Custom',
'backend.add.community': 'Community Backends',
'backend.community.title': 'Community Backends Marketplace'
'backend.community.title': 'Community Backend Marketplace'
};
+1 -1
View File
@@ -113,7 +113,7 @@ export default {
'clusters.table.ip.internal': 'Internal',
'clusters.table.ip.external': 'External',
'clusters.form.serverUrl.tips':
'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack directly.',
'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack Server directly.',
'clusters.form.setDefault': 'Set as Default',
'clusters.form.setDefault.tips': 'Default for deployment.',
'clusters.addworker.noClusters': 'No available Docker clusters found',
+1 -1
View File
@@ -39,5 +39,5 @@ export default {
'users.status.deactivate': 'Deactivate Account',
'users.status.inactiveAccount': 'Inactive Account',
'users.login.getInitialPassword':
'Run the following command on your server to retrieve the initial admin password.'
'Run the following command on your GPUStack Server to retrieve the initial admin password.'
};
+1 -1
View File
@@ -44,5 +44,5 @@ export default {
'backend.filter.source': 'Filter by source',
'backend.add.custom': 'Custom',
'backend.add.community': 'Community Backends',
'backend.community.title': 'Community Backends Marketplace'
'backend.community.title': 'Community Backend Marketplace'
};
+2 -2
View File
@@ -113,7 +113,7 @@ export default {
'clusters.table.ip.internal': 'Internal',
'clusters.table.ip.external': 'External',
'clusters.form.serverUrl.tips':
'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack directly.',
'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack Server directly.',
'clusters.form.setDefault': 'Set as Default',
'clusters.form.setDefault.tips': 'Default for deployment.',
'clusters.addworker.noClusters': 'No available Docker clusters found',
@@ -217,7 +217,7 @@ export default {
// 78. 'clusters.addworker.dataVolume.tips': 'Specify a data storage path for GPUStack.',
// 79. 'clusters.table.ip.internal': 'Internal',
// 80. 'clusters.table.ip.external': 'External',
// 81. 'clusters.form.serverUrl.tips': 'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack directly.',
// 81. 'clusters.form.serverUrl.tips': 'Specify an externally accessible GPUStack service URL if the worker cannot access GPUStack Server directly.',
// 82. 'clusters.addworker.externalIP.tips': 'Specify an external IP if the worker is in a VPC or private network.',
// 83. 'clusters.form.setDefault': 'Set as Default',
// 84. 'clusters.form.setDefault.tips': 'Default for deployment',
+2 -2
View File
@@ -40,7 +40,7 @@ export default {
'users.status.deactivate': 'Deactivate Account',
'users.status.inactiveAccount': 'Inactive Account',
'users.login.getInitialPassword':
'Run the following command on your server to retrieve the initial admin password.'
'Run the following command on your GPUStack Server to retrieve the initial admin password.'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -48,5 +48,5 @@ export default {
// 2. 'users.status.activate': 'Activate Account',
// 3. 'users.status.deactivate': 'Deactivate Account',
// 4. 'users.status.inactiveAccount': 'Inactive Account',
// 5. 'users.login.getInitialPassword': 'Run the following command on your server to retrieve the initial admin password.'
// 5. 'users.login.getInitialPassword': 'Run the following command on your GPUStack Server to retrieve the initial admin password.'
// ========== End of To-Do List ==========
+2 -2
View File
@@ -44,7 +44,7 @@ export default {
'backend.filter.source': 'Filter by source',
'backend.add.custom': 'Custom',
'backend.add.community': 'Community Backends',
'backend.community.title': 'Community Backends Marketplace'
'backend.community.title': 'Community Backend Marketplace'
};
// ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -53,5 +53,5 @@ export default {
// 3. 'backend.filter.source': 'Filter by source',
// 4. 'backend.add.custom': 'Custom',
// 5. 'backend.add.community': 'Community Backends',
// 6. 'backend.community.title': 'Community Backends Marketplace'
// 6. 'backend.community.title': 'Community Backend Marketplace'
// ========== End of To-Do List ==========
+1 -1
View File
@@ -113,7 +113,7 @@ export default {
'clusters.table.ip.internal': 'Внутренний',
'clusters.table.ip.external': 'Внешний',
'clusters.form.serverUrl.tips':
'Если рабочий узел не может напрямую получить доступ к GPUStack, укажите внешний URL службы GPUStack.',
'Если рабочий узел не может напрямую получить доступ к GPUStack Server, укажите внешний URL службы GPUStack Server.',
'clusters.form.setDefault': 'Установить по умолчанию',
'clusters.form.setDefault.tips':
'Использовать по умолчанию для развертывания.',
+2 -2
View File
@@ -102,7 +102,7 @@ export default {
'已将 {count} 个新节点添加到集群中。',
'clusters.addworker.message.success_multiple':
'已将 {count} 个新节点添加到集群中。',
'clusters.create.serverUrl': 'GPUStack 服务地址',
'clusters.create.serverUrl': 'GPUStack Server 节点地址',
'clusters.create.workerConfig': '节点配置',
'clusters.addworker.containerName': '节点容器名称',
'clusters.addworker.containerName.tips': '为节点容器指定一个名称。',
@@ -111,7 +111,7 @@ export default {
'clusters.table.ip.internal': '内',
'clusters.table.ip.external': '外',
'clusters.form.serverUrl.tips':
'如果节点无法直接访问 GPUStack,则指定一个可访问的外部 GPUStack 服务地址。',
'如果节点无法直接访问 GPUStack Server,则指定一个可访问的外部 GPUStack Server 地址。',
'clusters.form.setDefault': '设为默认',
'clusters.form.setDefault.tips': '部署时的默认集群。',
'clusters.addworker.noClusters': '无可用的 Docker 集群',
+1 -1
View File
@@ -258,7 +258,7 @@ export default {
'models.form.backendVersions.tips': `如需使用更多版本,请前往{link}页面并编辑对应的后端以添加版本。`,
'models.catalog.nogpus.tips': '所选集群中没有兼容该模型的 GPU。',
'models.form.modelfile.notfound':
'你指定的模型文件路径在 GPUStack 服务器上不存在。建议在 GPUStack 服务器和 GPUStack 节点上使用相同的模型文件路径,这有助于 GPUStack 做出更优的调度与决策。',
'你指定的模型文件路径在 GPUStack Server 节点上不存在。建议在 GPUStack Server 节点和 GPUStack 节点上使用相同的模型文件路径,这有助于 GPUStack 做出更优的调度与决策。',
'models.form.readyWorkers': '节点就绪',
'models.form.maxContextLength': '最大上下文长度',
'models.form.backend.helperText': '该社区后端暂未启用,部署后将自动启用',
@@ -1,8 +1,10 @@
import { enabledBackendsAtom } from '@/atoms/backend';
import GSDrawer from '@/components/scroller-modal/gs-drawer';
import ColumnWrapper from '@/pages/_components/column-wrapper';
import Separator from '@/pages/llmodels/components/separator';
import { useIntl } from '@umijs/max';
import React from 'react';
import { useAtom } from 'jotai';
import React, { useEffect } from 'react';
import styled from 'styled-components';
import { ListItem } from '../config/types';
import useEnableBackend from '../services/use-enable-backend';
@@ -23,6 +25,7 @@ const AddCommunityModal: React.FC<{
const intl = useIntl();
const { handleEnableBackend } = useEnableBackend();
const [currentData, setCurrentData] = React.useState<any>(null);
const [, setEnabledBackendAtom] = useAtom(enabledBackendsAtom);
const handleOnEnable = async (checked: boolean, data: ListItem) => {
await handleEnableBackend({
@@ -32,12 +35,23 @@ const AddCommunityModal: React.FC<{
enabled: checked
}
});
setEnabledBackendAtom({
...data,
enabled: checked
});
onRefresh?.();
};
const handleOnClick = (data: ListItem) => {
setCurrentData(data);
};
useEffect(() => {
if (!open) {
setEnabledBackendAtom(null);
}
}, [open]);
return (
<GSDrawer
open={open}
@@ -1,9 +1,11 @@
import { enabledBackendsAtom } from '@/atoms/backend';
import IconFont from '@/components/icon-font';
import ThemeTag from '@/components/tags-wrapper/theme-tag';
import useTableFetch from '@/hooks/use-table-fetch';
import { SearchOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Input, Tooltip } from 'antd';
import { useAtom } from 'jotai';
import _ from 'lodash';
import React, { useEffect } from 'react';
import styled from 'styled-components';
@@ -28,19 +30,46 @@ const CommunityBackends: React.FC<{
onClick: (data: ListItem) => void;
}> = ({ onEnable, onClick }) => {
const intl = useIntl();
const [enabledBackendAtom] = useAtom(enabledBackendsAtom);
const [currentData, setCurrentData] = React.useState<ListItem | null>(null);
const { dataSource, loadMore, queryParams, handleSearch, handleNameChange } =
useTableFetch<ListItem>({
fetchAPI: queryBackendsList,
API: INFERENCE_BACKEND_API,
watch: false,
isInfiniteScroll: true,
contentForDelete: 'backends.title',
defaultQueryParams: {
perPage: 24,
community: 1
}
});
const {
dataSource,
loadMore,
queryParams,
handleSearch,
setDataSource,
handleNameChange
} = useTableFetch<ListItem>({
fetchAPI: queryBackendsList,
API: INFERENCE_BACKEND_API,
watch: false,
isInfiniteScroll: true,
contentForDelete: 'backends.title',
defaultQueryParams: {
perPage: 24,
community: 1
}
});
useEffect(() => {
if (enabledBackendAtom) {
setDataSource((prev) => {
const newDataList = prev.dataList.map((item) => {
if (item.id === enabledBackendAtom.id) {
return {
...item,
enabled: enabledBackendAtom.enabled
};
}
return item;
});
return {
...prev,
dataList: newDataList
};
});
}
}, [enabledBackendAtom]);
const handleOnClickItem = (data: ListItem) => {
onClick(data);