fix: batch start/stop selected counts

main
jialin 1 year ago
parent 6ea8cc9986
commit 3a021e7879

@ -32,6 +32,9 @@ export default {
colorBgSpotlight: '#3e3e3e'
// sizePopupArrow: 0
},
Cascader: {
dropdownHeight: 240
},
Slider: {
handleSize: 8,
handleSizeHover: 8,

@ -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<HeaderPrefixProps> = (props) => {
const { expandable, enableSelection, onSelectAll, indeterminate, selectAll } =
props;
if (expandable && enableSelection) {
return (
<div className="header-row-prefix-wrapper">
<span style={{ marginRight: 5, padding: '0 14px' }}></span>
<Checkbox
onChange={onSelectAll}
indeterminate={indeterminate}
checked={selectAll}
></Checkbox>
</div>
);
}
if (expandable) {
return (
<div className="header-row-prefix-wrapper">
{_.isBoolean(expandable) ? (
<Button type="text" size="small">
<RightOutlined />
</Button>
) : (
expandable
)}
</div>
);
}
if (enableSelection) {
return (
<div className="header-row-prefix-wrapper">{<Checkbox></Checkbox>}</div>
);
}
return null;
};
export default React.memo(HeaderPrefix);

@ -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<SealColumnProps> = (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<EditButtonsProps> = (props) => {
const intl = useIntl();
const { isEditing, editable, handleSubmit, handleUndo, handleEdit } = props;
if (!editable) {
return null;
}
if (isEditing) {
return (
<span className="flex-column">
<Tooltip
key="confirm"
title={intl.formatMessage({ id: 'common.button.confirm' })}
>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleSubmit}
>
<CheckOutlined />
</Button>
</Tooltip>
<Tooltip
title={intl.formatMessage({ id: 'common.button.cancel' })}
key="undo"
>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleUndo}
>
<UndoOutlined />
</Button>
</Tooltip>
</span>
);
}
return (
<span className="flex-column">
<Tooltip
key="edit"
title={
_.isBoolean(editable) ? (
intl.formatMessage({ id: 'common.button.edit' })
) : (
<span>{editable.title || ''}</span>
)
}
>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleEdit}
>
<FormOutlined />
</Button>
</Tooltip>
</span>
);
};
const CellContent: React.FC<CellContentProps> = (props) => {
const { editable, current, isEditing, row, render, onChange } = props;
if (isEditing && editable) {
const isNumType =
typeof editable === 'object' && editable?.valueType === 'number';
return isNumType ? (
<InputNumber
style={{ width: '80px' }}
min={0}
value={current}
onChange={onChange}
/>
) : (
<Input value={current} onChange={(e) => onChange(e.target.value)} />
);
}
if (render) {
return render(current, row);
}
return current;
};
const SealColumn: React.FC<SealColumnProps> = (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<SealColumnProps> = (props) => {
setCurrent(cachedValue.current);
setIsEditing(false);
};
const handleValueChange = (val: any) => {
setCurrent(val);
};
useEffect(() => {
if (editable) {
cachedValue.current = row[dataIndex];
}
cachedValue.current = row[dataIndex];
setCurrent(row[dataIndex]);
}, [row[dataIndex], editable]);
}, [row[dataIndex]]);
const renderContent = () => {
if (isEditing && editable) {
const isNumType =
typeof editable === 'object' && editable.valueType === 'number';
return isNumType ? (
<InputNumber
style={{ width: '80px' }}
min={0}
value={current}
onChange={(val) => {
setCurrent(val as any);
}}
/>
) : (
<Input
value={current}
onChange={(e) => {
setCurrent(e.target.value);
}}
/>
);
}
if (render) {
return render(current, row);
}
return current;
};
return (
<div
className={classNames('cell', {
@ -78,55 +158,24 @@ const SealColumn: React.FC<SealColumnProps> = (props) => {
})}
>
<span className="cell-content flex-center">
{renderContent()}
{editable && (
<span className="flex-column">
{isEditing ? (
<>
<Tooltip
key="confirm"
title={intl.formatMessage({ id: 'common.button.confirm' })}
>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleSubmit}
>
<CheckOutlined />
</Button>
</Tooltip>
<Tooltip
title={intl.formatMessage({ id: 'common.button.cancel' })}
key="undo"
>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleUndo}
>
<UndoOutlined />
</Button>
</Tooltip>
</>
) : (
<Tooltip key="edit" title={<span>{editable?.title}</span>}>
<Button
type="text"
size="small"
className="m-l-10"
onClick={handleEdit}
>
<FormOutlined />
</Button>
</Tooltip>
)}
</span>
)}
<CellContent
onChange={handleValueChange}
isEditing={isEditing}
editable={editable}
current={current}
row={row}
render={render}
></CellContent>
<EditButtons
editable={editable}
isEditing={isEditing}
handleEdit={handleEdit}
handleSubmit={handleSubmit}
handleUndo={handleUndo}
></EditButtons>
</span>
</div>
);
};
export default React.memo(SealColumn);
export default SealColumn;

