mirror of
https://github.com/apache/superset.git
synced 2026-04-21 00:54:44 +00:00
* Adding full Annotation Framework * Viz types * Re organizing native annotations * liniting * Bug fix * Handle no data * Cleanup * Refactor slice form_data to data
196 lines
5.7 KiB
JavaScript
196 lines
5.7 KiB
JavaScript
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { Responsive, WidthProvider } from 'react-grid-layout';
|
|
|
|
import GridCell from './GridCell';
|
|
import { getExploreUrl } from '../../explore/exploreUtils';
|
|
|
|
require('react-grid-layout/css/styles.css');
|
|
require('react-resizable/css/styles.css');
|
|
|
|
const ResponsiveReactGridLayout = WidthProvider(Responsive);
|
|
|
|
const propTypes = {
|
|
dashboard: PropTypes.object.isRequired,
|
|
datasources: PropTypes.object,
|
|
charts: PropTypes.object.isRequired,
|
|
filters: PropTypes.object,
|
|
timeout: PropTypes.number,
|
|
onChange: PropTypes.func,
|
|
getFormDataExtra: PropTypes.func,
|
|
fetchSlice: PropTypes.func,
|
|
saveSlice: PropTypes.func,
|
|
removeSlice: PropTypes.func,
|
|
removeChart: PropTypes.func,
|
|
updateDashboardLayout: PropTypes.func,
|
|
toggleExpandSlice: PropTypes.func,
|
|
addFilter: PropTypes.func,
|
|
getFilters: PropTypes.func,
|
|
clearFilter: PropTypes.func,
|
|
removeFilter: PropTypes.func,
|
|
editMode: PropTypes.bool.isRequired,
|
|
};
|
|
|
|
const defaultProps = {
|
|
onChange: () => ({}),
|
|
getFormDataExtra: () => ({}),
|
|
fetchSlice: () => ({}),
|
|
saveSlice: () => ({}),
|
|
removeSlice: () => ({}),
|
|
removeChart: () => ({}),
|
|
updateDashboardLayout: () => ({}),
|
|
toggleExpandSlice: () => ({}),
|
|
addFilter: () => ({}),
|
|
getFilters: () => ({}),
|
|
clearFilter: () => ({}),
|
|
removeFilter: () => ({}),
|
|
};
|
|
|
|
class GridLayout extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.onResizeStop = this.onResizeStop.bind(this);
|
|
this.onDragStop = this.onDragStop.bind(this);
|
|
this.forceRefresh = this.forceRefresh.bind(this);
|
|
this.removeSlice = this.removeSlice.bind(this);
|
|
this.updateSliceName = this.props.dashboard.dash_edit_perm ?
|
|
this.updateSliceName.bind(this) : null;
|
|
}
|
|
|
|
onResizeStop(layout) {
|
|
this.props.updateDashboardLayout(layout);
|
|
this.props.onChange();
|
|
}
|
|
|
|
onDragStop(layout) {
|
|
this.props.updateDashboardLayout(layout);
|
|
this.props.onChange();
|
|
}
|
|
|
|
getWidgetId(slice) {
|
|
return 'widget_' + slice.slice_id;
|
|
}
|
|
|
|
getWidgetHeight(slice) {
|
|
const widgetId = this.getWidgetId(slice);
|
|
if (!widgetId || !this.refs[widgetId]) {
|
|
return 400;
|
|
}
|
|
return this.refs[widgetId].offsetHeight;
|
|
}
|
|
|
|
getWidgetWidth(slice) {
|
|
const widgetId = this.getWidgetId(slice);
|
|
if (!widgetId || !this.refs[widgetId]) {
|
|
return 400;
|
|
}
|
|
return this.refs[widgetId].offsetWidth;
|
|
}
|
|
|
|
findSliceIndexById(sliceId) {
|
|
return this.props.dashboard.slices
|
|
.map(slice => (slice.slice_id)).indexOf(sliceId);
|
|
}
|
|
|
|
forceRefresh(sliceId) {
|
|
return this.props.fetchSlice(this.props.charts['slice_' + sliceId], true);
|
|
}
|
|
|
|
removeSlice(slice) {
|
|
if (!slice) {
|
|
return;
|
|
}
|
|
|
|
// remove slice dashbaord and charts
|
|
this.props.removeSlice(slice);
|
|
this.props.removeChart(this.props.charts['slice_' + slice.slice_id].chartKey);
|
|
this.props.onChange();
|
|
}
|
|
|
|
updateSliceName(sliceId, sliceName) {
|
|
const index = this.findSliceIndexById(sliceId);
|
|
if (index === -1) {
|
|
return;
|
|
}
|
|
|
|
const currentSlice = this.props.dashboard.slices[index];
|
|
if (currentSlice.slice_name === sliceName) {
|
|
return;
|
|
}
|
|
|
|
this.props.saveSlice(currentSlice, sliceName);
|
|
}
|
|
|
|
isExpanded(slice) {
|
|
return this.props.dashboard.metadata.expanded_slices &&
|
|
this.props.dashboard.metadata.expanded_slices[slice.slice_id];
|
|
}
|
|
|
|
render() {
|
|
const cells = this.props.dashboard.slices.map((slice) => {
|
|
const chartKey = `slice_${slice.slice_id}`;
|
|
const currentChart = this.props.charts[chartKey];
|
|
const queryResponse = currentChart.queryResponse || {};
|
|
return (
|
|
<div
|
|
id={'slice_' + slice.slice_id}
|
|
key={slice.slice_id}
|
|
data-slice-id={slice.slice_id}
|
|
className={`widget ${slice.form_data.viz_type}`}
|
|
ref={this.getWidgetId(slice)}
|
|
>
|
|
<GridCell
|
|
slice={slice}
|
|
chartKey={chartKey}
|
|
datasource={this.props.datasources[slice.form_data.datasource]}
|
|
filters={this.props.filters}
|
|
formData={this.props.getFormDataExtra(slice)}
|
|
timeout={this.props.timeout}
|
|
widgetHeight={this.getWidgetHeight(slice)}
|
|
widgetWidth={this.getWidgetWidth(slice)}
|
|
exploreChartUrl={getExploreUrl(this.props.getFormDataExtra(slice))}
|
|
exportCSVUrl={getExploreUrl(this.props.getFormDataExtra(slice), 'csv')}
|
|
isExpanded={!!this.isExpanded(slice)}
|
|
isLoading={currentChart.chartStatus === 'loading'}
|
|
isCached={queryResponse.is_cached}
|
|
cachedDttm={queryResponse.cached_dttm}
|
|
toggleExpandSlice={this.props.toggleExpandSlice}
|
|
forceRefresh={this.forceRefresh}
|
|
removeSlice={this.removeSlice}
|
|
updateSliceName={this.updateSliceName}
|
|
addFilter={this.props.addFilter}
|
|
getFilters={this.props.getFilters}
|
|
clearFilter={this.props.clearFilter}
|
|
removeFilter={this.props.removeFilter}
|
|
editMode={this.props.editMode}
|
|
annotationQuery={currentChart.annotationQuery}
|
|
annotationError={currentChart.annotationError}
|
|
/>
|
|
</div>);
|
|
});
|
|
|
|
return (
|
|
<ResponsiveReactGridLayout
|
|
className="layout"
|
|
layouts={{ lg: this.props.dashboard.layout }}
|
|
onResizeStop={this.onResizeStop}
|
|
onDragStop={this.onDragStop}
|
|
cols={{ lg: 12, md: 12, sm: 10, xs: 8, xxs: 6 }}
|
|
rowHeight={100}
|
|
autoSize
|
|
margin={[20, 20]}
|
|
useCSSTransforms
|
|
draggableHandle=".drag"
|
|
>
|
|
{cells}
|
|
</ResponsiveReactGridLayout>
|
|
);
|
|
}
|
|
}
|
|
|
|
GridLayout.propTypes = propTypes;
|
|
GridLayout.defaultProps = defaultProps;
|
|
|
|
export default GridLayout;
|