mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
refactor: Replace usages of reactable in TableLoader (#11240)
* Refactor TableLoader to use react-bootstrap * Remove unnecessary css classes * Fix import * Fix styling for no data * Refactor TableLoader into functional component * Convert TableLoader to typescript
This commit is contained in:
committed by
GitHub
parent
04ee4a2d08
commit
dc5e5a978b
@@ -1,114 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 { Table, Tr, Td } from 'reactable-arc';
|
||||
import { t, SupersetClient } from '@superset-ui/core';
|
||||
|
||||
import withToasts from '../messageToasts/enhancers/withToasts';
|
||||
import Loading from './Loading';
|
||||
import '../../stylesheets/reactable-pagination.less';
|
||||
|
||||
const propTypes = {
|
||||
dataEndpoint: PropTypes.string.isRequired,
|
||||
mutator: PropTypes.func,
|
||||
columns: PropTypes.arrayOf(PropTypes.string),
|
||||
addDangerToast: PropTypes.func.isRequired,
|
||||
addInfoToast: PropTypes.func.isRequired,
|
||||
addSuccessToast: PropTypes.func.isRequired,
|
||||
addWarningToast: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class TableLoader extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
data: [],
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
const { dataEndpoint, mutator } = this.props;
|
||||
|
||||
SupersetClient.get({ endpoint: dataEndpoint })
|
||||
.then(({ json }) => {
|
||||
const data = mutator ? mutator(json) : json;
|
||||
this.setState({ data, isLoading: false });
|
||||
})
|
||||
.catch(() => {
|
||||
this.setState({ isLoading: false });
|
||||
this.props.addDangerToast(t('An error occurred'));
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
const {
|
||||
addDangerToast,
|
||||
addInfoToast,
|
||||
addSuccessToast,
|
||||
addWarningToast,
|
||||
...tableProps
|
||||
} = this.props;
|
||||
|
||||
let { columns } = this.props;
|
||||
if (!columns && this.state.data.length > 0) {
|
||||
columns = Object.keys(this.state.data[0]).filter(col => col[0] !== '_');
|
||||
}
|
||||
delete tableProps.dataEndpoint;
|
||||
delete tableProps.mutator;
|
||||
delete tableProps.columns;
|
||||
|
||||
return (
|
||||
<Table
|
||||
{...tableProps}
|
||||
className="table"
|
||||
itemsPerPage={50}
|
||||
style={{ textTransform: 'capitalize' }}
|
||||
>
|
||||
{this.state.data.map((row, i) => (
|
||||
<Tr key={i}>
|
||||
{columns.map(col => {
|
||||
if (row.hasOwnProperty(`_${col}`)) {
|
||||
return (
|
||||
<Td key={col} column={col} value={row[`_${col}`]}>
|
||||
{row[col]}
|
||||
</Td>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Td key={col} column={col}>
|
||||
{row[col]}
|
||||
</Td>
|
||||
);
|
||||
})}
|
||||
</Tr>
|
||||
))}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TableLoader.propTypes = propTypes;
|
||||
|
||||
export default withToasts(TableLoader);
|
||||
99
superset-frontend/src/components/TableLoader.tsx
Normal file
99
superset-frontend/src/components/TableLoader.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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, { useState, useEffect, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { t, SupersetClient, JsonObject } from '@superset-ui/core';
|
||||
import TableView from 'src/components/TableView';
|
||||
import withToasts from '../messageToasts/enhancers/withToasts';
|
||||
import Loading from './Loading';
|
||||
import '../../stylesheets/reactable-pagination.less';
|
||||
import { EmptyWrapperType } from './TableView/TableView';
|
||||
|
||||
const propTypes = {
|
||||
dataEndpoint: PropTypes.string.isRequired,
|
||||
mutator: PropTypes.func,
|
||||
columns: PropTypes.arrayOf(PropTypes.string),
|
||||
addDangerToast: PropTypes.func.isRequired,
|
||||
addInfoToast: PropTypes.func.isRequired,
|
||||
addSuccessToast: PropTypes.func.isRequired,
|
||||
addWarningToast: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
interface TableLoaderProps {
|
||||
dataEndpoint: string;
|
||||
mutator(data: JsonObject): any[];
|
||||
columns?: string[];
|
||||
addDangerToast(text: string): any;
|
||||
}
|
||||
|
||||
const TableLoader = (props: TableLoaderProps) => {
|
||||
const [data, setData] = useState<Array<any>>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const { dataEndpoint, mutator } = props;
|
||||
SupersetClient.get({ endpoint: dataEndpoint })
|
||||
.then(({ json }) => {
|
||||
const data = (mutator ? mutator(json) : json) as Array<any>;
|
||||
setData(data);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setIsLoading(false);
|
||||
props.addDangerToast(t('An error occurred'));
|
||||
});
|
||||
}, [props]);
|
||||
|
||||
const { columns, ...tableProps } = props;
|
||||
|
||||
const memoizedColumns = useMemo(() => {
|
||||
let tableColumns = columns;
|
||||
if (!columns && data.length > 0) {
|
||||
tableColumns = Object.keys(data[0]).filter(col => col[0] !== '_');
|
||||
}
|
||||
return tableColumns
|
||||
? tableColumns.map((column: string) => ({
|
||||
accessor: column,
|
||||
Header: column,
|
||||
}))
|
||||
: [];
|
||||
}, [columns, data]);
|
||||
|
||||
delete tableProps.dataEndpoint;
|
||||
delete tableProps.mutator;
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<TableView
|
||||
columns={memoizedColumns}
|
||||
data={data}
|
||||
pageSize={50}
|
||||
loading={isLoading}
|
||||
emptyWrapperType={EmptyWrapperType.Small}
|
||||
{...tableProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
TableLoader.propTypes = propTypes;
|
||||
|
||||
export default withToasts(TableLoader);
|
||||
@@ -25,6 +25,11 @@ import { SortColumns } from './types';
|
||||
|
||||
const DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
export enum EmptyWrapperType {
|
||||
Default,
|
||||
Small,
|
||||
}
|
||||
|
||||
export interface TableViewProps {
|
||||
columns: any[];
|
||||
data: any[];
|
||||
@@ -33,6 +38,8 @@ export interface TableViewProps {
|
||||
initialSortBy?: SortColumns;
|
||||
loading?: boolean;
|
||||
withPagination?: boolean;
|
||||
emptyWrapperType?: EmptyWrapperType;
|
||||
noDataText?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -65,6 +72,8 @@ const TableView = ({
|
||||
initialSortBy = [],
|
||||
loading = false,
|
||||
withPagination = true,
|
||||
emptyWrapperType = EmptyWrapperType.Default,
|
||||
noDataText,
|
||||
...props
|
||||
}: TableViewProps) => {
|
||||
const initialState = {
|
||||
@@ -95,6 +104,21 @@ const TableView = ({
|
||||
);
|
||||
|
||||
const content = withPagination ? page : rows;
|
||||
|
||||
let EmptyWrapperComponent;
|
||||
switch (emptyWrapperType) {
|
||||
case EmptyWrapperType.Small:
|
||||
EmptyWrapperComponent = ({ children }: any) => <>{children}</>;
|
||||
break;
|
||||
case EmptyWrapperType.Default:
|
||||
default:
|
||||
EmptyWrapperComponent = ({ children }: any) => (
|
||||
<EmptyWrapper>{children}</EmptyWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !loading && content.length === 0;
|
||||
|
||||
return (
|
||||
<TableViewStyles {...props}>
|
||||
<TableCollection
|
||||
@@ -106,10 +130,17 @@ const TableView = ({
|
||||
columns={columns}
|
||||
loading={loading}
|
||||
/>
|
||||
{!loading && content.length === 0 && (
|
||||
<EmptyWrapper>
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
</EmptyWrapper>
|
||||
{isEmpty && (
|
||||
<EmptyWrapperComponent>
|
||||
{noDataText ? (
|
||||
<Empty
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
description={noDataText}
|
||||
/>
|
||||
) : (
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
)}
|
||||
</EmptyWrapperComponent>
|
||||
)}
|
||||
{pageCount > 1 && withPagination && (
|
||||
<div className="pagination-container">
|
||||
|
||||
@@ -39,7 +39,7 @@ class CreatedContent extends React.PureComponent<CreatedContentProps> {
|
||||
return (
|
||||
<TableLoader
|
||||
dataEndpoint={`/superset/created_slices/${this.props.user.userId}/`}
|
||||
className="table table-condensed"
|
||||
className="table-condensed"
|
||||
columns={['slice', 'favorited']}
|
||||
mutator={mutator}
|
||||
noDataText={t('No charts')}
|
||||
@@ -57,7 +57,7 @@ class CreatedContent extends React.PureComponent<CreatedContentProps> {
|
||||
}));
|
||||
return (
|
||||
<TableLoader
|
||||
className="table table-condensed"
|
||||
className="table-condensed"
|
||||
mutator={mutator}
|
||||
dataEndpoint={`/superset/created_dashboards/${this.props.user.userId}/`}
|
||||
noDataText={t('No dashboards')}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class Favorites extends React.PureComponent<FavoritesProps> {
|
||||
return (
|
||||
<TableLoader
|
||||
dataEndpoint={`/superset/fave_slices/${this.props.user.userId}/`}
|
||||
className="table table-condensed"
|
||||
className="table-condensed"
|
||||
columns={['slice', 'creator', 'favorited']}
|
||||
mutator={mutator}
|
||||
noDataText={t('No favorite charts yet, go click on stars!')}
|
||||
@@ -58,7 +58,7 @@ export default class Favorites extends React.PureComponent<FavoritesProps> {
|
||||
}));
|
||||
return (
|
||||
<TableLoader
|
||||
className="table table-condensed"
|
||||
className="table-condensed"
|
||||
mutator={mutator}
|
||||
dataEndpoint={`/superset/fave_dashboards/${this.props.user.userId}/`}
|
||||
noDataText={t('No favorite dashboards yet, go click on stars!')}
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function RecentActivity({ user }: RecentActivityProps) {
|
||||
return (
|
||||
<div>
|
||||
<TableLoader
|
||||
className="table table-condensed"
|
||||
className="table-condensed"
|
||||
mutator={mutator}
|
||||
sortable
|
||||
dataEndpoint={`/superset/recent_activity/${user.userId}/?limit=${rowLimit}`}
|
||||
|
||||
Reference in New Issue
Block a user