@ -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<TableBodyProps> = ({
dataSource,
rowKey,
rowSelection,
expandable,
expandedRowKeys,
onExpand,
childParentKey,
pollingChildren,
watchChildren,
renderChildren,
loadChildren,
loadChildrenAPI,
columns,
onCell
}) => {
if (!dataSource.length) {
return (
<div className="empty-wrapper">
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</div>
);
}
return (
<div className="seal-table-content">
{dataSource.map((item, index) => (
<TableRow
key={item[rowKey]}
record={item}
rowIndex={index}
columns={columns}
rowSelection={rowSelection}
expandable={expandable}
rowKey={rowKey}
childParentKey={childParentKey}
pollingChildren={pollingChildren}
watchChildren={watchChildren}
renderChildren={renderChildren}
loadChildren={loadChildren}
loadChildrenAPI={loadChildrenAPI}
onCell={onCell}
onExpand={onExpand}
expandedRowKeys={expandedRowKeys}
/>
))}
</div>
);
};
export default TableBody;

@ -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<SealTableProps & { pagination: PaginationProps }> = (
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<SealTableProps & { pagination: PaginationProps }> = (
pagination?.onShowSizeChange?.(current, size);
};
const renderHeaderPrefix = useMemo(() => {
if (expandable && rowSelection) {
return (
<div className="header-row-prefix-wrapper">
<span style={{ marginRight: 5, padding: '0 14px' }}></span>
<Checkbox
onChange={handleSelectAllChange}
indeterminate={indeterminate}
checked={selectAll}
></Checkbox>
</div>
);
}
if (expandable) {
return (
<div className="header-row-prefix-wrapper">
{_.isBoolean(expandable) ? (
<Button type="text" size="small">
<RightOutlined />
</Button>
) : (
expandable
)}
</div>
);
}
if (rowSelection) {
return (
<div className="header-row-prefix-wrapper">{<Checkbox></Checkbox>}</div>
);
}
return null;
}, [expandable, rowSelection, selectAll, indeterminate]);
const renderContent = useMemo(() => {
if (!props.dataSource.length) {
return (
<div className="empty-wrapper">
<Empty
image={loadend ? Empty.PRESENTED_IMAGE_SIMPLE : null}
description={loadend ? undefined : null}
></Empty>
</div>
);
}
return (
<div className="seal-table-content" ref={tableContent}>
{props.dataSource.map((item, index) => {
return (
<TableRow
record={item}
rowIndex={index}
columns={children}
key={item[rowKey]}
rowSelection={rowSelection}
expandable={expandable}
rowKey={rowKey}
childParentKey={childParentKey}
pollingChildren={pollingChildren}
watchChildren={watchChildren}
renderChildren={renderChildren}
loadChildren={loadChildren}
loadChildrenAPI={loadChildrenAPI}
onCell={onCell}
onExpand={onExpand}
expandedRowKeys={expandedRowKeys}
></TableRow>
);
})}
</div>
);
}, [props.dataSource, expandedRowKeys, rowSelection, children]);
return (
<>
<div className="seal-table-container">
{
<div className="header-row-wrapper">
{renderHeaderPrefix}
<Header onSort={onSort}>{children}</Header>
</div>
}
<Spin spinning={loading}>{renderContent}</Spin>
<div className="header-row-wrapper">
<HeaderPrefix
selectAll={selectState.selectAll}
indeterminate={selectState.indeterminate}
onSelectAll={handleSelectAllChange}
expandable={expandable}
enableSelection={rowSelection?.enableSelection}
></HeaderPrefix>
<Header onSort={onSort}>{children}</Header>
</div>
<Spin spinning={loading}>
<TableBody
dataSource={props.dataSource}
columns={children}
rowSelection={rowSelection}
expandable={expandable}
rowKey={rowKey}
childParentKey={childParentKey}
pollingChildren={pollingChildren}
watchChildren={watchChildren}
renderChildren={renderChildren}
loadChildren={loadChildren}
loadChildrenAPI={loadChildrenAPI}
onCell={onCell}
onExpand={onExpand}
expandedRowKeys={expandedRowKeys}
/>
</Spin>
</div>
{pagination && (
<div className="pagination-wrapper">
@ -180,4 +137,4 @@ const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
);
};
export default React.memo(SealTable);
export default SealTable;

@ -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 {

@ -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,

@ -321,7 +321,6 @@ const Models: React.FC<ModelsProps> = ({
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<ModelsProps> = ({
};
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<ModelsProps> = ({
handleDelete(row);
}
if (val === 'start') {
handleStartModel(row);
await handleStartModel(row);
message.success(intl.formatMessage({ id: 'common.message.success' }));
}
if (val === 'stop') {

Loading…
Cancel
Save