mirror of
https://github.com/apache/superset.git
synced 2024-09-16 02:29:39 -04:00
feat(explore): Move timer, row counter and cached pills to chart container (#19458)
* feat(explore): Move timer, row counter and cached pills to chart container * Hide pills in standalone mode * Take pills out of chart-container
This commit is contained in:
parent
cccec9a6ab
commit
03d3eaacaf
88
superset-frontend/src/explore/components/ChartPills.tsx
Normal file
88
superset-frontend/src/explore/components/ChartPills.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* 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, { forwardRef, RefObject } from 'react';
|
||||||
|
import { css, QueryData, SupersetTheme } from '@superset-ui/core';
|
||||||
|
import RowCountLabel from 'src/explore/components/RowCountLabel';
|
||||||
|
import CachedLabel from 'src/components/CachedLabel';
|
||||||
|
import Timer from 'src/components/Timer';
|
||||||
|
|
||||||
|
enum CHART_STATUS_MAP {
|
||||||
|
failed = 'danger',
|
||||||
|
loading = 'warning',
|
||||||
|
success = 'success',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChartPillsProps = {
|
||||||
|
queriesResponse: QueryData[];
|
||||||
|
chartStatus: keyof typeof CHART_STATUS_MAP;
|
||||||
|
chartUpdateStartTime: number;
|
||||||
|
chartUpdateEndTime: number;
|
||||||
|
refreshCachedQuery: () => void;
|
||||||
|
rowLimit: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ChartPills = forwardRef(
|
||||||
|
(
|
||||||
|
{
|
||||||
|
queriesResponse,
|
||||||
|
chartStatus,
|
||||||
|
chartUpdateStartTime,
|
||||||
|
chartUpdateEndTime,
|
||||||
|
refreshCachedQuery,
|
||||||
|
rowLimit,
|
||||||
|
}: ChartPillsProps,
|
||||||
|
ref: RefObject<HTMLDivElement>,
|
||||||
|
) => {
|
||||||
|
const isLoading = chartStatus === 'loading';
|
||||||
|
const firstQueryResponse = queriesResponse?.[0];
|
||||||
|
return (
|
||||||
|
<div ref={ref}>
|
||||||
|
<div
|
||||||
|
css={(theme: SupersetTheme) => css`
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-bottom: ${theme.gridUnit * 4}px;
|
||||||
|
& .ant-tag:last-of-type {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{!isLoading && firstQueryResponse && (
|
||||||
|
<RowCountLabel
|
||||||
|
rowcount={Number(firstQueryResponse.rowcount) || 0}
|
||||||
|
limit={Number(rowLimit) || 0}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!isLoading && firstQueryResponse?.is_cached && (
|
||||||
|
<CachedLabel
|
||||||
|
onClick={refreshCachedQuery}
|
||||||
|
cachedTimestamp={firstQueryResponse.cached_dttm}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Timer
|
||||||
|
startTime={chartUpdateStartTime}
|
||||||
|
endTime={chartUpdateEndTime}
|
||||||
|
isRunning={isLoading}
|
||||||
|
status={CHART_STATUS_MAP[chartStatus]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
@ -36,22 +36,12 @@ import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
|
|||||||
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
||||||
import AlteredSliceTag from 'src/components/AlteredSliceTag';
|
import AlteredSliceTag from 'src/components/AlteredSliceTag';
|
||||||
import FaveStar from 'src/components/FaveStar';
|
import FaveStar from 'src/components/FaveStar';
|
||||||
import Timer from 'src/components/Timer';
|
|
||||||
import CachedLabel from 'src/components/CachedLabel';
|
|
||||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||||
import { sliceUpdated } from 'src/explore/actions/exploreActions';
|
import { sliceUpdated } from 'src/explore/actions/exploreActions';
|
||||||
import CertifiedBadge from 'src/components/CertifiedBadge';
|
import CertifiedBadge from 'src/components/CertifiedBadge';
|
||||||
import withToasts from 'src/components/MessageToasts/withToasts';
|
|
||||||
import RowCountLabel from '../RowCountLabel';
|
|
||||||
import ExploreAdditionalActionsMenu from '../ExploreAdditionalActionsMenu';
|
import ExploreAdditionalActionsMenu from '../ExploreAdditionalActionsMenu';
|
||||||
import { ChartEditableTitle } from './ChartEditableTitle';
|
import { ChartEditableTitle } from './ChartEditableTitle';
|
||||||
|
|
||||||
const CHART_STATUS_MAP = {
|
|
||||||
failed: 'danger',
|
|
||||||
loading: 'warning',
|
|
||||||
success: 'success',
|
|
||||||
};
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
canOverwrite: PropTypes.bool.isRequired,
|
canOverwrite: PropTypes.bool.isRequired,
|
||||||
@ -85,7 +75,7 @@ const StyledHeader = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
margin-right: ${theme.gridUnit * 6}px;
|
margin-right: ${theme.gridUnit * 12}px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-button-panel {
|
.right-button-panel {
|
||||||
@ -231,20 +221,8 @@ export class ExploreChartHeader extends React.PureComponent {
|
|||||||
sliceUpdated,
|
sliceUpdated,
|
||||||
sliceName,
|
sliceName,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const { latestQueryFormData, sliceFormData } = chart;
|
||||||
chartStatus,
|
|
||||||
chartUpdateEndTime,
|
|
||||||
chartUpdateStartTime,
|
|
||||||
latestQueryFormData,
|
|
||||||
queriesResponse,
|
|
||||||
sliceFormData,
|
|
||||||
} = chart;
|
|
||||||
// TODO: when will get appropriate design for multi queries use all results and not first only
|
|
||||||
const queryResponse = queriesResponse?.[0];
|
|
||||||
const oldSliceName = slice?.slice_name;
|
const oldSliceName = slice?.slice_name;
|
||||||
const chartFinished = ['failed', 'rendered', 'success'].includes(
|
|
||||||
chartStatus,
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<StyledHeader id="slice-header">
|
<StyledHeader id="slice-header">
|
||||||
<div className="title-panel">
|
<div className="title-panel">
|
||||||
@ -296,24 +274,6 @@ export class ExploreChartHeader extends React.PureComponent {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="right-button-panel">
|
<div className="right-button-panel">
|
||||||
{chartFinished && queryResponse && (
|
|
||||||
<RowCountLabel
|
|
||||||
rowcount={Number(queryResponse.rowcount) || 0}
|
|
||||||
limit={Number(formData.row_limit) || 0}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{chartFinished && queryResponse && queryResponse.is_cached && (
|
|
||||||
<CachedLabel
|
|
||||||
onClick={this.postChartFormData.bind(this)}
|
|
||||||
cachedTimestamp={queryResponse.cached_dttm}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Timer
|
|
||||||
startTime={chartUpdateStartTime}
|
|
||||||
endTime={chartUpdateEndTime}
|
|
||||||
isRunning={chartStatus === 'loading'}
|
|
||||||
status={CHART_STATUS_MAP[chartStatus]}
|
|
||||||
/>
|
|
||||||
<ExploreAdditionalActionsMenu
|
<ExploreAdditionalActionsMenu
|
||||||
onOpenInEditor={actions.redirectSQLLab}
|
onOpenInEditor={actions.redirectSQLLab}
|
||||||
onOpenPropertiesModal={this.openPropertiesModal}
|
onOpenPropertiesModal={this.openPropertiesModal}
|
||||||
@ -337,7 +297,4 @@ function mapDispatchToProps(dispatch) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(null, mapDispatchToProps)(ExploreChartHeader);
|
||||||
null,
|
|
||||||
mapDispatchToProps,
|
|
||||||
)(withToasts(ExploreChartHeader));
|
|
||||||
|
@ -30,6 +30,7 @@ import {
|
|||||||
} from 'src/utils/localStorageHelpers';
|
} from 'src/utils/localStorageHelpers';
|
||||||
import { DataTablesPane } from './DataTablesPane';
|
import { DataTablesPane } from './DataTablesPane';
|
||||||
import { buildV1ChartDataPayload } from '../exploreUtils';
|
import { buildV1ChartDataPayload } from '../exploreUtils';
|
||||||
|
import { ChartPills } from './ChartPills';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
@ -116,6 +117,10 @@ const ExploreChartPanel = props => {
|
|||||||
refreshMode: 'debounce',
|
refreshMode: 'debounce',
|
||||||
refreshRate: 300,
|
refreshRate: 300,
|
||||||
});
|
});
|
||||||
|
const { height: pillsHeight, ref: pillsRef } = useResizeDetector({
|
||||||
|
refreshMode: 'debounce',
|
||||||
|
refreshRate: 1000,
|
||||||
|
});
|
||||||
const [splitSizes, setSplitSizes] = useState(
|
const [splitSizes, setSplitSizes] = useState(
|
||||||
getItem(LocalStorageKeys.chart_split_sizes, INITIAL_SIZES),
|
getItem(LocalStorageKeys.chart_split_sizes, INITIAL_SIZES),
|
||||||
);
|
);
|
||||||
@ -150,10 +155,16 @@ const ExploreChartPanel = props => {
|
|||||||
}, [updateQueryContext]);
|
}, [updateQueryContext]);
|
||||||
|
|
||||||
const calcSectionHeight = useCallback(
|
const calcSectionHeight = useCallback(
|
||||||
percent =>
|
percent => {
|
||||||
(parseInt(props.height, 10) * percent) / 100 -
|
let containerHeight = parseInt(props.height, 10);
|
||||||
(gutterHeight / 2 + gutterMargin),
|
if (pillsHeight) {
|
||||||
[gutterHeight, gutterMargin, props.height, props.standalone],
|
containerHeight -= pillsHeight;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(containerHeight * percent) / 100 - (gutterHeight / 2 + gutterMargin)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[gutterHeight, gutterMargin, pillsHeight, props.height, props.standalone],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [tableSectionHeight, setTableSectionHeight] = useState(
|
const [tableSectionHeight, setTableSectionHeight] = useState(
|
||||||
@ -179,6 +190,17 @@ const ExploreChartPanel = props => {
|
|||||||
setSplitSizes(sizes);
|
setSplitSizes(sizes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const refreshCachedQuery = () => {
|
||||||
|
props.actions.postChartFormData(
|
||||||
|
props.form_data,
|
||||||
|
true,
|
||||||
|
props.timeout,
|
||||||
|
props.chart.id,
|
||||||
|
undefined,
|
||||||
|
props.ownState,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const onCollapseChange = openPanelName => {
|
const onCollapseChange = openPanelName => {
|
||||||
let splitSizes;
|
let splitSizes;
|
||||||
if (!openPanelName) {
|
if (!openPanelName) {
|
||||||
@ -229,6 +251,15 @@ const ExploreChartPanel = props => {
|
|||||||
const panelBody = useMemo(
|
const panelBody = useMemo(
|
||||||
() => (
|
() => (
|
||||||
<div className="panel-body" ref={chartPanelRef}>
|
<div className="panel-body" ref={chartPanelRef}>
|
||||||
|
<ChartPills
|
||||||
|
queriesResponse={props.chart.queriesResponse}
|
||||||
|
chartStatus={props.chart.chartStatus}
|
||||||
|
chartUpdateStartTime={props.chart.chartUpdateStartTime}
|
||||||
|
chartUpdateEndTime={props.chart.chartUpdateEndTime}
|
||||||
|
refreshCachedQuery={refreshCachedQuery}
|
||||||
|
rowLimit={props.form_data?.row_limit}
|
||||||
|
ref={pillsRef}
|
||||||
|
/>
|
||||||
{renderChart()}
|
{renderChart()}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import RowCountLabel from './RowCountLabel';
|
import RowCountLabel from '.';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'RowCountLabel',
|
title: 'RowCountLabel',
|
@ -21,7 +21,7 @@ import { shallow } from 'enzyme';
|
|||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
import { Tooltip } from 'src/components/Tooltip';
|
import { Tooltip } from 'src/components/Tooltip';
|
||||||
import RowCountLabel from 'src/explore/components/RowCountLabel';
|
import RowCountLabel from '.';
|
||||||
|
|
||||||
describe('RowCountLabel', () => {
|
describe('RowCountLabel', () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
Loading…
Reference in New Issue
Block a user