Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restyle Add 12 column layout option for all dashboards #4810

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions client/app/components/dashboards/DashboardGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cx from "classnames";
import { Responsive, WidthProvider } from "react-grid-layout";
import { VisualizationWidget, TextboxWidget, RestrictedWidget } from "@/components/dashboards/dashboard-widget";
import { FiltersType } from "@/components/Filters";
import cfg from "@/config/dashboard-grid-options";
import cfg, { dashboard12ColGridOptions as cfg12 } from "@/config/dashboard-grid-options";
import AutoHeightController from "./AutoHeightController";
import { WidgetTypeEnum } from "@/services/widget";

Expand Down Expand Up @@ -132,9 +132,11 @@ class DashboardGrid extends React.Component {
constructor(props) {
super(props);

const currentCfg = this.props.dashboard.use_12_column_layout ? cfg12 : cfg;
this.state = {
layouts: {},
disableAnimations: true,
cfg: currentCfg,
};

// init AutoHeightController
Expand All @@ -143,6 +145,7 @@ class DashboardGrid extends React.Component {
}

componentDidMount() {
this.onColumnCountChange(this.props.dashboard.use_12_column_layout);
this.onBreakpointChange(document.body.offsetWidth <= cfg.mobileBreakPoint ? SINGLE : MULTI);
// Work-around to disable initial animation on widgets; `measureBeforeMount` doesn't work properly:
// it disables animation, but it cannot detect scrollbars.
Expand All @@ -151,9 +154,26 @@ class DashboardGrid extends React.Component {
}, 50);
}

componentDidUpdate() {
onColumnCountChange(use12) {
const editGrid = document.getElementsByClassName("dashboard-wrapper")[0];

if (editGrid) {
// use CSS attribute to change background grid while editing dashboard
const columnsCountAttribute = document.createAttribute("columns-count");
columnsCountAttribute.value = use12 ? 12 : 6;
editGrid.attributes.setNamedItem(columnsCountAttribute);
this.setState({ cfg: use12 ? cfg12 : cfg });
}
}

componentDidUpdate(prevProps) {
// update, in case widgets added or removed
this.autoHeightCtrl.update(this.props.widgets);

// listen to changes of columns layout
if (prevProps.dashboard.use_12_column_layout !== this.props.dashboard.use_12_column_layout) {
this.onColumnCountChange(this.props.dashboard.use_12_column_layout);
}
}

componentWillUnmount() {
Expand Down Expand Up @@ -239,7 +259,7 @@ class DashboardGrid extends React.Component {
<div className={className}>
<ResponsiveGridLayout
className={cx("layout", { "disable-animations": this.state.disableAnimations })}
cols={{ [MULTI]: cfg.columns, [SINGLE]: 1 }}
cols={{ [MULTI]: this.state.cfg.columns, [SINGLE]: 1 }}
rowHeight={cfg.rowHeight - cfg.margins}
margin={[cfg.margins, cfg.margins]}
isDraggable={this.props.isEditing}
Expand Down
6 changes: 6 additions & 0 deletions client/app/components/dashboards/dashboard-grid.less
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
background-size: calc((100vw - 15px) / 6) 5px;
background-position: -7px 1px;
}

&[columns-count="12"] {
&::before {
background-size: calc((100vw - 15px) / 12) 5px;
}
}
}

.widget-auto-height-enabled {
Expand Down
16 changes: 15 additions & 1 deletion client/app/config/dashboard-grid-options.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
export const dashboard12ColGridOptions = {
columns: 12, // grid columns count
rowHeight: 50, // grid row height (incl. bottom padding)
margins: 15, // widget margins
mobileBreakPoint: 800,
// defaults for widgets
defaultSizeX: 4,
defaultSizeY: 3,
minSizeX: 1,
maxSizeX: 12,
minSizeY: 1,
maxSizeY: 1000,
};

export default {
columns: 6, // grid columns count
rowHeight: 50, // grid row height (incl. bottom padding)
Expand All @@ -7,7 +21,7 @@ export default {
defaultSizeX: 3,
defaultSizeY: 3,
minSizeX: 1,
maxSizeX: 6,
maxSizeX: 12, // you cannot go above 6 in the UI anyway
minSizeY: 1,
maxSizeY: 1000,
};
5 changes: 5 additions & 0 deletions client/app/pages/dashboards/DashboardPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ function DashboardSettings({ dashboardOptions }) {
onChange={({ target }) => updateDashboard({ dashboard_filters_enabled: target.checked })}>
Use Dashboard Level Filters
</Checkbox>
<Checkbox
checked={!!dashboard.use_12_column_layout}
onChange={({ target }) => updateDashboard({ use_12_column_layout: target.checked })}>
Use 12-column layout
</Checkbox>
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion client/app/pages/dashboards/hooks/useDashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function useDashboard(dashboardData) {
// reload dashboard when filter option changes
useEffect(() => {
loadDashboard();
}, [dashboard.dashboard_filters_enabled]); // eslint-disable-line react-hooks/exhaustive-deps
}, [dashboard.dashboard_filters_enabled, dashboard.use_12_column_layout]); // eslint-disable-line react-hooks/exhaustive-deps

return {
dashboard,
Expand Down
13 changes: 7 additions & 6 deletions client/app/services/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from "lodash";
import { axios } from "@/services/axios";
import dashboardGridOptions from "@/config/dashboard-grid-options";
import dashboardGridOptions, { dashboard12ColGridOptions } from "@/config/dashboard-grid-options";
import Widget from "./widget";
import { currentUser } from "@/services/auth";
import location from "@/services/location";
Expand Down Expand Up @@ -78,8 +78,9 @@ function prepareWidgetsForDashboard(widgets) {
return widgets;
}

function calculateNewWidgetPosition(existingWidgets, newWidget) {
const width = _.extend({ sizeX: dashboardGridOptions.defaultSizeX }, _.extend({}, newWidget.options).position).sizeX;
function calculateNewWidgetPosition(existingWidgets, newWidget, use12Cols) {
const gridOptions = use12Cols ? dashboard12ColGridOptions : dashboardGridOptions;
const width = _.extend({ sizeX: gridOptions.defaultSizeX }, _.extend({}, newWidget.options).position).sizeX;

// Find first free row for each column
const bottomLine = _.chain(existingWidgets)
Expand All @@ -102,13 +103,13 @@ function calculateNewWidgetPosition(existingWidgets, newWidget) {
result[i] = Math.max(result[i], item.bottom);
}
return result;
}, _.map(new Array(dashboardGridOptions.columns), _.constant(0)))
}, _.map(new Array(gridOptions.columns), _.constant(0)))
.value();

// Go through columns, pick them by count necessary to hold new block,
// and calculate bottom-most free row per group.
// Choose group with the top-most free row (comparing to other groups)
return _.chain(_.range(0, dashboardGridOptions.columns - width + 1))
return _.chain(_.range(0, gridOptions.columns - width + 1))
.map(col => ({
col,
row: _.chain(bottomLine)
Expand Down Expand Up @@ -227,7 +228,7 @@ Dashboard.prototype.addWidget = function addWidget(textOrVisualization, options

const widget = new Widget(props);

const position = calculateNewWidgetPosition(this.widgets, widget);
const position = calculateNewWidgetPosition(this.widgets, widget, this.use_12_column_layout);
widget.options.position.col = position.col;
widget.options.position.row = position.row;

Expand Down
29 changes: 29 additions & 0 deletions migrations/versions/dedeb4b35ab8_add_use_12_column_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""add use_12_column_layout

Revision ID: dedeb4b35ab8
Revises: e5c7a4e2df4d
Create Date: 2020-04-18 18:20:00.333654

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "dedeb4b35ab8"
down_revision = "e5c7a4e2df4d"
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
"dashboards",
sa.Column(
"use_12_column_layout", sa.Boolean(), nullable=False, server_default=False
),
)


def downgrade():
op.drop_column("dashboards", "use_12_column_layout")
2 changes: 2 additions & 0 deletions redash/handlers/dashboards.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def get(self, dashboard_slug=None):
:>json string updated_at: ISO format timestamp for last dashboard modification
:>json number version: Revision number of dashboard
:>json boolean dashboard_filters_enabled: Whether filters are enabled or not
:>json booleann use_12_column_layout: Whether to use 12-column layout or not
:>json boolean is_archived: Whether this dashboard has been removed from the index or not
:>json boolean is_draft: Whether this dashboard is a draft or not.
:>json array layout: Array of arrays containing widget IDs, corresponding to the rows and columns the widgets are displayed in
Expand Down Expand Up @@ -199,6 +200,7 @@ def post(self, dashboard_slug):
"is_draft",
"is_archived",
"dashboard_filters_enabled",
"use_12_column_layout"
),
)

Expand Down
1 change: 1 addition & 0 deletions redash/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model
# layout is no longer used, but kept so we know how to render old dashboards.
layout = Column(db.Text)
dashboard_filters_enabled = Column(db.Boolean, default=False)
use_12_column_layout = Column(db.Boolean, default=False)
is_archived = Column(db.Boolean, default=False, index=True)
is_draft = Column(db.Boolean, default=True, index=True)
widgets = db.relationship("Widget", backref="dashboard", lazy="dynamic")
Expand Down
3 changes: 2 additions & 1 deletion redash/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def public_widget(widget):
def public_dashboard(dashboard):
dashboard_dict = project(
serialize_dashboard(dashboard, with_favorite_state=False),
("name", "layout", "dashboard_filters_enabled", "updated_at", "created_at"),
("name", "layout", "dashboard_filters_enabled", "use_12_column_layout", "updated_at", "created_at"),
)

widget_list = (
Expand Down Expand Up @@ -252,6 +252,7 @@ def serialize_dashboard(obj, with_widgets=False, user=None, with_favorite_state=
"user": obj.user.to_dict(),
"layout": layout,
"dashboard_filters_enabled": obj.dashboard_filters_enabled,
"use_12_column_layout": obj.use_12_column_layout,
"widgets": widgets,
"is_archived": obj.is_archived,
"is_draft": obj.is_draft,
Expand Down