diff --git a/config/theme.ts b/config/theme.ts index 9a3a3883..7e7132ae 100644 --- a/config/theme.ts +++ b/config/theme.ts @@ -32,6 +32,9 @@ export default { colorBgSpotlight: '#3e3e3e' // sizePopupArrow: 0 }, + Cascader: { + dropdownHeight: 240 + }, Slider: { handleSize: 8, handleSizeHover: 8, diff --git a/src/components/markdown-viewer/code-viewer.tsx b/src/components/markdown-viewer/code-viewer.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/components/seal-table/components/header-prefix.tsx b/src/components/seal-table/components/header-prefix.tsx new file mode 100644 index 00000000..a8c4683a --- /dev/null +++ b/src/components/seal-table/components/header-prefix.tsx @@ -0,0 +1,50 @@ +import { RightOutlined } from '@ant-design/icons'; +import { Button, Checkbox } from 'antd'; +import _ from 'lodash'; +import React from 'react'; + +interface HeaderPrefixProps { + expandable?: boolean | React.ReactNode; + enableSelection?: boolean; + onSelectAll?: (e: any) => void; + indeterminate?: boolean; + selectAll?: boolean; +} + +const HeaderPrefix: React.FC = (props) => { + const { expandable, enableSelection, onSelectAll, indeterminate, selectAll } = + props; + if (expandable && enableSelection) { + return ( +
+ + +
+ ); + } + if (expandable) { + return ( +
+ {_.isBoolean(expandable) ? ( + + ) : ( + expandable + )} +
+ ); + } + if (enableSelection) { + return ( +
{}
+ ); + } + return null; +}; + +export default React.memo(HeaderPrefix); diff --git a/src/components/seal-table/components/seal-column.tsx b/src/components/seal-table/components/seal-column.tsx index cc76f468..d610a41a 100644 --- a/src/components/seal-table/components/seal-column.tsx +++ b/src/components/seal-table/components/seal-column.tsx @@ -2,18 +2,122 @@ import { CheckOutlined, FormOutlined, UndoOutlined } from '@ant-design/icons'; import { useIntl } from '@umijs/max'; import { Button, Input, InputNumber, Tooltip } from 'antd'; import classNames from 'classnames'; +import _ from 'lodash'; import React, { useContext, useEffect } from 'react'; import RowContext from '../row-context'; import '../styles/cell.less'; import { SealColumnProps } from '../types'; -const SealColumn: React.FC = (props) => { +interface EditButtonsProps { + isEditing: boolean; + editable?: any; + handleSubmit: () => void; + handleUndo: () => void; + handleEdit: () => void; +} + +interface CellContentProps { + isEditing: boolean; + current: any; + editable: any; + onChange: (val: any) => void; + row?: any; + render?: (text: any, record: any) => React.ReactNode; +} + +const EditButtons: React.FC = (props) => { const intl = useIntl(); + const { isEditing, editable, handleSubmit, handleUndo, handleEdit } = props; + if (!editable) { + return null; + } + + if (isEditing) { + return ( + + + + + + + + + ); + } + return ( + + {editable.title || ''} + ) + } + > + + + + ); +}; + +const CellContent: React.FC = (props) => { + const { editable, current, isEditing, row, render, onChange } = props; + if (isEditing && editable) { + const isNumType = + typeof editable === 'object' && editable?.valueType === 'number'; + return isNumType ? ( + + ) : ( + onChange(e.target.value)} /> + ); + } + + if (render) { + return render(current, row); + } + return current; +}; + +const SealColumn: React.FC = (props) => { const { row, onCell } = useContext(RowContext); const { dataIndex, render, align, editable } = props; const [isEditing, setIsEditing] = React.useState(false); const [current, setCurrent] = React.useState(row[dataIndex]); - const cachedValue = React.useRef(row[dataIndex]); + const cachedValue = React.useRef(null); const handleEdit = () => { setIsEditing(true); @@ -35,40 +139,16 @@ const SealColumn: React.FC = (props) => { setCurrent(cachedValue.current); setIsEditing(false); }; - useEffect(() => { - if (editable) { - cachedValue.current = row[dataIndex]; - } - setCurrent(row[dataIndex]); - }, [row[dataIndex], editable]); - const renderContent = () => { - if (isEditing && editable) { - const isNumType = - typeof editable === 'object' && editable.valueType === 'number'; - return isNumType ? ( - { - setCurrent(val as any); - }} - /> - ) : ( - { - setCurrent(e.target.value); - }} - /> - ); - } - if (render) { - return render(current, row); - } - return current; + const handleValueChange = (val: any) => { + setCurrent(val); }; + + useEffect(() => { + cachedValue.current = row[dataIndex]; + setCurrent(row[dataIndex]); + }, [row[dataIndex]]); + return (
= (props) => { })} > - {renderContent()} - {editable && ( - - {isEditing ? ( - <> - - - - - - - - ) : ( - {editable?.title}}> - - - )} - - )} + +
); }; -export default React.memo(SealColumn); +export default SealColumn; diff --git a/src/components/seal-table/components/table-body.tsx b/src/components/seal-table/components/table-body.tsx new file mode 100644 index 00000000..6f0ac0bc --- /dev/null +++ b/src/components/seal-table/components/table-body.tsx @@ -0,0 +1,72 @@ +import { Empty } from 'antd'; +import React from 'react'; +import TableRow from './table-row'; + +interface TableBodyProps { + dataSource: any[]; + columns: React.ReactNode[]; + rowKey: string; + rowSelection?: any; + expandable?: any; + expandedRowKeys?: any; + onExpand?: any; + childParentKey?: any; + pollingChildren?: any; + watchChildren?: any; + renderChildren?: any; + loadChildren?: any; + loadChildrenAPI?: any; + onCell?: any; +} + +const TableBody: React.FC = ({ + dataSource, + rowKey, + rowSelection, + expandable, + expandedRowKeys, + onExpand, + childParentKey, + pollingChildren, + watchChildren, + renderChildren, + loadChildren, + loadChildrenAPI, + columns, + onCell +}) => { + if (!dataSource.length) { + return ( +
+ +
+ ); + } + + return ( +
+ {dataSource.map((item, index) => ( + + ))} +
+ ); +}; + +export default TableBody; diff --git a/src/components/seal-table/index.tsx b/src/components/seal-table/index.tsx index 8949df83..a4709d9f 100644 --- a/src/components/seal-table/index.tsx +++ b/src/components/seal-table/index.tsx @@ -1,16 +1,9 @@ -import { RightOutlined } from '@ant-design/icons'; -import { - Button, - Checkbox, - Empty, - Pagination, - Spin, - type PaginationProps -} from 'antd'; +import { Pagination, Spin, type PaginationProps } from 'antd'; import _ from 'lodash'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import Header from './components/header'; -import TableRow from './components/table-row'; +import HeaderPrefix from './components/header-prefix'; +import TableBody from './components/table-body'; import './styles/index.less'; import { SealTableProps } from './types'; @@ -36,42 +29,58 @@ const SealTable: React.FC = ( loadChildren, loadChildrenAPI } = props; - console.log('sealtable===='); - const [selectAll, setSelectAll] = useState(false); - const [indeterminate, setIndeterminate] = useState(false); - const tableContent = useRef(null); + const [selectState, setSelectState] = useState({ + selectAll: false, + indeterminate: false + }); useEffect(() => { if (rowSelection) { const { selectedRowKeys } = rowSelection; - if (selectedRowKeys?.length === 0) { - setSelectAll(false); - setIndeterminate(false); - } else if ( - selectedRowKeys?.length === props.dataSource.length && - selectedRowKeys.length > 0 - ) { - setSelectAll(true); - setIndeterminate(false); + const selectedKeys = new Set(rowSelection.selectedRowKeys); + const allRowKeys = props.dataSource.map((record) => record[rowKey]); + if (!selectedRowKeys?.length) { + setSelectState({ + selectAll: false, + indeterminate: false + }); + } else if (allRowKeys.every((key) => selectedKeys.has(key))) { + setSelectState({ + selectAll: true, + indeterminate: false + }); } else { - setSelectAll(false); - setIndeterminate(true); + setSelectState({ + selectAll: false, + indeterminate: true + }); } } - }, [rowSelection, props.dataSource]); + }, [rowSelection?.selectedRowKeys, props.dataSource, rowKey]); + + const selectAllRows = () => { + const allKeys = new Set([ + ...props.dataSource.map((record) => record[rowKey]), + ...(rowSelection?.selectedRowKeys || []) + ]); + const allDatas = _.uniqBy( + [...props.dataSource, ...(rowSelection?.selectedRows || [])], + (record: any) => record[rowKey] + ); + + rowSelection?.onChange([...allKeys], allDatas); + }; + + const deselectAllRows = () => { + const currentKeys = props.dataSource.map((record) => record[rowKey]); + rowSelection?.removeSelectedKeys?.(currentKeys); + }; const handleSelectAllChange = (e: any) => { if (e.target.checked) { - rowSelection?.onChange( - props.dataSource.map((record) => record[rowKey]), - props.dataSource - ); - setSelectAll(true); - setIndeterminate(false); + selectAllRows(); } else { - rowSelection?.onChange([], []); - setSelectAll(false); - setIndeterminate(false); + deselectAllRows(); } }; @@ -83,89 +92,37 @@ const SealTable: React.FC = ( pagination?.onShowSizeChange?.(current, size); }; - const renderHeaderPrefix = useMemo(() => { - if (expandable && rowSelection) { - return ( -
- - -
- ); - } - if (expandable) { - return ( -
- {_.isBoolean(expandable) ? ( - - ) : ( - expandable - )} -
- ); - } - if (rowSelection) { - return ( -
{}
- ); - } - return null; - }, [expandable, rowSelection, selectAll, indeterminate]); - - const renderContent = useMemo(() => { - if (!props.dataSource.length) { - return ( -
- -
- ); - } - return ( -
- {props.dataSource.map((item, index) => { - return ( - - ); - })} -
- ); - }, [props.dataSource, expandedRowKeys, rowSelection, children]); return ( <>
- { -
- {renderHeaderPrefix} -
{children}
-
- } - - {renderContent} +
+ +
{children}
+
+ + +
{pagination && (
@@ -180,4 +137,4 @@ const SealTable: React.FC = ( ); }; -export default React.memo(SealTable); +export default SealTable; diff --git a/src/components/seal-table/types.ts b/src/components/seal-table/types.ts index 2db12a73..4a4208c4 100644 --- a/src/components/seal-table/types.ts +++ b/src/components/seal-table/types.ts @@ -14,7 +14,7 @@ export interface SealColumnProps { | boolean | { valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time'; - title?: string; + title?: React.ReactNode; }; valueType?: 'text' | 'number' | 'date' | 'datetime' | 'time'; sortOrder?: 'ascend' | 'descend' | null; @@ -27,7 +27,7 @@ export interface TableHeaderProps { dataIndex: string; onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void; children?: React.ReactNode; - title: string; + title: React.ReactNode; style?: React.CSSProperties; firstCell?: boolean; lastCell?: boolean; @@ -37,6 +37,8 @@ export interface TableHeaderProps { export interface RowSelectionProps { selectedRowKeys: React.Key[]; selectedRows: any[]; + enableSelection: boolean; + removeSelectedKeys: (rowKeys: React.Key[]) => void; onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => void; } export interface SealTableProps { diff --git a/src/hooks/use-table-row-selection.ts b/src/hooks/use-table-row-selection.ts index bc61a049..72cf04de 100644 --- a/src/hooks/use-table-row-selection.ts +++ b/src/hooks/use-table-row-selection.ts @@ -19,22 +19,28 @@ export default function useTableRowSelection() { const removeSelectedKey = (rowKey: React.Key | React.Key[]) => { if (Array.isArray(rowKey)) { - setSelectedRowKeys((keys) => keys.filter((key) => !rowKey.includes(key))); + const keys = selectedRowKeys.filter((key) => !rowKey.includes(key)); + setSelectedRowKeys(keys); setSelectedRows((rows) => rows.filter((row) => !rowKey.includes(row.id))); - return; + return keys; } - setSelectedRowKeys((keys) => keys.filter((key) => key !== rowKey)); + const keys = selectedRowKeys.filter((key) => key !== rowKey); + setSelectedRowKeys(keys); setSelectedRows((rows) => rows.filter((row) => row.id !== rowKey)); + return keys; }; const removeSelectedKeys = (rowKeys: React.Key[]) => { - setSelectedRowKeys((keys) => keys.filter((key) => !rowKeys.includes(key))); + const keys = selectedRowKeys.filter((key) => !rowKeys.includes(key)); + setSelectedRowKeys(keys); setSelectedRows((rows) => rows.filter((row) => !rowKeys.includes(row.id))); + return keys; }; const rowSelection = { selectedRowKeys, selectedRows, + enableSelection: true, clearSelections, onChange: onSelectChange, removeSelectedKeys, diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index 93a4546c..a3fca404 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -321,7 +321,6 @@ const Models: React.FC = ({ replicas: 1 } }); - message.success(intl.formatMessage({ id: 'common.message.success' })); updateExpandedRowKeys([row.id, ...expandedRowKeys]); } catch (error) { // ingore @@ -531,7 +530,7 @@ const Models: React.FC = ({ }; const handleSelect = useCallback( - (val: any, row: ListItem) => { + async (val: any, row: ListItem) => { if (val === 'edit') { handleEdit(row); } @@ -542,7 +541,8 @@ const Models: React.FC = ({ handleDelete(row); } if (val === 'start') { - handleStartModel(row); + await handleStartModel(row); + message.success(intl.formatMessage({ id: 'common.message.success' })); } if (val === 'stop') {