refactor: models list table columns from props
This commit is contained in:
@@ -4,16 +4,16 @@ import { SealColumnProps } from '../types';
|
|||||||
import TableHeader from './table-header';
|
import TableHeader from './table-header';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
children: React.ReactNode[];
|
columns: SealColumnProps[];
|
||||||
onSort?: (dataIndex: string, order: any) => void;
|
onSort?: (dataIndex: string, order: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Header: React.FC<HeaderProps> = (props) => {
|
const Header: React.FC<HeaderProps> = (props) => {
|
||||||
const { onSort } = props;
|
const { onSort } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="row">
|
<Row className="row">
|
||||||
{React.Children.map(props.children, (child, i) => {
|
{props.columns?.map((columnProps, i) => {
|
||||||
const { props: columnProps } = child as any;
|
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
dataIndex,
|
dataIndex,
|
||||||
@@ -24,25 +24,22 @@ const Header: React.FC<HeaderProps> = (props) => {
|
|||||||
sorter,
|
sorter,
|
||||||
defaultSortOrder
|
defaultSortOrder
|
||||||
} = columnProps as SealColumnProps;
|
} = columnProps as SealColumnProps;
|
||||||
if (React.isValidElement(child)) {
|
return (
|
||||||
return (
|
<Col span={span} key={dataIndex || i}>
|
||||||
<Col span={span} key={i}>
|
<TableHeader
|
||||||
<TableHeader
|
onSort={onSort}
|
||||||
onSort={onSort}
|
sorter={sorter}
|
||||||
sorter={sorter}
|
dataIndex={dataIndex}
|
||||||
dataIndex={dataIndex}
|
sortOrder={sortOrder}
|
||||||
sortOrder={sortOrder}
|
defaultSortOrder={defaultSortOrder}
|
||||||
defaultSortOrder={defaultSortOrder}
|
title={title}
|
||||||
title={title}
|
style={headerStyle}
|
||||||
style={headerStyle}
|
firstCell={i === 0}
|
||||||
firstCell={i === 0}
|
align={align}
|
||||||
align={align}
|
lastCell={i === props.columns.length - 1}
|
||||||
lastCell={i === props.children.length - 1}
|
></TableHeader>
|
||||||
></TableHeader>
|
</Col>
|
||||||
</Col>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})}
|
})}
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
|
import { Button, Checkbox } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface RowPrefixProps {
|
||||||
|
expandable?: boolean | React.ReactNode;
|
||||||
|
enableSelection?: boolean;
|
||||||
|
expanded?: boolean;
|
||||||
|
checked?: boolean;
|
||||||
|
handleRowExpand?: () => void;
|
||||||
|
handleSelectChange?: (e: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RowPrefix: React.FC<RowPrefixProps> = (props) => {
|
||||||
|
const {
|
||||||
|
expandable,
|
||||||
|
enableSelection,
|
||||||
|
expanded,
|
||||||
|
checked,
|
||||||
|
handleRowExpand,
|
||||||
|
handleSelectChange
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
if (expandable && enableSelection) {
|
||||||
|
return (
|
||||||
|
<div className="row-prefix-wrapper">
|
||||||
|
<span style={{ marginRight: 5 }}>
|
||||||
|
{_.isBoolean(expandable) ? (
|
||||||
|
<Button type="text" size="small" onClick={handleRowExpand}>
|
||||||
|
{expanded ? <DownOutlined /> : <RightOutlined />}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
expandable
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<Checkbox onChange={handleSelectChange} checked={checked}></Checkbox>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (expandable) {
|
||||||
|
return (
|
||||||
|
<div className="row-prefix-wrapper">
|
||||||
|
{_.isBoolean(expandable) ? (
|
||||||
|
<Button type="text" size="small" onClick={handleRowExpand}>
|
||||||
|
{expanded ? <DownOutlined /> : <RightOutlined />}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
expandable
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (enableSelection) {
|
||||||
|
return (
|
||||||
|
<div className="row-prefix-wrapper">
|
||||||
|
{<Checkbox onChange={handleSelectChange} checked={checked}></Checkbox>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RowPrefix;
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Checkbox } from 'antd';
|
|
||||||
import '../styles/skeleton.less';
|
|
||||||
|
|
||||||
const RowSkeleton = () => {
|
|
||||||
return (
|
|
||||||
<div className="row-skeleton">
|
|
||||||
<div className="holder"></div>
|
|
||||||
<Checkbox></Checkbox>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RowSkeleton;
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Empty } from 'antd';
|
import { Empty } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { SealColumnProps } from '../types';
|
||||||
import TableRow from './table-row';
|
import TableRow from './table-row';
|
||||||
|
|
||||||
interface TableBodyProps {
|
interface TableBodyProps {
|
||||||
dataSource: any[];
|
dataSource: any[];
|
||||||
columns: React.ReactNode[];
|
columns: SealColumnProps[];
|
||||||
rowKey: string;
|
rowKey: string;
|
||||||
rowSelection?: any;
|
rowSelection?: any;
|
||||||
expandable?: any;
|
expandable?: any;
|
||||||
|
|||||||
@@ -2,14 +2,21 @@ import useSetChunkRequest, {
|
|||||||
createAxiosToken
|
createAxiosToken
|
||||||
} from '@/hooks/use-chunk-request';
|
} from '@/hooks/use-chunk-request';
|
||||||
import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
|
import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
|
||||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
import { Col, Empty, Row, Spin } from 'antd';
|
||||||
import { Button, Checkbox, Col, Empty, Row, Spin } from 'antd';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
import RowContext from '../row-context';
|
import RowContext from '../row-context';
|
||||||
import TableContext from '../table-context';
|
import TableContext from '../table-context';
|
||||||
import { RowContextProps, SealTableProps } from '../types';
|
import { RowContextProps, SealTableProps } from '../types';
|
||||||
|
import RowPrefix from './row-prefix';
|
||||||
|
import TableColumn from './seal-column';
|
||||||
|
|
||||||
const TableRow: React.FC<
|
const TableRow: React.FC<
|
||||||
RowContextProps &
|
RowContextProps &
|
||||||
@@ -38,7 +45,7 @@ const TableRow: React.FC<
|
|||||||
}>(TableContext);
|
}>(TableContext);
|
||||||
const { setChunkRequest } = useSetChunkRequest();
|
const { setChunkRequest } = useSetChunkRequest();
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const [checked, setChecked] = useState(false);
|
// const [checked, setChecked] = useState(false);
|
||||||
const [childrenData, setChildrenData] = useState<any[]>([]);
|
const [childrenData, setChildrenData] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [firstLoad, setFirstLoad] = useState(true);
|
const [firstLoad, setFirstLoad] = useState(true);
|
||||||
@@ -56,17 +63,6 @@ const TableRow: React.FC<
|
|||||||
// callback: (list) => renderChildren?.(list)
|
// callback: (list) => renderChildren?.(list)
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (rowSelection) {
|
|
||||||
const { selectedRowKeys } = rowSelection;
|
|
||||||
if (selectedRowKeys.includes(record[rowKey])) {
|
|
||||||
setChecked(true);
|
|
||||||
} else {
|
|
||||||
setChecked(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [rowSelection]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (pollTimer.current) {
|
if (pollTimer.current) {
|
||||||
@@ -77,7 +73,23 @@ const TableRow: React.FC<
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const checked = useMemo(() => {
|
||||||
|
return rowSelection?.selectedRowKeys?.includes(record[rowKey]);
|
||||||
|
}, [rowSelection?.selectedRowKeys, record, rowKey]);
|
||||||
|
|
||||||
const renderChildrenData = () => {
|
const renderChildrenData = () => {
|
||||||
|
if (childrenData.length === 0) {
|
||||||
|
return (
|
||||||
|
<Empty
|
||||||
|
image={loading ? null : Empty.PRESENTED_IMAGE_SIMPLE}
|
||||||
|
description={loading ? null : undefined}
|
||||||
|
style={{
|
||||||
|
marginBlock: 0,
|
||||||
|
height: 54
|
||||||
|
}}
|
||||||
|
></Empty>
|
||||||
|
);
|
||||||
|
}
|
||||||
return renderChildren?.(childrenData, record);
|
return renderChildren?.(childrenData, record);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,7 +104,7 @@ const TableRow: React.FC<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoadChildren = async () => {
|
const handleLoadChildren = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
axiosToken.current?.cancel?.();
|
axiosToken.current?.cancel?.();
|
||||||
axiosToken.current = createAxiosToken();
|
axiosToken.current = createAxiosToken();
|
||||||
@@ -109,7 +121,7 @@ const TableRow: React.FC<
|
|||||||
} finally {
|
} finally {
|
||||||
setFirstLoad(false);
|
setFirstLoad(false);
|
||||||
}
|
}
|
||||||
};
|
}, [record, loadChildren]);
|
||||||
|
|
||||||
const filterUpdateChildrenHandler = () => {
|
const filterUpdateChildrenHandler = () => {
|
||||||
if (!expandedRowKeys?.includes(record[rowKey])) {
|
if (!expandedRowKeys?.includes(record[rowKey])) {
|
||||||
@@ -224,51 +236,6 @@ const TableRow: React.FC<
|
|||||||
};
|
};
|
||||||
}, [updateChild, tableContext.allChildren]);
|
}, [updateChild, tableContext.allChildren]);
|
||||||
|
|
||||||
const renderRowPrefix = () => {
|
|
||||||
if (expandable && rowSelection) {
|
|
||||||
return (
|
|
||||||
<div className="row-prefix-wrapper">
|
|
||||||
<span style={{ marginRight: 5 }}>
|
|
||||||
{_.isBoolean(expandable) ? (
|
|
||||||
<Button type="text" size="small" onClick={handleRowExpand}>
|
|
||||||
{expanded ? <DownOutlined /> : <RightOutlined />}
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
expandable
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<Checkbox onChange={handleSelectChange} checked={checked}></Checkbox>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (expandable) {
|
|
||||||
return (
|
|
||||||
<div className="row-prefix-wrapper">
|
|
||||||
{_.isBoolean(expandable) ? (
|
|
||||||
<Button type="text" size="small" onClick={handleRowExpand}>
|
|
||||||
{expanded ? <DownOutlined /> : <RightOutlined />}
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
expandable
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (rowSelection) {
|
|
||||||
return (
|
|
||||||
<div className="row-prefix-wrapper">
|
|
||||||
{
|
|
||||||
<Checkbox
|
|
||||||
onChange={handleSelectChange}
|
|
||||||
checked={checked}
|
|
||||||
></Checkbox>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowContext.Provider value={{ row: { ...record, rowIndex }, onCell }}>
|
<RowContext.Provider value={{ row: { ...record, rowIndex }, onCell }}>
|
||||||
<div className="row-box">
|
<div className="row-box">
|
||||||
@@ -277,40 +244,30 @@ const TableRow: React.FC<
|
|||||||
'row-wrapper-selected': checked
|
'row-wrapper-selected': checked
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{renderRowPrefix()}
|
<RowPrefix
|
||||||
|
expandable={expandable}
|
||||||
|
enableSelection={rowSelection?.enableSelection}
|
||||||
|
expanded={expanded}
|
||||||
|
checked={checked}
|
||||||
|
handleRowExpand={handleRowExpand}
|
||||||
|
handleSelectChange={handleSelectChange}
|
||||||
|
></RowPrefix>
|
||||||
<Row className="seal-table-row">
|
<Row className="seal-table-row">
|
||||||
{React.Children.map(columns, (child) => {
|
{columns?.map((columnProps) => {
|
||||||
const { props: columnProps } = child as any;
|
return (
|
||||||
if (React.isValidElement(child)) {
|
<Col
|
||||||
return (
|
key={`${columnProps.dataIndex}-${rowIndex}`}
|
||||||
<Col
|
span={columnProps.span}
|
||||||
key={`${columnProps.dataIndex}-${rowIndex}`}
|
>
|
||||||
span={columnProps.span}
|
<TableColumn {...columnProps}></TableColumn>
|
||||||
>
|
</Col>
|
||||||
{child}
|
);
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <Col span={columnProps.span}></Col>;
|
|
||||||
})}
|
})}
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
{expanded && (
|
{expanded && (
|
||||||
<div className="expanded-row">
|
<div className="expanded-row">
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>{renderChildrenData()}</Spin>
|
||||||
{childrenData.length ? (
|
|
||||||
renderChildrenData()
|
|
||||||
) : (
|
|
||||||
<Empty
|
|
||||||
image={loading ? null : Empty.PRESENTED_IMAGE_SIMPLE}
|
|
||||||
description={loading ? null : undefined}
|
|
||||||
style={{
|
|
||||||
marginBlock: 0,
|
|
||||||
height: 54
|
|
||||||
}}
|
|
||||||
></Empty>
|
|
||||||
)}
|
|
||||||
</Spin>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Checkbox } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import '../styles/skeleton.less';
|
||||||
|
|
||||||
|
const SkeletonItem = () => {
|
||||||
|
return (
|
||||||
|
<div className="row-skeleton">
|
||||||
|
<div className="holder"></div>
|
||||||
|
<Checkbox></Checkbox>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TableSkeleton = () => {
|
||||||
|
const dataSource = Array.from({ length: 5 });
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{dataSource.map((item, index) => (
|
||||||
|
<SkeletonItem key={index} />
|
||||||
|
))}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(TableSkeleton);
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
import { Pagination, Spin, type PaginationProps } from 'antd';
|
import { Pagination, Spin, type PaginationProps } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import Header from './components/header';
|
import Header from './components/header';
|
||||||
import HeaderPrefix from './components/header-prefix';
|
import HeaderPrefix from './components/header-prefix';
|
||||||
import TableBody from './components/table-body';
|
import TableBody from './components/table-body';
|
||||||
import './styles/index.less';
|
import './styles/index.less';
|
||||||
import { SealTableProps } from './types';
|
import { SealColumnProps, SealTableProps } from './types';
|
||||||
|
|
||||||
const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
|
const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
|
||||||
props
|
props
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
|
columns,
|
||||||
children,
|
children,
|
||||||
rowKey,
|
rowKey,
|
||||||
childParentKey,
|
childParentKey,
|
||||||
@@ -29,33 +30,46 @@ const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
|
|||||||
loadChildren,
|
loadChildren,
|
||||||
loadChildrenAPI
|
loadChildrenAPI
|
||||||
} = props;
|
} = props;
|
||||||
const [selectState, setSelectState] = useState({
|
|
||||||
selectAll: false,
|
|
||||||
indeterminate: false
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
const parsedColumns = useMemo(() => {
|
||||||
if (rowSelection) {
|
if (columns) return columns;
|
||||||
const { selectedRowKeys } = rowSelection;
|
|
||||||
const selectedKeys = new Set(rowSelection.selectedRowKeys);
|
return React.Children.toArray(children)
|
||||||
const allRowKeys = props.dataSource.map((record) => record[rowKey]);
|
.filter(React.isValidElement)
|
||||||
if (!selectedRowKeys?.length) {
|
.map((child) => {
|
||||||
setSelectState({
|
const column = child as React.ReactElement<SealColumnProps>;
|
||||||
selectAll: false,
|
const { title, dataIndex, key, render, ...restProps } = column.props;
|
||||||
indeterminate: false
|
|
||||||
});
|
return {
|
||||||
} else if (allRowKeys.every((key) => selectedKeys.has(key))) {
|
title,
|
||||||
setSelectState({
|
dataIndex,
|
||||||
selectAll: true,
|
key: key || dataIndex,
|
||||||
indeterminate: false
|
render,
|
||||||
});
|
...restProps
|
||||||
} else {
|
};
|
||||||
setSelectState({
|
});
|
||||||
selectAll: false,
|
}, [columns, children]);
|
||||||
indeterminate: true
|
|
||||||
});
|
const selectState = useMemo(() => {
|
||||||
}
|
const selectedRowKeys = rowSelection?.selectedRowKeys || [];
|
||||||
|
const selectedKeys = new Set(selectedRowKeys);
|
||||||
|
const allRowKeys = props.dataSource.map((record) => record[rowKey]);
|
||||||
|
if (!selectedRowKeys?.length) {
|
||||||
|
return {
|
||||||
|
selectAll: false,
|
||||||
|
indeterminate: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
if (allRowKeys.every((key) => selectedKeys.has(key))) {
|
||||||
|
return {
|
||||||
|
selectAll: true,
|
||||||
|
indeterminate: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
selectAll: false,
|
||||||
|
indeterminate: true
|
||||||
|
};
|
||||||
}, [rowSelection?.selectedRowKeys, props.dataSource, rowKey]);
|
}, [rowSelection?.selectedRowKeys, props.dataSource, rowKey]);
|
||||||
|
|
||||||
const selectAllRows = () => {
|
const selectAllRows = () => {
|
||||||
@@ -103,12 +117,12 @@ const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
|
|||||||
expandable={expandable}
|
expandable={expandable}
|
||||||
enableSelection={rowSelection?.enableSelection}
|
enableSelection={rowSelection?.enableSelection}
|
||||||
></HeaderPrefix>
|
></HeaderPrefix>
|
||||||
<Header onSort={onSort}>{children}</Header>
|
<Header onSort={onSort} columns={parsedColumns}></Header>
|
||||||
</div>
|
</div>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<TableBody
|
<TableBody
|
||||||
dataSource={props.dataSource}
|
dataSource={props.dataSource}
|
||||||
columns={children}
|
columns={parsedColumns}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
expandable={expandable}
|
expandable={expandable}
|
||||||
rowKey={rowKey}
|
rowKey={rowKey}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export interface SealColumnProps {
|
|||||||
title: React.ReactNode;
|
title: React.ReactNode;
|
||||||
render?: (text: any, record: any) => React.ReactNode;
|
render?: (text: any, record: any) => React.ReactNode;
|
||||||
dataIndex: string;
|
dataIndex: string;
|
||||||
|
key?: string;
|
||||||
width?: number;
|
width?: number;
|
||||||
span: number;
|
span: number;
|
||||||
align?: 'left' | 'center' | 'right';
|
align?: 'left' | 'center' | 'right';
|
||||||
@@ -18,6 +19,7 @@ export interface SealColumnProps {
|
|||||||
};
|
};
|
||||||
valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time';
|
valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time';
|
||||||
sortOrder?: 'ascend' | 'descend' | null;
|
sortOrder?: 'ascend' | 'descend' | null;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableHeaderProps {
|
export interface TableHeaderProps {
|
||||||
@@ -26,7 +28,7 @@ export interface TableHeaderProps {
|
|||||||
sortOrder?: 'ascend' | 'descend' | null;
|
sortOrder?: 'ascend' | 'descend' | null;
|
||||||
dataIndex: string;
|
dataIndex: string;
|
||||||
onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void;
|
onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactElement<SealColumnProps>;
|
||||||
title: React.ReactNode;
|
title: React.ReactNode;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
firstCell?: boolean;
|
firstCell?: boolean;
|
||||||
@@ -42,10 +44,11 @@ export interface RowSelectionProps {
|
|||||||
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => void;
|
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => void;
|
||||||
}
|
}
|
||||||
export interface SealTableProps {
|
export interface SealTableProps {
|
||||||
|
columns?: SealColumnProps[];
|
||||||
childParentKey?: string;
|
childParentKey?: string;
|
||||||
expandedRowKeys?: React.Key[];
|
expandedRowKeys?: React.Key[];
|
||||||
rowSelection?: RowSelectionProps;
|
rowSelection?: RowSelectionProps;
|
||||||
children: React.ReactNode[];
|
children?: React.ReactElement<SealColumnProps>[];
|
||||||
empty?: React.ReactNode;
|
empty?: React.ReactNode;
|
||||||
expandable?: React.ReactNode;
|
expandable?: React.ReactNode;
|
||||||
dataSource: any[];
|
dataSource: any[];
|
||||||
@@ -65,7 +68,6 @@ export interface SealTableProps {
|
|||||||
|
|
||||||
export interface RowContextProps {
|
export interface RowContextProps {
|
||||||
record: Record<string, any>;
|
record: Record<string, any>;
|
||||||
columns: React.ReactNode[];
|
|
||||||
pollingChildren?: boolean;
|
pollingChildren?: boolean;
|
||||||
rowIndex: number;
|
rowIndex: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { useIntl } from '@umijs/max';
|
|||||||
import { Button, Col, Divider, Row, Space, Tag, Tooltip } from 'antd';
|
import { Button, Col, Divider, Row, Space, Tag, Tooltip } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback } from 'react';
|
import React from 'react';
|
||||||
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
|
import { InstanceStatusMap, InstanceStatusMapValue, status } from '../config';
|
||||||
import { ModelInstanceListItem } from '../config/types';
|
import { ModelInstanceListItem } from '../config/types';
|
||||||
import '../style/instance-item.less';
|
import '../style/instance-item.less';
|
||||||
@@ -35,6 +35,38 @@ interface InstanceItemProps {
|
|||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const childActionList = [
|
||||||
|
{
|
||||||
|
label: 'common.button.viewlog',
|
||||||
|
key: 'viewlog',
|
||||||
|
status: [
|
||||||
|
InstanceStatusMap.Initializing,
|
||||||
|
InstanceStatusMap.Running,
|
||||||
|
InstanceStatusMap.Error,
|
||||||
|
InstanceStatusMap.Starting,
|
||||||
|
InstanceStatusMap.Downloading
|
||||||
|
],
|
||||||
|
icon: <IconFont type="icon-logs" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.button.delrecreate',
|
||||||
|
key: 'delete',
|
||||||
|
props: {
|
||||||
|
danger: true
|
||||||
|
},
|
||||||
|
icon: <DeleteOutlined />
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const setChildActionList = (item: ModelInstanceListItem) => {
|
||||||
|
return _.filter(childActionList, (action: any) => {
|
||||||
|
if (action.key === 'viewlog') {
|
||||||
|
return action.status.includes(item.state);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const InstanceItem: React.FC<InstanceItemProps> = ({
|
const InstanceItem: React.FC<InstanceItemProps> = ({
|
||||||
list,
|
list,
|
||||||
workerList,
|
workerList,
|
||||||
@@ -43,56 +75,6 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const distributeCols = [
|
|
||||||
{
|
|
||||||
title: 'Worker',
|
|
||||||
key: 'worker_name'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'IP',
|
|
||||||
key: 'worker_ip',
|
|
||||||
render: ({ row }: { row: ModelInstanceListItem }) => {
|
|
||||||
return row.port ? `${row.worker_ip}:${row.port}` : row.worker_ip;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage({ id: 'models.table.gpuindex' }),
|
|
||||||
key: 'gpu_index'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const childActionList = [
|
|
||||||
{
|
|
||||||
label: 'common.button.viewlog',
|
|
||||||
key: 'viewlog',
|
|
||||||
status: [
|
|
||||||
InstanceStatusMap.Initializing,
|
|
||||||
InstanceStatusMap.Running,
|
|
||||||
InstanceStatusMap.Error,
|
|
||||||
InstanceStatusMap.Starting,
|
|
||||||
InstanceStatusMap.Downloading
|
|
||||||
],
|
|
||||||
icon: <IconFont type="icon-logs" />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'common.button.delrecreate',
|
|
||||||
key: 'delete',
|
|
||||||
props: {
|
|
||||||
danger: true
|
|
||||||
},
|
|
||||||
icon: <DeleteOutlined />
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const setChildActionList = useCallback((item: ModelInstanceListItem) => {
|
|
||||||
return _.filter(childActionList, (action: any) => {
|
|
||||||
if (action.key === 'viewlog') {
|
|
||||||
return action.status.includes(item.state);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const renderWorkerInfo = (item: ModelInstanceListItem) => {
|
const renderWorkerInfo = (item: ModelInstanceListItem) => {
|
||||||
let workerIp = '-';
|
let workerIp = '-';
|
||||||
if (item.worker_ip) {
|
if (item.worker_ip) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import IconFont from '@/components/icon-font';
|
|||||||
import { PageSize } from '@/components/logs-viewer/config';
|
import { PageSize } from '@/components/logs-viewer/config';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import SealTable from '@/components/seal-table';
|
import SealTable from '@/components/seal-table';
|
||||||
import SealColumn from '@/components/seal-table/components/seal-column';
|
import { SealColumnProps } from '@/components/seal-table/types';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import HotKeys from '@/config/hotkeys';
|
import HotKeys from '@/config/hotkeys';
|
||||||
import useBodyScroll from '@/hooks/use-body-scroll';
|
import useBodyScroll from '@/hooks/use-body-scroll';
|
||||||
@@ -32,7 +32,7 @@ import { Button, Dropdown, Input, Select, Space, Tooltip, message } from 'antd';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import {
|
import {
|
||||||
MODELS_API,
|
MODELS_API,
|
||||||
@@ -113,6 +113,39 @@ const ActionList = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const generateSource = (record: ListItem) => {
|
||||||
|
if (record.source === modelSourceMap.modelscope_value) {
|
||||||
|
return `${modelSourceMap.modelScope}/${record.model_scope_model_id}`;
|
||||||
|
}
|
||||||
|
if (record.source === modelSourceMap.huggingface_value) {
|
||||||
|
return `${modelSourceMap.huggingface}/${record.huggingface_repo_id}`;
|
||||||
|
}
|
||||||
|
if (record.source === modelSourceMap.local_path_value) {
|
||||||
|
return `${record.local_path}`;
|
||||||
|
}
|
||||||
|
if (record.source === modelSourceMap.ollama_library_value) {
|
||||||
|
return `${modelSourceMap.ollama_library}/${record.ollama_library_model_name}`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const setActionList = (record: ListItem) => {
|
||||||
|
return _.filter(ActionList, (action: any) => {
|
||||||
|
if (action.key === 'chat') {
|
||||||
|
return record.ready_replicas > 0;
|
||||||
|
}
|
||||||
|
if (action.key === 'start') {
|
||||||
|
return record.replicas === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.key === 'stop') {
|
||||||
|
return record.replicas > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const Models: React.FC<ModelsProps> = ({
|
const Models: React.FC<ModelsProps> = ({
|
||||||
handleNameChange,
|
handleNameChange,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
@@ -270,28 +303,11 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const setActionList = useCallback((record: ListItem) => {
|
|
||||||
return _.filter(ActionList, (action: any) => {
|
|
||||||
if (action.key === 'chat') {
|
|
||||||
return record.ready_replicas > 0;
|
|
||||||
}
|
|
||||||
if (action.key === 'start') {
|
|
||||||
return record.replicas === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.key === 'stop') {
|
|
||||||
return record.replicas > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleOnSort = (dataIndex: string, order: any) => {
|
const handleOnSort = (dataIndex: string, order: any) => {
|
||||||
setSortOrder(order);
|
setSortOrder(order);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnCell = async (record: any, dataIndex: string) => {
|
const handleOnCell = useCallback(async (record: any, dataIndex: string) => {
|
||||||
const params = {
|
const params = {
|
||||||
id: record.id,
|
id: record.id,
|
||||||
data: _.omit(record, [
|
data: _.omit(record, [
|
||||||
@@ -304,7 +320,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
};
|
};
|
||||||
await updateModel(params);
|
await updateModel(params);
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const handleStartModel = async (row: ListItem) => {
|
const handleStartModel = async (row: ListItem) => {
|
||||||
try {
|
try {
|
||||||
@@ -502,7 +518,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
[deleteModelInstance]
|
[deleteModelInstance]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getModelInstances = async (row: any, options?: any) => {
|
const getModelInstances = useCallback(async (row: any, options?: any) => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
@@ -516,11 +532,11 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const generateChildrenRequestAPI = (params: any) => {
|
const generateChildrenRequestAPI = useCallback((params: any) => {
|
||||||
return `${MODELS_API}/${params.id}/instances`;
|
return `${MODELS_API}/${params.id}/instances`;
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const handleEdit = (row: ListItem) => {
|
const handleEdit = (row: ListItem) => {
|
||||||
setCurrentData(row);
|
setCurrentData(row);
|
||||||
@@ -588,22 +604,6 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
[workerList]
|
[workerList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const generateSource = useCallback((record: ListItem) => {
|
|
||||||
if (record.source === modelSourceMap.modelscope_value) {
|
|
||||||
return `${modelSourceMap.modelScope}/${record.model_scope_model_id}`;
|
|
||||||
}
|
|
||||||
if (record.source === modelSourceMap.huggingface_value) {
|
|
||||||
return `${modelSourceMap.huggingface}/${record.huggingface_repo_id}`;
|
|
||||||
}
|
|
||||||
if (record.source === modelSourceMap.local_path_value) {
|
|
||||||
return `${record.local_path}`;
|
|
||||||
}
|
|
||||||
if (record.source === modelSourceMap.ollama_library_value) {
|
|
||||||
return `${modelSourceMap.ollama_library}/${record.ollama_library_model_name}`;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleClickDropdown = (item: any) => {
|
const handleClickDropdown = (item: any) => {
|
||||||
if (item.key === 'huggingface') {
|
if (item.key === 'huggingface') {
|
||||||
setOpenDeployModal({
|
setOpenDeployModal({
|
||||||
@@ -667,6 +667,87 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const columns: SealColumnProps[] = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
title: intl.formatMessage({ id: 'common.table.name' }),
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: 400,
|
||||||
|
span: 5,
|
||||||
|
render: (text: string, record: ListItem) => (
|
||||||
|
<span className="flex-center" style={{ maxWidth: '100%' }}>
|
||||||
|
<AutoTooltip ghost>
|
||||||
|
<span className="m-r-5">{text}</span>
|
||||||
|
</AutoTooltip>
|
||||||
|
<ModelTag categoryKey={record.categories?.[0] || ''} />
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: intl.formatMessage({ id: 'models.form.source' }),
|
||||||
|
dataIndex: 'source',
|
||||||
|
key: 'source',
|
||||||
|
span: 6,
|
||||||
|
render: (text: string, record: ListItem) => (
|
||||||
|
<span className="flex flex-column" style={{ width: '100%' }}>
|
||||||
|
<AutoTooltip ghost>{generateSource(record)}</AutoTooltip>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: (
|
||||||
|
<Tooltip
|
||||||
|
title={intl.formatMessage({ id: 'models.form.replicas.tips' })}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: 'models.form.replicas' })}
|
||||||
|
<QuestionCircleOutlined className="m-l-5" />
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
dataIndex: 'replicas',
|
||||||
|
key: 'replicas',
|
||||||
|
align: 'center',
|
||||||
|
span: 4,
|
||||||
|
editable: {
|
||||||
|
valueType: 'number',
|
||||||
|
title: intl.formatMessage({ id: 'models.table.replicas.edit' })
|
||||||
|
},
|
||||||
|
render: (text: number, record: ListItem) => (
|
||||||
|
<span style={{ paddingLeft: 10, minWidth: '33px' }}>
|
||||||
|
{record.ready_replicas} / {record.replicas}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: intl.formatMessage({ id: 'common.table.createTime' }),
|
||||||
|
dataIndex: 'created_at',
|
||||||
|
key: 'created_at',
|
||||||
|
defaultSortOrder: 'descend',
|
||||||
|
sortOrder,
|
||||||
|
sorter: false,
|
||||||
|
span: 5,
|
||||||
|
render: (text: number) => (
|
||||||
|
<AutoTooltip ghost>
|
||||||
|
{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
|
</AutoTooltip>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: intl.formatMessage({ id: 'common.table.operation' }),
|
||||||
|
key: 'operation',
|
||||||
|
dataIndex: 'operation',
|
||||||
|
span: 4,
|
||||||
|
render: (text, record) => (
|
||||||
|
<DropdownButtons
|
||||||
|
items={setActionList(record)}
|
||||||
|
onSelect={(val) => handleSelect(val, record)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[sortOrder, intl]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageContainer
|
<PageContainer
|
||||||
@@ -776,6 +857,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
}
|
}
|
||||||
></PageTools>
|
></PageTools>
|
||||||
<SealTable
|
<SealTable
|
||||||
|
columns={columns}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
expandedRowKeys={expandedRowKeys}
|
expandedRowKeys={expandedRowKeys}
|
||||||
@@ -800,100 +882,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
hideOnSinglePage: queryParams.perPage === 10,
|
hideOnSinglePage: queryParams.perPage === 10,
|
||||||
onChange: handlePageChange
|
onChange: handlePageChange
|
||||||
}}
|
}}
|
||||||
>
|
></SealTable>
|
||||||
<SealColumn
|
|
||||||
title={intl.formatMessage({ id: 'common.table.name' })}
|
|
||||||
dataIndex="name"
|
|
||||||
key="name"
|
|
||||||
width={400}
|
|
||||||
span={5}
|
|
||||||
render={(text, record: ListItem) => {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className="flex-center"
|
|
||||||
style={{
|
|
||||||
maxWidth: '100%'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AutoTooltip ghost>
|
|
||||||
<span className="m-r-5">{text}</span>
|
|
||||||
</AutoTooltip>
|
|
||||||
<ModelTag
|
|
||||||
categoryKey={record.categories?.[0] || ''}
|
|
||||||
></ModelTag>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SealColumn
|
|
||||||
title={intl.formatMessage({ id: 'models.form.source' })}
|
|
||||||
dataIndex="source"
|
|
||||||
key="source"
|
|
||||||
span={6}
|
|
||||||
render={(text, record: ListItem) => {
|
|
||||||
return (
|
|
||||||
<span className="flex flex-column" style={{ width: '100%' }}>
|
|
||||||
<AutoTooltip ghost>{generateSource(record)}</AutoTooltip>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SealColumn
|
|
||||||
title={
|
|
||||||
<Tooltip
|
|
||||||
title={intl.formatMessage({ id: 'models.form.replicas.tips' })}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({ id: 'models.form.replicas' })}
|
|
||||||
<QuestionCircleOutlined className="m-l-5" />
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
dataIndex="replicas"
|
|
||||||
key="replicas"
|
|
||||||
align="center"
|
|
||||||
span={4}
|
|
||||||
editable={{
|
|
||||||
valueType: 'number',
|
|
||||||
title: intl.formatMessage({ id: 'models.table.replicas.edit' })
|
|
||||||
}}
|
|
||||||
render={(text, record: ListItem) => {
|
|
||||||
return (
|
|
||||||
<span style={{ paddingLeft: 10, minWidth: '33px' }}>
|
|
||||||
{record.ready_replicas} / {record.replicas}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SealColumn
|
|
||||||
span={5}
|
|
||||||
title={intl.formatMessage({ id: 'common.table.createTime' })}
|
|
||||||
dataIndex="created_at"
|
|
||||||
key="created_at"
|
|
||||||
defaultSortOrder="descend"
|
|
||||||
sortOrder={sortOrder}
|
|
||||||
sorter={false}
|
|
||||||
render={(text, row) => {
|
|
||||||
return (
|
|
||||||
<AutoTooltip ghost>
|
|
||||||
{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
|
||||||
</AutoTooltip>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<SealColumn
|
|
||||||
span={4}
|
|
||||||
title={intl.formatMessage({ id: 'common.table.operation' })}
|
|
||||||
key="operation"
|
|
||||||
dataIndex="operation"
|
|
||||||
render={(text, record) => {
|
|
||||||
return (
|
|
||||||
<DropdownButtons
|
|
||||||
items={setActionList(record)}
|
|
||||||
onSelect={(val) => handleSelect(val, record)}
|
|
||||||
></DropdownButtons>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SealTable>
|
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
<UpdateModel
|
<UpdateModel
|
||||||
open={openAddModal}
|
open={openAddModal}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ export interface FormData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelInstanceListItem {
|
export interface ModelInstanceListItem {
|
||||||
|
backend?: string;
|
||||||
|
backend_version?: string;
|
||||||
source: string;
|
source: string;
|
||||||
huggingface_repo_id: string;
|
huggingface_repo_id: string;
|
||||||
huggingface_filename: string;
|
huggingface_filename: string;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const AddWorker: React.FC<ViewModalProps> = (props) => {
|
|||||||
token: '${mytoken}',
|
token: '${mytoken}',
|
||||||
workerip: '${myworkerip}'
|
workerip: '${myworkerip}'
|
||||||
});
|
});
|
||||||
}, [versionInfo, activeKey, props.token, origin]);
|
}, [versionInfo, activeKey, props.token]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-install">
|
<div className="container-install">
|
||||||
|
|||||||
Reference in New Issue
Block a user