mirror of
https://github.com/valitydev/redash.git
synced 2024-11-07 01:25:16 +00:00
Merge pull request #2356 from kravets-levko/fix/dashboard-auto-height
Dashboard fixes and improvements
This commit is contained in:
commit
6049e2df17
@ -1,15 +1,37 @@
|
||||
import * as _ from 'underscore';
|
||||
import { requestAnimationFrame } from './utils';
|
||||
|
||||
function gridsterAutoHeight($timeout) {
|
||||
function gridsterAutoHeight($timeout, $parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'gridsterItem',
|
||||
link($scope, $element, attr, controller) {
|
||||
let destroyed = false;
|
||||
let autoSized = true;
|
||||
|
||||
const itemGetter = $parse(attr.gridsterItem);
|
||||
|
||||
$scope.$watch(attr.gridsterItem, (newValue, oldValue) => {
|
||||
const item = _.extend({}, itemGetter($scope));
|
||||
if (_.isObject(newValue) && _.isObject(oldValue)) {
|
||||
if ((newValue.sizeY !== oldValue.sizeY) && !autoSized) {
|
||||
item.autoHeight = false;
|
||||
if (_.isFunction(itemGetter.assign)) {
|
||||
itemGetter.assign($scope, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.autoHeight) {
|
||||
$element.addClass('gridster-auto-height-enabled');
|
||||
} else {
|
||||
$element.removeClass('gridster-auto-height-enabled');
|
||||
}
|
||||
autoSized = false;
|
||||
}, true);
|
||||
|
||||
function updateHeight() {
|
||||
if (controller.gridster) {
|
||||
const item = _.extend({}, itemGetter($scope));
|
||||
|
||||
if (controller.gridster && item.autoHeight) {
|
||||
const wrapper = $element[0];
|
||||
// Query element, but keep selector order
|
||||
const element = _.chain(attr.gridsterAutoHeight.split(','))
|
||||
@ -31,25 +53,22 @@ function gridsterAutoHeight($timeout) {
|
||||
const additionalHeight = 100 + _.last(controller.gridster.margins);
|
||||
const contentsHeight = childrenBounds.bottom - childrenBounds.top;
|
||||
$timeout(() => {
|
||||
controller.sizeY = Math.ceil((contentsHeight + additionalHeight) /
|
||||
const sizeY = Math.ceil((contentsHeight + additionalHeight) /
|
||||
controller.gridster.curRowHeight);
|
||||
if (controller.sizeY !== sizeY) {
|
||||
autoSized = true;
|
||||
controller.sizeY = sizeY;
|
||||
} else {
|
||||
autoSized = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!destroyed) {
|
||||
requestAnimationFrame(updateHeight);
|
||||
}
|
||||
requestAnimationFrame(updateHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (controller.sizeY < 0) {
|
||||
$element.addClass('gridster-auto-height-enabled');
|
||||
updateHeight();
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
destroyed = true;
|
||||
});
|
||||
}
|
||||
updateHeight();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -5,6 +5,30 @@ import template from './dashboard.html';
|
||||
import shareDashboardTemplate from './share-dashboard.html';
|
||||
import './dashboard.less';
|
||||
|
||||
function isWidgetPositionChanged(oldPosition, newPosition) {
|
||||
const fields = ['col', 'row', 'sizeX', 'sizeY', 'autoHeight'];
|
||||
oldPosition = _.pick(oldPosition, fields);
|
||||
newPosition = _.pick(newPosition, fields);
|
||||
return !!_.find(fields, key => newPosition[key] !== oldPosition[key]);
|
||||
}
|
||||
|
||||
function collectWidgetPositions(widgets) {
|
||||
return _.chain(widgets)
|
||||
.map(widget => [widget.id, _.clone(widget.options.position)])
|
||||
.object()
|
||||
.value();
|
||||
}
|
||||
|
||||
function getWidgetsWithChangedPositions(widgets, savedPositions) {
|
||||
return _.filter(widgets, (widget) => {
|
||||
const savedPosition = savedPositions[widget.id];
|
||||
if (!_.isObject(savedPosition)) {
|
||||
return true;
|
||||
}
|
||||
return isWidgetPositionChanged(savedPosition, widget.options.position);
|
||||
});
|
||||
}
|
||||
|
||||
function DashboardCtrl(
|
||||
$rootScope,
|
||||
$routeParams,
|
||||
@ -22,7 +46,11 @@ function DashboardCtrl(
|
||||
toastr,
|
||||
) {
|
||||
this.saveInProgress = false;
|
||||
const saveDashboardLayout = () => {
|
||||
|
||||
// This variable should always be in sync with widgets
|
||||
let savedWidgetPositions = {};
|
||||
|
||||
const saveDashboardLayout = (widgets) => {
|
||||
if (!this.dashboard.canEdit()) {
|
||||
return;
|
||||
}
|
||||
@ -33,7 +61,7 @@ function DashboardCtrl(
|
||||
this.dashboardGridOptions.draggable.enabled = false;
|
||||
this.dashboardGridOptions.resizable.enabled = false;
|
||||
return $q
|
||||
.all(_.map(this.dashboard.widgets, widget => widget.$save()))
|
||||
.all(_.map(widgets, widget => widget.$save()))
|
||||
.then(() => {
|
||||
if (showMessages) {
|
||||
toastr.success('Changes saved.');
|
||||
@ -181,6 +209,8 @@ function DashboardCtrl(
|
||||
$location.search('edit', null);
|
||||
this.editLayout(true);
|
||||
}
|
||||
|
||||
savedWidgetPositions = collectWidgetPositions(dashboard.widgets);
|
||||
},
|
||||
(rejection) => {
|
||||
const statusGroup = Math.floor(rejection.status / 100);
|
||||
@ -233,26 +263,26 @@ function DashboardCtrl(
|
||||
if (enableEditing) {
|
||||
if (!this.layoutEditing) {
|
||||
// Save current positions of widgets
|
||||
_.each(this.dashboard.widgets, (widget) => {
|
||||
widget.$savedPosition = _.clone(widget.options.position);
|
||||
});
|
||||
savedWidgetPositions = collectWidgetPositions(this.dashboard.widgets);
|
||||
}
|
||||
} else {
|
||||
if (applyChanges) {
|
||||
// Clear saved data and save layout
|
||||
_.each(this.dashboard.widgets, (widget) => {
|
||||
widget.$savedPosition = undefined;
|
||||
const changedWidgets = getWidgetsWithChangedPositions(
|
||||
this.dashboard.widgets,
|
||||
savedWidgetPositions,
|
||||
);
|
||||
saveDashboardLayout(changedWidgets).finally(() => {
|
||||
savedWidgetPositions = collectWidgetPositions(this.dashboard.widgets);
|
||||
});
|
||||
saveDashboardLayout();
|
||||
} else {
|
||||
// Revert changes
|
||||
_.each(this.dashboard.widgets, (widget) => {
|
||||
if (_.isObject(widget.$savedPosition)) {
|
||||
widget.options.position = widget.$savedPosition;
|
||||
if (_.isObject(savedWidgetPositions[widget.id])) {
|
||||
widget.options.position = savedWidgetPositions[widget.id];
|
||||
}
|
||||
widget.$savedPosition = undefined;
|
||||
});
|
||||
}
|
||||
savedWidgetPositions = collectWidgetPositions(this.dashboard.widgets);
|
||||
}
|
||||
|
||||
this.layoutEditing = enableEditing;
|
||||
@ -297,19 +327,14 @@ function DashboardCtrl(
|
||||
})
|
||||
.result.then(() => {
|
||||
this.extractGlobalParameters();
|
||||
if (this.layoutEditing) {
|
||||
// Save position of newly added widget (but not entire layout)
|
||||
const widget = _.last(this.dashboard.widgets);
|
||||
if (_.isObject(widget)) {
|
||||
return widget.$save().then(() => {
|
||||
if (this.layoutEditing) {
|
||||
widget.$savedPosition = _.clone(widget.options.position);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Update entire layout
|
||||
return saveDashboardLayout();
|
||||
// Save position of newly added widget (but not entire layout)
|
||||
const widget = _.last(this.dashboard.widgets);
|
||||
if (_.isObject(widget)) {
|
||||
return widget.$save().then(() => {
|
||||
if (this.layoutEditing) {
|
||||
savedWidgetPositions[widget.id] = _.clone(widget.options.position);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -320,7 +345,13 @@ function DashboardCtrl(
|
||||
// We need to wait a bit for `angular-gridster` before it updates widgets,
|
||||
// and only then save new layout
|
||||
$timeout(() => {
|
||||
saveDashboardLayout();
|
||||
const changedWidgets = getWidgetsWithChangedPositions(
|
||||
this.dashboard.widgets,
|
||||
savedWidgetPositions,
|
||||
);
|
||||
saveDashboardLayout(changedWidgets).finally(() => {
|
||||
savedWidgetPositions = collectWidgetPositions(this.dashboard.widgets);
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
|
@ -103,9 +103,13 @@ function Widget($resource, $http, Query, Visualization, dashboardGridOptions) {
|
||||
widget.options.position = extend(
|
||||
{},
|
||||
visualizationOptions,
|
||||
pick(widget.options.position, ['col', 'row', 'sizeX', 'sizeY']),
|
||||
pick(widget.options.position, ['col', 'row', 'sizeX', 'sizeY', 'autoHeight']),
|
||||
);
|
||||
|
||||
if (widget.options.position.sizeY < 0) {
|
||||
widget.options.position.autoHeight = true;
|
||||
}
|
||||
|
||||
return new WidgetResource(widget);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ const DISPLAY_AS_OPTIONS = [
|
||||
const DEFAULT_OPTIONS = {
|
||||
itemsPerPage: 15,
|
||||
defaultRows: -1,
|
||||
defaultColumns: 4,
|
||||
defaultColumns: 3,
|
||||
minColumns: 2,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user