mirror of
https://github.com/apache/superset.git
synced 2026-05-12 19:35:17 +00:00
feat(explore): allow opening charts with missing dataset (#12705)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user