Add detail resource name and detail id in download file name, such as ,`instance-fd3ec1bb-9423-4537-b74e-8f967ed011c7-volumes-all-2021-09-13 16_15_20.csv` means downlaod all the volumes in instance fd3ec1bb-9423-4537-b74e-8f967ed011c7 detail page Change-Id: Ied8e9ae5104b821866d44137679cccafc0f69656
1012 lines
26 KiB
JavaScript
1012 lines
26 KiB
JavaScript
// Copyright 2021 99cloud
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import classnames from 'classnames';
|
|
import isEqual from 'react-fast-compare';
|
|
import { toJS } from 'mobx';
|
|
import { Link } from 'react-router-dom';
|
|
import { includes, get, isArray, isString } from 'lodash';
|
|
import { Button, Table, Dropdown, Input, Typography, Tooltip } from 'antd';
|
|
import MagicInput from 'components/MagicInput';
|
|
import Pagination from 'components/Pagination';
|
|
import {
|
|
EyeOutlined,
|
|
SyncOutlined,
|
|
QuestionCircleOutlined,
|
|
PlayCircleOutlined,
|
|
PauseCircleOutlined,
|
|
FileTextOutlined,
|
|
} from '@ant-design/icons';
|
|
import TimeFilter from 'components/TimeFilter';
|
|
import {
|
|
getColumnSorter,
|
|
getSortOrder,
|
|
updateColumnSort,
|
|
checkIsStatusColumn,
|
|
getStatusRender,
|
|
getRender,
|
|
getValueRenderFunc,
|
|
} from 'utils/table';
|
|
import { getNoValue } from 'utils/index';
|
|
import { columnRender } from 'utils/render';
|
|
import { getLocalStorageItem, setLocalStorageItem } from 'utils/local-storage';
|
|
import { inject } from 'mobx-react';
|
|
import globalRootStore from 'stores/root';
|
|
import CustomColumns from './CustomColumns';
|
|
import ItemActionButtons from './ItemActionButtons';
|
|
import PrimaryActionButtons from './PrimaryActionButtons';
|
|
import BatchActionButtons from './BatchActionButtons';
|
|
import Download from './Download';
|
|
import styles from './index.less';
|
|
|
|
@inject('rootStore')
|
|
export default class BaseTable extends React.Component {
|
|
static propTypes = {
|
|
data: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
|
|
columns: PropTypes.array.isRequired,
|
|
selectedRowKeys: PropTypes.array,
|
|
isLoading: PropTypes.bool,
|
|
pagination: PropTypes.object,
|
|
filters: PropTypes.object,
|
|
keyword: PropTypes.string,
|
|
rowKey: PropTypes.any,
|
|
onFetch: PropTypes.func,
|
|
onFilterChange: PropTypes.func,
|
|
onSelectRowKeys: PropTypes.func,
|
|
getCheckboxProps: PropTypes.func,
|
|
hideHeader: PropTypes.bool,
|
|
hideSearch: PropTypes.bool,
|
|
hideCustom: PropTypes.bool,
|
|
batchActions: PropTypes.array,
|
|
alwaysUpdate: PropTypes.bool,
|
|
emptyText: PropTypes.oneOfType([PropTypes.string || PropTypes.func]),
|
|
resourceName: PropTypes.string,
|
|
detailName: PropTypes.string,
|
|
expandable: PropTypes.object,
|
|
showTimeFilter: PropTypes.bool,
|
|
timeFilter: PropTypes.any,
|
|
isPageByBack: PropTypes.bool,
|
|
isSortByBack: PropTypes.bool,
|
|
autoRefresh: PropTypes.bool,
|
|
hideRefresh: PropTypes.bool,
|
|
hideAutoRefresh: PropTypes.bool,
|
|
startRefreshAuto: PropTypes.func,
|
|
stopRefreshAuto: PropTypes.func,
|
|
dataDurationAuto: PropTypes.number,
|
|
defaultSortKey: PropTypes.string,
|
|
defaultSortOrder: PropTypes.string,
|
|
hideTotal: PropTypes.bool,
|
|
hideDownload: PropTypes.bool,
|
|
primaryActionsExtra: PropTypes.any,
|
|
isAdminPage: PropTypes.bool,
|
|
containerProps: PropTypes.any,
|
|
};
|
|
|
|
static defaultProps = {
|
|
rowKey: 'name',
|
|
selectedRowKeys: [],
|
|
onFetch() {},
|
|
hideHeader: false,
|
|
hideSearch: false,
|
|
hideCustom: false,
|
|
resourceName: '',
|
|
detailName: '',
|
|
expandable: undefined,
|
|
showTimeFilter: false,
|
|
isPageByBack: false,
|
|
isSortByBack: false,
|
|
autoRefresh: true,
|
|
hideRefresh: false,
|
|
hideAutoRefresh: false,
|
|
dataDurationAuto: 15,
|
|
defaultSortKey: '',
|
|
defaultSortOrder: '',
|
|
hideTotal: false,
|
|
hideDownload: false,
|
|
primaryActionsExtra: null,
|
|
isAdminPage: false,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
hideRow:
|
|
getLocalStorageItem(`${this.useId}-${this.props.resourceName}`) || [],
|
|
// eslint-disable-next-line react/no-unused-state
|
|
filters: [],
|
|
timeFilter: {},
|
|
autoRefresh: props.autoRefresh,
|
|
};
|
|
|
|
this.sortKey = props.defaultSortKey;
|
|
this.sortOrder = props.defaultSortOrder;
|
|
this.hideableRow = props.columns
|
|
.filter((column) => !column.hidden)
|
|
.filter((column) => column.isHideable)
|
|
.map((column) => ({
|
|
label: column.title,
|
|
value: this.getDataIndex(column.dataIndex) || column.key,
|
|
}));
|
|
|
|
this.hideableColValues = this.hideableRow.map((item) => item.value);
|
|
|
|
this.suggestions = props.columns
|
|
.filter((column) => column.search && column.dataIndex)
|
|
.map((column) => ({
|
|
label: column.title,
|
|
key: column.dataIndex,
|
|
options:
|
|
column.filters &&
|
|
column.filters.map((filter) => ({
|
|
label: filter.text,
|
|
key: filter.value,
|
|
})),
|
|
}));
|
|
}
|
|
|
|
get useId() {
|
|
const { user = {} } = toJS(this.props.rootStore) || {};
|
|
const { user: { id } = {} } = user || {};
|
|
return id;
|
|
}
|
|
|
|
get itemActions() {
|
|
const { itemActions = {} } = this.props;
|
|
return itemActions;
|
|
}
|
|
|
|
getDataIndex = (dataIndex) => {
|
|
if (isArray(dataIndex)) {
|
|
return dataIndex.join(',');
|
|
}
|
|
return dataIndex;
|
|
};
|
|
|
|
getSortKey = (sorter) => {
|
|
const { field, column } = sorter;
|
|
if (!field) {
|
|
return null;
|
|
}
|
|
if (!column) {
|
|
return null;
|
|
}
|
|
return column.sortKey || column.dataIndex;
|
|
};
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
handleChange = (pagination, filters, sorter, extra) => {
|
|
const { action } = extra;
|
|
let params = {
|
|
limit: pagination.pageSize,
|
|
page: pagination.current,
|
|
current: pagination.current,
|
|
sortKey: this.getSortKey(sorter),
|
|
sortOrder: sorter.order,
|
|
...filters,
|
|
};
|
|
const { isCourier, isPageByBack } = this.props;
|
|
if (action === 'sort') {
|
|
if (!(isCourier || !isPageByBack)) {
|
|
const { pagination: propsPagination } = this.props;
|
|
params = {
|
|
...params,
|
|
limit: propsPagination.pageSize,
|
|
page: propsPagination.current,
|
|
current: propsPagination.current,
|
|
};
|
|
}
|
|
this.sortKey = this.getSortKey(sorter);
|
|
this.sortOrder = sorter.order;
|
|
this.props.onFetchBySort(params);
|
|
} else {
|
|
this.props.onFetch(params);
|
|
}
|
|
};
|
|
|
|
handlePageChange = (current, pageSize) => {
|
|
const { filters } = this.state;
|
|
const { onFetch, defaultSortKey, defaultSortOrder } = this.props;
|
|
onFetch &&
|
|
onFetch({
|
|
limit: pageSize,
|
|
page: current,
|
|
current,
|
|
sortKey: this.sortKey || defaultSortKey,
|
|
sortOrder: this.sortOrder || defaultSortOrder,
|
|
...filters,
|
|
});
|
|
};
|
|
|
|
handleRefresh = () => {
|
|
this.props.onRefresh(true);
|
|
};
|
|
|
|
handleRowHide = (columns) => {
|
|
this.setState(
|
|
{
|
|
hideRow: this.hideableColValues.filter(
|
|
(value) => !columns.includes(value)
|
|
),
|
|
},
|
|
() => {
|
|
setLocalStorageItem(
|
|
`${this.useId}-${this.props.resourceName}`,
|
|
this.state.hideRow
|
|
);
|
|
}
|
|
);
|
|
};
|
|
|
|
handleCancelSelect = () => {
|
|
this.props.onSelectRowKeys([]);
|
|
};
|
|
|
|
handleFilterChange = (filters, timeFilter) => {
|
|
if (
|
|
!isEqual(filters, this.props.filters) ||
|
|
!isEqual(timeFilter, this.props.timeFilter)
|
|
) {
|
|
this.setState({
|
|
// eslint-disable-next-line react/no-unused-state
|
|
filters,
|
|
timeFilter,
|
|
});
|
|
const { pageSize } = this.props.pagination;
|
|
const { sortKey, sortOrder, onFilterChange } = this.props;
|
|
onFilterChange &&
|
|
onFilterChange(
|
|
{
|
|
limit: pageSize,
|
|
page: 1,
|
|
sortKey,
|
|
sortOrder,
|
|
...filters,
|
|
},
|
|
timeFilter
|
|
);
|
|
}
|
|
};
|
|
|
|
handleTimeChange = (values) => {
|
|
this.handleFilterChange(this.state.filters, values);
|
|
};
|
|
|
|
handleFilterInput = (tags) => {
|
|
const filters = {};
|
|
tags.forEach((n) => {
|
|
filters[n.filter.name] = n.value;
|
|
});
|
|
this.handleFilterChange(filters, this.state.timeFilter);
|
|
};
|
|
|
|
handleInputFocus = (value) => {
|
|
const { handleInputFocus } = this.props;
|
|
handleInputFocus && handleInputFocus(value);
|
|
};
|
|
|
|
handleFilterInputText = (e) => {
|
|
const filters = {};
|
|
const { value } = e.currentTarget;
|
|
if (value) {
|
|
filters.keywords = value;
|
|
}
|
|
this.handleFilterChange(filters, this.state.timeFilter);
|
|
};
|
|
|
|
hasItemActions = () => {
|
|
const { firstAction, moreActions, actionList } = this.itemActions;
|
|
if (firstAction) {
|
|
return true;
|
|
}
|
|
if (moreActions && moreActions.length) {
|
|
return true;
|
|
}
|
|
return actionList && actionList.length > 0;
|
|
};
|
|
|
|
getProjectId = (record) =>
|
|
record.project_id || record.owner || record.fingerprint || record.tenant;
|
|
|
|
getProjectRender = (render) => {
|
|
if (render) {
|
|
return render;
|
|
}
|
|
return (value, record) => {
|
|
const projectId = this.getProjectId(record);
|
|
if (!projectId) {
|
|
return '-';
|
|
}
|
|
const url = `/identity/project-admin/detail/${projectId}`;
|
|
return (
|
|
<>
|
|
<div>
|
|
{globalRootStore.hasAdminRole ? (
|
|
<Link to={url}>{projectId}</Link>
|
|
) : (
|
|
projectId
|
|
)}
|
|
</div>
|
|
<div>{value || '-'}</div>
|
|
</>
|
|
);
|
|
};
|
|
};
|
|
|
|
getNoValueRender = (render) => {
|
|
if (render) {
|
|
return render;
|
|
}
|
|
return (value) => getNoValue(value);
|
|
};
|
|
|
|
getLinkUrl = (prefix, id) => {
|
|
if (!prefix) {
|
|
return null;
|
|
}
|
|
if (prefix[prefix.length - 1] === '/') {
|
|
return `${prefix}${id}`;
|
|
}
|
|
return `${prefix}/${id}`;
|
|
};
|
|
|
|
getNameRender = (render, column) => {
|
|
if (render) {
|
|
return render;
|
|
}
|
|
const {
|
|
linkPrefix,
|
|
dataIndex,
|
|
idKey,
|
|
linkPrefixFunc,
|
|
linkFunc,
|
|
hasNoDetail = false,
|
|
} = column;
|
|
const { rowKey } = this.props;
|
|
return (value, record) => {
|
|
const idValue = get(record, idKey || rowKey);
|
|
let url = null;
|
|
if (linkFunc) {
|
|
url = linkFunc(value, record);
|
|
} else {
|
|
const linkValue = linkPrefixFunc
|
|
? linkPrefixFunc(value, record)
|
|
: linkPrefix;
|
|
url = this.getLinkUrl(linkValue, idValue);
|
|
}
|
|
const nameValue = value || get(record, dataIndex) || '-';
|
|
if (hasNoDetail) {
|
|
return (
|
|
<div>
|
|
<div>{idValue}</div>
|
|
<div>{nameValue}</div>
|
|
</div>
|
|
);
|
|
}
|
|
if (!url && !hasNoDetail) {
|
|
return nameValue;
|
|
}
|
|
return (
|
|
<div>
|
|
<div>
|
|
<Link to={url}>{idValue}</Link>
|
|
</div>
|
|
<div>{nameValue}</div>
|
|
</div>
|
|
);
|
|
};
|
|
};
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
getPriceRender = (render, column) => {
|
|
if (render) {
|
|
return render;
|
|
}
|
|
return (value) => {
|
|
const valueStr = isString(value) ? value : (value || 0).toFixed(2);
|
|
return <span style={{ color: '#f50' }}>{valueStr}</span>;
|
|
};
|
|
};
|
|
|
|
getTipRender = (tip, render, dataIndex, Icon = FileTextOutlined) => {
|
|
const newRender = (value, record) => {
|
|
const tipValue = tip(value, record);
|
|
const realValue = render ? render(value, record) : get(record, dataIndex);
|
|
if (!tipValue) {
|
|
return realValue;
|
|
}
|
|
return (
|
|
<div>
|
|
{realValue}
|
|
<Tooltip title={tipValue}>
|
|
<Icon style={{ marginLeft: 8 }} />
|
|
</Tooltip>
|
|
</div>
|
|
);
|
|
};
|
|
return newRender;
|
|
};
|
|
|
|
getColumnTitle = (column) => {
|
|
const { title, titleTip } = column;
|
|
if (!titleTip) {
|
|
return title;
|
|
}
|
|
return (
|
|
<span>
|
|
{title}
|
|
<Tooltip title={titleTip}>
|
|
<QuestionCircleOutlined style={{ marginLeft: 8 }} />
|
|
</Tooltip>
|
|
</span>
|
|
);
|
|
};
|
|
|
|
getBaseColumns = (columns) =>
|
|
columns.map((column) => {
|
|
const { Paragraph } = Typography;
|
|
const {
|
|
sortable,
|
|
dataIndex,
|
|
valueRender,
|
|
sorter,
|
|
sortOrder,
|
|
render,
|
|
copyable,
|
|
tip,
|
|
isStatus,
|
|
isName,
|
|
isPrice,
|
|
...rest
|
|
} = column;
|
|
const newSorter = getColumnSorter(column, this.props);
|
|
const newSortOrder =
|
|
sortOrder || newSorter ? getSortOrder(dataIndex, this.props) : null;
|
|
let newRender = render || getRender(valueRender);
|
|
if (checkIsStatusColumn(dataIndex, isStatus)) {
|
|
newRender = getStatusRender(newRender);
|
|
}
|
|
if (dataIndex === 'description') {
|
|
newRender = this.getNoValueRender(newRender);
|
|
}
|
|
if (dataIndex === 'project_name') {
|
|
newRender = this.getProjectRender(newRender);
|
|
}
|
|
if (dataIndex === 'name' || isName) {
|
|
newRender = this.getNameRender(newRender, column);
|
|
}
|
|
if (dataIndex === 'cost' || isPrice) {
|
|
newRender = this.getPriceRender(newRender, column);
|
|
}
|
|
if (copyable) {
|
|
newRender = (value) => {
|
|
if (value && value !== '-') {
|
|
return <Paragraph copyable>{value}</Paragraph>;
|
|
}
|
|
return '-';
|
|
};
|
|
}
|
|
if (tip) {
|
|
const { tipIcon } = column;
|
|
newRender = this.getTipRender(tip, newRender, dataIndex, tipIcon);
|
|
}
|
|
const newColumn = {
|
|
...rest,
|
|
title: this.getColumnTitle(column),
|
|
dataIndex,
|
|
align: column.align || 'left',
|
|
};
|
|
if (newSorter) {
|
|
newColumn.sorter = newSorter;
|
|
}
|
|
if (sortOrder) {
|
|
newColumn.sortOrder = newSortOrder;
|
|
}
|
|
updateColumnSort(newColumn, this.props);
|
|
if (newRender) {
|
|
newColumn.render = newRender;
|
|
}
|
|
return {
|
|
...newColumn,
|
|
render: (value, record) =>
|
|
columnRender(newColumn.render, value, record),
|
|
};
|
|
});
|
|
|
|
getColumns = () => {
|
|
const {
|
|
columns,
|
|
containerProps,
|
|
onClickAction,
|
|
onFinishAction,
|
|
onCancelAction,
|
|
isAdminPage,
|
|
} = this.props;
|
|
const { hideRow } = this.state;
|
|
const currentColumns = columns
|
|
.filter((it) => !it.hidden)
|
|
.filter((it) => !includes(hideRow, this.getDataIndex(it.dataIndex)));
|
|
const baseColumns = this.getBaseColumns(currentColumns);
|
|
if (!this.hasItemActions()) {
|
|
return baseColumns;
|
|
}
|
|
return [
|
|
...baseColumns,
|
|
{
|
|
title: t('Action'),
|
|
key: 'operation',
|
|
width: 150,
|
|
render: (text, record, index) => (
|
|
<ItemActionButtons
|
|
isAdminPage={isAdminPage}
|
|
actions={this.itemActions}
|
|
onFinishAction={onFinishAction}
|
|
onCancelAction={onCancelAction}
|
|
item={record}
|
|
index={index}
|
|
containerProps={containerProps}
|
|
onClickAction={onClickAction}
|
|
/>
|
|
),
|
|
},
|
|
];
|
|
};
|
|
|
|
stopRefreshAuto = () => {
|
|
this.setState({
|
|
autoRefresh: false,
|
|
});
|
|
const { stopRefreshAuto } = this.props;
|
|
if (stopRefreshAuto) {
|
|
stopRefreshAuto();
|
|
}
|
|
};
|
|
|
|
startRefreshAuto = () => {
|
|
this.setState({
|
|
autoRefresh: true,
|
|
});
|
|
const { startRefreshAuto } = this.props;
|
|
if (startRefreshAuto) {
|
|
startRefreshAuto();
|
|
}
|
|
};
|
|
|
|
filterDownloadColumns(columns) {
|
|
const { rowKey } = this.props;
|
|
const downloadColumns = columns
|
|
.filter((it) => !it.hidden)
|
|
.map((it) => {
|
|
const { title, splitColumnForDownload = true } = it;
|
|
if (title.includes('/') && splitColumnForDownload) {
|
|
const [fTitle, sTitle] = it.title.split('/');
|
|
let sName = sTitle;
|
|
if (fTitle.length > 2) {
|
|
sName = `${fTitle.split('ID')[0]}${sTitle}`;
|
|
}
|
|
let fIndex = it.idKey || rowKey;
|
|
if (
|
|
it.title.includes(t('Project')) &&
|
|
it.dataIndex === 'project_name'
|
|
) {
|
|
fIndex = 'project_id';
|
|
}
|
|
return [
|
|
{
|
|
title: fTitle,
|
|
dataIndex: fIndex,
|
|
},
|
|
{
|
|
...it,
|
|
title: sName,
|
|
},
|
|
];
|
|
}
|
|
return it;
|
|
});
|
|
return [].concat(...downloadColumns);
|
|
}
|
|
|
|
renderBatchActions() {
|
|
const {
|
|
batchActions,
|
|
selectedRowKeys,
|
|
data,
|
|
rowKey,
|
|
containerProps,
|
|
onClickAction,
|
|
onFinishAction,
|
|
onCancelAction,
|
|
resourceName,
|
|
isAdminPage,
|
|
} = this.props;
|
|
const selectedItems = data.filter(
|
|
(it) => selectedRowKeys.indexOf(it[rowKey]) >= 0
|
|
);
|
|
if (batchActions) {
|
|
return (
|
|
<BatchActionButtons
|
|
isAdminPage={isAdminPage}
|
|
visibleButtonNumber={3}
|
|
selectedItemKeys={selectedRowKeys}
|
|
selectedItems={selectedItems}
|
|
batchActions={batchActions}
|
|
onFinishAction={onFinishAction}
|
|
onCancelAction={onCancelAction}
|
|
containerProps={containerProps}
|
|
onClickAction={onClickAction}
|
|
resourceName={resourceName}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
renderSelectedTitle = () => (
|
|
<div className={styles.selectTitle}>
|
|
<div>{this.renderBatchActions()}</div>
|
|
<div>
|
|
<Button
|
|
type="flat"
|
|
className={styles.cancelSelect}
|
|
onClick={this.handleCancelSelect}
|
|
>
|
|
{t('Cancel Select')}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
renderTimeFilter() {
|
|
const { showTimeFilter, filterTimeDefalutValue } = this.props;
|
|
if (!showTimeFilter) {
|
|
return null;
|
|
}
|
|
const props = {
|
|
onChange: this.handleTimeChange,
|
|
className: styles.timer,
|
|
};
|
|
if (filterTimeDefalutValue !== undefined) {
|
|
props.defaultValue = filterTimeDefalutValue;
|
|
}
|
|
return <TimeFilter {...props} />;
|
|
}
|
|
|
|
renderSearch() {
|
|
const { hideSearch, searchFilters, initFilter = {} } = this.props;
|
|
|
|
if (hideSearch) {
|
|
return null;
|
|
}
|
|
|
|
if (searchFilters.length > 0) {
|
|
return (
|
|
<div className={styles['search-row']}>
|
|
<MagicInput
|
|
filterParams={searchFilters}
|
|
initValue={initFilter}
|
|
onInputChange={this.handleFilterInput}
|
|
onInputFocus={this.handleInputFocus}
|
|
placeholder={t('Multiple filter tags are separated by enter')}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// if (searchType === 'keyword') {
|
|
// const placeholder =
|
|
// this.props.placeholder || t('Please input a keyword to find');
|
|
|
|
// return (
|
|
// <div className={styles['search-row']}>
|
|
// <MagicInput
|
|
// filterParams={searchFilters}
|
|
// onInputChange={this.handleFilterInput}
|
|
// initValue={filters}
|
|
// />
|
|
// {/* <Input.Search
|
|
// className={styles['search-input']}
|
|
// value={keyword}
|
|
// onSearch={this.handleSearch}
|
|
// placeholder={placeholder}
|
|
// allowClear
|
|
// /> */}
|
|
// </div>
|
|
// );
|
|
// }
|
|
// return null;
|
|
return (
|
|
<div className={styles['search-row']}>
|
|
<Input
|
|
placeholder={t('Enter query conditions to filter')}
|
|
onChange={this.handleFilterInputText}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderActions() {
|
|
const {
|
|
isAdminPage,
|
|
primaryActions,
|
|
containerProps,
|
|
onClickAction,
|
|
onFinishAction,
|
|
onCancelAction,
|
|
primaryActionsExtra,
|
|
} = this.props;
|
|
if (primaryActions) {
|
|
return (
|
|
<PrimaryActionButtons
|
|
isAdminPage={isAdminPage}
|
|
primaryActions={primaryActions}
|
|
containerProps={containerProps}
|
|
onClickAction={onClickAction}
|
|
onFinishAction={onFinishAction}
|
|
onCancelAction={onCancelAction}
|
|
primaryActionsExtra={primaryActionsExtra}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
renderCustomButton() {
|
|
const { hideCustom } = this.props;
|
|
if (hideCustom) {
|
|
return null;
|
|
}
|
|
return (
|
|
<Dropdown overlay={this.renderRowMenu()}>
|
|
<Button
|
|
className={styles['custom-button']}
|
|
type="default"
|
|
icon={<EyeOutlined />}
|
|
/>
|
|
</Dropdown>
|
|
);
|
|
}
|
|
|
|
renderDownload() {
|
|
const {
|
|
pagination,
|
|
data,
|
|
columns,
|
|
resourceName,
|
|
detailName,
|
|
getDownloadData,
|
|
onClickAction,
|
|
onCancelAction,
|
|
hideDownload,
|
|
} = this.props;
|
|
if (hideDownload) {
|
|
return null;
|
|
}
|
|
const { total } = pagination;
|
|
const downloadColumns = this.filterDownloadColumns(columns);
|
|
const props = {
|
|
data,
|
|
columns: downloadColumns,
|
|
total,
|
|
getValueRenderFunc,
|
|
resourceName,
|
|
extraName: detailName,
|
|
getData: getDownloadData,
|
|
onBeginDownload: onClickAction,
|
|
onFinishDownload: onCancelAction,
|
|
onCancelDownload: onCancelAction,
|
|
};
|
|
return <Download {...props} />;
|
|
}
|
|
|
|
renderRefresh() {
|
|
const { hideRefresh } = this.props;
|
|
if (hideRefresh) {
|
|
return null;
|
|
}
|
|
return (
|
|
<Button
|
|
type="default"
|
|
icon={<SyncOutlined />}
|
|
onClick={this.handleRefresh}
|
|
/>
|
|
);
|
|
}
|
|
|
|
renderRefreshAuto() {
|
|
// const { hideAutoRefresh, dataDurationAuto } = this.props;
|
|
const { hideAutoRefresh } = this.props;
|
|
if (hideAutoRefresh) {
|
|
return null;
|
|
}
|
|
const { autoRefresh } = this.state;
|
|
if (autoRefresh) {
|
|
// const tip = t('Stop refreshing data every {num} seconds', { num: dataDurationAuto });
|
|
const tip = t('Stop auto refreshing data');
|
|
return (
|
|
<Tooltip title={tip}>
|
|
<Button
|
|
type="primary"
|
|
icon={<PauseCircleOutlined />}
|
|
onClick={this.stopRefreshAuto}
|
|
/>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
// const tip = t('Start refreshing data every {num} seconds', { num: dataDurationAuto });
|
|
const tip = t('Start auto refreshing data');
|
|
return (
|
|
<Tooltip title={tip}>
|
|
<Button
|
|
type="default"
|
|
icon={<PlayCircleOutlined />}
|
|
onClick={this.startRefreshAuto}
|
|
/>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
renderNormalTitle() {
|
|
return (
|
|
<div className={styles['table-header']}>
|
|
<div
|
|
className={classnames(
|
|
styles['table-header-btns'],
|
|
'table-header-btns'
|
|
)}
|
|
>
|
|
{this.renderRefresh()}
|
|
{this.renderActions()}
|
|
{this.renderBatchActions()}
|
|
{this.renderCustomButton()}
|
|
{this.renderDownload()}
|
|
{this.renderRefreshAuto()}
|
|
</div>
|
|
{this.renderTimeFilter()}
|
|
{this.renderSearch()}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderTableTitle = () => this.renderNormalTitle();
|
|
|
|
renderRowMenu = () => {
|
|
const { hideRow } = this.state;
|
|
|
|
const getHideColKeys = (cols) => {
|
|
const results = [];
|
|
this.hideableRow.forEach((item) => {
|
|
if (cols.indexOf(item.value) === -1) {
|
|
results.push(item.value);
|
|
}
|
|
});
|
|
return results;
|
|
};
|
|
|
|
return (
|
|
<CustomColumns
|
|
className={styles.columnMenu}
|
|
options={this.hideableRow}
|
|
value={getHideColKeys(hideRow)}
|
|
onChange={this.handleRowHide}
|
|
/>
|
|
);
|
|
};
|
|
|
|
renderTableFooter = (currentPageData) => {
|
|
const { page, current, pageSize, total, pageSizeOptions } =
|
|
this.props.pagination;
|
|
const { isLoading, hideTotal } = this.props;
|
|
return (
|
|
<Pagination
|
|
current={page || current || 1}
|
|
pageSize={pageSize}
|
|
onChange={this.handlePageChange}
|
|
currentDataSize={currentPageData.length}
|
|
pageSizeOptions={pageSizeOptions || [10, 20, 50, 100]}
|
|
total={total}
|
|
isLoading={isLoading}
|
|
onFocusChange={this.handleInputFocus}
|
|
hideTotal={hideTotal}
|
|
/>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
className,
|
|
data,
|
|
isLoading,
|
|
silentLoading,
|
|
rowKey,
|
|
selectedRowKeys,
|
|
onSelectRowKeys,
|
|
hideHeader,
|
|
getCheckboxProps,
|
|
pagination,
|
|
scrollY,
|
|
expandable,
|
|
isPageByBack = true,
|
|
isCourier,
|
|
childrenColumnName,
|
|
// scrollX,
|
|
} = this.props;
|
|
|
|
let rowSelection = null;
|
|
|
|
const props = {};
|
|
const newPagination =
|
|
isCourier || !isPageByBack
|
|
? {
|
|
...pagination,
|
|
size: 'small',
|
|
}
|
|
: false;
|
|
|
|
if (!hideHeader) {
|
|
props.title = this.renderTableTitle;
|
|
}
|
|
const footer = !(isCourier || !isPageByBack)
|
|
? this.renderTableFooter
|
|
: null;
|
|
|
|
if (onSelectRowKeys) {
|
|
rowSelection = {
|
|
selectedRowKeys,
|
|
getCheckboxProps,
|
|
onChange: onSelectRowKeys,
|
|
// onSelect: (record, checked, selectedRows) => {
|
|
// onSelectRowKeys(selectedRows.map(row => row[rowKey]));
|
|
// },
|
|
// onSelectAll: (checked, selectedRows) => {
|
|
// onSelectRowKeys(selectedRows.map(row => row[rowKey]));
|
|
// }
|
|
};
|
|
}
|
|
|
|
const header = this.renderTableTitle();
|
|
const currentColumns = this.getColumns();
|
|
const scroll = {
|
|
// x: 'max-content',
|
|
// x: scrollX || this.hasItemActions() ? 1300 : 1500
|
|
};
|
|
if (scrollY > 0) {
|
|
scroll.y = scrollY || 400;
|
|
}
|
|
return (
|
|
<div>
|
|
{header}
|
|
<Table
|
|
className={classnames(styles.table, 'sl-table', className)}
|
|
rowKey={rowKey}
|
|
columns={currentColumns}
|
|
dataSource={toJS(data)}
|
|
loading={silentLoading ? false : isLoading}
|
|
onChange={this.handleChange}
|
|
pagination={newPagination}
|
|
rowSelection={rowSelection}
|
|
sortDirections={['ascend', 'descend', 'ascend']}
|
|
scroll={scroll}
|
|
showSorterTooltip={false}
|
|
expandable={expandable}
|
|
footer={footer}
|
|
childrenColumnName={childrenColumnName}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
}
|