chore: merge fetch data request

This commit is contained in:
jialin
2025-03-12 16:53:43 +08:00
parent e04874d074
commit a7170a4eee
4 changed files with 229 additions and 218 deletions
+1 -1
View File
@@ -32,7 +32,7 @@
border-radius: var(--border-radius-base) var(--border-radius-base) 0 0; border-radius: var(--border-radius-base) var(--border-radius-base) 0 0;
&.danger { &.danger {
background-color: var(--ant-color-error-bg-hover); background-color: var(--ant-color-error-bg-filled-hover);
} }
&.warning { &.warning {
@@ -232,7 +232,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
)} )}
<div style={{ display: 'flex', flex: 1, maxWidth: '100%' }}> <div style={{ display: 'flex', flex: 1, maxWidth: '100%' }}>
<ColumnWrapper <ColumnWrapper
paddingBottom={warningStatus.show ? 125 : 50} paddingBottom={warningStatus.show ? 140 : 50}
footer={ footer={
<> <>
{warningStatus.show && ( {warningStatus.show && (
+134 -180
View File
@@ -29,7 +29,6 @@ import {
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import _ from 'lodash'; import _ from 'lodash';
import React, { useCallback, useEffect, useMemo } from 'react'; import React, { useCallback, useEffect, useMemo } from 'react';
import styled from 'styled-components';
import { MODEL_INSTANCE_API } from '../apis'; import { MODEL_INSTANCE_API } from '../apis';
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config'; import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
import { ModelInstanceListItem } from '../config/types'; import { ModelInstanceListItem } from '../config/types';
@@ -65,6 +64,52 @@ const WorkerInfo = (props: {
</span> </span>
); );
}; };
const InstanceStatusTag = (
props: Pick<InstanceItemProps, 'instanceData' | 'handleChildSelect'>
) => {
const intl = useIntl();
const { instanceData, handleChildSelect } = props;
if (!instanceData.state) {
return null;
}
return (
<StatusTag
download={
instanceData.state === InstanceStatusMap.Downloading
? { percent: instanceData.download_progress }
: undefined
}
extra={
instanceData.state === InstanceStatusMap.Error &&
instanceData.worker_id ? (
<Button
type="link"
size="small"
style={{ paddingLeft: 0 }}
onClick={() => handleChildSelect('viewlog', instanceData)}
>
{intl.formatMessage({ id: 'models.list.more.logs' })}
</Button>
) : null
}
statusValue={{
status:
instanceData.state === InstanceStatusMap.Downloading &&
instanceData.download_progress === 100
? status[InstanceStatusMap.Running]
: status[instanceData.state],
text: InstanceStatusMapValue[instanceData.state],
message:
instanceData.state === InstanceStatusMap.Downloading &&
instanceData.download_progress === 100
? ''
: instanceData.state_message
}}
/>
);
};
interface InstanceItemProps { interface InstanceItemProps {
instanceData: ModelInstanceListItem; instanceData: ModelInstanceListItem;
workerList: WorkerListItem[]; workerList: WorkerListItem[];
@@ -129,9 +174,6 @@ const distributeCols: ColumnProps[] = [
title: 'models.table.vram.allocated', title: 'models.table.vram.allocated',
locale: true, locale: true,
key: 'vram', key: 'vram',
// rowSpan: ({ row, rowIndex, colIndex, dataIndex, dataList }) => {
// return rowIndex === 0 ? dataList.length : 0;
// },
render: ({ rowIndex, row, dataList }) => { render: ({ rowIndex, row, dataList }) => {
return convertFileSize(row.vram, 1); return convertFileSize(row.vram, 1);
} }
@@ -153,40 +195,6 @@ const renderMessage = (title: string) => {
); );
}; };
const InfoItem = (props: { label: string; value: any; width?: number }) => {
const { label, value, width } = props;
const Wrapper = styled.div`
.info-item {
width: ${width ? `${width}px` : '100%'};
height: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 4px 8px;
background-color: var(--color-gray-fill-3);
border-radius: 4px;
.value {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
color: var(--color-white-quaternary);
.index {
color: var(--ant-color-text-light-solid);
}
}
}
`;
return (
<Wrapper>
<div className="info-item">
<span className="label">{label}</span>
<span className="value">{value}</span>
</div>
</Wrapper>
);
};
const InstanceItem: React.FC<InstanceItemProps> = ({ const InstanceItem: React.FC<InstanceItemProps> = ({
instanceData, instanceData,
workerList, workerList,
@@ -206,7 +214,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
} }
return true; return true;
}); });
}, [instanceData]); }, [instanceData.state]);
const createFileName = (name: string) => { const createFileName = (name: string) => {
const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss'); const timestamp = dayjs().format('YYYY-MM-DD_HH-mm-ss');
@@ -239,23 +247,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
[] []
); );
const displayGPUs = (vrams: Record<string, number>) => {
return (
<span className="flex-column">
{Object.keys(vrams)
?.sort?.()
.map((index) => {
return (
<span key={index}>
[{index}] {''}
{convertFileSize(vrams?.[index], 0)}
</span>
);
})}
</span>
);
};
const renderWorkerInfo = useMemo(() => { const renderWorkerInfo = useMemo(() => {
let workerIp = '-'; let workerIp = '-';
if (instanceData.worker_ip) { if (instanceData.worker_ip) {
@@ -283,85 +274,87 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
</div> </div>
</div> </div>
); );
}, [modelData, instanceData, intl]); }, [
instanceData.worker_name,
instanceData.worker_ip,
instanceData.port,
instanceData.gpu_indexes,
modelData?.backend,
modelData?.backend_version,
intl
]);
const calcTotalVram = (vram: Record<string, number>) => { const calcTotalVram = (vram: Record<string, number>) => {
return _.sum(_.values(vram)); return _.sum(_.values(vram));
}; };
const renderDistributedServer = useCallback( const renderDistributedServer = (severList: any[]) => {
(severList: any[]) => { const list = _.map(severList, (item: any) => {
const list = _.map(severList, (item: any) => { const data = _.find(workerList, { id: item.worker_id });
const data = _.find(workerList, { id: item.worker_id }); return {
return { worker_name: data?.name,
worker_name: data?.name, worker_ip: data?.ip,
worker_ip: data?.ip, port: '',
port: '', vram: calcTotalVram(item.computed_resource_claim?.vram || {}),
vram: calcTotalVram(item.computed_resource_claim?.vram || {}), gpu_index: _.keys(item.computed_resource_claim?.vram).join(',')
gpu_index: _.keys(item.computed_resource_claim?.vram).join(',') };
}; });
});
const mainWorker = [ const mainWorker = [
{ {
worker_name: `${instanceData.worker_name}`, worker_name: `${instanceData.worker_name}`,
worker_ip: `${instanceData.worker_ip}`, worker_ip: `${instanceData.worker_ip}`,
port: '', port: '',
vram: calcTotalVram(instanceData.computed_resource_claim?.vram || {}), vram: calcTotalVram(instanceData.computed_resource_claim?.vram || {}),
gpu_index: `${instanceData.gpu_indexes?.join?.(',')}(main)` gpu_index: `${instanceData.gpu_indexes?.join?.(',')}(main)`
}
];
return (
<div>
<SimpleTabel
columns={distributeCols}
dataSource={[...mainWorker, ...list]}
></SimpleTabel>
</div>
);
},
[workerList, instanceData, intl]
);
const renderDistributionInfo = useCallback(
(severList: any[]) => {
if (!severList.length) {
return null;
} }
return ( ];
<Tooltip
overlayInnerStyle={{ return (
width: 'max-content', <div>
maxWidth: '500px', <SimpleTabel
minWidth: '400px' columns={distributeCols}
dataSource={[...mainWorker, ...list]}
></SimpleTabel>
</div>
);
};
const renderDistributionInfo = (severList: any[]) => {
if (!severList.length) {
return null;
}
return (
<Tooltip
overlayInnerStyle={{
width: 'max-content',
maxWidth: '500px',
minWidth: '400px'
}}
title={renderDistributedServer(severList)}
>
<Tag
color="processing"
style={{
display: 'flex',
alignItems: 'center',
maxWidth: '100%',
minWidth: 50,
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
opacity: 0.75,
borderRadius: 12
}} }}
title={renderDistributedServer(severList)}
> >
<Tag <InfoCircleOutlined className="m-r-5" />
color="processing" {intl.formatMessage({
style={{ id: 'models.table.acrossworker'
display: 'flex', })}
alignItems: 'center', </Tag>
maxWidth: '100%', </Tooltip>
minWidth: 50, );
textOverflow: 'ellipsis', };
whiteSpace: 'nowrap',
overflow: 'hidden',
opacity: 0.75,
borderRadius: 12
}}
>
<InfoCircleOutlined className="m-r-5" />
{intl.formatMessage({
id: 'models.table.acrossworker'
})}
</Tag>
</Tooltip>
);
},
[renderDistributedServer]
);
const renderOffloadInfo = useMemo(() => { const renderOffloadInfo = useMemo(() => {
const total_layers = instanceData.computed_resource_claim?.total_layers; const total_layers = instanceData.computed_resource_claim?.total_layers;
@@ -425,21 +418,17 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
instanceData.computed_resource_claim?.offload_layers instanceData.computed_resource_claim?.offload_layers
]); ]);
const handleOnSelect = useCallback( const handleOnSelect = (val: string) => {
(val: string) => { if (val === 'download') {
console.log('handleOnSelect', val); downloadStream({
if (val === 'download') { url: `${MODEL_INSTANCE_API}/${instanceData.id}/logs`,
downloadStream({ filename: createFileName(instanceData.name),
url: `${MODEL_INSTANCE_API}/${instanceData.id}/logs`, downloadNotification
filename: createFileName(instanceData.name), });
downloadNotification } else {
}); handleChildSelect(val, instanceData);
} else { }
handleChildSelect(val, instanceData); };
}
},
[handleChildSelect, instanceData]
);
return ( return (
<> <>
@@ -487,45 +476,10 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
style={{ paddingLeft: '62px' }} style={{ paddingLeft: '62px' }}
className="flex justify-center" className="flex justify-center"
> >
{instanceData.state && ( <InstanceStatusTag
<StatusTag instanceData={instanceData}
download={ handleChildSelect={handleChildSelect}
instanceData.state === InstanceStatusMap.Downloading />
? { percent: instanceData.download_progress }
: undefined
}
extra={
instanceData.state === InstanceStatusMap.Error &&
instanceData.worker_id ? (
<Button
type="link"
size="small"
style={{ paddingLeft: 0 }}
onClick={() =>
handleChildSelect('viewlog', instanceData)
}
>
{intl.formatMessage({
id: 'models.list.more.logs'
})}
</Button>
) : null
}
statusValue={{
status:
instanceData.state === InstanceStatusMap.Downloading &&
instanceData.download_progress === 100
? status[InstanceStatusMap.Running]
: (status[instanceData.state] as any),
text: InstanceStatusMapValue[instanceData.state],
message:
instanceData.state === InstanceStatusMap.Downloading &&
instanceData.download_progress === 100
? ''
: instanceData.state_message
}}
></StatusTag>
)}
</span> </span>
</Col> </Col>
<Col span={5}> <Col span={5}>
+93 -36
View File
@@ -81,16 +81,6 @@ const Models: React.FC = () => {
setDataList: setModelInstances setDataList: setModelInstances
}); });
const getWorkerList = async () => {
try {
const data = await queryWorkersList({ page: 1, perPage: 100 });
setWorkerList(data.items || []);
} catch (error) {
// ingore
setWorkerList([]);
}
};
const getAllModelInstances = useCallback(async () => { const getAllModelInstances = useCallback(async () => {
try { try {
instancesToken.current?.cancel?.(); instancesToken.current?.cancel?.();
@@ -110,7 +100,16 @@ const Models: React.FC = () => {
}, []); }, []);
const fetchData = useCallback( const fetchData = useCallback(
async (loadingVal?: boolean) => { async (params?: {
loadingVal?: boolean;
query?: {
page: number;
perPage: number;
search: string;
categories: any[];
};
}) => {
const { loadingVal, query } = params || {};
axiosToken?.cancel?.(); axiosToken?.cancel?.();
axiosToken = createAxiosToken(); axiosToken = createAxiosToken();
setDataSource((pre) => { setDataSource((pre) => {
@@ -119,7 +118,7 @@ const Models: React.FC = () => {
}); });
try { try {
const params = { const params = {
..._.pickBy(queryParams, (val: any) => !!val) ..._.pickBy(query || queryParams, (val: any) => !!val)
}; };
const res: any = await queryModelsList(params, { const res: any = await queryModelsList(params, {
cancelToken: axiosToken.token cancelToken: axiosToken.token
@@ -153,6 +152,13 @@ const Models: React.FC = () => {
page: page, page: page,
perPage: pageSize || 10 perPage: pageSize || 10
}); });
fetchData({
query: {
...queryParams,
page: page,
perPage: pageSize || 10
}
});
}, },
[queryParams] [queryParams]
); );
@@ -213,7 +219,9 @@ const Models: React.FC = () => {
await getAllModelInstances(); await getAllModelInstances();
await createModelsInstanceChunkRequest(); await createModelsInstanceChunkRequest();
await createModelsChunkRequest(); await createModelsChunkRequest();
fetchData(false); fetchData({
loadingVal: false
});
}, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]); }, [fetchData, createModelsChunkRequest, createModelsInstanceChunkRequest]);
const handleSearch = useCallback(async () => { const handleSearch = useCallback(async () => {
@@ -226,29 +234,69 @@ const Models: React.FC = () => {
page: 1, page: 1,
search: e.target.value search: e.target.value
}); });
fetchData({
query: {
...queryParams,
page: 1,
search: e.target.value
}
});
}, 350); }, 350);
const handleNameChange = useCallback(debounceUpdateFilter, [queryParams]); const handleNameChange = useCallback(debounceUpdateFilter, [queryParams]);
const handleCategoryChange = useCallback( const handleCategoryChange = useCallback(
(value: any) => { async (value: any) => {
setQueryParams({ setQueryParams({
...queryParams, ...queryParams,
page: 1, page: 1,
categories: value categories: value
}); });
fetchData({
query: {
...queryParams,
page: 1,
categories: value
}
});
}, },
[queryParams] [queryParams]
); );
useEffect(() => { useEffect(() => {
fetchData(); // fetch data first time
return () => { const getTableData = async (loadingVal?: boolean) => {
axiosToken?.cancel?.(); axiosToken?.cancel?.();
axiosToken = createAxiosToken();
setDataSource((pre) => {
pre.loading = loadingVal ?? true;
return { ...pre };
});
try {
const params = {
..._.pickBy(queryParams, (val: any) => !!val)
};
const res: any = await queryModelsList(params, {
cancelToken: axiosToken.token
});
return res;
} catch (error) {
return {};
}
}; };
}, [queryParams]);
useEffect(() => { // get worker list
const getWorkerList = async (): Promise<any> => {
try {
const data = await queryWorkersList({ page: 1, perPage: 100 });
return data;
} catch (error) {
// ingore
return {};
}
};
// get catalog list
const getCataLogList = async () => { const getCataLogList = async () => {
const isFirstLogin = readState(IS_FIRST_LOGIN); const isFirstLogin = readState(IS_FIRST_LOGIN);
if (!isFirstLogin) { if (!isFirstLogin) {
@@ -260,8 +308,7 @@ const Models: React.FC = () => {
page: 1 page: 1
}); });
if (!res?.items?.length) { if (!res?.items?.length) {
setCatalogList([]); return [];
return;
} }
const name = _.toLower(res?.items[0]?.name).replace(/\s/g, '-') || ''; const name = _.toLower(res?.items[0]?.name).replace(/\s/g, '-') || '';
const catalogSpecs: any = await queryCatalogItemSpec({ const catalogSpecs: any = await queryCatalogItemSpec({
@@ -281,24 +328,36 @@ const Models: React.FC = () => {
-1) -1)
); );
}); });
setCatalogList(resultList || []); return resultList || [];
} catch (error) { } catch (error) {
// ignore // ignore
setCatalogList([]); return [];
} }
}; };
getCataLogList();
}, []);
useEffect(() => { const init = async () => {
createModelsChunkRequest(); const [modelRes, workerRes, cList] = await Promise.all([
}, [createModelsChunkRequest]); getTableData(),
getWorkerList(),
useEffect(() => { getCataLogList()
getWorkerList(); ]);
createModelsInstanceChunkRequest(); setDataSource({
dataList: modelRes.items || [],
loading: false,
loadend: true,
total: modelRes.pagination?.total || 0,
deletedIds: []
});
setWorkerList(workerRes.items || []);
setCatalogList(cList);
setTimeout(() => {
createModelsInstanceChunkRequest();
}, 500);
};
init();
return () => { return () => {
axiosToken?.cancel?.();
chunkRequedtRef.current?.current?.cancel?.(); chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = []; cacheDataListRef.current = [];
cacheInsDataListRef.current = []; cacheInsDataListRef.current = [];
@@ -307,10 +366,6 @@ const Models: React.FC = () => {
}; };
}, []); }, []);
useEffect(() => {
console.log('modelInstances====', modelInstances);
}, [modelInstances]);
useEffect(() => { useEffect(() => {
const handleVisibilityChange = async () => { const handleVisibilityChange = async () => {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
@@ -318,7 +373,9 @@ const Models: React.FC = () => {
await getAllModelInstances(); await getAllModelInstances();
await createModelsInstanceChunkRequest(); await createModelsInstanceChunkRequest();
await createModelsChunkRequest(); await createModelsChunkRequest();
fetchData(false); fetchData({
loadingVal: false
});
} else { } else {
isPageHidden.current = true; isPageHidden.current = true;
chunkRequedtRef.current?.current?.cancel?.(); chunkRequedtRef.current?.current?.cancel?.();