feat(explore): allow opening charts with missing dataset (#12705)

This commit is contained in:
Jesse Yang
2021-01-25 15:09:03 -08:00
committed by GitHub
parent 29ad78e11a
commit 55c8f9ba60
47 changed files with 278 additions and 249 deletions

View File

@@ -29,9 +29,9 @@ export type ControlProps = {
// signature to the original action factory.
actions: Partial<ExploreActions> & Pick<ExploreActions, 'setControlValue'>;
type: ControlType;
label: string;
label?: ReactNode;
name: string;
description?: string;
description?: ReactNode;
tooltipOnClick?: () => ReactNode;
places?: number;
rightNode?: ReactNode;

View File

@@ -17,57 +17,25 @@
* under the License.
*/
import React, { useEffect, useState } from 'react';
import { styled, t, QueryFormData } from '@superset-ui/core';
import { styled, t } from '@superset-ui/core';
import { Collapse } from 'src/common/components';
import {
ColumnOption,
MetricOption,
ControlType,
ControlConfig,
DatasourceMeta,
} from '@superset-ui/chart-controls';
import { debounce } from 'lodash';
import { matchSorter, rankings } from 'match-sorter';
import { ExploreActions } from '../actions/exploreActions';
import Control from './Control';
interface DatasourceControl {
validationErrors: Array<any>;
mapStateToProps: QueryFormData;
type: ControlType;
label: string;
datasource?: DatasourceControl;
interface DatasourceControl extends ControlConfig {
datasource?: DatasourceMeta;
}
type Columns = {
column_name: string;
description: string | undefined;
expression: string | undefined;
filterable: boolean;
groupby: string | undefined;
id: number;
is_dttm: boolean;
python_date_format: string;
type: string;
verbose_name: string;
};
type Metrics = {
certification_details: string | undefined;
certified_by: string | undefined;
d3format: string | undefined;
description: string | undefined;
expression: string;
id: number;
is_certified: boolean;
metric_name: string;
verbose_name: string;
warning_text: string;
};
interface Props {
datasource: {
columns: Array<Columns>;
metrics: Array<Metrics>;
};
datasource: DatasourceMeta;
controls: {
datasource: DatasourceControl;
};
@@ -193,15 +161,8 @@ export default function DataSourcePanel({
const metricSlice = lists.metrics.slice(0, 50);
const columnSlice = lists.columns.slice(0, 50);
return (
<DatasourceContainer>
<Control
{...datasourceControl}
name="datasource"
validationErrors={datasourceControl.validationErrors}
actions={actions}
formData={datasourceControl.mapStateToProps}
/>
const mainBody = (
<>
<input
type="text"
onChange={evt => {
@@ -245,6 +206,13 @@ export default function DataSourcePanel({
</Collapse.Panel>
</Collapse>
</div>
</>
);
return (
<DatasourceContainer>
<Control {...datasourceControl} name="datasource" actions={actions} />
{datasource.id != null && mainBody}
</DatasourceContainer>
);
}

View File

@@ -26,6 +26,8 @@ import Icon from 'src/components/Icon';
import ChangeDatasourceModal from 'src/datasource/ChangeDatasourceModal';
import DatasourceModal from 'src/datasource/DatasourceModal';
import { postForm } from 'src/explore/exploreUtils';
import Button from 'src/components/Button';
import ErrorAlert from 'src/components/ErrorMessage/ErrorAlert';
const propTypes = {
actions: PropTypes.object.isRequired,
@@ -51,6 +53,9 @@ const Styles = styled.div`
border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
padding: ${({ theme }) => 2 * theme.gridUnit}px;
}
.error-alert {
margin: ${({ theme }) => 2 * theme.gridUnit}px;
}
.ant-dropdown-trigger {
margin-left: ${({ theme }) => 2 * theme.gridUnit}px;
box-shadow: none;
@@ -152,6 +157,7 @@ class DatasourceControl extends React.PureComponent {
render() {
const { showChangeDatasourceModal, showEditDatasourceModal } = this.state;
const { datasource, onChange } = this.props;
const isMissingDatasource = datasource;
const datasourceMenu = (
<Menu onClick={this.handleMenuItemClick}>
{this.props.isEditable && (
@@ -164,16 +170,22 @@ class DatasourceControl extends React.PureComponent {
</Menu>
);
// eslint-disable-next-line camelcase
const { health_check_message: healthCheckMessage } = datasource;
return (
<Styles className="DatasourceControl">
<div className="data-container">
<Icon name="dataset-physical" className="dataset-svg" />
<Tooltip title={datasource.name}>
<span className="title-select">{datasource.name}</span>
</Tooltip>
{/* Add a tooltip only for long dataset names */}
{!isMissingDatasource && datasource.name.length > 25 ? (
<Tooltip title={datasource.name}>
<span className="title-select">{datasource.name}</span>
</Tooltip>
) : (
<span title={datasource.name} className="title-select">
{datasource.name}
</span>
)}
{healthCheckMessage && (
<Tooltip title={healthCheckMessage}>
<Icon
@@ -196,6 +208,35 @@ class DatasourceControl extends React.PureComponent {
</Tooltip>
</Dropdown>
</div>
{/* missing dataset */}
{isMissingDatasource && (
<div className="error-alert">
<ErrorAlert
level="warning"
title={t('Missing dataset')}
source="explore"
subtitle={
<>
<p>
{t(
'The dataset linked to this chart may have been deleted.',
)}
</p>
<p>
<Button
buttonStyle="primary"
onClick={() =>
this.handleMenuItemClick({ key: CHANGE_DATASET })
}
>
{t('Change dataset')}
</Button>
</p>
</>
}
/>
</div>
)}
{showEditDatasourceModal && (
<DatasourceModal
datasource={datasource}