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