mirror of
https://github.com/apache/superset.git
synced 2026-04-22 17:45:21 +00:00
Moving to a grid that is 4 times more granular. 48 columns. Shipping a db migration script which will upgrade the position metadata to reflect this change. Also adapting the examples to the new grid parameters.
199 lines
5.7 KiB
JavaScript
199 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';
|
|
|
|
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,
|
|
exploreChart: PropTypes.func,
|
|
exportCSV: 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: () => ({}),
|
|
exploreChart: () => ({}),
|
|
exportCSV: () => ({}),
|
|
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 dashboard 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)}
|
|
exploreChart={this.props.exploreChart}
|
|
exportCSV={this.props.exportCSV}
|
|
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: 48, md: 48, sm: 40, xs: 32, xxs: 24 }}
|
|
rowHeight={10}
|
|
autoSize
|
|
margin={[20, 20]}
|
|
useCSSTransforms
|
|
draggableHandle=".drag"
|
|
>
|
|
{cells}
|
|
</ResponsiveReactGridLayout>
|
|
);
|
|
}
|
|
}
|
|
|
|
GridLayout.propTypes = propTypes;
|
|
GridLayout.defaultProps = defaultProps;
|
|
|
|
export default GridLayout;
|