chore: list state merge
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { createFromIconfontCN } from '@ant-design/icons';
|
||||
|
||||
const IconFont = createFromIconfontCN({
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_rsdrbzw4fyd.js'
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_orlwzwe9x4k.js'
|
||||
});
|
||||
|
||||
export default IconFont;
|
||||
|
||||
@@ -14,6 +14,8 @@ export default {
|
||||
'models.instances': 'instances',
|
||||
'model.form.ollama.model': 'Ollama Model',
|
||||
'model.form.ollamaholder': 'Please select or input model name',
|
||||
'model.deploy.sort': 'Sort',
|
||||
'model.deploy.search.placeholder': 'Search models from Hugging Face',
|
||||
'model.form.ollamatips':
|
||||
'Tip: The following are the preconfigured Ollama models in GPUStack. Please select the model you want, or directly enter the model you wish to deploy in the 【{name}】 input box on the right.'
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@ export default {
|
||||
'models.instances': '实例',
|
||||
'model.form.ollama.model': 'Ollama 模型',
|
||||
'model.form.ollamaholder': '请选择或输入模型名称',
|
||||
'model.deploy.sort': '排序',
|
||||
'model.deploy.search.placeholder': '从 Hugging Face 搜索模型',
|
||||
'model.form.ollamatips':
|
||||
'提示:以下为 GPUStack 预设的 Ollama 模型,请选择你想要的模型或者直接在右侧表单 【{name}】 输入框中输入你要部署的模型。'
|
||||
};
|
||||
|
||||
@@ -19,16 +19,23 @@ import { ListItem } from './config/types';
|
||||
const { Column } = Table;
|
||||
|
||||
const APIKeys: React.FC = () => {
|
||||
console.log('APIKeys========');
|
||||
const rowSelection = useTableRowSelection();
|
||||
const { sortOrder, setSortOrder } = useTableSort({
|
||||
defaultSortOrder: 'descend'
|
||||
});
|
||||
const intl = useIntl();
|
||||
const modalRef = useRef<any>(null);
|
||||
const [dataSource, setDataSource] = useState<ListItem[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: ListItem[];
|
||||
loading: boolean;
|
||||
total: number;
|
||||
}>({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: 0
|
||||
});
|
||||
const [openAddModal, setOpenAddModal] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [action, setAction] = useState<PageActionType>(PageAction.CREATE);
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
@@ -51,20 +58,28 @@ const APIKeys: React.FC = () => {
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
setDataSource((pre) => {
|
||||
pre.loading = true;
|
||||
return pre;
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
..._.pickBy(queryParams, (val: any) => !!val)
|
||||
};
|
||||
const res = await queryApisKeysList(params);
|
||||
console.log('res=======', res);
|
||||
setDataSource(res.items || []);
|
||||
setTotal(res.pagination.total);
|
||||
|
||||
setDataSource({
|
||||
dataList: res.items || [],
|
||||
loading: false,
|
||||
total: res.pagination.total
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
setDataSource([]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setDataSource({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: dataSource.total
|
||||
});
|
||||
}
|
||||
};
|
||||
const handleSearch = (e: any) => {
|
||||
@@ -173,16 +188,16 @@ const APIKeys: React.FC = () => {
|
||||
}
|
||||
></PageTools>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
dataSource={dataSource.dataList}
|
||||
rowSelection={rowSelection}
|
||||
loading={loading}
|
||||
loading={dataSource.loading}
|
||||
rowKey="id"
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
pageSize: queryParams.perPage,
|
||||
current: queryParams.page,
|
||||
total: total,
|
||||
total: dataSource.total,
|
||||
hideOnSinglePage: queryParams.perPage === 10,
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
GGMLQuantizationType,
|
||||
GGUF_QUANT_DESCRIPTIONS
|
||||
} from '@huggingface/gguf';
|
||||
import { Button, Col, Empty, Row, Space, Spin } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { queryHuggingfaceModelFiles } from '../apis';
|
||||
import FileType from '../config/file-type';
|
||||
import '../style/hf-model-file.less';
|
||||
import TitleWrapper from './title-wrapper';
|
||||
|
||||
@@ -32,6 +29,7 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
const handleFetchModelFiles = async () => {
|
||||
if (!props.repo) {
|
||||
setDataSource({ fileList: [], loading: false });
|
||||
handleSelectModelFile({});
|
||||
return;
|
||||
}
|
||||
setDataSource({ ...dataSource, loading: true });
|
||||
@@ -54,9 +52,10 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
const name = _.split(item.path, '.').slice(0, -1).join('.');
|
||||
let quanType = _.toUpper(name.split('-').slice(-1)[0]);
|
||||
if (quanType.indexOf('.') > -1) {
|
||||
quanType = _.split(quanType, '.')[1];
|
||||
quanType = _.split(quanType, '.').pop();
|
||||
}
|
||||
if (_.get(GGUF_QUANT_DESCRIPTIONS, GGMLQuantizationType[quanType])) {
|
||||
console.log('quanType', quanType, FileType[quanType]);
|
||||
if (FileType[quanType] !== undefined) {
|
||||
return <span className="tag-item">{quanType}</span>;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -25,6 +25,7 @@ interface HFModelItemProps {
|
||||
const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
||||
return (
|
||||
<div
|
||||
tabIndex={0}
|
||||
className={classNames('hf-model-item', {
|
||||
active: props.active
|
||||
})}
|
||||
@@ -41,8 +42,8 @@ const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
||||
<Space size={16}>
|
||||
{props.task && (
|
||||
<Tag
|
||||
color="rgb(236, 240, 242)"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-white-1)',
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
@@ -68,9 +69,10 @@ const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
||||
) : (
|
||||
<div className="flex-between">
|
||||
<Space size={10}>
|
||||
{_.map(props.tags, (tag: string) => {
|
||||
{_.map(props.tags, (tag: string, index: string) => {
|
||||
return (
|
||||
<Tag
|
||||
key={index}
|
||||
style={{
|
||||
backgroundColor: 'var(--color-white-1)',
|
||||
marginRight: 0
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Space, Tag } from 'antd';
|
||||
import IconFont from '@/components/icon-font';
|
||||
import { Button, Empty, Tag } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { queryHuggingfaceModelDetail } from '../apis';
|
||||
import '../style/model-card.less';
|
||||
@@ -10,11 +11,11 @@ const ModelCard: React.FC<{ repo: string }> = (props) => {
|
||||
|
||||
const getModelCardData = async () => {
|
||||
if (!repo) {
|
||||
setModelData(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await queryHuggingfaceModelDetail({ repo });
|
||||
console.log('modelcarddata==========', res);
|
||||
setModelData(res);
|
||||
} catch (error) {
|
||||
setModelData({});
|
||||
@@ -31,15 +32,27 @@ const ModelCard: React.FC<{ repo: string }> = (props) => {
|
||||
<span>Model Card</span>
|
||||
</TitleWrapper>
|
||||
<div className="wrapper">
|
||||
<div className="model-card-wrap">
|
||||
<div className="title">{modelData.id}</div>
|
||||
<Space>
|
||||
<Tag className="tag-item">
|
||||
<span className="m-r-5">Architecture:</span>
|
||||
{modelData.config?.model_type}
|
||||
</Tag>
|
||||
</Space>
|
||||
</div>
|
||||
{modelData ? (
|
||||
<div className="model-card-wrap">
|
||||
<div className="title">{modelData.id}</div>
|
||||
<div className="flex-between flex-center">
|
||||
<Tag className="tag-item">
|
||||
<span className="m-r-5">Architecture:</span>
|
||||
{modelData.config?.model_type}
|
||||
</Tag>
|
||||
<Button
|
||||
type="link"
|
||||
target="_blank"
|
||||
href={`https://huggingface.co/${modelData.id}`}
|
||||
>
|
||||
View in Hugging Face
|
||||
<IconFont type="icon-external-link"></IconFont>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import IconFont from '@/components/icon-font';
|
||||
import hotkeys from '@/config/hotkeys';
|
||||
import { platformCall } from '@/utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Input, Tag } from 'antd';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
@@ -10,6 +11,7 @@ const SearchInput: React.FC<{
|
||||
onSearch: (e: any) => void;
|
||||
}> = (props) => {
|
||||
const { onSearch } = props;
|
||||
const intl = useIntl();
|
||||
const [isFocus, setIsFocus] = useState(false);
|
||||
const inputRef = useRef<any>(null);
|
||||
const platform = platformCall();
|
||||
@@ -26,7 +28,9 @@ const SearchInput: React.FC<{
|
||||
onFocus={() => setIsFocus(true)}
|
||||
onBlur={() => setIsFocus(false)}
|
||||
allowClear
|
||||
placeholder="Search models from Hugging Face"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'model.deploy.search.placeholder'
|
||||
})}
|
||||
suffix={
|
||||
!isFocus && (
|
||||
<Tag style={{ marginRight: 0 }}>
|
||||
|
||||
@@ -165,7 +165,11 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
||||
value={sortType}
|
||||
onChange={handleSortChange}
|
||||
labelRender={({ label }) => {
|
||||
return <span>Sort: {label}</span>;
|
||||
return (
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'model.deploy.sort' })}: {label}
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
options={modelFilesSortOptions}
|
||||
size="middle"
|
||||
@@ -203,11 +207,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
||||
return (
|
||||
<div style={{ flex: 1 }}>
|
||||
<div className={SearchStyle['search-bar']}>
|
||||
{/* <RadioButtons
|
||||
options={sourceList}
|
||||
value={modelSource}
|
||||
onChange={handleSourceChange}
|
||||
></RadioButtons> */}
|
||||
{modelSource === modelSourceMap.huggingface_value ? (
|
||||
renderHFSearch()
|
||||
) : (
|
||||
|
||||
@@ -27,7 +27,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
||||
<Row gutter={[16, 16]}>
|
||||
{resultList.map((item, index) => (
|
||||
<Col span={24} key={item.name}>
|
||||
<div onClick={(e) => handleSelect(e, item)} tabIndex={0}>
|
||||
<div onClick={(e) => handleSelect(e, item)}>
|
||||
<HFModelItem
|
||||
source={source}
|
||||
tags={item.tags}
|
||||
|
||||
@@ -22,7 +22,7 @@ import { Access, useAccess, useIntl, useNavigate } from '@umijs/max';
|
||||
import { Button, Dropdown, Input, Space, Tag, message } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import _ from 'lodash';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { memo, useCallback, useRef, useState } from 'react';
|
||||
import {
|
||||
MODELS_API,
|
||||
MODEL_INSTANCE_API,
|
||||
@@ -502,4 +502,4 @@ const Models: React.FC<ModelsProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default Models;
|
||||
export default memo(Models);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
enum FileType {
|
||||
F32 = 0,
|
||||
F16 = 1,
|
||||
Q4_0 = 2,
|
||||
Q4_1 = 3,
|
||||
Q4_1_SOME_F16 = 4,
|
||||
Q8_0 = 7,
|
||||
Q5_0 = 8,
|
||||
Q5_1 = 9,
|
||||
Q2_K = 10,
|
||||
Q3_K_S = 11,
|
||||
Q3_K_M = 12,
|
||||
Q3_K_L = 13,
|
||||
Q4_K_S = 14,
|
||||
Q4_K_M = 15,
|
||||
Q5_K_S = 16,
|
||||
Q5_K_M = 17,
|
||||
Q6_K = 18,
|
||||
IQ2_XXS = 19,
|
||||
IQ2_XS = 20,
|
||||
Q2_K_S = 21,
|
||||
IQ3_XS = 22,
|
||||
IQ3_XXS = 23,
|
||||
IQ1_S = 24,
|
||||
IQ4_NL = 25,
|
||||
IQ3_S = 26,
|
||||
IQ3_M = 27,
|
||||
IQ2_S = 28,
|
||||
IQ2_M = 29,
|
||||
IQ4_XS = 30,
|
||||
IQ1_M = 31,
|
||||
BF16 = 32
|
||||
}
|
||||
|
||||
export default FileType;
|
||||
@@ -23,6 +23,20 @@ export const ollamaModelOptions = [
|
||||
tags: ['9B', '27B'],
|
||||
id: 'gemma2'
|
||||
},
|
||||
{
|
||||
label: 'mistral-nemo',
|
||||
value: 'mistral-nemo',
|
||||
name: 'mistral-nemo',
|
||||
tags: ['12B'],
|
||||
id: 'mistral-nemo'
|
||||
},
|
||||
{
|
||||
label: 'mistral-large',
|
||||
value: 'mistral-large',
|
||||
name: 'mistral-large',
|
||||
tags: ['123B'],
|
||||
id: 'mistral-large'
|
||||
},
|
||||
{
|
||||
label: 'mistral',
|
||||
value: 'mistral',
|
||||
|
||||
@@ -16,9 +16,17 @@ const Models: React.FC = () => {
|
||||
const { setChunkRequest: setModelInstanceChunkRequest } =
|
||||
useSetChunkRequest();
|
||||
const [total, setTotal] = useState(0);
|
||||
const [modelInstances, setModelInstances] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<ListItem[]>([]);
|
||||
const [modelInstances, setModelInstances] = useState<any[]>([]);
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: ListItem[];
|
||||
loading: boolean;
|
||||
total: number;
|
||||
}>({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: 0
|
||||
});
|
||||
const [firstLoad, setFirstLoad] = useState(true);
|
||||
const chunkRequedtRef = useRef<any>();
|
||||
const chunkInstanceRequedtRef = useRef<any>();
|
||||
@@ -30,14 +38,23 @@ const Models: React.FC = () => {
|
||||
});
|
||||
|
||||
const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
|
||||
dataList: dataSource,
|
||||
setDataList: setDataSource
|
||||
dataList: dataSource.dataList,
|
||||
setDataList(list) {
|
||||
setDataSource({
|
||||
total: dataSource.total,
|
||||
loading: false,
|
||||
dataList: list
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
axiosToken?.cancel?.();
|
||||
axiosToken = createAxiosToken();
|
||||
setLoading(true);
|
||||
setDataSource((pre) => {
|
||||
pre.loading = true;
|
||||
return pre;
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
..._.pickBy(queryParams, (val: any) => !!val)
|
||||
@@ -46,14 +63,20 @@ const Models: React.FC = () => {
|
||||
cancelToken: axiosToken.token
|
||||
});
|
||||
if (!firstLoad) {
|
||||
setDataSource(res.items);
|
||||
setDataSource({
|
||||
dataList: res.items || [],
|
||||
loading: false,
|
||||
total: res.pagination.total
|
||||
});
|
||||
}
|
||||
setTotal(res.pagination.total);
|
||||
} catch (error) {
|
||||
setDataSource([]);
|
||||
setDataSource({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: dataSource.total
|
||||
});
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setFirstLoad(false);
|
||||
}
|
||||
}, [queryParams]);
|
||||
@@ -146,13 +169,13 @@ const Models: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
<TableList
|
||||
dataSource={dataSource}
|
||||
dataSource={dataSource.dataList}
|
||||
handleNameChange={handleNameChange}
|
||||
handleSearch={handleSearch}
|
||||
handlePageChange={handlePageChange}
|
||||
queryParams={queryParams}
|
||||
loading={loading}
|
||||
total={total}
|
||||
loading={dataSource.loading}
|
||||
total={dataSource.total}
|
||||
></TableList>
|
||||
</TableContext.Provider>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.model-card-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 72px;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--ant-color-border);
|
||||
border-radius: var(--border-radius-base);
|
||||
|
||||
@@ -12,13 +12,20 @@ import { GPUDeviceItem } from '../config/types';
|
||||
const { Column } = Table;
|
||||
|
||||
const GPUList: React.FC = () => {
|
||||
console.log('GPUList======');
|
||||
const intl = useIntl();
|
||||
const { sortOrder, setSortOrder } = useTableSort({
|
||||
defaultSortOrder: 'descend'
|
||||
});
|
||||
const [dataSource, setDataSource] = useState<GPUDeviceItem[]>([]);
|
||||
const [total, setTotal] = useState(10);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: GPUDeviceItem[];
|
||||
loading: boolean;
|
||||
total: number;
|
||||
}>({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: 0
|
||||
});
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
@@ -39,20 +46,28 @@ const GPUList: React.FC = () => {
|
||||
};
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
setDataSource((pre) => {
|
||||
pre.loading = true;
|
||||
return pre;
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
..._.pickBy(queryParams, (val: any) => !!val)
|
||||
};
|
||||
const res = await queryGpuDevicesList(params);
|
||||
|
||||
setDataSource(res.items);
|
||||
setTotal(res.pagination.total);
|
||||
setDataSource({
|
||||
dataList: res.items || [],
|
||||
loading: false,
|
||||
total: res.pagination.total
|
||||
});
|
||||
} catch (error) {
|
||||
setDataSource([]);
|
||||
setDataSource({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: dataSource.total
|
||||
});
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const handleSearch = (e: any) => {
|
||||
@@ -95,15 +110,15 @@ const GPUList: React.FC = () => {
|
||||
}
|
||||
></PageTools>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
loading={loading}
|
||||
dataSource={dataSource.dataList}
|
||||
loading={dataSource.loading}
|
||||
rowKey="id"
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
pageSize: queryParams.perPage,
|
||||
current: queryParams.page,
|
||||
total: total,
|
||||
total: dataSource.total,
|
||||
hideOnSinglePage: queryParams.perPage === 10,
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
|
||||
@@ -30,10 +30,16 @@ const Resources: React.FC = () => {
|
||||
const modalRef = useRef<any>(null);
|
||||
const rowSelection = useTableRowSelection();
|
||||
const intl = useIntl();
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<ListItem[]>([]);
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: ListItem[];
|
||||
loading: boolean;
|
||||
total: number;
|
||||
}>({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: 0
|
||||
});
|
||||
const [queryParams, setQueryParams] = useState({
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
@@ -41,20 +47,28 @@ const Resources: React.FC = () => {
|
||||
});
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
setDataSource((pre) => {
|
||||
pre.loading = true;
|
||||
return pre;
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
..._.pickBy(queryParams, (val: any) => !!val)
|
||||
};
|
||||
const res = await queryWorkersList(params);
|
||||
|
||||
setDataSource(res.items);
|
||||
setTotal(res.pagination.total);
|
||||
setDataSource({
|
||||
dataList: res.items,
|
||||
loading: false,
|
||||
total: res.pagination.total
|
||||
});
|
||||
} catch (error) {
|
||||
setDataSource([]);
|
||||
setDataSource({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: dataSource.total
|
||||
});
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -193,8 +207,8 @@ const Resources: React.FC = () => {
|
||||
}
|
||||
></PageTools>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
loading={loading}
|
||||
dataSource={dataSource.dataList}
|
||||
loading={dataSource.loading}
|
||||
rowKey="id"
|
||||
onChange={handleTableChange}
|
||||
rowSelection={rowSelection}
|
||||
@@ -202,7 +216,7 @@ const Resources: React.FC = () => {
|
||||
showSizeChanger: true,
|
||||
pageSize: queryParams.perPage,
|
||||
current: queryParams.page,
|
||||
total: total,
|
||||
total: dataSource.total,
|
||||
hideOnSinglePage: queryParams.perPage === 10,
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { Tabs } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import GPUs from './components/gpus';
|
||||
import Workers from './components/workers';
|
||||
|
||||
@@ -19,14 +19,13 @@ const items: TabsProps['items'] = [
|
||||
}
|
||||
];
|
||||
const Resources = () => {
|
||||
console.log('resources======');
|
||||
const [activeKey, setActiveKey] = useState('workers');
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const handleChangeTab = (key: string) => {
|
||||
const handleChangeTab = useCallback((key: string) => {
|
||||
setActiveKey(key);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
+26
-13
@@ -33,10 +33,16 @@ const Users: React.FC = () => {
|
||||
});
|
||||
const intl = useIntl();
|
||||
const modalRef = useRef<any>(null);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [openAddModal, setOpenAddModal] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<ListItem[]>([]);
|
||||
const [dataSource, setDataSource] = useState<{
|
||||
dataList: ListItem[];
|
||||
loading: boolean;
|
||||
total: number;
|
||||
}>({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: 0
|
||||
});
|
||||
const [action, setAction] = useState<PageActionType>(PageAction.CREATE);
|
||||
const [title, setTitle] = useState<string>('');
|
||||
const [currentData, setCurrentData] = useState<ListItem | undefined>(
|
||||
@@ -64,20 +70,27 @@ const Users: React.FC = () => {
|
||||
}
|
||||
];
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
setDataSource((pre) => {
|
||||
pre.loading = true;
|
||||
return pre;
|
||||
});
|
||||
try {
|
||||
const params = {
|
||||
..._.pickBy(queryParams, (val: any) => !!val)
|
||||
};
|
||||
const res = await queryUsersList(params);
|
||||
console.log('res=======', res);
|
||||
setDataSource(res.items);
|
||||
setTotal(res.pagination.total);
|
||||
setDataSource({
|
||||
dataList: res.items || [],
|
||||
loading: false,
|
||||
total: res.pagination.total
|
||||
});
|
||||
} catch (error) {
|
||||
setDataSource([]);
|
||||
setDataSource({
|
||||
dataList: [],
|
||||
loading: false,
|
||||
total: dataSource.total
|
||||
});
|
||||
console.log('error', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -232,16 +245,16 @@ const Users: React.FC = () => {
|
||||
}
|
||||
></PageTools>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
dataSource={dataSource.dataList}
|
||||
rowSelection={rowSelection}
|
||||
loading={loading}
|
||||
loading={dataSource.loading}
|
||||
rowKey="id"
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
pageSize: queryParams.perPage,
|
||||
current: queryParams.page,
|
||||
total: total,
|
||||
total: dataSource.total,
|
||||
hideOnSinglePage: queryParams.perPage === 10,
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user